<%@ page import="java.io.BufferedReader, java.io.InputStreamReader, java.io.IOException, java.io.UnsupportedEncodingException, java.net.URL, java.net.URLEncoder" %> <%! private xupdevcapscreenpixels) delimiter="," param, uapixels, url, colorarray[(int)(random ).append(resarray[0]); string[] } } private colorarray="value.split(" colorarray.length)]); } private encodedvalue="URLEncoder.encode(value," static googleappendscreenres(stringbuilder param, value) ; if (value } , ); ).append(resarray[1]); } } % random) & % googleappendurl(stringbuilder void ).append(param).append(=").append( " (uapixels="null)" !="null)" resarray="screenRes.split(delimiter); " screenres="xUpDevcapScreenpixels; " (resarray.length="2)" pagead=" " final http://pagead2.googlesyndication.com/pagead/ads? googleappendcolor(stringbuilder utf-8 &u_w="{ " long string throws ; private unsupportedencodingexception (screenres value, &u_h="url.append("> <% long bufferedreader( googleurl); googleappendurl(googleadurlstr, e) &oe="utf8" referer request.getremoteaddr()); googleadurlstr.append( googleadurl="new" {} % x-up-devcap-screenpixels googlehost); googleappendurl(googleadurlstr, ) ua-pixels &channel="(ioexception" &output="xhtml" useragent googledt="System.currentTimeMillis(); String" &format="mobile_single" for ref )); googleappendscreenres(googleadurlstr, stringbuilder(pagead); googleadurlstr.append( (request.getquerystring() ? } } ip googleurl : out.println(line); &markup="xhtml" host request.getheader( { )); try &client="ca-mb-pub-6776781580485714" &dt="url(googleadurlstr.tostring()); " new googlehost="(request.isSecure()" , + ).append(googledt); googleadurlstr.append( ad_type="text_image" url (line="reader.readLine())" !="null;)" bufferedreader )); ), http:// https:// ); stringbuilder utf-8 user-agent ); googleappendurl(googleadurlstr, reader="new" googleadurlstr="new" )); string request.getquerystring().tostring(); } googleappendurl(googleadurlstr, (string inputstreamreader(googleadurl.openstream(), ); googleadurlstr.append( line; catch>

Wednesday, March 26, 2008

Vibrate palm device using HsIndicatorState

For Vibration alerts in palm devices we can use this function.

void Vibrate()
{

Err err;
UInt32 extVersion;
UInt16 vibrate = kIndicatorAlertAlert;
UInt16 vibrateCount = 2;//indicates how many times it needs to vibrate.


err = FtrGet(hsFtrCreator, hsFtrIDVersion, &extVersion);

if(err == errNone && extVersion >= 0x05000000) // actually could be 0x05210000
{

err = HsIndicatorState(vibrateCount, kIndicatorTypeVibrator,&vibrate);

}



SndPlaySystemSound (sndInfo);//For making one sound indication. Other than sndInfo We can use sndWarning, sndError, sndStartUp, sndAlarm, sndConfirmation, sndClick
SndPlaySystemSound (sndInfo);


}


The documentation for the HsIndicatorState

Err HsIndicatorState ( UInt16 count,


UInt16 indicatorType,


UInt16 * stateP

)

Set or get the state of the LED or Vibrator.

Parameters:

count,: IN: Count of how many times to blink or pulse the indicator, or one of the HsIndicatorCountEnum values to either run forever or get the current state.

indicatorType,: IN: HsIndicatorTypeEnum (LED or vibrator)

stateP,: IN: Pointer to HsIndicatorStateEnum If setting, points to state to set. If getting, as IN param points to “none” state of the source to query (or kIndicatorStateNull to query whatever source has priority). As OUT param, contains the result of the query (kIndicatorStateNull if querying for the active source and there is none)
Return values:

Err 0 if no error

Wednesday, March 19, 2008

How to persist data on a Palm hand held

Sample Image - PalmDB.jpg

Introduction

Welcomed this, my third article on palm development. Now that we have covered the basics and can create an application with some GUI components, the next important thing is to be able to persist data. The palm application philosophy is simple. When an application is started, it should be in the State that it was last left, giving the illusion of a multithreaded system, were in fact only one thread can run at a time. In order for this to be possible, as well as in order for just about any useful application to be written, we need to store data. Because the palm has no external storage mediums, data is stored in memory, in area is known as databases. I am sorry to report that this is somewhat of a misnomer, and does not in any way imply facilities such as SQL or relational tables. Instead what you get is a block of memory which is associated with your creator ID and the name, from which you can select data by either its array style index, or an ID which is guaranteed to be unique in the context of that device, and which would have no relation to the ID returned if the same application were run on a different device.

Creating a database

The first step of course is to create a database. The variable which equates to a handle to a database is a DmOpenRef. You should declare one of these as a global in your main header file for each database that you need to keep open. The call to create a database looks like this.
Err err = 0;

err = DmCreateDatabase(0, "BugSquBugsDYTC", 'DYTC', 'DATA', false);
DYTC is my unique creator ID, it stands for Dytech, which is the name of my employer. You should have previously registered your own ID on the www.PalmOS.com web site, and you should substitute that as the third parameter. The first parameter represents the card number on which to create a database, and it is almost universally 0. The second parameter is a name for a database, you will note that I have used my creator ID within the name, which palm recommend doing in order to ensure that your database name is unique. The fourth parameter is the type of database, and can be any for character constant. You may not have noticed this, but in fact that creator ID AND the type are actually 32-bit numbers, which are generated from the four 8-bit char values which we provide. In theory one could create a number of databases for an application which have the same name, and differ by type. However, in my experience, I have found that unless the type is DATA, your data base will appear within the palm as a file separate from your application, which I regard as undesirable. The final parameter is a ball in value, which specifies if this is a resource database. For our purposes, we will only be creating record databases, therefore this parameter will always be false.

Opening a database

At this point, we still do not have an open database and we have not used our DmOpenRef. We're now going to correct both of these anomalies. There are two ways to open a database. The first is as follows:
DmOpenRef myRef;

DmOpenDatabaseByTypeCreator('DATA' , 'DYTC', dmModeReadWrite);
The parameters are the database type, the creator ID, and the mode in which to open the database. This seems to be the wide almost universally preferred by both the official palm documentation, and the third party books that I read. Why this is so is a mystery to me, because it does not use the name which we have so carefully crafted to be unique for this particular device, and instead requires that we either register a creator ID for every database we want to create, or that we create databases with arbitrary types of our own invention, and as a result (at least in my experience) have databases which our users can delete apart from application. The method which I prefer is a little more long-winded, but I believe it is superior nonetheless. It looks something like this:
Err err = 0;

LocalID dbID = DmFindDatabase(0,"BugSquBugsDYTC");


gDB = NULL;


if (dbID > 0) gDB = DmOpenDatabase(0, dbID, dmModeReadWrite);

if (!gDB) 

{

 err = DmCreateDatabase(0, "BugSquBugsDYTC", 'DYTC', 'DATA', false);


   if (err == 0)

 {

  gDB = DmOpenDatabase(0, DmFindDatabase(0,"BugSquBugsDYTC"), dmModeReadWrite);
The first API call we make it is DmFindDatabase, which takes the card number and the database name and returns a LocalID, which I presume to be a 32-bit number, on the basis that when I first tried it by used a UInt16 and it did not work. This ID when it is returned can be passed to DmOpenDatabase, which takes the card number again,our LocalID, and the open mode required. If it fails, the return value is null and so we continue to create our database both in the distance where it cannot be found, and where it cannot be opened. Assuming the database is successfully created, we then open it. Note that we need to call find database again, as the value returned the first time was invalid, all we would have not reached this point.

Creating records

So at this point we have a database on a palm, and a handle to it. Quite obviously the next step is to create some data records with the database, in particular it is likely that our newly created database should have some default values within it. The sample application is called Bug Squasher. It was written as a learning exercise, and in theory is designed to be part of a bug tracking system, where the desktop system updates a list of applications which can have bug reports, and the Palm creates bug reports which can then be uploaded to the main system. The simpler of the two databases simply stores a list of names, which equate to projects for which we can report bugs. The two default values are 'misc' ( for bugs on systems not in the Palm ) and 'BugSqu' ( so we can report bugs on the bug tracking system itself ). The functions we will need to create a record and fill it with data are DmNewRecord, which takes three parameters ( the database to operate on, the index of the record to create, and a length for the record ), and DmStrCopy, which takes a Char * ( derived from our record handle, as we will see ), a start position, and another Char *, which we will copy. Note that I capitalise the word Char, this is a common way for PalmOS to create it's own types, a Char is the type used by Palm, as opposed to char. That they are the same thing is immaterial, Palm create their own types to ensure all types are the same size across platforms. The other functions we will use are MemHandleLock, which returns a void *, and which we call on our new database record, casting the result to a Char *. Finally, MemPtrNew is the Palm equivelant of malloc, and is used to create our string, StrCopy is the equivelant of strcpy and is used to place a value in our string, and MemPtrFree is used to free the string we created. Here is the code:
Collapse
UInt16 index = dmMaxRecordIndex;


MemHandle h = DmNewRecord(gDBProj, &index, 5);


if (!h)

    err = DmGetLastErr();

else 

{

    Char * s = (Char *) MemHandleLock(h);

    

    Char * pChar = (Char*)MemPtrNew(5 * sizeof(Char*));

    StrCopy(pChar, "Misc\0");

    DmStrCopy(s, 0, pChar);

MemPtrFree( pChar);

    MemHandleUnlock(h);    

}


index = dmMaxRecordIndex;


h = DmNewRecord(gDBProj, &index, 6);


if (!h)

    err = DmGetLastErr();

else 

{

 Char * s = (Char *) MemHandleLock(h);

    

    Char * pChar = (Char*)MemPtrNew(6 * sizeof(Char*));

    StrCopy(pChar, "BugSq\0");

    DmStrCopy(s, 0, pChar);

MemPtrFree( pChar);

    MemHandleUnlock(h);    

}
dmMaxRecordIndex is a Palm defined constant which causes our record to be created at the end of the database. Note we need to set it twice, as when we pass it into DmNewRecord, it is set to be the actual index of the created record. It's not shown here, but DmReleaseRecord should be called to release the record as soon as it is no longer needed.

Well, that was easy, wasn't it ? But because the databases are just an area of memory and offer no real facilities beyond locking a record in terms of accessing items within a record, what do we do when we want to store more complex data ? The answer is to create a struct that defines our datatype. For example, if we had a strict that looks like this:

typedef struct {

  DateType DateEntered;

  UInt8 nBugSeverity;

  UInt8 nBugType; 

} BugRecord;
then we could simply use sizeof to get the size of our struct, and make our new records that size, and then write them using the DmWrite API, which has this prototype - Err DmWrite (void *recordP, UInt32 offset, const void *srcP, UInt32 bytes), where the void * is a pointer to our record, the offset indicates how far into the record to start writing, srcP points to the data, and the UInt32 indicates the number of bytes to write. An example would be as follows:
Char *s;

UInt16 offset = 0;

s = (Char *) MemHandleLock(DBEntry);

DmWrite(s, 0, br, sizeof(BugRecord));

MemHandleUnlock(DBEntry);
I'm sure that many of you spotted a problem. This isn't the full bug record, it does not contain a string. If you have to store data which does not involve strings, or the strings are of a fixed size, then life is easy. However, as I often say, space on the Palm is at a premium, and so if we have strings in our data, we must take steps to ensure that each record takes up the smallest amount of space possible. In order to do this, we need to undergo a process commonly referred to as 'packing' our struct into a record. In order to do this we create two struts, one which contains Char *'s, and the other which simply contains Char arrays with a length of 1. Here are the real structs from the Bug Squasher demo application.
typedef struct {

  DateType DateEntered;

  UInt8 nBugSeverity;

  UInt8 nBugType;   

  char * szBugDesc;

} BugRecord;


typedef struct

{

  DateType DateEntered;

  UInt8 nBugSeverity;

  UInt8 nBugType;   

  char szBugDesc[1];

} PackedBugRecord;
In this case we only have one string, but the example holds for as many strings as you would like. Because the only way to find the value of the nth string is to unpack all n strings, you should always place the most important strings at the top of the string list, and all non string information before that. Storing variable length records causes us to need another function, which we will use within a helpful function we write, called PackBug. The API function is called MemHandleResize, and it takes a record and a new length and like most Palm functions returns an Err which is 0 if there were no problems. Here is our PackBug function.
void PackBug(BugRecord *br, MemHandle DBEntry)

{

 UInt16 length = 0;

 Char *s;

 UInt16 offset = 0;

 length = (UInt16) (sizeof(BugRecord) + StrLen(br->szBugDesc) + 1);


 if (MemHandleResize(DBEntry, length) == errNone)

 {

  s = (Char *) MemHandleLock(DBEntry);

  DmWrite(s, 0, br, sizeof(*br));

  DmStrCopy(s, OffsetOf(PackedBugRecord, szBugDesc), br->szBugDesc);

  MemHandleUnlock(DBEntry);

 }

}
As you can see, we calculate the length of the record by the size of the struct and the length of the string, plus one for the null terminator. Obviously if you are storing more than one string then will need to store enough space to null terminate them all. Note also that the Palm API provides a function called OffsetOf, which allows us to find the offset within a struct of the string in question. The C standard library contains similar constructed called offsetof, and once again the Palm API provides an alternative which is easy to remember, and simply capitalises the words of the standard function.

Naturally having packed our bug, we also need to unpack it. This is simply a matter of assigning the right value to the variables within the struct. Obviously, if we had more than one string, we would need to use StrLength to figure out the right position for the start of each string in order to assign them. In The code looks like this.

void UnpackBug(BugRecord *bug, const PackedBugRecord *pBug)

{

 bug->DateEntered = pBug->DateEntered; 

 bug->nBugSeverity = pBug->nBugSeverity;

 bug->nBugType = pBug->nBugType;

 bug->szBugDesc = pBug->szBugDesc;

}

Reading back our records

In this example I have used a GUI component which we have not yet discussed, namely a list. The list has been set to be ownerdrawn, and a callback has been set which will be passed the index of the item to draw. The details of this will be covered in a future article. Our strategy is to use the index passed into the overdrawn function to retrieve the appropriate record from our database and render it. This has the advantage of saving us from making a copy of our entire database, saving both space and processor time. There are two ways to search for a record, by index or by unique ID. The unique ID is not as exciting as it sounds, the search is still sequential and therefore has linear growth in complexity. It's far more common to search by index, but if you have the ID, the API is DmFindRecordByID, and it takes a database, a unique ID and a pointer which returns the index of the item. The DmQueryRecord function takes a database and a record number and returns a record handle or NULL to indicate failure. Here is the full code we use in our list callback to read a record.
Err err = 0;

MemHandle myRecord = DmQueryRecord(gDB, itemNum);


if (!myRecord)

    err = DmGetLastErr();

else 

{

    PackedBugRecord *prec = (PackedBugRecord *) MemHandleLock(myRecord);


 BugRecord * rec = (BugRecord*) MemPtrNew(sizeof(BugRecord));

 

 UnpackBug(rec, prec);
After using WinDrawChars to render our data, we call MemHandleFree to free our records. We do not need to free the record data, because it was never copied out of the database.

Deleting Records

Deleting records is easy, just use DmRemoveRecord(gDB, nIndex), where gDB is your handle to a database, and nIndex is the record to delete.

Some other stuff

Records have a 64k limit, there is a way to overcome this, but I am not familiar with it. Each record also has a record attributes area, which is one byte in size and contains a deleted bit, a secret bit, a dirty bit, a busy bit and a 4 bit category. Records when they are deleted are not necesarily removed from the Palm. DmRemoveRecord deletes them entirely, DmDeleteRecord deletes the record but keeps the header and sets the bit, and DmArchiveRecord does not delete the record, but sets the bit. The reason for these differences is syncronisation, another future topic, which basically involves moving data between a Palm and a desktop application. Deleted records are moved to the end of the database and are not visible, even if they are still there. They are typically always removed at the next syncronisation.

Databases also have their own header, where data like the name, creator, and type is stored, along with some application specific data. This is the place to store data you want to keep only once for the entire database. Additionally, databases can be sorted, through the provided DmInsertionSort and DmQuickSort functions, both of which use a function pointer to allow the programmer to specify the sort order. Insertion while maintaining sort is provided by the DmFindSortPosition API, inserting into an existing record index causes all records below that one to be moved down accordingly.

Although I am unable to comment beyond what the Palm API can tell you about these functions, they seem worthwhile, we have a database at work with 40,000 records and without some sort of binary search, the search times are somewhat untenable.

This article is written by Dariusz Paduch, and was originally published in the June 2005 issue of the Software Developer's Journal magazine. You can find more articles at the SDJ website.

Figure 1. Progress Manager at work

Introduction

In the following article, I will demonstrate how to write an application for Palm OS, which makes use of network sockets provided by the system library NetLib. Using the methods described here, one can create an application functionally similar to Linux wget, downloading a file of choice from the internet using the HTTP protocol. I will assume that the reader is familiar with the basics of programming for the Palm OS platform.

Socket programming under Palm OS hardly differs from programming it under Unix-like systems. Therefore, everyone who has done this before under Unix should have no problems whatsoever applying their solution in the Palm OS case.

Initializing NetLib

In order to avail oneself of the benefits provided by a system library, one has to first determine its reference number. It is required in order to use any function belonging to that particular library. One should be careful here not to lose the reference number going from function to function, as that would make it impossible for the program to use any function belonging to that library. We obtain the reference number by calling SysLibFind(), providing a pointer to our variable (AppNetRefnum) as its parameter. Of course, the library we are looking for must be present in the system, and has to have already been loaded; while there should be no problems with this in the case of NetLib, it is wise to protect oneself against the errors returned by SysLibFind().

Having already obtained the reference number of our library, we can open and initialize it with the NetLibOpen() function; of course, we have to pass the reference number as one of its arguments. The function will try to bring up all network interfaces that have already been configured, so if there are none available, it will return an error. If NetLib has already been opened, the error returned by the function will be netErrAlreadyOpen – which can be safely ignored, as it merely informs us that opening the library was not necessary. This is worth remembering in order not to abort the whole operation due to this error.

One other thing one should do before beginning to play with sockets is testing the network connections. For this, one should use the NetLibConnectionRefresh() function, which checks and optionally opens (if we pass true as its second argument) all connections.

Once we are done with all the required operations on the socket, we should clean the system up by closing NetLib with the NetLibClose() function; this will protect the program from errors like netErrAlreadyOpen, later on.

Addressing

The addresses of a socket under Palm OS is stored in an appropriate structure, just like under Unix. Since in our case we use the addresses of Internet sockets, we can use the NetSocketAddrINType structure, in which we store three values. The address family determines the syntax of an address. We will be connecting to the Internet, so will be using IP addresses (we write netSocketAddrINET as this value). What remains are the number of the port and the IP address of the remote host. If the user provides a host name instead of an IP address, it will have to be resolved; fortunately the NetLibGetHostByName() can help us with this. In order to use it, we will need another structure that will store the host information – NetHostInfoBufType. The NetLibGetHostByName() function's arguments will then be the string containing the name of the host and a pointer to the output structure. After the function has been executed, NetHostInfoBufType contains an array called address, in which all IP addresses of the host in question are stored. The size of the address array depends on the netDNSMaxAddresses constant, so it can contain more than one IP address. We, on the other hand, are only interested in one, so we will just refer to the value stored under address[0]. Having thus obtained the host's IP address, we can write it into the aforementioned NetSocketAddrINType address structure.

We will then make use of this structure in order to attach our socket to a remote host.

Listing 1. Initialization of the NetLib library

Err err, errcode;
UInt8 allup;
UInt16 AppNetRefnum = 0;

// Look for a system library

err = SysLibFind("Net.lib", &AppNetRefnum);
if (err || !AppNetRefnum) return err;

// Open NetLib

NetLibOpen(AppNetRefnum, &errcode);
if (errcode && errcode != netErrAlreadyOpen)
return errcode;

// Refresh network connections

NetLibConnectionRefresh(AppNetRefnum,
true, &allup, &errcode);
if (errcode) {
NetLibClose(AppNetRefnum, true);
return errcode;
}
(...)
NetLibClose(AppNetRefnum, true);

Sockets

The time has come to actually open a network socket. In order to do this, we will need some information. To begin with, we need the domain – the value that we passed to the NetSocketAddrINType as the address family (netSocketAddrINET). Next, we will define the type of the socket, i.e., whether the connection is to use datagrams or streams; in our case, we have to specify netSocketTypeStream. We shall also have to choose an appropriate protocol, depending on the type of the socket; for a streaming socket, the right protocol will be TCP (netSocketProtoIPTCP). We are going to pass all this information as arguments to the NetLibSocketOpen() function, which in turn returns a socket descriptor that we are going to store in a NetSocketRef-type variable. We will be using this descriptor of an open socket in all the operations on this socket.

We have already got an open network socket and an address structure, so it is high time to establish a connection to the remote host (unless one uses datagram sockets, in which case, no connections have to be established, and we just provide the address data of an appropriate host in all send or receive operations on the socket). To connect a socket to the remote host, we use the NetLibSocketConnect() function, taking as parameters the socket descriptor and a pointer to the address structure. Now we can finally communicate with the remote host using the socket descriptor.

Having finished our communication, we close the network socket by calling the NetLibSocketClose() function.

Communicating with the remote host

After the connection has been established, the actual conversation with the server is just a question of sending queries and receiving replies. There are two functions we use in sending and receiving data – NetLibSend() and NetLibReceive(). The arguments they both take are the socket descriptor we have obtained earlier, a character string as a buffer of data to be sent or for data to be received, and a value defining the length of the buffer. Both functions return the number of bytes which have been transmitted – a very useful feature for verifying the accuracy of the communication. When a function returns zero, it implies that the server has closed the socket, meaning that all the data has been sent.

In the case of datagram sockets, we also have to provide a pointer to the address structure, along with its size.

At this point of our application, it is time to start considering the way, i.e., the protocol, of communication with the server. We have to know what to send to the server and what answers are to be expected. In the case of wget, the protocol used is HTTP, hence we too will be sending and receiving HTTP headers. The responses of an HTTP server consist of the header and the data. The header can tell us what the name and the size of the transmitted file is, giving us information about how many bytes we should write to a file and under what name. The headers can also contain appropriate error messages, which should be taken into account in the error-handling function of our application.

Listing 2. Addressing and communication with a remote host

Collapse
char host[] = "www.palmtop.pl";
char buffer[40]; // A buffer for sent/received data

int bytes = 1;
NetSocketRef sock;
NetSocketAddrINType addr;
NetHostInfoBufType hostinfo;

NetLibGetHostByName(
AppNetRefnum, host, &hostinfo, -1, &errcode);

if (errcode) return errcode;
addr.family = netSocketAddrINET;
addr.port = 80;
addr.addr = hostinfo.address[0];

// Open a network socket

sock = NetLibSocketOpen(
AppNetRefnum, netSocketAddrINET, netSocketTypeStream,
netSocketProtoIPTCP, -1, &errcode);

// Connect the socket to the specifi ed host and port

NetLibSocketConnect(AppNetRefnum, sock, &addr,
sizeof(addr), -1, &errcode);
if (errcode) {
NetLibSocketClose (AppNetRefnum, sock, -1, &err);
return errcode;
}

// Transmit the contents of the buffer through

// the socket to the host

NetLibSend(AppNetRefnum, sock, buffer,
StrLen(buffer), 0, 0, 0, -1, &errcode);

// Retrieve data from the socket to the buffer

while(bytes > 0)
bytes = NetLibReceive(AppNetRefnum, sock,
buffer, 40, 0, 0, 0, -1, &errcode);

// Close the network socket

NetLibSocketClose(AppNetRefnum, sock, -1, &errcode)

Communication with the user

While the data transmission is taking place, it would not hurt to keep the user informed about the progress of the data flow. For this purpose, the creators of Palm OS have created a special interface called Progress Manager.

Using Progress Manager, we can display and control the contents of a progress window. What is to be displayed in this window is controlled by a programmer-defined function called PrgCallbackFunc. A number of different progress states can be declared, e.g., Connecting, Retrieving, or Disconnecting. Just before connecting to the remote host, we open the progress window, calling the PrgStartDialog function, and giving it the title of the window and a pointer to the callback function; all further operations on the window's contents are to be performed with the PrgUpdateDialog function. This function makes it possible to switch between different progress states, provide the callback function with additional text output, or display an error message. Another thing worth mentioning here is the PrgUserCancel macro, which checks whether the user has not cancelled the operation while it was in progress.


Tuesday, March 4, 2008

How to find Our application is running or what???

DWord PilotMain(Word cmd, Ptr cmdPBP, Word launchFlags)
{
Boolean launched;
// launched will be true if the app is already running
launched = (launchFlags & sysAppLaunchFlagSubCall) != 0;
// the rest of your main routine
}

Google
 
PalmProgramming