Продолжим тему разработки под ушедшие в историю платформы. Сегодня расскажем про органайзеры Casio серии Pocket Viewer, бывшие популярными в узких кругах в первой половине нулевых.
В ходе статьи узнаем, как и на чём под него писать, где взять софт, какие остались тематические сайты, а также много чего интересного.
Что это такое?
Casio Pocket Viewer позиционировался как электронный органайзер (при этом стоил он куда дешевле КПК «старших» моделей, который были основаны уже на Pocket PC и выпускались под линейкой Cassiopeia). Выпускалось их весьма большое количество моделей, но наибольшую популярность получили PV-S250 (PV-S450) и PV-S460 (PV-S660). Все они основаны на встраиваемой системе (на базе процессора NEC V30), имели монохромный экран разрешением 160х160, подключались к компьютеру по RS-232, работали на проприетарной ОС Pocket Viewer OS (или просто PVOS). Отличительной чертой был накопитель на флеш-памяти (первая цифра номера модели означает число её мегабайт), благодаря которому не требовалось постоянно следить за зарядом батареек, чтобы не потерять данные. Также поддерживалось и обновление ОС. Минусом этого варианта было низкое быстродействие — сохранение чего-либо занимало видимые секунды.
Таким образом, Casio PV был едва ли не последним массово производившимся КПК на базе процессора с архитектурой X86 (различные околопромышленные устройства вроде ТСД Symbol PDT или Psion Workabout в расчёт не берём). Последняя выпущенная модель, PV-S1600 имела подключение по USB и работала на процессоре SH-3, чем сильно отличалась от «классического» Pocket Viewer.
Главным конкурентом Pocket Viewer’а (в частности, модели PV-S450) был КПК Palm M100/M105, с которым чаще всего и сравнивался данный аппарат. PV имел ряд выгодных преимуществ: энергонезависимая память, колёсико прокрутки, удобное для чтения книг, большой экран, небывалое даже тогда время работы от батарей, стильный тонкий дизайн. Palm в ответ «брал» большим количеством приложений и лучшим, нежели PV, быстродействием.
В мои руки попал Casio PV-S450. Именно о нём и пойдёт речь дальше. Впрочем, всё, что будет сказано далее, справедливо для всех остальных моделей Casio Pocket Viewer на базе процессора x86. Устройства модели PV-S1600 у меня нет, так что тему разработки под него оставим до лучших времён. Также под управлением PVOS работали калькуляторы Casio ClassPad. За неимением у меня такого устройства, упоминание его тоже пока что скромно опустим.
Почему именно PV-S450?
На самом деле ставку на какую бы то ни было популярность этой модели я не делал. Всё дело в том, что PV-S450 был единственным экземпляром, который мне удалось достать в комплектном состоянии. На всем известном сайте объявлений можно найти устройства вместе с подставкой, но на момент написания статьи цена на все из них выходит далеко за рамки приличия.
На всякий случай напомню: единственно возможная связь с внешним миром обеспечивается через интерфейс RS-232. Casio PV не оснащён ни ИК-портом (за исключением одной-единственной модели, но установка приложений там не поддерживается, увы), ни каким-либо другим беспроводным интерфейсом, так что подключить его как-то иначе вряд ли выйдет. Кроме того, разъём подключения проприетарный (не думаю, что в обычном магазине радиодеталей вы его найдёте), так что покупка Casio PV без кабеля или подставки — крайне такое себе решение.
Также стоит учесть, что установка приложений возможна только на те КПК, в названии модели которых есть буква S (что, видимо, означает «Software»).
Обзор оборудования
Прежде чем переходить к средствам разработки, рассмотрим вначале сам органайзер.
У моего экземпляра интересное прошлое: ранее он принадлежал Дмитрию Newbilius Моисееву. Засветившись в его обзоре на YouTube, он был выставлен на вторичку и позже был приобретён мною. Ну что же, пришло его время снова оказаться продемонстрированным на просторах сети.
Экран КПК защищает пластиковая крышечка, которая у моего экземпляра даже умудрилась не отломаться и дожить до наших дней.
Помимо сенсорного экрана с сенсорными же подэкранными кнопками никаких элементов управления на передней панели нет.
На обратной стороне переключатель блокировки крышки отсека батареек (а заодно и выключатель питания), кнопка перезагрузки (у данного экземпляра она запала и не нажимается. Это особенность конкретного устройства: Pocket Viewer’ов у меня два, и на втором всё отлично работает), этикетка с моделью.
Слева джойстик прокрутки. Именно за этот элемент управления многие любили PV — читать на этом устройстве было очень удобно. Это не колёсико, аналогичное JogDial на КПК Sony, это именно джойстик, который можно нажимать или наклонять в две стороны.
На фото для сравнения джойстик у PV и у Sony Clié.
Снизу тот самый проприетарный разъём для подключения к компьютеру.
А вот и подставка. Весьма удобная, кстати.
Разбирать КПК я не стал: побоялся сломать защёлки. Но на просторах обнаружились фото внутренностей.
Отчётливо видны процессор системы «китайская капля», микросхема памяти (на фото представлена модель PV-S250, рядом видно место для ещё одной, которая установлена в модели PV-S450), ОЗУ, шлейфы, катушка преобразователя для ЭЛИ-подсветки.
Pocket Viewer SDK
Casio приняла правильное решение: средства разработки под данный КПК находились полностью в открытом доступе. В лучшие времена SDK можно было скачать с официального сайта.
Хотя для древнего софта правило «интернет ничего не забывает» традиционно не работает, SDK удалось найти вообще без проблем — находился он тут. Internet Archive продолжает радовать: помимо SDK обнаружились и архивы некоторых ныне ушедших в историю тематических сайтов.
Итак, для начала разработки под Casio PV понадобится примерно следующее:
- Компьютер с ОС Windows 98/NT/2000 или виртуальная машина с таковой. На современные ОС установить SDK не выходит: инсталлятор банально не запускается. Впрочем, ничто не мешает поставить его на старой ОС, а затем перенести папки на новую, все компоненты запускаются даже на Windows 10 x64.
- Собственно, сам Pocket Viewer SDK. Где его взять, уже было сказано чуть выше. Для вашего удобства все ссылки будут продублированы в конце поста.
- Любой удобный для вас редактор кода, например, тот же Notepad++. Впрочем, при желании можно использовать и банальный «Блокнот».
- Casio PVOS Application Manager. Позволяет устанавливать приложения в формате *.bin на реальный КПК. Также есть версия на русском языке.
- КПК с подставкой для подключения к компьютеру. На нём будем запускать протестированные в эмуляторе приложения. Также следует отметить, что компьютер должен быть оснащён COM-портом. Различные переходники USB2COM работают, но крайне плохо.
Ставим софт
Установка SDK каких-любо нюансов не имеет, ставится он как и любое другое Windows-приложение. Так что документировать данный процесс смысла не вижу. После установки в корне системного диска появятся папки LSIJ и CASIO. В первой находится компилятор LSIC86PV, позволяющий собрать приложение для Pocket Viewer OS. Во второй будет находиться вложенная папка (название зависит от версии установленного вами SDK), где лежат все остальные средства разработки: библиотеки, примеры программ (впрочем, для введения в разработку под PVOS они сложноваты), документация, эмулятор, Application Manager.
Больше никаких манипуляций типа установки PATH или чего-то вроде этого не требуется.
Симулятор
В папке SIM находится симулятор данного КПК. Это не полный его эмулятор, то есть вполне возможно, что поведение программы в нём и на реальном устройстве будет отличаться. С этим ничего не поделать.
Для запуска открываем имеющийся в папке рядом с ним проект PV-S450 и всё, можно запускать.
Для того, чтобы поменять установленное приложение, жмём на панели меню «Project», далее «Configuration», в открывшемся окне переходим на вкладку «Chips».
Далее ищем в списке «SAMPLE», жмякаем правой кнопкой мыши, выбираем «Proparties» (угу, так и написано), выбираем нужный нам бинарник вместо sample.bin.
Не забываем после каждого изменения (например, после очередной компиляции) перезагрузить наш виртуальный КПК.
Разумеется, можно использовать данную прогу не только для разработки, а ещё и для того, чтобы запустить софт для PVOS при отсутствии самого КПК.
Application Manager
Для установки и удаления приложений на реальном КПК существует Application Manager. Пользоваться им предельно просто: запускаем программу, насаживаем КПК на подставку, инициируем загрузку (через кнопку «Menu bar» из главного экрана, а не кнопкой на подставке, иначе будет ошибка связи!), запускаем обмен данными крайней левой кнопочкой на панели меню Application Manager.
Установив связь и получив список программ, добавляем или удаляем нужные, а затем производим обмен данными (той же самой кнопкой или «Execute\Update PV»). Всё, приложение установлено (ну, или снесено).
Структура проекта
Итак, заглянем в папку C и посмотрим, что же у нас там лежит. В папке Bin хранятся скомпилированные бинарники, пригодные для загрузки в КПК или запуска в симуляторе. Также есть несколько папок с библиотеками, а также разделы Sample и Sample1. Это и есть проекты. Откроем какой-нибудь из них. В каждой из этих двух папок лежит Makefile, батник для сборки, каталоги с исходниками. Также есть папка MENUICON — там хранится иконка приложения для отображения в списке в главном меню.
Запустим батник и убедимся, что проект успешно компилируется.
Пишем первую программу
Ну что, со сборкой разобрались. Пришло время написать что-то своё. Итак, создаём в папке C ещё какую-нибудь папку, скажем, Test. А в ней — такую же структуру папок, какую видели в других проектах. Копируем также содержимое MENUICON.
Берём MAKEFILE из уже имеющегося проекта и слегка модифицируем его под наши задачи. Примерно так:
#Makefile for PocketViewer2 Sample Program
include ..\COM_LNK\MakeSDK.1
### -------- Define Make Application -------- ###
#== TargetName ==
TARGET = test
#== Program Name ==
PROGNAME = "test"
#== ProgramVersion(EX. 0100->Ver1.00) ==
VERSION = 0100
#== MenuIcon (Xsize=45dot,Ysize=28dot) ==
MICON = menuicon\icon.bmp
#== ListMenuIcon (Xsize=27dot,Ysize=20dot) ==
LICON = menuicon\Licon.bmp
#== CompileObjectFile ==
APLOBJS = $(ODIR)\test.obj
### ----------------------------------------- ###
include ..\COM_LNK\MakeSDK.2
В папке C создаём какой-нибудь файл, скажем, test.c. И пишем там следующее:
#include<stdrom.h> #include"define.h" #include"libc.h" TCHTBL TchList[1] = { 0, 0, 0, 0, ACT_NONE, OBJ_END, 0x0000 }; void main() { TCHSTS tsts; LibTchStackClr(); LibTchStackPush(NULL); LibTchStackPush(TchHardIcon); LibTchStackPush(&TchList[0]); LibClrDisp(); LibPutDisp(); LibTchInit(); while(1) { LibTchWait(&tsts); } LibTchStackClr(); LibJumpMenu(); }
С батником для сборки заморачиваться не будем — позаимствуем его у того же предыдущего проекта. Запускаем его. Если всё было сделано правильно, компиляция должна пройти успешно, а в папке Bin появится наш бинарник test.bin. Загружаем его в симулятор и пробуем запускать. И получаем совершенно пустой экран. Да, всё так и должно быть. Что важно, КПК при этом не завис, не перезагрузился и никак иначе не заглючил. Нажмём «Menu», и программа закроется.
Что тут происходит?
Теперь разберёмся, как оно вообще работает.
TCHSTS tsts; — создание структуры для работы с сенсорным экраном. Именно из неё мы будем получать все данные о касаниях.
Следующие четыре строки — инициализация стека сенсорного экрана. В ходе данной процедуры мы очищаем стек и загружаем туда две таблицы — TchHardIcon и TchList. Таблица касаний — это сведения о каждом объекте на сенсорном экране, доступном для касания. Первая из них — это подэкранные кнопки (Menu, Esc и все остальные), вторая — пользовательские объекты. Их определяет созданный в начале текста программы массив:
TCHTBL TchList[1] = { 0, 0, 0, 0, ACT_NONE, OBJ_END, 0x0000 };
Именно в него должны будут записываться данные обо всех размещённых нами на экране элементах управления. Для каждого элемента необходимо указать координаты, в пределах которых на него можно нажать, а также ряд параметров вроде ID этого объекта. Подробнее об этом поговорим чуть позже.
Следом идут ещё две команды — LibClrDisp() и LibPutDisp(). Первая из них производит очистку, вторая — выводит на дисплей содержимое экранного буфера. Без вызова LibPutDisp() изображение на экране останется без изменений.
Далее идёт бесконечный цикл, в котором мы вызываем функцию LibTchWait(&tsts). Дело в том, что для получения данных сенсорного экрана его необходимо постоянно опрашивать. Если мы уберём эту функцию, при запуске программы она зависнет, не в силах считать даже нажатие кнопки «Menu». После опроса мы можем получить данные о том, что было нажато на экране.
И, напоследок, очистка стека тачскрина и выход в меню.
Hello, world!
Попробуем вывести что-то на экран. Для этого предусмотрена функция LibStringDisp().
Добавим её в нашу первую программу:
#include<stdrom.h> #include"define.h" #include"libc.h" TCHTBL TchList[1] = { 0, 0, 0, 0, ACT_NONE, OBJ_END, 0x0000 }; void main() { TCHSTS tsts; char * str = "Hello, Habrahabr!"; LibTchStackClr(); LibTchStackPush(NULL); LibTchStackPush(TchHardIcon); LibTchStackPush(&TchList[0]); LibClrDisp(); LibPutDisp(); LibTchInit(); LibStringDsp(str,0,0,100,IB_PFONT2); LibPutDisp(); while(1) { LibTchWait(&tsts); } LibTchStackClr(); LibJumpMenu(); }
Первый аргумент данной функции — указатель на строку, далее идут координаты, максимальный размер (в пикселях) и шрифт.
Компилируем, загружаем в симулятор:
Работает. Кто бы сомневался. Время загрузить в «железный» девайс. Открываем Application Manager, соединяемся…
Жмём на иконку нашего приложения, и на экране появляется примерно следующее:
Отлично. Работает.
BMP
Вывели текст — попробуем вывести и картинку. Такую, например:
Разумеется, нельзя просто так взять и загрузить её в память PV. Для этого необходимо сделать ряд нехитрых манипуляций.
Перво-наперво, откроем Photoshop и сделаем её такой:
Обесцветим её, а заодно и подгоним под размер экрана.
Теперь откроем папку Tools из комплекта SDK, где лежит утилита для преобразования BMPшек в массив. Запускаем её, открываем в ней нашу картинку, конвертируем:
На выходе получаем файл с расширением *.BMT. Не буду копировать всё его содержимое, покажу только первые несколько строк:
GSIZE(152, 160), 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0x83, 0x8F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFB, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFD, 0xFC, 0x01, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFB, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFD, 0xDF, 0xFE, 0x82, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFB, 0xBF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0xD9, 0xFF, 0x80, 0xF7, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0xD9, 0x8F, 0x80, 0xD7, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xEF, 0xBE, 0xCF, 0xFF, 0xFD, 0xFF, 0xFF, 0xFC, 0x60, 0x0F, 0x80, 0x27, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xEF, 0x3B, 0xCF, 0xFF, 0xFC, 0xFF, 0xFD, 0xFC, 0x00, 0x0F, 0x00, 0x3F, 0xFF, 0xFF, 0xFF,
Первые байты массива отражают размер картинки, далее идёт стандартный bitmap.
Программа в итоге получается такая:
#include<stdrom.h> #include"define.h" #include"libc.h" #include "l_define.h" #include "l_libc.h" #define OBJ_ICN1 0x9000 TCHTBL TchList[2] = { 0, 0, 152, 160, ACT_ICON, OBJ_ICN1, 0x0000, 0, 0, 0, 0, ACT_NONE, OBJ_END, 0x0000 }; byte bitmap[] = { /*Вот здесь должно быть полное содержимое *.BMT-файла*/ }; T_ICON newIcon = {&TchList[0], bitmap, NULL, 0x01}; void main() { TCHSTS tsts; LibTchStackClr(); LibTchStackPush(NULL); LibTchStackPush(TchHardIcon); LibTchStackPush(&TchList[0]); LibClrDisp(); LibIconPrint(&newIcon); LibPutDisp(); LibTchInit(); while(1) { LibTchWait(&tsts); } LibTchStackClr(); LibJumpMenu(); }
OBJ_ICN1 — это ID элемента, находящегося на экране. В качестве него можно взять любое значение в диапазоне 0x8000-0xFFFF. Далее пропишем нашу картинку в TchList. Укажем координаты (x1, y1, x2, y2), а также то, что этот объект — иконка. Создадим массив байт, куда скопируем наш файл *.BMT, а также объект newIcon — он связывает элемент из TchList и изображение. В функции main() добавится строка LibIconPrint(&newIcon); — вывод картинки на экран.
Компилируем, и всё, можно запускать!
Кнопки
Рассмотрим теперь работу с кнопками. Вообще, в PVOS нет понятия кнопок, есть просто область на экране, нажатия на которую мы отслеживаем. Но тыкать в пустое место не хочется, поэтому обозначим место кнопки соответствующей BMPшкой.
Откроем папку DOC\GRAPHICS. Там лежит целая куча картинок, что называется, на все случаи жизни. Берём какую-нибудь из них и перегоняем в BMT:
И пишем вот такую программу:
#include<stdrom.h> #include"define.h" #include"libc.h" #include "l_define.h" #include "l_libc.h" #define OBJ_BTN1 0x9000 TCHTBL TchList[2] = { 25, 25, 25 + 45, 25 + 28, ACT_ICON, OBJ_BTN1, 0x0000, 0, 0, 0, 0, ACT_NONE, OBJ_END, 0x0000 }; byte bitmap[] = { GSIZE(45, 28), 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x7F, 0xFF, 0xFF, 0xE0, 0x07, 0x00, 0x40, 0x00, 0x00, 0x30, 0x07, 0x00, 0x40, 0x00, 0x00, 0x30, 0x07, 0x00, 0x40, 0x1C, 0x00, 0x30, 0x07, 0x00, 0x40, 0x27, 0x80, 0x30, 0x07, 0x00, 0x40, 0x20, 0xE0, 0x30, 0x07, 0x00, 0x40, 0x58, 0x38, 0x30, 0x07, 0x00, 0x40, 0x5E, 0x14, 0x30, 0x07, 0x00, 0x40, 0xBF, 0x94, 0x30, 0x07, 0x00, 0x40, 0xBF, 0xD4, 0x30, 0x07, 0x00, 0x40, 0xBF, 0xAC, 0x30, 0x07, 0x00, 0x41, 0x7F, 0xA8, 0x30, 0x07, 0x00, 0x41, 0x7F, 0x28, 0x30, 0x07, 0x00, 0x41, 0x7F, 0x58, 0x30, 0x07, 0x00, 0x41, 0x7F, 0x50, 0x30, 0x07, 0x00, 0x42, 0xFE, 0x50, 0x30, 0x07, 0x00, 0x42, 0x7E, 0xB0, 0x30, 0x07, 0x00, 0x42, 0x1C, 0xA0, 0x30, 0x07, 0x00, 0x42, 0x05, 0x60, 0x30, 0x07, 0x00, 0x43, 0x01, 0x40, 0x30, 0x07, 0x00, 0x41, 0xC2, 0xC0, 0x30, 0x07, 0x00, 0x40, 0x73, 0x80, 0x30, 0x07, 0x00, 0x40, 0x1F, 0x00, 0x30, 0x07, 0x00, 0x40, 0x00, 0x00, 0x30, 0x07, 0x00, 0x40, 0x00, 0x00, 0x30, 0x07, 0x00, 0x7F, 0xFF, 0xFF, 0xF0, 0x07, 0x00, 0x3F, 0xFF, 0xFF, 0xF0, 0x07, }; T_ICON IconButton1 = {&TchList[0], bitmap, NULL, 0x01}; void buttonPressed() { char * str = "Button pressed"; LibStringDsp(str, 0, 0, 100, IB_PFONT2); LibPutDisp(); } void main() { TCHSTS tsts; LibTchStackClr(); LibTchStackPush(NULL); LibTchStackPush(TchHardIcon); LibTchStackPush(&TchList[0]); LibClrDisp(); LibIconPrint(&IconButton1); LibPutDisp(); LibTchInit(); while(1) { LibTchWait(&tsts); if(tsts.obj == OBJ_BTN1) { buttonPressed(); } } LibTchStackClr(); LibJumpMenu(); }
Создаём функции обработчика кнопок. Думаю, в пояснении они не нуждаются.
Собственно, всё происходит так же, как и с картинками, за исключением функции main(). Помимо постоянного опроса тачскрина мы проверяем, были ли нажаты кнопки (точнее говоря, был ли тык в отчерченную координатами область). Для этого используются всё те же заданные нами ID.
Ну что, компилируем и запускаем? Работает? Отлично.
#include<stdrom.h> #include"define.h" #include"libc.h" #include "l_define.h" #include "l_libc.h" #define OBJ_BTN1 0x9000 #define OBJ_BTN2 0x9001 TCHTBL TchList[3] = { 25, 25, 25 + 45, 25 + 28, ACT_ICON, OBJ_BTN1, 0x0000, 25, 80, 25 + 45, 80 + 28, ACT_ICON, OBJ_BTN2, 0x0000, 0, 0, 0, 0, ACT_NONE, OBJ_END, 0x0000 }; byte bitmap[] = { GSIZE(45, 28), 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x7F, 0xFF, 0xFF, 0xE0, 0x07, 0x00, 0x40, 0x00, 0x00, 0x30, 0x07, 0x00, 0x40, 0x00, 0x00, 0x30, 0x07, 0x00, 0x40, 0x1C, 0x00, 0x30, 0x07, 0x00, 0x40, 0x27, 0x80, 0x30, 0x07, 0x00, 0x40, 0x20, 0xE0, 0x30, 0x07, 0x00, 0x40, 0x58, 0x38, 0x30, 0x07, 0x00, 0x40, 0x5E, 0x14, 0x30, 0x07, 0x00, 0x40, 0xBF, 0x94, 0x30, 0x07, 0x00, 0x40, 0xBF, 0xD4, 0x30, 0x07, 0x00, 0x40, 0xBF, 0xAC, 0x30, 0x07, 0x00, 0x41, 0x7F, 0xA8, 0x30, 0x07, 0x00, 0x41, 0x7F, 0x28, 0x30, 0x07, 0x00, 0x41, 0x7F, 0x58, 0x30, 0x07, 0x00, 0x41, 0x7F, 0x50, 0x30, 0x07, 0x00, 0x42, 0xFE, 0x50, 0x30, 0x07, 0x00, 0x42, 0x7E, 0xB0, 0x30, 0x07, 0x00, 0x42, 0x1C, 0xA0, 0x30, 0x07, 0x00, 0x42, 0x05, 0x60, 0x30, 0x07, 0x00, 0x43, 0x01, 0x40, 0x30, 0x07, 0x00, 0x41, 0xC2, 0xC0, 0x30, 0x07, 0x00, 0x40, 0x73, 0x80, 0x30, 0x07, 0x00, 0x40, 0x1F, 0x00, 0x30, 0x07, 0x00, 0x40, 0x00, 0x00, 0x30, 0x07, 0x00, 0x40, 0x00, 0x00, 0x30, 0x07, 0x00, 0x7F, 0xFF, 0xFF, 0xF0, 0x07, 0x00, 0x3F, 0xFF, 0xFF, 0xF0, 0x07, }; T_ICON IconButton1 = {&TchList[0], bitmap, NULL, 0x01}; T_ICON IconButton2 = {&TchList[1], bitmap, NULL, 0x01}; void button1Pressed() { char * str = "Button 1 pressed"; LibStringDsp(str, 0, 0, 100, IB_PFONT2); LibPutDisp(); } void button2Pressed() { char * str = "Button 2 pressed"; LibStringDsp(str, 0, 0, 100, IB_PFONT2); LibPutDisp(); } void main() { TCHSTS tsts; LibTchStackClr(); LibTchStackPush(NULL); LibTchStackPush(TchHardIcon); LibTchStackPush(&TchList[0]); LibClrDisp(); LibIconPrint(&IconButton1); LibIconPrint(&IconButton2); LibPutDisp(); LibTchInit(); while(1) { LibTchWait(&tsts); if(tsts.obj == OBJ_BTN1) { button1Pressed(); } if(tsts.obj == OBJ_BTN2) { button2Pressed(); } } LibTchStackClr(); LibJumpMenu(); }
RS-232
Несколько неожиданно, но имеющийся у КПК COM-порт можно использовать и в своих целях, а не только лишь для связи с ПК.
Итак, для начала порт надо открыть:
byte openPort() { SRL_STAT srl; srl.port = IB_SRL_COM2; srl.speed = IB_SRL_9600BPS; srl.parit = IX_SRL_NONE; srl.datab = IX_SRL_8DATA; srl.stopb = IX_SRL_1STOP; srl.fctrl = IX_SRL_NOFLOW; if (LibSrlPortOpen(&srl) != IW_SRL_NOERR) { LibPutMsgDlg("LibSrlPortOpen error"); return 1; } return 0; }
Здесь мы задаём параметры порта и записываем их.
Пропишем в функции main():
if(!openPort()) { LibStringDsp("Port opened", 0, 0, 100, IB_PFONT2); LibPutDisp(); } else LibJumpMenu();
Теперь разберёмся с тем, как производить сам обмен данными. Для этого существуют функции LibSrlRecvByte() и LibSrlSendByte(). Используются они примерно так:
byte ReadCOM(byte * data) { byte sReceivedByte; if (LibSrlRecvByte(&sReceivedByte) == IW_SRL_NODATA) return 1; *data = sReceivedByte; return 0; } byte WriteCOM(byte data) { if(LibSrlSendByte(IB_FOLLOW_BUSY, data) == IW_SRL_NOERR) return 0; else return 1; }
Ну а теперь посмотрим, как это применять на практике. Возьмём нашу программу с двумя кнопками и добавим ранее упомянутые функции:
#include<stdrom.h> #include"define.h" #include"libc.h" #include "l_define.h" #include "l_libc.h" #define OBJ_BTN1 0x9000 #define OBJ_BTN2 0x9001 TCHTBL TchList[3] = { 25, 25, 25 + 45, 25 + 28, ACT_ICON, OBJ_BTN1, 0x0000, 25, 80, 25 + 45, 80 + 28, ACT_ICON, OBJ_BTN2, 0x0000, 0, 0, 0, 0, ACT_NONE, OBJ_END, 0x0000 }; byte bitmap[] = { GSIZE(45, 28), 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x7F, 0xFF, 0xFF, 0xE0, 0x07, 0x00, 0x40, 0x00, 0x00, 0x30, 0x07, 0x00, 0x40, 0x00, 0x00, 0x30, 0x07, 0x00, 0x40, 0x1C, 0x00, 0x30, 0x07, 0x00, 0x40, 0x27, 0x80, 0x30, 0x07, 0x00, 0x40, 0x20, 0xE0, 0x30, 0x07, 0x00, 0x40, 0x58, 0x38, 0x30, 0x07, 0x00, 0x40, 0x5E, 0x14, 0x30, 0x07, 0x00, 0x40, 0xBF, 0x94, 0x30, 0x07, 0x00, 0x40, 0xBF, 0xD4, 0x30, 0x07, 0x00, 0x40, 0xBF, 0xAC, 0x30, 0x07, 0x00, 0x41, 0x7F, 0xA8, 0x30, 0x07, 0x00, 0x41, 0x7F, 0x28, 0x30, 0x07, 0x00, 0x41, 0x7F, 0x58, 0x30, 0x07, 0x00, 0x41, 0x7F, 0x50, 0x30, 0x07, 0x00, 0x42, 0xFE, 0x50, 0x30, 0x07, 0x00, 0x42, 0x7E, 0xB0, 0x30, 0x07, 0x00, 0x42, 0x1C, 0xA0, 0x30, 0x07, 0x00, 0x42, 0x05, 0x60, 0x30, 0x07, 0x00, 0x43, 0x01, 0x40, 0x30, 0x07, 0x00, 0x41, 0xC2, 0xC0, 0x30, 0x07, 0x00, 0x40, 0x73, 0x80, 0x30, 0x07, 0x00, 0x40, 0x1F, 0x00, 0x30, 0x07, 0x00, 0x40, 0x00, 0x00, 0x30, 0x07, 0x00, 0x40, 0x00, 0x00, 0x30, 0x07, 0x00, 0x7F, 0xFF, 0xFF, 0xF0, 0x07, 0x00, 0x3F, 0xFF, 0xFF, 0xF0, 0x07, }; T_ICON IconButton1 = {&TchList[0], bitmap, NULL, 0x01}; T_ICON IconButton2 = {&TchList[1], bitmap, NULL, 0x01}; byte openPort() { SRL_STAT srl; srl.port = IB_SRL_COM2; srl.speed = IB_SRL_9600BPS; srl.parit = IX_SRL_NONE; srl.datab = IX_SRL_8DATA; srl.stopb = IX_SRL_1STOP; srl.fctrl = IX_SRL_NOFLOW; if (LibSrlPortOpen(&srl) != IW_SRL_NOERR) { LibPutMsgDlg("LibSrlPortOpen error"); return 1; } return 0; } byte ReadCOM(byte * data) { byte sReceivedByte; if (LibSrlRecvByte(&sReceivedByte) == IW_SRL_NODATA) return 1; *data = sReceivedByte; return 0; } byte WriteCOM(byte data) { if(LibSrlSendByte(IB_FOLLOW_BUSY, data) == IW_SRL_NOERR) return 0; else return 1; } void button1Pressed() { LibStringDsp("Serial data sent", 0, 0, 100, IB_PFONT2); WriteCOM('1'); LibPutDisp(); } void button2Pressed() { byte serialData = 0; if(!ReadCOM(&serialData)) { LibStringDsp("New serial data!", 0, 0, 100, IB_PFONT2); WriteCOM(serialData); } LibPutDisp(); } void main() { TCHSTS tsts; LibTchStackClr(); LibTchStackPush(NULL); LibTchStackPush(TchHardIcon); LibTchStackPush(&TchList[0]); LibClrDisp(); LibIconPrint(&IconButton1); LibIconPrint(&IconButton2); LibPutDisp(); LibTchInit(); if(!openPort()) { LibStringDsp("Port opened", 0, 0, 100, IB_PFONT2); LibPutDisp(); } else LibJumpMenu(); while(1) { LibTchWait(&tsts); if(tsts.obj == OBJ_BTN1) { button1Pressed(); } if(tsts.obj == OBJ_BTN2) { button2Pressed(); } } LibTchStackClr(); LibJumpMenu(); }
Теперь при нажатии первой кнопки в порт будет отправляться «1», а при нажатии второй — только что считанный байт (если в буфере он есть).
Проверим:
Кто бы сомневался.
Вот как-то так…
Увы, материалов по программированию под PVOS в сети исчезающе мало. Раньше их было больше, но теперь большая часть ссылок не работает.
Понятное дело, вряд ли это может быть хоть как-то полезно на практике. Но я совершенно уверен, что кого-то это заинтересует, и где-то станет одной программой для PVOS больше. Такие дела.
Ссылки
Увы, большинство тематических сайтов на данный момент уже невозможно открыть. Какого-либо крупного и ещё живого, наподобие palmdb.com, но для PV, просто нет. Даже на ещё живых сайтах большая часть ссылок уже не открывается. Если вы знаете какие-то ресурсы, которые не отражены здесь — пишите, я их обязательно добавлю.
Живые сайты (те, которые на момент написания статьи всё ещё нормально работают и содержат минимум битых ссылок):
- Архив софта для PVOS
- Русский Application Manager
- Каталог софта для Casio PV, материалы по программированию (признаться, именно этот сайт очень сильно помог разобраться в данной теме)
- Неплохой раздел по Casio PV
- Русскоязычное сообщество пользователей PV
- SSC Localization group (раздел с ПО уже умер, а вот ОС ещё можно скачать)
- Сайт Костика Рассказова
- Программы для Casio PV
Мёртвые сайты (представлены для ознакомительных целей, доступны для изучения в Internet Archive):
ссылка на оригинал статьи https://habr.com/ru/post/692146/
Добавить комментарий