Here is some simple palm programming tip for beginners

Back to the development page
Indietro alla pagina Italiana

How to exit from the application:

Palm suggests do not exit from applications, but if you wish to do it ...

/************************************/
/* Returns to launcher                                      */
static void Uti_Exit(void)
{
 EventType event;
 MemSet(&event,sizeof(event),0);
 event.eType = keyDownEvent;
 event.data.keyDown.chr = vchrLaunch;
event.data.keyDown.modifiers = commandKeyMask;
 EvtAddEventToQueue(&event);
}

/************************************/
/* Returns to the previous application               */
static void Uti_Exit(void)
{
 EventType event;
 MemSet(&event,sizeof(event),0);
 event.eType = appStopEvent;
 EvtAddEventToQueue(&event);
}

How to power off:

Add the vchrPowerOff  keyDownEvent to the queue, see Uti_PowerOff();
Add  the appStopEvent event if you want to exit from the application too, see Uti_Exit();

/************************************/
static void Uti_PowerOff(void)
{
 EventType event;
 MemSet(&event,sizeof(event),0);
 event.eType = keyDownEvent;
 event.data.keyDown.chr = vchrPowerOff;
 event.data.keyDown.keyCode = 0;
 event.data.keyDown.modifiers = commandKeyMask;
 EvtAddEventToQueue(&event);
}

How to store a permanent value and have it back to the next run or pass it to another application:

Use the Features to store a UInt32 value

Store with
FtrSet(AppCreator, Feature_number, Feature_Value);

Retrive with
FtrGet(AppCreator, Feature_number, &Feature_Value);

How to know if the palm is powering on or is going to sleep:

Register for some notification and handle them as follows
Unregister with SysNotifyUnregister() when no more needed
You can use a Feature (see
How to store a permanent value... ) to store the program start time

/************************************/
static void RegisterForNotifications()
{
 UInt16   cardNo=0;
 UInt32   romVersion=0;
 LocalID dbID=0;

  FtrGet(sysFtrCreator, sysFtrNumROMVersion, &romVersion);
  if(romVersion < MinVersion)
   return;
  if(SysCurAppDatabase(&cardNo, &dbID)!=0)
   return;
 // Register the Notification you need
 SysNotifyRegister(cardNo, dbID, sysNotifyEarlyWakeupEvent, NULL, sysNotifyNormalPriority, 0);
 SysNotifyRegister(cardNo, dbID, sysNotifyLateWakeupEvent, NULL, sysNotifyNormalPriority, 0);
 SysNotifyRegister(cardNo, dbID, sysNotifySleepRequestEvent, NULL, sysNotifyNormalPriority, 0);
}

/************************************/
static void HandleNotifications(SysNotifyParamType *np)
{
  if(np->notifyType==sysNotifyEarlyWakeupEvent)
  {
  
// Do something
  }
 else if(np->notifyType==sysNotifyLateWakeupEvent)
  {
   // Do something
  }
 else if(np->notifyType==sysNotifySleepRequestEvent)
  {
  
// Do something
  }
}

/************************************/
UInt32 PilotMain(UInt16 cmd,void *cmdPBP,UInt16 launchFlags)
{
  switch(cmd)
  {
   case sysAppLaunchCmdSystemReset:
   case sysAppLaunchCmdSyncNotify:
    RegisterForNotifications();
    break;

   case sysAppLaunchCmdNotify:
   case sysNotifySleepRequestEvent:
    HandleNotifications((SysNotifyParamType *)cmdPBP);
    break;

   case sysAppLaunchCmdNormalLaunch:
    ... Normal code ...

How to create a progress bar:

/************************************/
// Clear a progress bar
/************************************/
static void ProgressBarClear(UInt16 unTop,UInt16 unLeft,UInt16 unWidth)
 {
  Rect.topLeft.x=unLeft;
  Rect.topLeft.y=unTop;
  Rect.extent.x=unWidth;
  Rect.extent.y=12;
  WinEraseRectangle(&Rect,0);
 }

/************************************/
// Draw a progress bar
/************************************/
static void ProgressBarInit(UInt16 unTop,UInt16 unLeft,UInt16 unWidth)
 {
  ProgressBarClear(unTop,unLeft,unWidth);
  Rect.topLeft.x=unLeft+1;
  Rect.topLeft.y=unTop+1;
  Rect.extent.x=unWidth-2;
  Rect.extent.y=10;
  newRgb.r=0x00;
  newRgb.g=0x00;
  newRgb.b=0x00;
  WinSetForeColorRGB(&newRgb,&prevRgb);
  WinDrawRectangleFrame(rectangleFrame,&Rect);
 }

/*******************************************************/
// ProgressBar
// Use example:
// Init with:         ProgressBarInit(17,2,123);
// Call several time: ProgressBar(17,2,123,unIx,200);
// Clear with:        ProgressBarClear(17,2,123);
/*******************************************************/
static void ProgressBar(UInt16 unTop,UInt16 unLeft,UInt16 unWidth,UInt32 unValue,UInt32 unMaxValue)
 {
  UInt32 ulTemp=0;
  if(unMaxValue)
   ulTemp=(unWidth-2)*unValue/unMaxValue;
  if(ulTemp>(unWidth-2))
   ulTemp=(unWidth-2);
  Rect.topLeft.x=unLeft+1;
  Rect.topLeft.y=unTop+1;
  Rect.extent.x=ulTemp;
  Rect.extent.y=10;
  newRgb.r=0x00;
  newRgb.g=0x00;
  newRgb.b=0xFF;
  WinSetForeColorRGB(&newRgb,&prevRgb);
  WinDrawRectangle(&Rect,0);
 }

How to turn IrDA On/Off:

Boolean  bIrDAEnabled;
Boolean  bIrDAisPresent;
UInt16   irLibRefNum;
UInt16   unLen;
Err         err;

...

// Checks if Irda is present at program start and gets irLibRefNum
err = SysLibFind("IrDA Library", &irLibRefNum);
 if(err == 0)
  bIrDAisPresent=true;
else
  bIrDAisPresent=false;

...

// Set the state of bIrDAEnabled boolean
unLen=sizeof(bIrDAEnabled);
if(bIrDAisPresent)
 ExgLibControl(irLibRefNum, irSetScanningMode, &bIrDAEnabled, &unLen);

How to associate a file extension to a card directory:

When you try to sync a file to the expansion card, often, you got an error saing that there is not a program associated to that file type

// For example to unregister the .txt extension write this
VFSUnregisterDefaultDirectory(".txt", expMediaType_Any);

// To associate the .txt extension to the /PALM/Laungher directory use this
VFSRegisterDefaultDirectory(".txt", expMediaType_Any, "/PALM/Launcher");

How to avoid menu overwrite:

You can avoid menu overwrite by, for example, a WinDrawChars() managing the messages winExitEvent and winEnterEvent to set a boolean bCanDraw that determine if you can do the write/draw or not.

/************************************/
static Boolean PreprocessEvent(EventPtr eventP)
{
  ... Your code here ....

  switch(eventP->eType)
  {
   case winExitEvent:
    if(eventP->data.winExit.exitWindow==(WinHandle)FrmGetFormPtr(MainForm))
     bCanDraw=false;
    if(eventP->data.winExit.exitWindow==(WinHandle)FrmGetFormPtr(AnotherForm))
     bCanDraw=false;
    break;
   case winEnterEvent:
    if(eventP->data.winEnter.enterWindow==(WinHandle)FrmGetFirstForm())
     {
      if(eventP->data.winEnter.enterWindow==(WinHandle)FrmGetFormPtr(MainForm))
       bCanDraw=true;
      if(eventP->data.winEnter.enterWindow==(WinHandle)FrmGetFormPtr(AnotherForm))
       bCanDraw=true;
     }
    break;

  ... Your code continue here ....

How to connect the palm to your phone, PC or other serial device through Bluetooth:

Here is a simple way to communicate with your bluetooth serial device, this example code  is as simple as possible you have to implement the errors management.
You have to:
1) Load the Library
2) Find a device if not already known
3) Open the connection
4) Use it (Receive, Send, Flush, etc.)
5) Close the connection

/**************/
/* BT Globals      */
/**************/
static UInt16 unPortId;
static UInt16 btLibRefNum;
static UInt8   cAddress[6];
static Err err;
static SrmOpenConfigType config;
static BtVdOpenParams    btParams;
static BtLibSdpUuidType  sppUuid;
/************************************/
/* Pause n milliseconds                                    */
/************************************/
static void Uti_WaitMilliSec(UInt32 ulMilliSec)
{
 UInt16  unTickPerSec;

 unTickPerSec=SysTicksPerSecond();
 if(unTickPerSec)
  SysTaskDelay(ulMilliSec*unTickPerSec/1000);
 else
  SysTaskDelay(ulMilliSec/10);
}
/**************************************/
/* Close a Bluetooth serial connetion                    */
/**************************************/
static void BT_Close()
{
 if(unPortId)
  {
   SrmClose(unPortId);
   unPortId=0;
   Uti_WaitMilliSec(500);
   SrmClose(unPortId); // Retry, on some system it's hard to die
  }
}
/*************************************/
/* Open a Bluetooth serial connetion                  */
/*************************************/
static void BT_Open()
 {
  BT_Close();
  MemSet(&sppUuid, sizeof(sppUuid), 0);
  sppUuid.size = btLibUuidSize16;
  sppUuid.UUID[0] = 0x11;
  sppUuid.UUID[1] = 0x01;
  MemSet(&btParams, sizeof(btParams), 0);
  btParams.u.client.remoteDevAddr.address[0]=cAddress[0];
  btParams.u.client.remoteDevAddr.address[1]=cAddress[1];
  btParams.u.client.remoteDevAddr.address[2]=cAddress[2];
  btParams.u.client.remoteDevAddr.address[3]=cAddress[3];
  btParams.u.client.remoteDevAddr.address[4]=cAddress[4];
  btParams.u.client.remoteDevAddr.address[5]=cAddress[5];
  btParams.role = btVdClient;
  btParams.u.client.method = btVdUseUuidList;
  btParams.u.client.u.uuidList.tab = &sppUuid;
  btParams.u.client.u.uuidList.len = 1;
  MemSet(&config, sizeof(config), 0);
  config.function = serFncUndefined;
  config.drvrDataP = (MemPtr)&btParams;
  config.drvrDataSize = sizeof(btParams);
  err=SrmExtOpen(sysFileCVirtRfComm,&config,sizeof(config),&unPortId);
 }
/***************************/
/* Find a BT device on air             */
/***************************/
static void BT_FindDevice()
{
 BT_Close();

 if(btLibRefNum)
  {
   err=BtLibOpen(btLibRefNum,false);
   if(err==0)
     err=BtLibDiscoverSingleDevice(btLibRefNum,NULL,NULL,0, (BtLibDeviceAddressType *)cAddress,false,true);
   BtLibClose(btLibRefNum);
  }
}
/***********************/
/* Load the BT library           */
/***********************/
static void BT_LoadLibrary()
{
 btLibRefNum=0;

 err=SysLibFind("Bluetooth Library",&btLibRefNum);
 if(err)
  err=SysLibLoad(sysFileTLibrary,sysFileCBtLib,&btLibRefNum);
}
/****************/
/* Flush BT ser        */
/****************/
static void BT_Flush(UInt16 unTimeout)
{
 if(unPortId)
   err=SrmReceiveFlush(unPortId,unTimeout);
}
/****************/
/* Send BT data      */
/****************/
static void BT_Send(char * pData,UInt16 unLen)
{
 if(unPortId)
   SrmSend(unPortId,pData,unLen,&err);
}
/*******************/
/* Receive BT data        */
/*******************/
static UInt16 BT_Receive(char * pData,UInt16 unLen,UInt16 unTimeout)
{
 UInt16 unLenRead;
 if(unPortId)
   unLenRead=SrmReceive(unPortId,pData,unLen,unTimeout,&err);
 return(unLenRead);
}

How to read/write the expansion card:

See "System Management / Virtual File System Manager" on PODS "Palm OS Reference.pdf" for details

// Globals
Err        errVFS;
Err        err;
UInt16  unVol;
UInt32  ulIter;
UInt32  ulVFSMgrVer;
UInt32  ulBytesToWrite;
UInt32  ulBytesWritten;
UInt32  ulBytesToRead;
UInt32  ulBytesRead;
UInt32  ulOffset;
void *   cBuffer;
FileRef  fRef;

//------------------
// We need the volume reference unVol
errVFS = FtrGet(sysFileCVFSMgr, vfsFtrIDVersion, &ulVFSMgrVer);
if(errVFS==errNone) // check if VFS's present
 {
  ulIter = vfsIteratorStart; //Start value
// Here we get the first card, if you want more cards call VFSVolumeEnumerate in a loop
  errVFS = VFSVolumeEnumerate(&unVol, &ulIter);
 }
// Use errVFS as appropriate

//------------------
// To open for write xor ...
err=VFSFileOpen(unVol, "/PALM/Launcher/filename.txt", vfsModeWrite|vfsModeCreate|vfsModeTruncate, &fRef);
// ... for read (choice only one open call)
err=VFSFileOpen(unVol, "/PALM/Launcher/filename.txt", vfsModeRead, &fRef);

//------------------
// To write data
// cBuffer points to your data buffer
cBuffer = ...
ulBytesToWrite = ...
err=VFSFileWrite(fRef, ulBytesToWrite, cBuffer, &ulBytesWritten);

//------------------
// To read data
// cBuffer points to your data buffer
cBuffer = ...
ulBytesToRead = ...
err=VFSFileRead(fRef, ulBytesToRead, cBuffer, &ulBytesRead);

//------------------
// To move the file pointer somewhere
ulOffset = ...
err=VFSFileSeek(fRef, vfsOriginBeginning, ulOffset);

//------------------
// Close the file
VFSFileClose(fRef);

//------------------
// Test EOF
if(VFSFileEOF(fRef))
  ...

How to read/write files in the internal RAM as a simple standard file (streams)

Note1: when you create the file the backup flag is cleared, so if you need to backup it in the HotSync operation you need to set the flag before

Note2: although you use the file as a binary one the Palm stores it as a database, so if you transfer it to your PC the file structure is database like not just a plain binary

// Globals
#define    AppCreator      'you four bytes creator ID'
FileHand fHandle;
UInt32    ulOffset;
UInt32    ulNumBytes;
UInt32    ulFileLen;
UInt32    ulPosition;
Err          err;

//------------------
// To open for write xor ...
fHandle=FileOpen(0,"YourFileName",AppCreator,AppCreator,fileModeReadWrite,&err);
// ... for read
fHandle=FileOpen(0,"YourFileName",AppCreator,AppCreator,fileModeReadOnly,&err);

//------------------
// To read
pBuffer= your buffer
ulNumBytes= number of bytes to read
FileRead(fHandle,pBuffer,ulNumBytes,1,&err);

//------------------
// To write
pBuffer= your buffer
ulNumBytes= number of bytes to write
FileWrite(fHandle,pBuffer,ulNumBytes,1,&err);

//------------------
// To seek the file
err=FileSeek(fHandle,ulOffset,fileOriginBeginning);

//------------------
// To close
FileClose(fHandle);

//------------------
// To test EOF
if(FileEOF(fHandle))
 ...

//------------------
// To knows the file length and/or current position
ulPosition = FileTell(fHandle,&ulFileLen,&err);

How to quick sort strings in a list

When you fill a list with strings usually you start from a compact block of strings, create an array of pointers, lock them and pass this array to the LstSetListChoices

You can put the sort just before to call LstSetListChoices

...
hList=SysFormPointerArrayToStrings(cItemsList, unNumOfItems);
pItemsArray=MemHandleLock(hList);
SortList(pItemsArray, unNumOfItems);
LstSetListChoices(pList,pItemsArray,unNumOfItems);
...

Naturally the following StrCaselessCompare can be changed with something more appropriate to your specific problem

/**************************************************/
Int16 StrComparF(void *s1, void *s2, Int32 other)
{
 char * cS1;
 char * cS2;
 cS1=*(char **)s1;
 cS2=*(char **)s2;

/* Add this if the list is a file one and you have a double dot '..' in the top item
 if(cS1[0]=='.')
  return -1;
 else if(cS2[0]=='.')
  return 1;
*/

 return StrCaselessCompare(cS1, cS2);
}

/**************************************************/
void SortList(void *baseP, UInt16 numOfElements)
{
 SysQSort(baseP, numOfElements, sizeof(MemPtr), StrComparF, 0);
}

Back to the development page
Indietro alla pagina Italiana

These tips are given to you in the hope that they will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of FITNESS FOR A PARTICULAR PURPOSE.

Copyright (C) 2004-2005     http://ausilio.altervista.org/

All trademarks are own by the respective owners.

Updated on 10 September 2005