/* ************************************************************************** 
 *             The Pebbles Personal Digital Assistant Project               *
 * **************************************************************************
 * This code was written as part of the Pebbles project at                  *
 * Carnegie Mellon University.  See the following for more information:     *
 *                http://www.cs.cmu.edu/~pebbles                            *
 * This library code is available for use by others.                        *
 * Please contact us for more information: pebbles@cs.cmu.edu               *  
 *                                                                          *
 *         Copyright (C) 1998-2000 - Carnegie Mellon University             *
 * **************************************************************************/

/*
	This file describes the Pebbles protocol for communicating 
	synchronously between a handheld PDA and a PC.
	
	Designed and implemented by Rob Miller.
*/

//
// Pebbles protocol
//
//
// A Pebbles application consists of two parts: an application running
// on a handheld device (referred to as the "app"), and a server running
// on a desktop computer (referred to as the "plugin").
//
// The app and the plugin communicate through a central mediator
// called PebblesPC (a process which runs on the desktop
// computer and multiplexes apps with users):
//
//        App  <--------->  PebblesPC  <-----------------> Plugin
//          (serial port)            (Windows event queues)
//
// This file defines both protocols: App-to-PebblesPC and PebblesPC-
// to-plugin. It is written portably so that it can be included
// without error by any platform compiler (PalmPilot, WinCE, Win95/NT),
// but the WM_... constants are available only on Win platforms.
//

#ifndef _PEBBLES_H_
#define _PEBBLES_H_

//////////////////////////////////////////////////////////////////
//
// App-to-PebblesPC protocol
//
//////////////////////////////////////////////////////////////////

//
// PEBBLES_BAUDRATE: the baud rate of the serial connection between app
//                   and PebblesPC, in bits per second.
//
// Other serial parameters: 8 data bits, 1 stop bit, No parity bit.
//
#define PEBBLES_BAUDRATE    57600

#define PEBBLES_APP_PORTNUM 4343
#define PEBBLES_DLL_PORTNUM 4242

//
// A message sent across the serial connection (in either direction)
// has three fields:
//
//      command       1 byte     Command code (see below)
//      length        2 bytes    Length of data field, LSB first
//      data        len bytes    Data or arguments for command
//

// Number of bytes in a Pebbles message header (cmd and length fields)
#define PEBBLES_HEADER_SIZE			3
#define PEBBLES_LONG_HEADER_SIZE	7

// Maximum size of a Pebbles message
#define PEBBLES_MAX_MESSAGE_SIZE 0xFFFE

// Indicates that a four-byte message length follows the header
#define PEBBLES_LONG_MESSAGE_SIZE 0xFFFF

// Returns the command code of a message
#define PEBBLES_CMD(msg)		(  ((unsigned char *)(msg))[0]  )

// Returns the length of a message's data block
#define PEBBLES_LEN(msg)		(  ((unsigned char *)(msg))[1] | (((unsigned char *)(msg))[2] << 8)   )

// Returns the length of a long message
#define PEBBLES_LONG_LEN(msg)  (  ((unsigned char *)(msg))[3] | (((unsigned char *)(msg))[4] << 8) | (((unsigned char *)(msg))[5] << 16) | (((unsigned char *)(msg))[6] << 24) )

// Returns a pointer to the message's data
#define PEBBLES_DATA(msg)		(  ((char *)(msg)) + PEBBLES_HEADER_SIZE  )

// Returns the data from a long message
#define PEBBLES_LONG_DATA(msg) (  ((char *)(msg)) + PEBBLES_LONG_HEADER_SIZE  ) 

// Sets the command code of a message
#define PEBBLES_SET_CMD(msg, cmd)		(	PEBBLES_CMD(msg) = (cmd)  )

// Sets the length of a message
#define PEBBLES_SET_LEN(msg, len)		(  ((unsigned char *)(msg))[1] = ((unsigned)(len)) & 0xFF, \
										   ((unsigned char *)(msg))[2] = (((unsigned)(len)) >> 8) & 0xFF  )

// Sets the length of a long message
#define PEBBLES_SET_LONG_LEN(msg, len)	(  ((unsigned char *)(msg))[3] = ((unsigned int)(len)) & 0xFF, \
										   ((unsigned char *)(msg))[4] = (((unsigned int)(len)) >> 8) & 0xFF, \
										  ((unsigned char *)(msg))[5] = (((unsigned int)(len)) >> 16) & 0xFF, \
										   ((unsigned char *)(msg))[6] = (((unsigned int)(len)) >> 24) & 0xFF )

#define PEBBLES_SOCKET_HEADER_SIZE 4

#define PEBBLES_GET_USERID(msg) ( ((PEBBLES_LEN(msg) == PEBBLES_LONG_MESSAGE_SIZE) ? ((unsigned char *) (msg))[PEBBLES_LONG_HEADER_SIZE] : ((unsigned char *)(msg))[PEBBLES_HEADER_SIZE] ) )
#define PEBBLES_SET_USERID(msg, id) (	PEBBLES_GET_USERID(msg) = (id)  )

#define PEBBLES_USERID_ALL_USERS	0
#define PEBBLES_USERID_NO_USER		255
#define PEBBLES_MAX_USERS               256


#define PEBBLES_SOCKET_MESSAGE(msg)	(  ((PEBBLES_LEN(msg) == PEBBLES_LONG_MESSAGE_SIZE) ? (((char *)(msg)) + PEBBLES_LONG_HEADER_SIZE + 1) : ((char *)(msg)) + PEBBLES_SOCKET_HEADER_SIZE  ))


//
// System command codes
//

#define CMD_PEBBLES_NO_MESSAGE           0
        // Reserved as a return value for PebblesReceiveHeader()

#define CMD_PEBBLES_STARTUP              1
        // Data: none
        //
        // Sent by PebblesPC to app when PebblesPC opens a serial port,
        // just in case an app is listening at the other end.
        // App responds by sending CMD_PEBBLES_CHANGE_PLUGIN.

#define CMD_PEBBLES_CHANGE_PLUGIN        2
        // Data: plugin name (case doesn't matter) or none (PebblesPC 2.0)
		//       plugin name, null byte, user name, null byte (PebblesPC 3.0)
		//		 pulgin name, null byte, user name, null byte, flags (PebblesPC 4.0)
        //
        // Sent by app to switch to a plugin.  If no argument is sent,
        // the app is disconnected from its plugin.  App should send a no-data
        // CMD_PEBBLES_CHANGE_PLUGIN when it exits, to notify plugin that it's
        // gone.
#define PEBBLES_PLUGIN_FLAG_FLOW_CONTROL	0x1
#define PEBBLES_PLUGIN_FLAG_SPOOF_USER		0x2

#define CMD_PEBBLES_ACK_CHANGE_PLUGIN    3
        // Data: none
        //
        // Sent by PebblesPC to acknowledge that it has found and
        // connected to the plugin requested by CMD_PEBBLES_CHANGE_PLUGIN.
        // App should not send any user-defined commands
        // until it sees this acknowledgement.

#define CMD_PEBBLES_NO_ACK_CHANGE_PLUGIN    4
        // Data: none
        //
        // Sent by PebblesPC to inform the PDA that the requested
		// plugin could not be found.

#define CMD_PEBBLES_KEEPALIVE    5
        // Data: none
        //
        // Sent to ensure that connection between PDA and PC
	// is still active

#define CMD_PEBBLES_FLOW_CONTROL 6
        // Data: 1-byte flag to turn on or off flow control (1 means on, 0 means off) 
        //
	// Sent by an app to change PebblesPC's output hardware flow control.
	// Flow control needs to be turned off for raw IR (which doesn't support it)
        // and turned on for regular serial ports.
        //
        // Hardware flow control is always re-enabled after every CHANGE_PLUGIN,
        // so the app must disable it after every CHANGE_PLUGIN if desired.

#define CMD_PEBBLES_CHANGE_USERNAME	7
        // Data: user name
        //
        // Sent by app to PC and contains  user name 

#define CMD_PEBBLES_RESERVED1            8
        // Reserved because of a bug -- PalmPilot sometimes sends this byte
        // when it opens its serial port.


// sent to Socket Plugin when a new user arrives
#define CMD_SOCKET_NEW_USER	9
	// Data: user name

// sent to Socket Plugin when a user leaves
#define CMD_SOCKET_DONE_USER	10

// sent by Socket Plugin 
#define CMD_SOCKET_PLUGIN_NAME 12
	// Data: plugin name


//
// User-defined command codes
//

//
// User-defined commands should start from CMD_PEBBLES_BASE.
// (CMD_PEBBLES_BASE is set rather high, to avoid dangerous ASCII control
// characters like XON and XOFF.)
//
#define CMD_PEBBLES_BASE                32

//
// User-defined commands should not exceed CMD_PEBBLES_MAX.
// (All command codes must fit in 8 bits; furthermore, we reserve 127 because
// of a PalmPilot bug.  Thus the maximum user-defined command is 126.)
//
#define CMD_PEBBLES_MAX                 126




//
// Other system command codes
//

#define CMD_PEBBLES_RESERVED2              127
        // Reserved because of a bug -- PalmPilot sometimes sends this byte
        // when it closes its serial port.


//////////////////////////////////////////////////////////////////
//
// PebblesPC-to-plugin protocol
//
//////////////////////////////////////////////////////////////////

//
// A Pebbles plugin should be compiled as a DLL with one exported
// function:
//
//        extern "C" BOOL WINAPI PebblesMain (HWND hwnd, PebblesPlugin *pPlugin)
//
//            Description:  initializes the plugin and creates its thread.
//
//            Parameters:   hwnd -- handle of PebblesPC window

//                          pPlugin -- structure which plugin should fill
//                                     with a description of itself. See
//                                     PebblesPlugin definition below. Some
//                                     fields are initialized with defaults,
//                                     but pPlugin->thread and pPlugin->hThread
//                                     should always be set.
//
//            Returns:      true if plugin successfully started;
//                          false if not.
//
//
// PebblesMain should start a running thread to serve as the plugin,
// and return the thread handle in pPlugin->thread.  You can create a
// thread in a variety of ways under Win95/NT. CreateThread(),
// _beginthread(), and _beginthreadex() all return a thread handle.
// If you use MFC, the class CWinThread makes the thread handle available
// in the field m_nThreadID.
//
// When PebblesPC starts up, it attempts to load all DLLs located in the
// same directory as PebblesPC.exe and calls PebblesMain () on each one.
//
// After a plugin thread has been created, PebblesPC communicates with it
// using Windows events (PostThreadMessage).
//

//
// Description of a Pebbles plugin returned by PebblesMain.
//
typedef struct _PebblesPlugin {

    unsigned long   thread;     // Plugin thread ID.
                                // Plugin should always set this field!

    int             hasAbout;   // true if plugin has an About dialog box
                                // and will respond to WM_PEBBLES_ABOUT event.
                                // Defaults to false.

    int             hasPrefs;   // true if plugin has a configuration dialog box
                                // and will respond to WM_PEBBLES_PREFS event.
                                // Defaults to false.

    void *          hThread;    // Plugin thread handle (the return value of CreateThread).
                                // Plugin should always set this field!

} PebblesPlugin;


//
// Description of a Pebbles user.  A pointer to this structure is passed
// with many Pebbles events.
//
typedef struct _PebblesUser {
    int id;               // Small integer corresponding to user's serial
                          // connection (numbered from 0).
  //const char *name;     // User name (null-terminated; may be zero
    char *name;           // User name (null-terminated; may be zero
                          // length, but never NULL).

    unsigned long thread; // User thread ID; outgoing
                          // WM_PEBBLES_SEND events should be posted
                          // here.

} PebblesUser;


//
// PebblesPC <--> plugin events
//
// These events are passed between PebblesPC and a plugin,
// using PostThreadMessage.
//
// A plugin can receive any of the following events:
//        WM_PEBBLES_NEW_USER
//        WM_PEBBLES_DONE_USER
//        WM_PEBBLES_RECEIVED
//        WM_PEBBLES_ABOUT
//        WM_PEBBLES_PREFS
//
// Plugins are not required to handle any of these events.
// However, most plugins handle at least WM_PEBBLES_RECEIVED to execute
// commands received from the app.
//
// Like all Windows events, these events have two parameters,
// wParam and lParam.  The meaning of wParam and lParam varies
// according to the event type;  see the comments below.
//



#define WM_PEBBLES_BASE                (WM_USER + 4242)

#define WM_PEBBLES_NEW_USER         (WM_PEBBLES_BASE +  0)
    // Sent by PebblesPC to plugin when a new user connects to the plugin.
    //
    //            wParam      (PebblesUser*) points to PebblesUser struct.
    //                        Pointer is valid as long as user remains
    //                        connected; plugin should not free it.
    //
    //            lParam        0

#define WM_PEBBLES_DONE_USER        (WM_PEBBLES_BASE +  1)
    // Sent by PebblesPC to plugin when a user disconnects from the plugin.
    //
    //            wParam      (PebblesUser*) points to PebblesUser struct.
    //                        Pointer is valid as long as user remains
    //                        connected; plugin should not free it.
    //
    //            lParam        0

#define WM_PEBBLES_RECEIVED        (WM_PEBBLES_BASE +  2)
    // Sent by PebblesPC to the plugin when a user-defined command is
    // received from a connected app.
    //
    //            wParam      (PebblesUser*) points to PebblesUser struct.
    //                        Pointer is valid as long as user remains
    //                        connected; plugin should not free it.
    //
    //            lParam      (char*) points to the message,
    //                        which starts with a CMD_ code and a
    //                        length field, in the format described above.
    //                        Plugin must free this block.

#define WM_PEBBLES_SEND            (WM_PEBBLES_BASE +  3)
    // Sent by plugin to PebblesPC to send a message back to the app.
    // The plugin should send this message with PostThreadMessage()
    // using the thread handle in the PebblesUser structure.
    //
    //            wParam      (PebblesUser*) points to PebblesUser struct.
    //                        Pointer is valid as long as user remains
    //                        connected; plugin should not free it.
    //
    //            lParam      (char*) points to the message,
    //                        which starts with a CMD_ code and a
    //                        length field, in the format described above.
    //                        PebblesPC will free this block.

#define WM_PEBBLES_ABOUT            (WM_PEBBLES_BASE +  6)
    // Sent by PebblesPC to plugin to display an About box describing
    // the plugin. Plugins with no About box can beep or do nothing.
    //
    //            wParam        (HWND) PebblesPC window handle
    //
    //            lParam        0

#define WM_PEBBLES_PREFS            (WM_PEBBLES_BASE +  7)
    // Sent by PebblesPC to plugin to display an optional configuration
    // dialog for the plugin.  Plugins with no configuration can beep
    // or do nothing.
    //
    //            wParam        (HWND) PebblesPC window handle
    //
    //            lParam        0


#define WM_PEBBLES_SOCKET_PLUGIN_NAME            (WM_PEBBLES_BASE +  8)
    // Sent by PluginData to notify Pebbles that it has received a name
	// and is ready to be added to the plugin list
    //
    //            wParam        (CPebblesPluginData *) Pointer to Plugin Data class
    //
    //            lParam        0



#endif
