
«Из всех искусств для нас важнейшими являются кино и цирк»
— В.И. Ленин
Просмотр видео — одно из любимых развлечений в современном мире, фильмы сейчас смотрят практически на всех устройствах, даже на холодильниках. К сожалению, рядом не оказалось подходящего холодильника, и я решил просмотреть фильм на сканере штрихкодов. Под рукой оказался сканер Cipher Lab 8001. Технические характеристики
- 16-битный CMOS процессор
- 1 Мб памяти для программ
- 1 Мб SRAM для данных
- FSTN дисплей с LED подсветкой разрешением 100×64
1 Мб памяти должно было хватить для хранения ролика, но это бы лишило плеер интерактивности, и усложнило процесс разработки. Поэтому выводить на экран будем данные, которые поступают непосредственно с инфракрасного порта. Также для простоты не используются крайние 4 столбца экрана. Итоговое разрешение картинки 96×64 (количество точек в строке кратно размеру байта).
Прошивка сканера
В прошивке нет ничего сложного:
- Считываем данные с инфракрасного порта;
- выводим на экран;
- посылаем компьютеру запрос на следующий кадр.
Единственное, на что следует обратить внимание — размер входящего буфера ограничен 256 байтам. А так как размер целого кадра 96×64/8 = 768 байт, нам придется разбить кадр на 4 блока по 16 строчек. Да, данные влезли бы в 3 блока по 256 байт, но хотелось, чтобы номер блока передавался как первый байт входного буфера.
int PlaceFromCom(void) {
long timer;
int position;
char c, picture[BLOCK_SIZE];
unsigned char blockId, loaded;
SendRequest();
timer = sys_msec;
loaded = 0;
position = 0;
while (sys_msec <= timer + TIMEOUT_MSEC) {
if (read_com(COM_PORT_NUM, &c)){
picture[position] = c;
position++;
if (position == BLOCK_SIZE){
loaded = 1;
break;
}
}
}
if (!loaded){
printf("Comm error\r\n");
return 1;
}
blockId = (picture[0] % 4);
show_image (0, blockId * BLOCK_H, IMAGE_WIDTH, BLOCK_H, &(picture[1]));
return 0;
}
Программа вывода
Программа для вывода видео в COM выглядит еще проще, чем прошивка:
- Делаем скриншот экрана;
- меняем его размер и конвертируем в двухцветное изображение;
- разбиваем на блоки и конвертируем в поток байтов;
- ждем запроса от сканера, возвращаем буфер.
По какой-то причине снятие скриншота в Питоне занимает очень много времени, поэтому в программе это действие вынесено в отдельный поток. Остальной код тривиален. Например, цикл вывода:
while True:
data = ser.read(9999)
if len(data) > 0:
if data[0] == "V":
ser.write(chr(currentBlock))
ser.write(desktop.strings[currentBlock])
currentBlock = (currentBlock + 1) % blockCount
Результат работы
Исходники программ можно скачать тут.