Электронная книжка в качестве дисплея

dlinyj 5 октября 2012 в 01:56 56,6k
Нетрадиционное применение распространённых вещей — это то, что всегда нам интересно! Ведь так хочется порой похачить очередное устройство. Понять как оно работает и внести какие-то свои коррективы в его работу, добавив новых функций.


Выводим свои картинки

Я расскажу, как можно старенькую читалку Sony PRS-505 превратить в удобный дисплейчик. И также расскажу, как можно писать свои программы для этой книжечки



Постановка задачи



Для одного устройства мне понадобился дисплейчик для отображения графиков и экспериментальных данных. Данные должны отображаться нечасто, но желательно чтобы дисплей был с низким энергопотреблением, большого размера и с неплохим разрешением.
Моё исходное устройство бегает под линуксом и имеет USB-host. Сначала я поглядел в сторону дисплея Vogue, но отмёл его по причине небольших размеров и разрешения. Начал искать дальше.
У меня давно без дела валяется электронная книжка PRS-505. Достал я его и положил перед собой, помня что там внутрях линукс и я где-то слышал, что можно достучатся до него через консоль. Но так же понимая, что эта вещь в себе. Положил и забыл.

Через некоторое время я пошёл в поход с товарищем Vshmuk и внезапно увидел, что он читает точно такую же книжку. И поведал ему свои мысли. В ответ на что был осмеян — как оказалось уважаемый камрад как-то писал в Хакер статью, о том как получить аппаратный доступ к этой книжке, а самое главное, что он сказал, что у этой штуки есть Фреймбуффер, как у десткопа, и с ним можно даже работать.

Нормальные люди в походе наслаждаются природой...

Для тех, кто не понимает в линухах, поясняю, что фреймбуффер — это файл в линуксе (как и любое устройство в общем-то), в который можно (теоретически), тупо записать файл-слепок памяти, и вывести его на экран. Так же можно сделать аппаратный скриншот, т.е. просто сдампить видеопамять, скопировав этот файл в другое место и просмотреть его, скопировав (точнее записав в) его обратно.

Зачем это нужно:
Зачем это нужно: Например на целевой машине идёт видеовывод в виртуальный экран, с разрешением, равным разрешению книжки (а именно 600х800). Далее периодически, берётся файл фреймбуффера виртуального экрана и перенаправляется в сом-порт, а на том конце из ком-порта, командой cat это перенаправляется во фреймбуффер книжки.

Иллюстрирую, все команды выполняются на целевой машине, книжка подключена по UART, через VCP, который висит на /dev/ ttyUSB0. Комманды вызываются раз в несколько минут, например в кроне.

echo «cat /dev/ttyS0 >/dev/fb0» > /dev/ttyUSB0

Эта команда по UART передаёт команду перенаправлять содержимое файла СОМ-порта во фреймбуффер. Следом идёт вторая команда:

cat /dev/fbn > /dev/ttyUSB0

Эта команда передаёт содержимое виртуального экрана fbn (где n-номер экрана) в СОМ-порт. Всё должно отработать прекрасно, передача кончится по приходу символа конца файла.


Приступаем к делу



Когда мы вернулись из нашего эпичного похода, я разыскал его статью www.xakep.ru/magazine/xa/129/092/1.asp и дальше понеслась.

Первоначально я разобрал книжку, и припаялся к отладочной консоли, используя микросхему ft232rl для сопряжения интерфейсов (см. мой пост «UART и с чем его едят» — habrahabr.ru/post/109395 )


Распатроненная читалка с подпаянным интерфейсом


Вид сзади

Подробнее о том, как и к каким контактам подпаиваться, можно прочитать тут: www.the-ebook.org/forum/viewtopic.php?p=120092#120092

Я не хочу заниматься цитированием статьи камрада Vshmuk о том как залогиниться, какие процессы надо убить и т. п. Лучше всего прочитать у него в этой статье. Скажу лишь: эмпирически установлено, что при подключённой книжке к компьютеру по штатному USB никаких процессов убивать не надо, всё работает и так. В качестве терминалки я использую любимый minicom.
После подпайки я начал проводить изучение операционки. Перво-наперво поглядел скрипт, о котором говорится в статье, что он всё монтирует и выводит загрузочную картинку. Поглядим же, что это за зверь такой:

root@(none):/# cat /etc/rc.d/rcS.d/S20libromount

из всего форшмака, что там вывалилось, нам наиболее интересно вот что:

# display booting image 
/usr/local/sony/bin/nblconfig -dump | head -3 | awk '{print $9}' | grep 02 > /dev/null
if [ $? == 0 ]; then
        # init screen load
        grep BootImg /proc/mtd > /dev/null
        if [ $? == 0 ]; then
                NUM=`grep BootImg /proc/mtd | awk -F: '{print $1}' | awk -Fd '{print$2}'`
                dd if=/dev/mtd$NUM of=/dev/fb0 bs=256 count=1875
                /opt/sony/ebook/bin/writescreen init 0
        else
                /opt/sony/ebook/bin/writescreen init 1
                echo no boot image
        fi
else
        /opt/sony/ebook/bin/writescreen init 1
fi
...


Я решил попробовать забить случайным фаршем экран, и сделал вот такую команду:

root@(none):/# dd if=/dev/urandom of=/dev/fb0 bs=256 count=1875
1875+0 records in
1875+0 records out

Но ничего не произошло…

Попробуем выполнить следующую команду:

root@(none):/# /opt/sony/ebook/bin/writescreen init 0
latest nblconfig read from 0x00035000
latest nblconfig written to 0x00035800
И… чуда не произошло. Более того, команда
root@(none):/# /opt/sony/ebook/bin/writescreen init 1


тупо гасит экран и всё, после чего он уже не подавал признаков жизни.

В общем нахрапом решить проблему не удалось. Посему я переключился на аппаратную часть. Начал думать, как мне аккуратнее сделать книжку, т. к. эти сопли из тонких проводов легко могут оторваться. В результате я вывел отладочную консоль через разъём наушников. Там производители прямо возле разъёма предусмотрели нульомные резисторы, которые я благополучно снял и повесил туда два провода RX и TX, а землю оставил от наушников. Она оказалась гальванически не развязанной с цифрой.


Выведенный отладочный порт на аудиоразъём

После того, как я закончил эксперименты, я решил попробовать прямо через консоль погонять файлики. Это нужно, чтобы не тянуть два провода и не расходовать ресурс флешки (запись изображения на флешку, затем воспроизведение). Передача с книжки на комп у меня вполне удалась, а вот обратно уже нет.

Для эксперимента я попробовал передать файл картинки. Помните я выше уже говорил о скрипте вывода загрузочной картинки? Он её читает с раздела NAND-флешки читалки и записывает его во фреймбуффер:

NUM=`grep BootImg /proc/mtd | awk -F: '{print $1}' | awk -Fd '{print$2}'`
dd if=/dev/mtd$NUM of=/dev/fb0 bs=256 count=1875
/opt/sony/ebook/bin/writescreen init 0


Первой строчкой определяется раздел на котором лежит картинка. Выполним эту команду (которая находися в одинарных кавычках), и узнаем номер раздела. В моём случае он был равен девяти.

Ну дальше вторую команду немного поправим, чтобы передача велась в СОМ-порт. Опытным путём установил, что консоль для приёмо-передачи — это файл /dev/tty. Перебрасываем картинку, для этого на компе закрываем терминал и выполняем:

cat /dev/ttyUSB2 > bootimg.raw, где ttyUSB2 — это мой интерфейс VCP на базе ft232rl.

После чего в другой консоли компьютера даём команду:

echo «dd if=/dev/mtd9 of=/dev/tty bs=256 count=1875» > /dev/ttyUSB2, что посылает через консоль команду передачи образа по консоли.

Преобразуем эту картинку из бинарного слепка в png:

echo -e «P5\n800 600\n255\n» >result.pgm
cat bootimg.raw>>result.pgm
convert result.pgm result.png


В результате получаем вот такую картинку. Я не знаю почему её так перекособочило, но явно были какие-то ошибки передачи.

image
Полученная картинка

Кстати, что из себя представляет картинка, которую можно записать во фреймбуффер? Это битовая маска, где каждый байт равен цвету пикселя и весит она ровно 800х600 = 480000 байт. Следовательно картинка, которую мы хотим передать во фрейм буффер должна быть размером 800х600 и весить ровно 480000 байт. По сути это и есть *.pgm-файл, только с отрезанным заголовком.
Обратно мне не удалось передать файл. Видимо потому, что консоль является стандартным устройством ввода, и ей не нравятся непечатные символы. Подробнее об этих экспериментах можно почитать тут: dlinyj.livejournal.com/608961.html.

Поняв, что у меня пока с программой не получается, я решил убрать книжку в корпус, благо теперь уже ничего не мешало это сделать.

После исследования системы, скриптов, стало понятно, что средствами консоли вывести на экран изображение не представляется возможным. Мне подсказали, что уже один товарищ решал эту задачу и даже описывал ещё в своём блоге systemsand.me/sony-prs-300prs-505-hack. Говоря кратко, программу писать придётся, хотя она будет и очень простой.

Я скачал тулчейн (говоря проще компилятор для сборки, хотя это и не совсем точно) отсюда www.mentor.com/embedded-software/sourcery-tools/sourcery-codebench/editions/lite-edition немного попарившись с регистрацией, я таки накатил его на свою любимую убунту. И попробовал собрать hello word

Для справки, собирался он командой arm-none-linux-gnueabi-gcc -mcpu=arm920t hello.c -o hello

Самое главное было то, как передать полученный файл на книжку. Я заметил, что при подключённом USB на компе видится некий диск, объёмом примерно 200 метров. Но в системе на книжке его нет.

У меня есть вся прошивка кникжи, и я понял что жёский диск используется в приложении книги (имеется в виду то, для чего предназначено устройство). Это файлик cramfs.Fsk.img
Я примонтировал этот образ на своём компьютере и поглядел скрипт sony/ebook/bin/tinyhttp.sh. Как это сделать опять же описано в статье в Хакере. Троло пыщ пыщ, никто не читает. Это тот самый скрипт, который мы придушиваем в самом начале, чтобы получить консоль, согласно статье Vshmuk. И там была такая строка:

NUM=`grep Data /proc/mtd | awk -F: '{print $1}' | awk -Fd '{print$2}'`
/usr/local/sony/bin/mkdosfs /dev/mtdblock$NUM


Опять же первая строчка получает номер устройства. Выполнив первый скрипт (то что в кавычка), я получил число семнадцать, и дальше подмонтировал /dev/mtdblock17 в /tmp/t1. Объяснить как я понял, что именно это будет флешкой я не могу, но просто логика подсказала, что именно в этом файле должна идти инициализация пользовательских данных.

И в результате я увидел содержимое диска, которое я вижу на своём компе.

И я решил попробовать его запустить:

root@(none):/tmp/t1# ls
Digital Editions autorun.inf database hello tmp
root@(none):/tmp/t1# cp hello /tmp/
root@(none):/tmp/t1# cd…
root@(none):/tmp# ls
hello t1
root@(none):/tmp# ./hello
bash: ./hello: No such file or directory
root@(none):/tmp# chmod +x hello
root@(none):/tmp# ./hello
bash: ./hello: No such file or directory


Умные люди подсказали, что там может не хватать нужных библиотек, и посоветовали собрать с опцией -static. После этого всё стало ещё хуже

root@(none):/tmp# ./hello
Segmentation fault


Стало понятно, что надо искать компилятор. Благодаря помощи многих людей, я узнал что под эту книжку пилят альтернативную прошивку openinkpot.org/wiki! А следовательно тулчейн должен быть.

Начал гуглить Поиском «prs-505 toolchain» он был найден тут code.google.com/p/prs-plus/downloads/detail?name=arm-toolchain-sony-300.tar.gz&can=4&q=. После чего хелло ворд завёлся без проблем (даже без статика!). Ну дальше дело техники, согласно systemsand.me/sony-prs-300prs-505-hack набросал небольшую программку

/* showpic.c */
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <string.h>


#define FBIO_EINK_GET_TEMPERATURE        0x46A1    //Returns temperature in degree Celsius
#define FBIO_EINK_DISP_PIC                0x46A2    //Displays picture

int main (int argc, char* argv[])
{
    printf ("Show image\n");

    int *fb, *image;
    int pio_fd = open ( "/dev/fb0", O_RDWR);
    int f_image = open ( argv[1], O_RDWR);                                 //open file into arg
    int t= ioctl (pio_fd, FBIO_EINK_GET_TEMPERATURE, NULL);    //configure framebuffer

    fb= mmap(0, 800*600, PROT_WRITE, MAP_SHARED, pio_fd, 0);    //map device into memory
    image= mmap(0, 800*600, PROT_READ, MAP_SHARED, f_image, 0); //load image into memory
    
    memcpy(fb,image,800*600);
    ioctl (pio_fd, FBIO_EINK_DISP_PIC, 0);
    
    close(pio_fd);
    close(f_image);
    return 0;
}


Дефайны взял из кода драёвера с сайта Sony www.sony.net/Products/Linux/Audio/PRS-505.html файл 8track20070714.tgz

Компилировал примитивнной командой с минимум опций: path to toolchain/arm-unknown-linux-gnu-gcc -static showpic.c -o showpic

Без статика не захотел работать.

Теперь в gimp создаём картинку с разрешением 800х600, рисуем что хотим и сохраняем как habrahabr.pgm.


Мои художества

Вы простите мои художества. Мне было лениво особо стараться.

После чего открываем его в любом хекс-редакторе и удаляем весь заголовок до FF


Удаляем заголовок

Заливаем на жёсткий диск книжки. Лезем в консоль и выполняем:

root@(none):/# cd tmp/
root@(none):/tmp# mkdir t1
root@(none):/tmp# mount /dev/mtdblock17 t1
root@(none):/tmp# cd t1/
root@(none):/tmp/t1# ls
Digital Editions autorun.inf habrahabr.raw showpic
a.out database send.raw tmp
root@(none):/tmp/t1# ./showpic habrahabr.raw
Show image
root@(none):/tmp/t1#


И видим:


Фаршмак

ой! Это мы картинку не повернули. Поворачиваем исходную картинку в gimp на 90 градусов и повторяем процедуры. В результате нашему взору предстанет


Что и требовалось доказать!

Итоги



Мне удалось написать свою программу для книжки и даже выводить картинки. Надо сказать, что цель выводить графики gnuplot. Сей пакет прекрасно умеет генерировать сам файлы pgm, и остаётся только командой dd отрезать заголовок.


Пример графика

Главная проблема, которая сейчас не решена — это как передавать файлы графиков на книжку. Я хотел это делать прямо по отладочной консоли, но для этого надо уметь её отучать быть консолью и превращать в обычный UART. Как это сделать я не знаю. Ещё более того, я думаю это делать на лету.
Мне подсказывают, что можно собрать драйвер, чтобы устройство виделось как COM-порт по USB, но мне кажется что это может вылиться в тот ещё гемморой. Я думаю можно попробовать создать папку на флешке, а в неё монтировать виртуальную временную файловую систему в оперативной памяти. Я не пробовал ещё этот метод. Но передача файла через флешку является абсурдным и неразумным решением.
В общем вопрос остаётся открытым и я готов услышать все разумные предложения по этому поводу.

Благодарности


Выражаю благодарности всем людям, которые помогли и помогают мне в этом странном проекте. Надеюсь их будет ещё больше

Ссылки:


1.Исходная статья в Хакере www.xakep.ru/magazine/xa/129/092/1.asp откуда я начал свой эксперимент.
2.Инструкция по подпайке книжки www.the-ebook.org/forum/viewtopic.php?p=120092#120092
3.Аналогичную задачу решал наш соотечественник так systemsand.me/sony-prs-300prs-505-hack к сожалению, он не смог мне помочь исходниками и тулчейном.
4.Исходные тексты прошивки книжки и драйверов www.sony.net/Products/Linux/Audio/PRS-505.html
5.Открытый проект альтернативной прошивки openinkpot.org/wiki
6.Рабочий тулчейн code.google.com/p/prs-plus/downloads/detail?name=arm-toolchain-sony-300.tar.gz&can=4&q=
7. О моих муках с книжкой можно прочитать у меня в ЖЖ dlinyj.livejournal.com/tag/prs-505

P.S. Я не очень грамотный человек, буду очень признателен за личные сообщения с помарками, чтобы статья выглядела более достойно.
P.P.S.Так же замечания по сути приму с удовольствием. Я не крутой разработчик ПО под Linux, хотя очень хотелось бы им стать :).

Помните лучшая благодарность автору за пост — это оставленный комментарий!

UPD Пока спал придумал, как решить проблему с текстовым вводом и консолью. Ничего не мешает файл передавать в текстовом виде. Нужно немного переписать файлик, чтобы он принимал данные из кинсоли, и передавать ему две команды:
start — начало передачи и stop — окончание. Далее считывать на исходном компьютере передаваемый файл по байтам и разбивать байт на ниблы (пол байта). Нибл принимает значение от 0 до 15 или в HEX от 0 до F. Ну и передавать символ от нуля до F. На стороне книжки делать обратное преобразование текстовых ниблов в байты. Начало передачи обозначает start, конец stop. Контролируем передачу по эху консоли.
Это займёт в два раза больше времени, но зато решение самое простое и очевидное.
Побежал писать программу!
UPD-UPD Спустя 5 лет написал программу превращающую книжку в часы. Код на гитхабе github.com/dlinyj/sony_prs-505_clock
Проголосовать:
+125
Сохранить: