Thursday, August 23, 2007
Improving Code Completion in V9
How Does Code Completion Work?
Code completion has two parts: symbol acquisition and context discovery. Symbol acquisition is the process by which entries are put into the IDE's symbol browser database. You can see most of this database using the View/Browser Contents command.
The "Build Extras" panel of your project controls how this database is built. There are two options: compiler or code parser. The compiler method is the same one used in previous versions of CodeWarrior. With this, the compiler reports back to the IDE about the functions it compiled and the the macros and typedefs it saw. This data isn't very detailed, since it doesn't include prototypes for funtions that weren't also compiled, and it also doesn't include argument information for functions or macros. This data also requires that your code compile to be created. The IDE supports merging data from several projects -- if you link your project to another project and setup a dependency relationship, then the compiled browser data from that project will be imported into your own. This is how we setup browse info for precompiled headers in the past. See my article Palm OS Precompiled Headers for details.
The other option on the Build Extras panel is "Code Parser". This is usually the preferred option. When you pick this, the IDE uses its own C/C++ parser to read through all your source files, picking up information straight from your source and headers. This usually works, but there are some tweaks that have to be made for this step to succeed.
First, you need sane values for the Prefix File and Macro File settings. The prefix file setting should match your prefix setting in the C/C++ Compiler panel, but with one exception. If you're directly using a precompiled header as a prefix, you need to mention the file that generates that PCH here instead. Our default for Palm OS projects is "PalmOS.win.pch", the header that builds the PalmOS_Header precompiled header file.
The Macro File setting is very important for completion using the Palm OS headers. Normally, the code parser doesn't try to expand macros it sees in the source or header files. However, if you have macros that affect how the code is parsed, you need to specify them in a separate source file and mention it here. The Palm OS headers are full of these kind of macros, since all of the Palm OS API functions use them to define how they are called. We have provided a good default file, PalmOSMacros.h, which lives in the "CW for Palm OS Support" folder. You need a "\{Compiler\}CW for Palm OS Support" system access path in your project to see this file. Without this, the parser will get very confused with the Palm OS headers and just give up on them, which means you won't get completions for the Palm OS API calls.
OK, so if all this is working, then shortly after opening your project, you should see all the symbols turn pretty colors and a big database of items in the View/Browser Contents dialog. Now, we come to context discovery.
Even when you're using the compiler to gather symbols, you're also using the code parser to let the IDE know where you are in your source file. The IDE uses this information to provide itself with context about what symbols could be completed at the cursor location. If you look at the "Editor/Code Completion" settings in the IDE's preferences dialog, you'll see settings that control when it pops up a completion box. If the IDE isn't providing help on its own, you can manually bring up help using the alt-period key. This keystroke can be changed by altering the key binding of the "Edit/Complete Code" command. The completion window provides both symbol names, and also type information.
Why Doesn't This Work?
Here are two reasons:
1) The code parser has bugs that make it give up on some source files. One bug that made it into the IDE build that we shipped on V9 involved the binary and operator. The parser sometimes dies when it sees it, since its parsing it as a address-of operator and getting confused. This IDE also doesn't parse macros that have a space between the macro name and the argument list. Both of these bugs have been fixed for the 9.1 patch.
2) The PalmOSMacros.h file is incomplete. I built this file based on the Palm OS 4 SDK headers, and I missed some macros that are used in the Palm OS 5 SDK. A new version of this file is coming in the 9.1 patch.
Source :http://www.palmoswerks.com/stories/storyReader$124
Monday, August 20, 2007
How to programmatically open the find dialog
/* Emulate a keydown event */
static void AddKeyDownEvent(WChar character)
{
EventType theEvent;
MemSet(&theEvent, sizeof(EventType), 0);
/* Create the key down event */
theEvent.eType = keyDownEvent;
theEvent.data.keyDown.chr = character;
theEvent.data.keyDown.keyCode = 0;
theEvent.data.keyDown.modifiers = commandKeyMask;
/* Add the event to the event queue */
EvtAddEventToQueue(&theEvent);
}
In this case, pass in a character code of vchrFind Some other possible values that youmay find useful for the character argument are:
vchrMenu - Shows the menu bar
VchrCommand - Simulate a command stroke
vchrLaunch - Opens the launcher
vchrCalc - Opens the calculator
VchrRonamatic - Simulates a stroke from the graffiti writing area to the top of the screenvchrGraffitiReference - Opens the graffiti reference
dialogvchrLock - Locks and powers off the unit
vchrBacklight - Toggles the state of the backlight
For a complete listing see Chars.h.
Overriding the silk screen buttons
For example:
static void EventLoop()
{ Err error; EventType event;
do
{
EvtGetEvent(&event, evtWaitForever);
// Eat all find key events
if (event.eType == keyDownEvent && event.data.keyDown.chr == vchrFind)
{
continue;
}
if (!SysHandleEvent(&event))
{
if (!MenuHandleEvent(0, &event, &error))
{
if (!ApplicationHandleEvent(&event))
{
FrmDispatchEvent(&event);
}
}
}
}while (event.eType != appStopEvent);
}
/***************************************OR*****************************************************/
PenBtnInfoPtr btnInfo;
UInt16 numButtons;
btnInfo = (const PenBtnInfoPtr)EvtGetPenBtnList(&numButtons); //Get the list of silk screen buttons.
for(int i =0; i
{
if((pEvent->data.keyDown.chr)==btnInfo[i].asciiCode)
{
FrmCustomAlert(GenericErrorAlert,"Silk Screen button selected","","");
return true;
}
}
Launching Application From SD Card
DmDatabaseInfo (card, locid, NULL, &attr, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
attr=dmHdrAttrRecyclable;
DmSetDatabaseInfo (card, locid, NULL, &attr, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
SysUIAppSwitch (card, locid, sysAppLaunchCmdNormalLaunch, cmdPBP);
This code copies database from memory card to main memory, sets it's attribute to 'delete it automatically after closing' and then runs it in main memory.
This works fine with one exception: if reset occurs during running this app, it remains in main memory. But I think that it happens even in case of standard launcher running app from card.
How to power off programmatically
/***********************************************************************************/
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 know if the palm is powering on or is going to sleep
/*********************************************************************************************/
static void RegisterForNotifications()
{
UInt16 cardNo=0;
UInt32 romVersion=0;
LocalID dbID=0;
FtrGet(sysFtrCreator, sysFtrNumROMVersion, &romVersion);
if(romVersion <>
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 ...
}
Friday, August 17, 2007
How to exit from the application
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 create 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 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