

/* serial.c - The code for Maus, a simple Pilot Mouse! */
/* 

   Feel free to use this code as you wish, no guarantees are given 
   or implied. The code was not designed to be seen by others, it just
   turned out that way! Excuse the mess, it was quick and dirty, but fun!
   
   Have fun,
   Iain - isb@pobox.com
   
   Hints
   -----
   
   I never got this to run under the emulator, all my debugging had to be 
   done after loading to the Pilot.
   
   Please distribute anything interesting that comes of this, people really seem 
   to appreciate it!
   
*/

/* This code was once... */

/***********************************************************************
 *
 *	Copyright © Palm Computing 1995 -- All Rights Reserved
 *
 * PROJECT: Memo Pad Sample Application
 *
 * FILE: MemoPad.c (Phase 1)
 *
 * DESCRIPTION: Sample application to demonstrate the various
 * 	features available.
 *
 *	OBJECTIVE: Create an initial main form with a title and an
 * 	exit button.
 *
 * REVISION HISTORY:
 * 	 9/1/95	David		Initial version
 *
 **********************************************************************/
 
#include <Pilot.h>				// all the system toolbox headers
#include <SerialMgr.h>
#include <KeyMgr.h>

#include "serialRsc.h"		// application resource defines


/***********************************************************************
 * Prototypes for internal functions
 **********************************************************************/
static Err StartApplication(void);
static void StopApplication(void);

static Boolean MainFormHandleEvent(EventPtr event);
static void EventLoop(void);
static void SetSerialSettings();
static void SendData(char *data);

void YieldTime() {return;} //Gets through the linker! (This line is new, it wasn't in STv0.3)
                           //The idea came from comp.sys.palmtops a few days ago

UInt SerialRef;
SerSettingsType SerialSettings;

Int DownX;
Int DownY;

Int Bits = 7;
Int Parity = 0; //Use 0 for none, 1 for odd and 2 for even!
Int Baud = 1200;

static char InputStr[80];
Handle bufferHandle;
static Boolean portClosed;
static Boolean mouseOn = false;

/***********************************************************************
 *
 * FUNCTION:     StartApplication
 *
 * DESCRIPTION:  This routine sets up the initial state of the application.
 *
 * PARAMETERS:   None.
 *
 * RETURNED:     Nothing.
 *
 ***********************************************************************/
static Err StartApplication(void)
{
	FormPtr	frm;

	Err error;
	
	//Try to open the serial port...
	error = SysLibFind("Serial Library", &SerialRef);
	if (error)
		ErrDisplay("Error trying to load the serial library");


	// Initialize and draw the main form.
	frm = FrmInitForm(mainForm);	
	FrmSetActiveForm(frm);
		
	FrmDrawForm(frm);

	error = SerOpen(SerialRef, 0, Baud);
	// Best do something if there's an error!
	if (error)
	{
			ErrNonFatalDisplayIf( (error == serErrAlreadyOpen), "Another application is using the serial port");
			ErrNonFatalDisplayIf( (error == memErrNotEnoughSpace), "Not enough memory to open the serial port");
			ErrNonFatalDisplayIf( (error == serErrBadParam), "The serial port could not be opened");
			return true;
	}
					
	SetSerialSettings();

	portClosed = false;
	
	return 0;
}

static void StopApplication (void)
{
	//ErrDisplay("Stop App called!");
	if (!portClosed)
	{
		SerClose(SerialRef);
	}        
}

void SendData(char *data)
{
	Err error;
	
	// Best do something if there's an error!
	if (error)
	{
			ErrNonFatalDisplayIf( (error == serErrAlreadyOpen), "Another application is using the serial port");
			ErrNonFatalDisplayIf( (error == memErrNotEnoughSpace), "Not enough memory to open the serial port");
			ErrNonFatalDisplayIf( (error == serErrBadParam), "The serial port could not be opened");
	}
	

	error = SerSend(SerialRef, data, StrLen(data));
	ErrNonFatalDisplayIf( (error!=0), "Failed to send data to PC");
					
	SerClearErr(SerialRef);	
					
	//Just pause until the send buffer clears...
	SerSendWait(SerialRef, -1);	
}

void SetSerialSettings()
{
		Err error = 0;
		
		SerialSettings.baudRate = 1200;
		SerialSettings.ctsTimeout = serDefaultCTSTimeout;
		SerialSettings.flags = serSettingsFlagStopBits1 | serSettingsFlagBitsPerChar7;			
		
		error = SerSetSettings(SerialRef, &SerialSettings);
		if (error)
			ErrDisplay("Error when setting serial port values");
}

/***********************************************************************
 *
 * FUNCTION:		MainFormHandleEvent
 *
 * DESCRIPTION:	Handles processing of events for the ÒmainÓ form.
 *
 * PARAMETERS:		event	- the most recent event.
 *
 * RETURNED:		True if the event is handled, false otherwise.
 *
 ***********************************************************************/
static Boolean MainFormHandleEvent(EventPtr event)
{
	Boolean handled = false;
	Err error;
	
	if (event->eType == ctlSelectEvent)
  	{
  	 		if (event->data.ctlEnter.controlID == leftButton)
			{
	  				InputStr[0] = (char)224; //Just a left click
  					InputStr[1] = (char)128;
  					InputStr[2] = (char)128; 
  				
  					SendData(InputStr);
					InputStr[0] = (char)192;
  					SendData(InputStr);
  					
  					mouseOn = false;
			}
			else
  	 		if (event->data.ctlEnter.controlID == middleButton)
			{
					//Toggle left on and off
					if (mouseOn)
						mouseOn = false;
					else
						mouseOn = true;	
			}
			else
  	 		if (event->data.ctlEnter.controlID == rightButton)
			{
	  				InputStr[0] = (char)208; //Just a right click
  					InputStr[1] = (char)128;
  					InputStr[2] = (char)128; 
  				
  					SendData(InputStr);
					InputStr[0] = (char)192;
  					SendData(InputStr);
			}							
	}
	else
   if (event->eType == penDownEvent)
  	{	
			DownX = event->screenX;
			DownY = event->screenY;
	}
	else
	if (event->eType == penMoveEvent)
  	{	
  			int moveX;
  			int moveY;
  			int difX;
  			int difY;
  			
  			int byte1 = 192;
  			int byte2 = 128;
  			int byte3 = 128;
  			
  			char InputStr[3];
  			
  			moveX = event->screenX;
  			moveY = event->screenY;
  			
  			difX = moveX - DownX;
			difY = moveY - DownY;
  			
			DownX = moveX; //Ready for the next movement...
			DownY = moveY;
  			
 			if (difX < 0)
				difX = difX + 256; //To get 2's complement
  				
			if (difX >= 128)
 			{
  					byte1 = byte1 + 2;
  					difX = difX - 128;
  				}
  			
  				if (difX >= 64)
	  			{
  					byte1 = byte1 + 1;
  					difX = difX - 64;
  				}
  
	  			if (difY < 0)
  					difY = difY + 256;
  				
    			if (difY >= 128)
  				{
  					byte1 = byte1 + 8;
  					difY = difY -128;
  				}
  			
  				if (difY >= 64)
  				{
  					byte1 = byte1 + 4;
  					difY = difY - 64;
  				}
				
  				if (difX >= 0)
  					InputStr[1] = (char)(byte2 + difX);
  				
 	 			if (difY >= 0)
  					InputStr[2] = (char)(byte3 + difY);

				if (mouseOn)
					byte1 = byte1 + 32; //Left mouse toggled on
					  			  			
  				InputStr[0] = (char)byte1;

				SendData(InputStr);
	}
	
	return handled;
}

/***********************************************************************
 *
 * FUNCTION:		EventLoop
 *
 * DESCRIPTION:	A simple loop that obtains events from the Event
 *						Manager and passes them on to various applications and
 *						system event handlers before passing them on to
 *						FrmHandleEvent for default processing.
 *
 * PARAMETERS:		None.
 *
 * RETURNED:		Nothing.
 *
 ***********************************************************************/
static void EventLoop(void)
{
	EventType	event;
	Word			error;
	
	do
		{
		// Get the next available event.
		EvtGetEvent(&event, evtWaitForever);

		//I want first go at the event...
		if (! MainFormHandleEvent(&event))
		
			// Give the system a chance to handle the event.
			if (! SysHandleEvent (&event))

						// Let the form object provide default handling of the event.
						FrmHandleEvent(FrmGetActiveForm(), &event);
		} 
	while (event.eType != appStopEvent);
								// ** SPECIAL NOTE **
								// In order for the Emulator to exit
								// cleanly when the File|Quit menu option is
								// selected, the running application
								// must exit.  The emulator will generate an 
								// ÒappStopEventÓ when Quit is selected.
}


/***********************************************************************
 *
 * FUNCTION:		PilotMain
 *
 * DESCRIPTION:	This function is the equivalent of a main() function
 *						in standard ÒCÓ.  It is called by the Emulator to begin
 *						execution of this application.
 *
 * PARAMETERS:		cmd - command specifying how to launch the application.
 *						cmdPBP - parameter block for the command.
 *						launchFlags - flags used to configure the launch.			
 *
 * RETURNED:		Any applicable error code.
 *
 ***********************************************************************/
DWord PilotMain(Word cmd, Ptr cmdPBP, Word launchFlags)
{
	Err error;

	if (cmd == sysAppLaunchCmdNormalLaunch)
	{
		// Set up initial form.
		error = StartApplication();
		if (error) return error;
		
		// Start up the event loop.
		EventLoop();
		StopApplication ();
	}
		
	return(0);

}