Category: Projects Related to Palm OS PDAs
Published on: 2019-11-17
This page describes how to write a small Palm OS application that can send some data via the serial interface.
The code is fully compilable with the tools mentioned here: Compiling and building Palm OS applications on Ubuntu 18.04 LTS (64 Bit).
Feel free to make your own copy and edit it as you want/need.
To build a functional Palm OS application, three files are needed:
This is the header file of the application:
#ifndef SERIALCOMM_H_ #define SERIALCOMM_H_ #define appFileCreator 'TJS9' #define appName "SerialComm" #define appVersionNum 0x01 #define appPrefID 0x00 #define appPrefVersionNum 0x01 #define MainForm 1000 #define PredefinedStringButton 1001 #define CustomStringButton 1002 #define PredefinedHexButton 1003 #define CustomStringField 1004 #define MainMenu 1018 #define MainOptionsHelpCmd 1019 #define MainOptionsAboutCmd 1020 #define HelpAlert 1050 #define AboutApplicationAlert 1051 #define OsVersionTooLowAlert 1052 #define ErrorOccurredAlert 1053 #endif
90% of these are definitions for forms, buttons, menus, and alerts. "appFileCreator" needs some attention because this is an ID that identifies your application and must not be identical to other "appFileCreator" IDs, otherwise it can lead to data loss. There was a service from Palm that ensured there was only one unique ID for each application. Of course, this service is not online anymore. So today, it is pure luck if it works with other applications or not.
This is the resources file of the application:
GENERATEHEADER "serialcomm_Rsc.h" #include "serialcomm.h" FORM ID MainForm AT (0 0 160 160) MENUID MainMenu BEGIN TITLE "Serial Comm. with Palm OS" LABEL "Send a predefined String:" AUTOID AT (CENTER 20) FONT 1 BUTTON "Send" ID PredefinedStringButton AT (CENTER 35 AUTO AUTO) FONT 0 LABEL "Send a custom String:" AUTOID AT (CENTER 100) FONT 1 FIELD ID CustomStringField AT (CENTER PREVBOTTOM+8 110 AUTO) FONT 0 UNDERLINED MAXCHARS 23 BUTTON "Send" ID CustomStringButton AT (CENTER 140 AUTO AUTO) FONT 0 FRAME FRAME LABEL "Send predefined hex-values:" AUTOID AT (CENTER 55) FONT 1 BUTTON "41 42 43 44 45 46 47 48 49 4A" ID PredefinedHexButton AT (CENTER 75 AUTO AUTO) FONT 0 END ALERT ID HelpAlert INFORMATION BEGIN TITLE "Help" MESSAGE "Help is available at\n"\ "https://palm2000.de/\n"\ "projects/\n"\ "serialCommunication\nWithPalmOsPart1.php" BUTTONS "OK" END ALERT ID AboutApplicationAlert INFORMATION BEGIN TITLE "Serial Comm. with Palm OS" MESSAGE "This is a small demo-application to send some data over the serial interface of a Palm PDA.\n" BUTTONS "OK" END ALERT ID OsVersionTooLowAlert ERROR BEGIN TITLE "Palm OS Version too low!" MESSAGE "Palm OS 2.0 or greater is required to run this application." BUTTONS "OK" END MENU ID MainMenu BEGIN PULLDOWN "Options" BEGIN MENUITEM "Help" ID MainOptionsHelpCmd "H" MENUITEM SEPARATOR MENUITEM "About this application" ID MainOptionsAboutCmd "A" END END ALERT ID ErrorOccurredAlert ERROR BEGIN TITLE "An error occurred!" MESSAGE "^1\n^2\n^3" BUTTONS "OK" END VERSION 1 "0.0.1" LAUNCHERCATEGORY ID 1000 "Utilities" ICON "serialcomm_22.bmp" SMALLICON "serialcomm_9.bmp"
Here all UI elements are defined, along with their parameters like titles and locations.
This is the C file with all the code, containing the "business logic" of the application:
#include "serialcomm.h" #include <UI/UIPublic.h> #include <System/SystemPublic.h> #include <PalmCompatibility.h> #include <PalmTypes.h> // Here is the baud rate defined. It is very important that this value matches the baud rate of the server application #define BAUDRATE 9600 UInt16 comPort = 0; static Char* GetFromInputField(UInt16, UInt16); static void SendDataSerial(void*); // This function fetches the input from the "CustomStringField" and returns it static Char* GetFromInputField(UInt16 formID, UInt16 fieldID) { FormPtr formPtr; FieldPtr fieldPtr; UInt16 objectIndex; formPtr = FrmGetFormPtr(formID); objectIndex = FrmGetObjectIndex(formPtr, fieldID); fieldPtr = (FieldPtr)FrmGetObjectPtr(formPtr, objectIndex); return FldGetTextPtr(fieldPtr); } // This is the function with the business logic static Boolean MainFormHandleEvent(EventType *event) { //char hexVar[10] = {0x7E,0xFF,0x06,0x09,0x00,0x00,0x04,0x44,0xDD,0xEF}; Boolean handled = false; Err err; char *custStrFieldInputPtr; // This is the predefined hex codes and the predefined char array char hexVar[10] = {0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4A}; char preDefStr[31] = "A text from a Palm OS device.\0"; char (*hexVarPtr)[10]; char (*preDefStrPtr)[31]; hexVarPtr = &hexVar; preDefStrPtr = &preDefStr; if(event->eType == frmOpenEvent) { FrmDrawForm(FrmGetActiveForm()); handled = true; } if(event->eType == ctlSelectEvent) { switch (event->data.ctlSelect.controlID) { case PredefinedHexButton: // For sending hex data, a slight modification of the SendDataSerial function is needed, this is why the code is separate SrmReceiveFlush(comPort, 0); SrmSend(comPort, hexVarPtr, 11, &err); // The "\n" char gives the command to actually send the data SrmSend(comPort, "\n", 1, &err); break; case PredefinedStringButton: SendDataSerial(preDefStrPtr); break; case CustomStringButton: custStrFieldInputPtr = GetFromInputField(MainForm,CustomStringField); // This avoids problems when the input field is empty and the user hits "send" if(!custStrFieldInputPtr) { SendDataSerial("NULL"); }else{ SendDataSerial(custStrFieldInputPtr); } break; default: break; } } return handled; } // This function sends text over the serial interface static void SendDataSerial(void* value){ Err err; SrmReceiveFlush(comPort, 0); SrmSend(comPort, value, StrLen(value), &err); SrmSend(comPort, "\n", 1, &err); } static Boolean AppHandleEvent(EventPtr event) { FormType* formTypePtr; UInt16 formId; Boolean handled = false; if (event->eType == frmLoadEvent) { formId = event->data.frmLoad.formID; formTypePtr = FrmInitForm(formId); FrmSetActiveForm(formTypePtr); switch (formId) { case MainForm: FrmSetEventHandler(formTypePtr, MainFormHandleEvent); break; default: break; } return true; } if (event->eType == menuEvent) { MenuEraseStatus(NULL); switch (event->data.menu.itemID) { case MainOptionsHelpCmd: FrmAlert(HelpAlert); handled = true; break; case MainOptionsAboutCmd: FrmAlert(AboutApplicationAlert); handled = true; break; default: break; } return true; } return false; } static void AppEventLoop(void) { EventType event; Err error; do { EvtGetEvent(&event, evtWaitForever); if (SysHandleEvent(&event)) { continue; } if (MenuHandleEvent((void *)0, &event, &error)) { continue; } if (AppHandleEvent(&event)) { continue; } FrmDispatchEvent(&event); } while (event.eType != appStopEvent); } static Err stopApplication() { Err returnCode; FrmCloseAllForms(); returnCode = SrmClose(comPort); return returnCode; } static Err startApplication() { Err returnCode = 0; returnCode = SrmOpen(serPortCradlePort, BAUDRATE, &comPort); if (returnCode == 0) { FrmGotoForm(MainForm); } return returnCode; } UInt32 PilotMain(UInt16 cmd, MemPtr cmdPBP, UInt16 launchFlags) { UInt32 currentRomVersion; UInt32 requiredRomVersion; requiredRomVersion = 0x02000000; FtrGet(sysFtrCreator, sysFtrNumROMVersion, ¤tRomVersion); if (currentRomVersion < requiredRomVersion) { FrmAlert(OsVersionTooLowAlert); return(sysErrRomIncompatible); } if (cmd == sysAppLaunchCmdNormalLaunch) { Err returnCode; returnCode = startApplication(); if (returnCode != 0) { ErrAlert(returnCode); return(returnCode); } AppEventLoop(); returnCode = stopApplication(); if (returnCode != 0) { ErrAlert(returnCode); return(returnCode); } } return 0; }
The complete package is downloadable with a proper Makefile HERE.
The PRC file is also available: HERE.
This application only works with the old COM port (DE-9 connector). If the application is started on a device connected to a USB cable or cradle (the USB cable does not need to be plugged in!), the application crashes with a "Serial: timeout [...] (Ser 0305)" error message.
Always make sure the baud rate is configured the same on all devices (Client/Server, Palm/PC), e.g., 9600 [bits per second]. Otherwise, the transmission will fail.
The application was successfully developed and tested on a Palm m100 and POSE.
The next part (2/4) describes how the data from the application can be read on a Linux command line:
Serial Communication with Palm OS on Ubuntu 18.04 and the command line