Продолжим тему разработки под ушедшие в историю платформы. Сегодня расскажем про органайзеры 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.
Установив связь и получив список программ, добавляем или удаляем нужные, а затем производим обмен данными (той же самой кнопкой или «ExecuteUpdate PV»). Всё, приложение установлено (ну, или снесено).
Структура проекта
Итак, заглянем в папку C и посмотрим, что же у нас там лежит. В папке Bin хранятся скомпилированные бинарники, пригодные для загрузки в КПК или запуска в симуляторе. Также есть несколько папок с библиотеками, а также разделы Sample и Sample1. Это и есть проекты. Откроем какой-нибудь из них. В каждой из этих двух папок лежит Makefile, батник для сборки, каталоги с исходниками. Также есть папка MENUICON — там хранится иконка приложения для отображения в списке в главном меню.
Запустим батник и убедимся, что проект успешно компилируется.
Пишем первую программу
Ну что, со сборкой разобрались. Пришло время написать что-то своё. Итак, создаём в папке C ещё какую-нибудь папку, скажем, Test. А в ней — такую же структуру папок, какую видели в других проектах. Копируем также содержимое MENUICON.
Берём MAKEFILE из уже имеющегося проекта и слегка модифицируем его под наши задачи. Примерно так:
#Makefile for PocketViewer2 Sample Program
include ..COM_LNKMakeSDK.1
### -------- Define Make Application -------- ###
#== TargetName ==
TARGET = test
#== Program Name ==
PROGNAME = "test"
#== ProgramVersion(EX. 0100->Ver1.00) ==
VERSION = 0100
#== MenuIcon (Xsize=45dot,Ysize=28dot) ==
MICON = menuiconicon.bmp
#== ListMenuIcon (Xsize=27dot,Ysize=20dot) ==
LICON = menuiconLicon.bmp
#== CompileObjectFile ==
APLOBJS = $(ODIR)test.obj
### ----------------------------------------- ###
include ..COM_LNKMakeSDK.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шкой.
Откроем папку DOCGRAPHICS. Там лежит целая куча картинок, что называется, на все случаи жизни. Берём какую-нибудь из них и перегоняем в 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):
Автор:
MaFrance351