[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [coldsync-hackers] Sync'ing a non-palm device using HotSync/ColdSync




Hi Alessandro,

The attached patch adds the CMP negotiation and DLP (base) functions required to emulate a Palm device. The patch is currently only for serial connections. The more useful Net synchronisation is on the todo list; I don't have the time right now (or a device to emulate the behaviour).

The main body of work will be contained in a separate library and/or application program.

Cheers

/Ferry Hendrikx


"Alessandro Zummo" <azummo-coldsync3@towertech.it> wrote:

Hello Ferry,

congratulations for your amazing work. To decide i think we'll have to see
the changes. Maybe you can post a "diff -u" to this list. If they're minor
and clearly written i think they should be integrated.

_________________________________________________________________ Check out the Xtra gaming servers at http://xtramsn.co.nz/gaming !
diff -ur coldsync-3.0-pre3/include/pconn/cmp.h coldsync-mod/include/pconn/cmp.h
--- coldsync-3.0-pre3/include/pconn/cmp.h 2001-09-07 10:56:29.000000000 +0000
+++ coldsync-mod/include/pconn/cmp.h 2003-10-27 16:48:21.000000000 +0000
@@ -101,6 +101,7 @@
extern int cmp_write(struct PConnection *pconn,
const struct cmp_packet *packet);
extern udword cmp_accept(struct PConnection *pconn, udword bps);
+extern udword cmp_wakeup(struct PConnection *pconn, udword bps);


#endif	/* _cmp_h_ */

diff -ur coldsync-3.0-pre3/include/pconn/dlp_cmd.h coldsync-mod/include/pconn/dlp_cmd.h
--- coldsync-3.0-pre3/include/pconn/dlp_cmd.h 2002-10-27 20:40:06.000000000 +0000
+++ coldsync-mod/include/pconn/dlp_cmd.h 2003-10-27 16:50:30.000000000 +0000
@@ -253,7 +253,10 @@
#define DLPARGLEN_ReadStorageInfo_Req 2


#define DLPRET_ReadStorageInfo_Info	DLPRET_BASE
+#define DLPRETLEN_ReadStorageInfo_Info	64
+
#define DLPRET_ReadStorageInfo_Ext	DLPRET_BASE+1	/* v1.1 */
+#define DLPRETLEN_ReadStorageInfo_Ext	32

#define DLPCMD_MEMCARD_LEN 32 /* Max. length of card and
* manufacturer name, including
diff -ur coldsync-3.0-pre3/include/pconn/dlp.h coldsync-mod/include/pconn/dlp.h
--- coldsync-3.0-pre3/include/pconn/dlp.h 2002-09-29 17:38:03.000000000 +0000
+++ coldsync-mod/include/pconn/dlp.h 2003-10-27 16:55:58.000000000 +0000
@@ -188,6 +188,12 @@
extern int dlp_recv_resp(struct PConnection *pconn, const ubyte id,
struct dlp_resp_header *header,
const struct dlp_arg **argv);
+extern int dlp_recv_req(struct PConnection *pconn,
+ struct dlp_req_header *header,
+ const struct dlp_arg **argv);
+extern int dlp_send_resp(struct PConnection *pconn,
+ const struct dlp_resp_header *header,
+ const struct dlp_arg argv[]);
extern int dlp_dlpc_req(struct PConnection *pconn,
const struct dlp_req_header *header,
const struct dlp_arg argv[],
diff -ur coldsync-3.0-pre3/include/pconn/PConnection.h coldsync-mod/include/pconn/PConnection.h
--- coldsync-3.0-pre3/include/pconn/PConnection.h 2002-11-25 01:34:34.000000000 +0000
+++ coldsync-mod/include/pconn/PConnection.h 2003-10-27 16:57:56.000000000 +0000
@@ -78,6 +78,7 @@
* HotSync button.
*/
#define PCONNFL_NOCHANGESPEED 0x0004 /* This is a modem, don't change speeds */
+#define PCONNFL_EMULATEPALM 0x0008 /* Emulate a Palm device, for device -> desktop connections */


/* Misc defines */
#define PCONN_NET_CONNECT_RETRIES 10	/* connect() retries */
diff -ur coldsync-3.0-pre3/libpconn/cmp.c coldsync-mod/libpconn/cmp.c
--- coldsync-3.0-pre3/libpconn/cmp.c	2002-09-29 17:38:09.000000000 +0000
+++ coldsync-mod/libpconn/cmp.c	2003-10-27 16:48:46.000000000 +0000
@@ -179,6 +179,63 @@
	return cmpp.rate;
}

+/* cmp_wakeup
+ * Negotiate the CMP part of establishing a connection with the Desktop.
+ * 'bps' gives the desired connection speed. 0 means "default to 57600".
+ * Returns the speed in bps if successful, or ~0 in case of error.
+*/
+
+udword
+cmp_wakeup(PConnection *pconn, udword bps)
+{
+    int err;
+    struct cmp_packet cmpp;
+
+    do {
+	/* Compose a wakeup message */
+	cmpp.type = (ubyte) CMP_TYPE_WAKEUP;
+	cmpp.ver_major = CMP_VER_MAJOR;
+	cmpp.ver_minor = CMP_VER_MINOR;
+	cmpp.flags = 0;
+
+	if (bps != 0){
+	    cmpp.rate = bps;
+	}
+	else{
+	    /* this is what my old Palm Pilot Pro suggests */
+
+	    cmpp.rate = 57600;
+	}
+
+	CMP_TRACE(5)
+	    fprintf(stderr, "===== Sending WAKEUP packet\n");
+
+	err = cmp_write(pconn, &cmpp);
+	if (err < 0)
+	    return ~0;
+
+    	CMP_TRACE(5)
+	    fprintf(stderr, "===== Waiting for INIT packet\n");
+
+	err = cmp_read(pconn, &cmpp);
+	if (err < 0){
+	    if (PConn_get_palmerrno(pconn) == PALMERR_TIMEOUT)
+		continue;
+
+	    fprintf(stderr, _("Error during cmp_read: (%d) %s.\n"),
+		    (int) PConn_get_palmerrno(pconn),
+		    _(palm_strerror(PConn_get_palmerrno(pconn))));
+	    return ~0;
+	}
+    } while (cmpp.type != (ubyte) CMP_TYPE_INIT);
+
+    CMP_TRACE(4)
+	fprintf(stderr, "Initialized CMP, returning speed %ld\n",
+		cmpp.rate);
+
+    return cmpp.rate;
+}
+
/* This is for Emacs's benefit:
 * Local Variables: ***
 * fill-column:	75 ***
diff -ur coldsync-3.0-pre3/libpconn/dlp.c coldsync-mod/libpconn/dlp.c
--- coldsync-3.0-pre3/libpconn/dlp.c	2002-11-04 02:05:29.000000000 +0000
+++ coldsync-mod/libpconn/dlp.c	2003-10-27 16:55:11.000000000 +0000
@@ -363,6 +363,259 @@
	return 0;
}

+
+/* dlp_recv_req
+ * Receive a DLP request from the Desktop. The header will be put in
+ * 'header', and the arguments will be written to 'argv'. No more than
+ * 'argc' arguments will be written.
+ * Returns 0 if successful. In case of error, returns a negative
+ * value; 'palm_errno' is set to indicate the error.
+ */
+
+int
+dlp_recv_req(PConnection *pconn, /* Connection to Desktop */
+ struct dlp_req_header *header,
+ const struct dlp_arg **argv)
+{
+ int i;
+ int err;
+ const ubyte *inbuf; /* Input data (from PADP or NetSync) */
+ uword inlen; /* Length of input data */
+ const ubyte *rptr; /* Pointer into buffers (for reading) */
+
+ /* Read the request */
+ err = (*pconn->dlp.read)(pconn, &inbuf, &inlen);
+ if (err < 0)
+ return err; /* Error */
+
+ DLP_TRACE(7)
+ debug_dump(stderr, "DLP<<<", inbuf, inlen);
+
+ /* Parse the request header */
+ rptr = inbuf;
+ header->id = get_ubyte(&rptr);
+ header->argc = get_ubyte(&rptr);
+
+ DLP_TRACE(6)
+ fprintf(stderr, "Got request, id 0x%02x, argc %d\n",
+ header->id, header->argc);
+
+ /* Make sure there's room for all of the arguments */
+ if (header->argc > pconn->dlp.argv_len){
+ struct dlp_arg *eptr; /* Pointer to reallocated argv */
+
+ /* Grow argv. Use the temporary variable 'eptr' in case
+ * realloc() fails.
+ */
+ eptr = (struct dlp_arg *)
+ realloc(pconn->dlp.argv,
+ sizeof(struct dlp_arg) * header->argc);
+ if (eptr == NULL){
+ /* Reallocation failed */
+ /* XXX - Set an error code */
+ return -1;
+ }
+ /* Update the new argv */
+ pconn->dlp.argv = eptr;
+ pconn->dlp.argv_len = header->argc;
+ }
+
+ /* Parse the arguments */
+ for (i = 0; i < header->argc; i++){
+
+ /* See if it's a tiny, small or long argument */
+ switch (*rptr & 0xc0){
+
+ case 0xc0: /* Long argument */
+ DLP_TRACE(5)
+ fprintf(stderr, "Arg %d is long\n", i);
+ pconn->dlp.argv[i].id = get_uword(&rptr);
+ pconn->dlp.argv[i].id &= 0x3f;
+ /* Strip off the size bits */
+ pconn->dlp.argv[i].size = get_udword(&rptr);
+ break;
+ case 0x80: /* Small argument */
+ DLP_TRACE(5)
+ fprintf(stderr, "Arg %d is small\n", i);
+ pconn->dlp.argv[i].id = get_ubyte(&rptr);
+ pconn->dlp.argv[i].id &= 0x3f;
+ /* Strip off the size bits */
+ get_ubyte(&rptr); /* Skip over padding */
+ pconn->dlp.argv[i].size = get_uword(&rptr);
+ break;
+ default: /* Tiny argument */
+ DLP_TRACE(5)
+ fprintf(stderr, "Arg %d is tiny\n", i);
+ pconn->dlp.argv[i].id = get_ubyte(&rptr);
+ pconn->dlp.argv[i].id &= 0x3fff;
+ /* Strip off the size bits */
+ pconn->dlp.argv[i].size = get_ubyte(&rptr);
+ break;
+ }
+ DLP_TRACE(6)
+ fprintf(stderr, "Got arg %d, id 0x%02x, size %ld\n",
+ i, pconn->dlp.argv[i].id,
+ pconn->dlp.argv[i].size);
+ pconn->dlp.argv[i].data = (ubyte *) rptr;
+ rptr += pconn->dlp.argv[i].size;
+ }
+
+ *argv = pconn->dlp.argv;
+ return 0;
+}
+
+
+/* dlp_send_resp
+ * Send the DLP response defined by 'header' to the Desktop. 'argv' is
+ * the list of arguments.
+ * Returns 0 if successful. In case of error, returns a negative
+ * value. 'palm_errno' is set to indicate the error.
+ */
+
+int
+dlp_send_resp(PConnection *pconn, /* Connection to Desktop */
+ const struct dlp_resp_header *header,
+ const struct dlp_arg argv[])
+{
+ int i;
+ int err;
+ ubyte *outbuf; /* Outgoing response buffer */
+ long buflen; /* Length of outgoing request */
+ ubyte *wptr; /* Pointer into buffers (for writing) */
+
+ PConn_set_palmerrno(pconn, PALMERR_NOERR);
+
+ /* Calculate size of outgoing request */
+ DLP_TRACE(6)
+ fprintf(stderr,
+ "dlp_send_resp: Calculating outgoing request buffer\n");
+
+ buflen = 2L; /* Request id and argc */
+ for (i = 0; i < header->argc; i++){
+
+ if (argv[i].size <= DLP_TINYARG_MAXLEN){
+ /* Tiny argument */
+ buflen += 2 + argv[i].size;
+ /* 2 bytes for id and 1-byte size */
+ DLP_TRACE(7)
+ fprintf(stderr, "Tiny argument: %ld bytes, "
+ "buflen == %ld\n",
+ argv[i].size, buflen);
+ }
+ else if (argv[i].size <= DLP_SMALLARG_MAXLEN){
+ /* Small argument */
+ buflen += 4 + argv[i].size;
+ /* 4 bytes for id, unused, and
+ * 2-byte size */
+ DLP_TRACE(7)
+ fprintf(stderr, "Small argument: %ld bytes, "
+ "buflen == %ld\n",
+ argv[i].size, buflen);
+ }
+ else {
+ /* Long argument */
+ buflen += 6 + argv[i].size;
+ /* 6 bytes: 2-byte id and 4-byte
+ * size */
+ DLP_TRACE(7)
+ fprintf(stderr, "Long argument: %ld bytes, "
+ "buflen == %ld\n",
+ argv[i].size, buflen);
+ }
+ }
+
+ /* Allocate a buffer of the proper length */
+ outbuf = (ubyte *) malloc(buflen);
+ if (outbuf == NULL){
+ fprintf(stderr,
+ _("%s: Can't allocate %ld-byte buffer.\n"),
+ "dlp_send_req",
+ buflen);
+ return -1;
+ }
+
+ /* Construct a DLP response header in the output buffer */
+ wptr = outbuf;
+ put_ubyte(&wptr, header->id | 0x80); /* ensure response flag is set */
+ put_ubyte(&wptr, header->argc);
+ put_uword(&wptr, header->error);
+
+ DLP_TRACE(5)
+ fprintf(stderr, ">>> response id 0x%02x, %d args, errno %d\n",
+ header->id, header->argc, header->error);
+
+ /* Append the response headers to the output buffer */
+ for (i = 0; i < header->argc; i++){
+ /* See whether this argument ought to be tiny, small
+ * or large, and construct an appropriate header.
+ */
+ if (argv[i].size <= DLP_TINYARG_MAXLEN){
+ /* Tiny argument */
+ DLP_TRACE(10)
+ fprintf(stderr,
+ "Tiny argument %d, id 0x%02x, "
+ "size %ld\n",
+ i, argv[i].id, argv[i].size);
+ put_ubyte(&wptr, argv[i].id & 0x3f);
+ /* Make sure the high two bits are
+ * 00, since this is a tiny
+ * argument.
+ */
+ put_ubyte(&wptr, argv[i].size);
+ }
+ else if (argv[i].size <= DLP_SMALLARG_MAXLEN){
+ /* Small argument */
+ DLP_TRACE(10)
+ fprintf(stderr,
+ "Small argument %d, id 0x%02x, "
+ "size %ld\n",
+ i, argv[i].id, argv[i].size);
+ put_ubyte(&wptr, (argv[i].id & 0x3f) | 0x80);
+ /* Make sure the high two bits are
+ * 10, since this is a small
+ * argument.
+ */
+ put_ubyte(&wptr, 0); /* Padding */
+ put_uword(&wptr, argv[i].size);
+ }
+ else {
+ /* Long argument */
+ /* XXX - Check to make sure the comm. protocol
+ * supports long arguments.
+ */
+ DLP_TRACE(10)
+ fprintf(stderr,
+ "Long argument %d, id 0x%04x, "
+ "size %ld\n",
+ i, argv[i].id, argv[i].size);
+ put_uword(&wptr, (argv[i].id & 0x3fff) | 0xc000);
+ /* Make sure the high two bits are
+ * 11, since this is a long
+ * argument.
+ */
+ put_udword(&wptr, argv[i].size);
+ }
+
+ /* Append the argument data to the header */
+ memcpy(wptr, argv[i].data, argv[i].size);
+ wptr += argv[i].size;
+ }
+
+ /* Send the response */
+ DLP_TRACE(7)
+ debug_dump(stderr, "DLP>>>", outbuf, wptr-outbuf);
+
+ err = (*pconn->dlp.write)(pconn, outbuf, wptr-outbuf);
+ if (err < 0){
+ free(outbuf);
+ return err;
+ }
+
+ free(outbuf);
+ return 0; /* Success */
+}
+
+
/* dlp_dlpc_req
* Send a DLP command, and receive a response. If there's a timeout waiting
* for data, resends the request, up to 5 times.
diff -ur coldsync-3.0-pre3/libpconn/PConnection_serial.c coldsync-mod/libpconn/PConnection_serial.c
--- coldsync-3.0-pre3/libpconn/PConnection_serial.c 2002-11-04 02:05:29.000000000 +0000
+++ coldsync-mod/libpconn/PConnection_serial.c 2003-10-27 17:03:35.000000000 +0000
@@ -338,9 +338,17 @@
pconn->speed = 0L;
}
}
-
-
- newspeed = cmp_accept(pconn, pconn->speed);
+
+ if (pconn->flags & PCONNFL_EMULATEPALM){
+ IO_TRACE(5)
+ fprintf(stderr, "Emulating a Palm device.\n");
+
+ newspeed = cmp_wakeup(pconn, pconn->speed);
+ }
+ else{
+ newspeed = cmp_accept(pconn, pconn->speed);
+ }
+
if (newspeed == ~0)
{
fprintf(stderr,
@@ -389,6 +397,11 @@
IO_TRACE(5)
fprintf(stderr, "This is a modem, so not changing speed.\n");
} else {
+ if (pconn->flags & PCONNFL_EMULATEPALM){
+ /* let the serial device finish */
+ usleep(50000);
+ }
+
if ((err = setspeed(pconn, tcspeed)) < 0)
{
fprintf(stderr, _("Error trying to set speed.\n"));