/************************************************************************* * * PROJECT: Serial Communication Tutorial * FILE: SerialComm.c * AUTHOR: Lon Tierney, 5/20/99 * Adapted from code by Mike Esler, 1/19/99 * * DECLARER: Section 9 * * DESCRIPTION: This is the sixth phase in the development of the Serial * Communication Tutorial. This code provides the functionality for * sending serial data to another computing device. * * **********************************************************************/ #include #include #include #include "SerialComm_res.h" /*********************************************************************** * * Internal Structures * ***********************************************************************/ typedef struct { Byte replaceme; } StarterPreferenceType; typedef struct { Byte replaceme; } StarterAppInfoType; typedef StarterAppInfoType* StarterAppInfoPtr; /*********************************************************************** * * Internal Constants * ***********************************************************************/ #define FALSE 0 #define TRUE 1 #define appVersionNum 0x01 #define appPrefID 0x00 #define appPrefVersionNum 0x01 #define ourMinVersion sysMakeROMVersion(2,0,0,sysROMStageRelease,0) #define CenterScrX 80 #define CenterScrY 80 #define MaxX 160 #define MinX 0 #define MaxY 0 #define MinY 160 #define BaudRate 19200 #define Timeout 0 #define SerRcvQueueSize 100 #define SerSendQueueSize 100 /*********************************************************************** * * Global variables * ***********************************************************************/ static UInt serRefNum; static Long numBytesRcvd; static Char serRcvQueue[SerRcvQueueSize]; //Serial receive queue static Char serSendQueue[SerSendQueueSize]; //Serial send queue /*********************************************************************** * * Internal Functions * ***********************************************************************/ static void InitSettings(); static void AllocateTextBoxes(char * buffer, FieldPtr fld, int size); static void InitTextBoxes(); static void Error(char * error_msg); static void ConnectSerial(); static void DisconnectSerial(); static void CheckSerial(); static Err SendSerial(int numChars, Long* numSent); static void TestSend(); /*********************************************************************** * * FUNCTION: RomVersionCompatible * * DESCRIPTION: This routine checks that a ROM version is meet your * minimum requirement. * * PARAMETERS: requiredVersion - minimum rom version required * (see sysFtrNumROMVersion in SystemMgr.h * for format) * launchFlags - flags that indicate if the application * UI is initialized. * * RETURNED: error code or zero if rom is compatible * ***********************************************************************/ static Err RomVersionCompatible(DWord requiredVersion, Word launchFlags) { DWord romVersion; /* ** see if we're running on a minimum required version of the ROM or ** later */ FtrGet(sysFtrCreator, sysFtrNumROMVersion, &romVersion); if (romVersion < requiredVersion) { if ((launchFlags & (sysAppLaunchFlagNewGlobals | sysAppLaunchFlagUIApp)) == (sysAppLaunchFlagNewGlobals | sysAppLaunchFlagUIApp)) { FrmAlert (RomIncompatibleAlert); /* ** Pilot 1.0 will continuously relaunch this app unless we ** switch to another safe one */ if (romVersion < sysMakeROMVersion(2,0,0,sysROMStageRelease,0)) AppLaunchWithCommand(sysFileCDefaultApp, sysAppLaunchCmdNormalLaunch, NULL); } return (sysErrRomIncompatible); } return 0; } /*********************************************************************** * * FUNCTION: GetObjectPtr * * DESCRIPTION: This routine returns a pointer to an object in the current * form. * * PARAMETERS: formId - id of the form to display * * RETURNED: VoidPtr * ***********************************************************************/ static VoidPtr GetObjectPtr(Word objectID) { FormPtr frmP; frmP = FrmGetActiveForm(); return (FrmGetObjectPtr(frmP, FrmGetObjectIndex(frmP, objectID))); } /*********************************************************************** * * FUNCTION: MainFormInit * * DESCRIPTION: This routine initializes the MainForm form. * * PARAMETERS: frm - pointer to the MainForm form. * * RETURNED: nothing * ***********************************************************************/ static void MainFormInit(FormPtr frmP) { } /*********************************************************************** * * FUNCTION: MainFormDoCommand * * DESCRIPTION: This routine performs the menu command specified. * * PARAMETERS: command - menu item id * * RETURNED: nothing * ***********************************************************************/ static Boolean MainFormDoCommand(Word command) { Boolean handled = false; switch (command) { case ConnectStart: MenuEraseStatus(0); handled = true; break; case ConnectStop: MenuEraseStatus(0); handled = true; break; default: break; } return handled; } /*********************************************************************** * * FUNCTION: MainFormHandleEvent * * DESCRIPTION: This routine is the event handler for the * "MainForm" of this application. * * PARAMETERS: eventP - a pointer to an EventType structure * * RETURNED: true if the event has handle and should not be passed * to a higher level handler. * ***********************************************************************/ static Boolean MainFormHandleEvent(EventPtr eventP) { Boolean handled = false; FormPtr frmP; switch (eventP->eType) { case ctlSelectEvent: switch(eventP->data.ctlEnter.controlID) { case TestHarnessStartButton: ConnectSerial(); handled = true; break; case TestHarnessStopButton: DisconnectSerial(); handled = true; break; case TestHarnessClearBufferButton: handled = true; break; case TestHarnessSendSerialButton: TestSend(); handled = true; break; case TestHarnessClearScrnButton: handled = true; break; case TestHarnessRedrawScrnButton: handled = true; break; default: break; } break; case menuEvent: return MainFormDoCommand(eventP->data.menu.itemID); break; case frmOpenEvent: frmP = FrmGetActiveForm(); MainFormInit(frmP); FrmDrawForm(frmP); handled = true; break; default: break; } return handled; } /*********************************************************************** * * FUNCTION: AppHandleEvent * * DESCRIPTION: This routine loads form resources and set the event * handler for the form loaded. * * PARAMETERS: event - a pointer to an EventType structure * * RETURNED: true if the event has handle and should not be passed * to a higher level handler. * ***********************************************************************/ static Boolean AppHandleEvent( EventPtr eventP) { Word formId; FormPtr frmP; if (eventP->eType == frmLoadEvent) { /* ** load the form resource */ formId = eventP->data.frmLoad.formID; frmP = FrmInitForm(formId); FrmSetActiveForm(frmP); /* ** Set the event handler for the form. The handler of the ** currently active form is called by FrmHandleEvent each ** time is receives an event. */ switch (formId) { case TestHarnessForm: InitTextBoxes(); FrmSetEventHandler(frmP, MainFormHandleEvent); break; default: ErrFatalDisplay("Invalid Form Load Event"); break; } return true; } return false; } /*********************************************************************** * * FUNCTION: AppEventLoop * * DESCRIPTION: This routine is the event loop for the application. * * PARAMETERS: nothing * * RETURNED: nothing * ***********************************************************************/ static void AppEventLoop(void) { Word error; EventType event; do { EvtGetEvent(&event, 50); if (! SysHandleEvent(&event)) if (! MenuHandleEvent(0, &event, &error)) if (! AppHandleEvent(&event)) FrmDispatchEvent(&event); CheckSerial(); } while (event.eType != appStopEvent); } /*********************************************************************** * * FUNCTION: AppStart * * DESCRIPTION: Startup code. * * PARAMETERS: nothing * * RETURNED: Err value 0 if nothing went wrong * ***********************************************************************/ static Err AppStart(void) { serRefNum = 0; return 0; } /*********************************************************************** * * FUNCTION: AppStop * * DESCRIPTION: Cleanup code. * * PARAMETERS: nothing * * RETURNED: nothing * ***********************************************************************/ static void AppStop(void) { DisconnectSerial(); } /*********************************************************************** * * FUNCTION: StarterPilotMain * * DESCRIPTION: This is the main entry point for the application. * PARAMETERS: cmd - word value specifying the launch code. * cmdPB - pointer to a structure that is associated with the launch code. * launchFlags - word value providing extra information about the launch. * * RETURNED: Result of launch * ***********************************************************************/ static DWord StarterPilotMain(Word cmd, Ptr cmdPBP, Word launchFlags) { Err error; error = RomVersionCompatible(ourMinVersion, launchFlags); if (error) return error; switch (cmd) { case sysAppLaunchCmdNormalLaunch: error = AppStart(); InitSettings(); if (error) return error; FrmGotoForm(TestHarnessForm); AppEventLoop(); AppStop(); break; default: break; } return 0; } /*********************************************************************** * * FUNCTION: PilotMain * * DESCRIPTION: This is the main entry point for the application. * * PARAMETERS: cmd - word value specifying the launch code. * cmdPB - pointer to a structure that is associated with the launch code. * launchFlags - word value providing extra information about the launch. * RETURNED: Result of launch * ***********************************************************************/ DWord PilotMain( Word cmd, Ptr cmdPBP, Word launchFlags) { return StarterPilotMain(cmd, cmdPBP, launchFlags); } /*********************************************************************** * * FUNCTION: InitTextBoxes * * DESCRIPTION: This handles getting memory allocated for the text boxes * we have on our form. * * PARAMETERS: nothing * * RETURNED: nothing * ***********************************************************************/ void InitTextBoxes() { FieldPtr Data; FieldPtr RawData; //Get pointers to our test fields RawData = GetObjectPtr(TestHarnessRawDataField); Data = GetObjectPtr(TestHarnessDataField); //Allocate memory for them AllocateTextBoxes("RawData: ", RawData, 1000); AllocateTextBoxes("Data", Data, 1000); } /*********************************************************************** * * FUNCTION: AllocateTextBoxes * * DESCRIPTION: This handles allocating memory allocated for the object * pointer passed to it. * * PARAMETERS: buffer - Initial memory contents for field * fld - Pointer to the field we want to allocate memory to * size - How much memory we are to allocate * * RETURNED: nothing * ***********************************************************************/ void AllocateTextBoxes(char * buffer, FieldPtr fld, int size) { char * newText; Handle handle; handle = MemHandleNew(size); // Lock down the handle and get a pointer to the memory chunk. newText = MemHandleLock(handle); // Copy the data from the record to the new memory chunk. StrCopy(newText, buffer); // Unlock the new memory chunk. MemHandleUnlock(handle); // Set the field's text to the data in the new memory chunk. FldSetTextHandle(fld, handle); } void Error(char * error_msg) { WinDrawInvertedChars(error_msg, StrLen(error_msg), 0, 20 ); } /*********************************************************************** * * FUNCTION: InitSettings * * DESCRIPTION: Used for ensuring the initial settings of item in our * application. * * PARAMETERS: nothing * * RETURNED: nothing * ***********************************************************************/ static void InitSettings() { int i; for (i=0; i < SerSendQueueSize; i++) { serSendQueue[i] = '\0'; } } /*********************************************************************** * * FUNCTION: ConnectSerial * * DESCRIPTION: Establishes serial connection * * PARAMETERS: nothing * * RETURNED: nothing * ***********************************************************************/ static void ConnectSerial() { Err err = 0; SerSettingsType settings; int i; /* ** Are we already connected? If so, we don't want to establish ** a new connection */ if (serRefNum != 0) { return; } /* ** Since we are not already connected, we need to initialize our ** global variables. */ numBytesRcvd = 0; for (i=0; i < SerRcvQueueSize; i++) { serRcvQueue[i] = '\0'; } /* ** Get a reference to the serial library for our serial connection. */ err = SysLibFind("Serial Library", &serRefNum); ErrFatalDisplayIf(err, "Can't find Serial Library!"); if (err) { SerClose(serRefNum); serRefNum = 0; return; } /* ** Open the serial connection at the specified baud rate. ** The '0' is the port number. We only have one serial port on a Palm. */ err = SerOpen(serRefNum, 0, BaudRate); ErrFatalDisplayIf(err, "Problem opening the serial port!"); if (err) { SerClose(serRefNum); serRefNum = 0; return; } settings.baudRate = BaudRate; settings.ctsTimeout = Timeout; settings.flags = serSettingsFlagStopBits1 | serSettingsFlagBitsPerChar8 | serSettingsFlagRTSAutoM; SerSetSettings(serRefNum, &settings); } /*********************************************************************** * * FUNCTION: DisconnectSerial * * DESCRIPTION: Closes serial connection * * PARAMETERS: nothing * * RETURNED: nothing * ***********************************************************************/ static void DisconnectSerial() { /* ** Are we already connected? If yes, close connection, otherwise ** do nothing. */ if (serRefNum != 0) { SerClose(serRefNum); serRefNum = 0; } else { } } /*********************************************************************** * * FUNCTION: CheckSerial * * DESCRIPTION: Checks the serial line for data. * * PARAMETERS: nothing * * RETURNED: nothing * ***********************************************************************/ static void CheckSerial() { Err err = 0; /* ** If connected, receive any data alrady on the line */ if (serRefNum == 0) return; numBytesRcvd = SerReceive(serRefNum, serRcvQueue, 1, 1, &err); if (0 == numBytesRcvd || err == serErrTimeOut || err == serErrLineErr) return; WinDrawInvertedChars(serRcvQueue, 1, 60, 40 ); return; } /*********************************************************************** * * FUNCTION: SendSerial * * DESCRIPTION: Sends the contents of the serSendBuffer out over * the serial line. * * PARAMETERS: numChars - number of characters to send from the queue. * numSent - I/O parameter to return number of chars sent. * * RETURNED: Error if any * 0 if successful * -1 if no connection * ***********************************************************************/ static Err SendSerial(int numChars, Long* numSent) { Err err = 0; /* ** If connected, send data. */ if (serRefNum == 0) return(0); *numSent = SerSend(serRefNum, serSendQueue, numChars, &err); return(err); } /*********************************************************************** * * FUNCTION: TestSend * * DESCRIPTION: Sends the contents of the serSendBuffer out over * the serial line. * * PARAMETERS: nothing * * RETURNED: nothing * ***********************************************************************/ static void TestSend() { Err error = 0; Long numSent; StrCopy(serSendQueue, "Testing \n\0"); error = SendSerial(StrLen(serSendQueue), &numSent); ErrFatalDisplayIf(error, "Can't send data!"); }