Friday, August 17, 2007
How to connect the palm to your phone, PC or other serial device through Bluetooth
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 associate a file extension to a card directory
// 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");
Drawing a Bitmap Family Member
This description is specific to Palm OS 3.5 and later, but for information on earlier Palm OS versions, see the [CompatNote compatibility notes] below.
# Use Constructor for Palm OS to open the form that will contain the bitmap.
# In the Project Window, create a new Bitmap Family.
# Open the Bitmap Family resource and set the values for the properties.
# Note that every member of the Bitmap Family must have the same Width and Height.
# You can set one of the colors to be transparent when the bitmap is drawn to the screen.
# You can add bitmaps of different depths to the bitmap family by selecting Edit > New Family Member(also by using Ctrl-K on Windows or Cmd-K on Macintosh). You can use up to five bitmap depths in one bitmap family, but bitmap images must be stored in increasing order of bit depth, and the bit depths must be unique. For backward compatibility, you should always have a 1-bit black and white bitmap as the first bitmap in the bitmap family.
# Do not add a Form Bitmap to the form. Rather, use the following code to draw the correct member of the bitmap family for the handheld's bit depth at runtime:
MemHandle hRsc = DmGetResource(bitmapRsc, TestBitmapFamily);
BitmapType* bitmapP = (BitmapType*) MemHandleLock(hRsc);
WinDrawBitmap(bitmapP, topLeftCoordX, topLeftCoordY);
MemHandleUnlock(hRsc);
DmReleaseResource(hRsc);
To improve the performance of drawing the bitmap, you can call the "Get" and "Lock" functions well in advance to calling the "Draw" function. In addition, if you plan to reuse the same bitmap, you can call the "Unlock" and "Release" functions later in your code. For example, you could load and lock a number of bitmaps in an AppStart function, and then unlock and release them in an AppStop function.
# Compatibility Notes
Prior to Palm OS 3.5, the steps for adding a bitmap were similar, but you would simply add a black-and-white bitmap rather than a bitmap family. For Palm OS 3.5 and later, using a bitmap family allows Palm OS to select the right bit depth that is supported for the screen hardware. If your version of Constructor has no support for Bitmap Family resources, then you need to upgrade to the version of Constructor that comes with Palm OS 4.0 SDK. Note that when you create a bitmap family in Constructor, it will look like each bitmap has its own object ID. However, these object IDs are for use by Constructor; your code cannot access an individual member of a bitmap family.
Fetching Unique ID of SD Card
m505: SD016_00016437230807,
T-T : SD016_000164372300D1
and even worse on a Handera 330:H330: SD016_00016437
The last 3 chars of m505 and T-T could be some kind of Checksum but whatabout the H330? This leads to the question:
How much of the numbers are significant? How much of these is the realCard-ID and whats irrelevant?
////////////////////////////////////////////////////////////////////////////////////////////
The last 4 digits of the card ID contains the date the card wasmanufactured. On the Tungsten T, there was some sort of byte ordering problem with this DWord, That explains why "0807" != "00D1" in your data above. Palm stated they will fix this problem on future devices, so that M- and T-class devices shall report the same number. This glitchrenders the last 4 digits insignificant.
The significant digits, then, are the last 8 hex chars after the *last* underscore are the card's serial number (exception: the last 2 charswill be 0x00 for old MMC cards). This serial number is required to be unique for a particular product line of cards, however this is not aglobal unique ID across all SD/MMC card vendors, or even across multiple models (product lines) of the same vendor. In other words, SanDisk could make a 512 Meg card with s/n 00000000, and then make a 1 GB cardwith the same s/n. To create a global unique ID that takes models & manufactures into account, one could hash the data before the *last* underscore, which is the card's manufacture and model number, and thenconcatenate it with the serial number.
I emphasize 'last' underscore above, because the manufacture's text ID(the first 5 bytes) could also contain an underscore.
So in your example above, "00016437" is the unique serial number of theSD card, the characters after this should be ignored, and "SD016" can beused to differentiate the model (product line).
Creating text with transparent background
WinPushDrawState();
WinSetDrawMode(winOverlay);
WinPaintChar(char,xpos,ypos);
WinPopDrawState();
Thursday, August 16, 2007
Checking for New Features in Palm OS 5
err = FtrGet(sysFtrCreator, sysFtrNumROMVersion, &romVersion);
if (romVersion >= sysMakeROMVersion(5,0,0,sysROMStageRelease,0)) //OS 5 or above
Pace Version ================================================================= You can check to see if you are running under the Palm Application Environment (PACE) and and at the same time get the version of PACE with:
FtrGet('pace', 0, &version);
Processor Type
================================================================
FtrGet(sysFtrCreator, sysFtrNumProcessorID, &procType);procType &= sysFtrNumProcessorMask;
You can then compare procType against the processor types defined in SysMgr.h
#define sysFtrNumProcessor328 0x00010000 // Motorola 68328 (Dragonball)
#define sysFtrNumProcessorEZ 0x00020000 // Motorola 68EZ328 (Dragonball EZ)
#define sysFtrNumProcessorVZ 0x00030000 // Motorola 68VZ328 (Dragonball VZ)
#define sysFtrNumProcessorSuperVZ 0x00040000 // Motorola 68SZ328 (Dragonball SuperVZ)
#define sysFtrNumProcessorARM720T 0x00100000 // ARM 720T
#define sysFtrNumProcessorARM7TDMI 0x00110000 // ARM7TDMI
#define sysFtrNumProcessorARM920T 0x00120000 // ARM920T
#define sysFtrNumProcessorARM922T 0x00130000 // ARM922T
#define sysFtrNumProcessorARM925 0x00140000 // ARM925
#define sysFtrNumProcessorStrongARM 0x00150000 // StrongARM
#define sysFtrNumProcessorXscale 0x00160000 // Xscale
#define sysFtrNumProcessorARM710A 0x00170000 // ARM710A
#define sysFtrNumProcessorx86 0x01000000 // Intel CPU (Palm Simulator)
High Density Display
===========================================================
To see if the High Density Feature Set is present, check the version of the Window Manager and confirm that it is 4 or greater:
err = FtrGet(sysFtrCreator, sysFtrNumWinVersion, &version);
Once you have confirmed that the High Density Feature Set is present, you can check the density of the screen with:
WinScreenGetAttribute(winScreenDensity, &attr);if (attr == kDensityDouble)//the screen is high density
Sampled Sound ==================================================================
err = FtrGet(sysFileCSoundMgr, sndFtrIDVersion, &version);
if(err)
{
// Sampled Sound Feature Set not present
}
else
{
// The Sampled Sound Feature Set is present.
// Check version number of Sound Manager, if necessary
if(version == expectedSndMgrVersionNum)
// everything is OK
}
SSL Library =====================================================================
theError = SysLibFind("SslLib", &refNum);
if (theError)
theError = SysLibLoad(sysFileTLibrary, 'ssl0', &refNum);
if (theError)
//no SSL library
else
//SSL library is present
Crypto Library
================================================================
theError = SysLibFind("CPMlib", &refNum);
if (theError)
theError = SysLibLoad(sysFileTLibrary, 'cpml', &refNum);
if (theError)
//no crypto library
else
//crypto library is present
Wednesday, May 2, 2007
Using the Palm OS Progress Manager
The Progress Manager was introduced with Palm OS 3.0. It provides application developers with a way of giving status feedback to users during long operations, and offers users the chance to abort or cancel the long operation. The Progress Manager is useful when an application has to perform either a sequence of operations - for example, connecting to a server - or to carry out a complex and time consuming algorithm. In either case the user may want to interrupt the operation before it is completed.
Using the Progress Manager has four stages: launching the dialog box, updating the dialog box's display to show the current status, listening for events in the progress dialog and finally removing the dialog box when the operation is complete. To demonstrate the use of the Progress Manager I have created a sample application, which simulates a slow operation. In the example a loop counting to 1000 is initiated when the user presses a 'Start' button. The application launches a progress dialog and updates the user as to how far the count has reached. When the count reaches 1000 the operation is complete, and the progress dialog box is removed. The code below shows the event handler for the 'Start' button. The call to launch the progress dialog box is PrgStartDialog. This call is made just before the slow operation commences. PrgStartDialog takes two parameters, a title for the dialog box and a pointer to a callback function.
switch(eventP>data.ctlSelect.controlID)
{
case MainStartButton:
{
ProgressPtr prg;
Long i=0, cnt=0;
EventType event;
prg = PrgStartDialog("Counting to 1000...", callbackFunction);
//Do something complicated...
while (i<1000)>
{
i++;
cnt++;
StrIToA(message, i);
if (cnt==10)
{
PrgUpdateDialog(prg, 0, i, message, false);
cnt=0;
}
EvtGetEvent(&event, 0);
if (!PrgHandleEvent(prg, &event))
if (PrgUserCancel(prg))
break;
}
PrgStopDialog(prg, false);
break;
}
default:
break;
}
Once the complex operation is underway, we need to make periodic calls to the Progress Manager to update the state of the progress dialog. This provides an opportunity to give the user feedback on how far into the operation we are, and how much longer they might have to wait. This call is made with PrgUpdateDialog. The function takes a pointer to the progress dialog (which was returned by PrgStartDialog) and error flag, a stage indicator, a text message and a boolean flag to determine whether to redraw the dialog or not. The interesting parameters are the stage indicator and the text message. The stage indicator represents the progress that the application has made so far, and can be used in our callback function to give the user some meaningful feedback. In a sequential operation we might pass an indicator to say which step of the sequence we have reached. (In the sample application I pass the current count.) The text message parameter is also used to give feedback to the user. This parameter is usually used to pass dynamic text information to the progress dialog box. For example, if the application was connecting to a server we might use the message parameter to pass the phone number that we had dialled.
Because the progress dialog box has a 'Cancel' button, which the user can press to stop the operation, we need to look for events in the Progress Manager. We do this by taking control of the event loop during the processing of long operation. To get events we make an EvtGetEvent call to the Event Manager. This gives us the next event from the event queue. We immediately pass this event to the Progress Manager, with a call to PrgHandleEvent. The Progress Manager calls our callback function to get the information that it should display. It should be noted that PrgHandleEvent internally makes a call to the system event handler (SysHandleEvent), so any system events - like the user pressing the power key - will be handled correctly.
The callback function was established when we made the call to PrgStartDialog. It is called during the PrgHandleEvent handler to give the application an opportunity to set the messages that will be displayed on the progress dialog. In the sample code we use callbackFunction, and its definition is shown below. This structure is defined in the header file progress.h and is copied below for reference. It is a complex structure, but fortunately the callback function only has to use a couple of fields, the rest are for system use. The most significant task of callbackFunction is to fill the textP field. This is used to give the user an indication of the progress through the operation. A typical use would be to perform a look up on the value given in the stage field and to set an appropriate text message describing the stage. The text message we sent with the call to PrgUpdateDialog can also be used to supplement the display with some dynamic information. For example, if we were connecting to a server we might have a value that indicated we were at stage 1. We would set textP to 'Dialing:' and then concatenate the value in the message field to provide the number we were dialing. This would give the output: 'Dialing: 01119 998229'. When we change textP we need to set the textChanged flag to true to force the dialog box to redraw. Finally, callbackFunction can set a bitmap to display on the progress dialog, and again this can be determined by the stage that the operation is at.
typedef struct
{
Word stage; // current stage
CharPtr textP; // buffer to hold text to display
Word textLen; // length of text buffer
CharPtr message; // additional text for display
Err error; // current error
Word bitmapId; // resource ID of bitmap to display
Word canceled:1; // true if user has pressed the cancel button
Word showDetails:1; // true if user pressed down arrow for more details
Word textChanged:1; // if true then update text (defaults to true)
Word timedOut:1; // true if update caused by a timeout
ULong timeout; // timeout in ticks to force next update (for animation)
DWord barMaxValue;
DWord barCurValue;
CharPtr barMessage; // text for display below the progress bar.
Word barFlags; // reserved for future use.
} PrgCallbackData;
Boolean callbackFunction(PrgCallbackDataPtr cbP)
{
if (cbP->stage<250)>textP, "Starting: ");
StrCat(cbP->textP, cbP->message);
cbP->bitmapId = startBitmap;
}
else if (cbP->stage>750)
{
StrCopy(cbP->textP, "Finishing: ");
StrCat(cbP->textP, cbP->message);
cbP->bitmapId = endBitmap;
}
else
{
StrCopy(cbP->textP, "In the middle: ");
StrCat(cbP->textP, cbP->message);
cbP->bitmapId = middleBitmap;
}
cbP->textChanged = true;
return true;
}
In most cases PrgHandleEvent will return true, allowing us to continue processing our task. If it returns false we should call PrgUserCancel. This will return true if the user pressed the cancel button on the progress dialog box. When the user presses cancel we should perform any tidy up that is necessary and then abort the long operation. The last call we make to the ProgressManager is made when our operation is complete. This is a call to PrgStopDialog, and it removes the progress dialog box from the screen.
Source : http://www.developer.com/lang/other/article.php/615961