/* ************************************************************************** * 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