* monitor.c: Move all xmodem stuff into xmodem.[ch]. Remove

unnecessary remoteloadprotocol and remoteloadtype support.
	* (expect expect_prompt):  Change names to monitor_expect and
	monitor_expect_prompt.  Make them global.
	* (printf_monitor):  Change name to monitor_printf.  Make global.
	* (monitor_read_memory):  Flush command echo to avoid parsing
	ambiguity with CPU32Bug monitor.
	* (monitor_load):  Remove remoteloadprotocol and remoteloadtype
	support.  Call target_ops->load_routine, default to
	monitor_load_srec.
	* (monitor_load_srec):  Remove everything but S-record support.
	* monitor.h (monitor_ops):  Add load_routine to provide monitor
	specific download capability.
	* remote-est.c:  Clean up copyrights and comments.
	* w89k-rom.c:  Use new xmodem support.
	* xmodem.c xmodem.h:  New files to support xmodem downloads.
	* rom68k-rom.c remote-est.c:  Fix copyrights, add load_routine
	entry to monitor_ops.
	* cpu32bug-rom.c:  New file to support Moto BCC debuggers.
	* config/m68k/est.mt (TDEPFILES):  Add cpu32bug.o.
	* config/pa/hppapro.mt (TDEPFILES):  Add xmodem.o.
This commit is contained in:
Stu Grossman 1995-04-17 06:31:39 +00:00
parent 9ce0322db8
commit 5de0c6486d
10 changed files with 627 additions and 54 deletions

View File

@ -112,6 +112,7 @@ core.c
coredep.c
corelow.c
cp-valprint.c
cpu32bug-rom.c
cxux-nat.c
dbxread.c
dcache.c
@ -326,6 +327,8 @@ w89k-rom.c
xcoffread.c
xcoffsolib.c
xcoffsolib.h
xmodem.c
xmodem.h
z8k-tdep.c

View File

@ -1,3 +1,3 @@
# Target: m68k emulator EST-300
TDEPFILES= m68k-tdep.o monitor.o remote-est.o
TDEPFILES= m68k-tdep.o monitor.o remote-est.o cpu32bug-rom.o
TM_FILE= tm-est.h

View File

@ -1,4 +1,4 @@
# Target: PA based debug monitor
TDEPFILES= hppa-tdep.o op50-rom.o w89k-rom.o monitor.o
TDEPFILES= hppa-tdep.o op50-rom.o w89k-rom.o monitor.o xmodem.o
TM_FILE= tm-pro.h
XDEPFILES= ser-tcp.o

177
gdb/cpu32bug-rom.c Normal file
View File

@ -0,0 +1,177 @@
/* Remote debugging interface for CPU32Bug Rom monitor for GDB, the GNU debugger.
Copyright 1995 Free Software Foundation, Inc.
Written by Stu Grossman of Cygnus Support
This file is part of GDB.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "defs.h"
#include "gdbcore.h"
#include "target.h"
#include "monitor.h"
#include "serial.h"
static void cpu32bug_open PARAMS ((char *args, int from_tty));
static void
cpu32bug_supply_register (regname, regnamelen, val, vallen)
char *regname;
int regnamelen;
char *val;
int vallen;
{
int regno;
if (regnamelen != 2)
return;
switch (regname[0])
{
case 'S':
if (regname[1] != 'R')
return;
regno = PS_REGNUM;
break;
case 'P':
if (regname[1] != 'C')
return;
regno = PC_REGNUM;
break;
case 'D':
if (regname[1] < '0' || regname[1] > '7')
return;
regno = regname[1] - '0' + D0_REGNUM;
break;
case 'A':
if (regname[1] < '0' || regname[1] > '7')
return;
regno = regname[1] - '0' + A0_REGNUM;
break;
default:
return;
}
monitor_supply_register (regno, val);
}
/*
* This array of registers needs to match the indexes used by GDB. The
* whole reason this exists is because the various ROM monitors use
* different names than GDB does, and don't support all the
* registers either. So, typing "info reg sp" becomes an "A7".
*/
static char *cpu32bug_regnames[NUM_REGS] =
{
"D0", "D1", "D2", "D3", "D4", "D5", "D6", "D7",
"A0", "A1", "A2", "A3", "A4", "A5", "A6", "A7",
"SR", "PC",
};
/*
* Define the monitor command strings. Since these are passed directly
* through to a printf style function, we need can include formatting
* strings. We also need a CR or LF on the end.
*/
static struct target_ops cpu32bug_ops;
static char *cpu32bug_loadtypes[] = {"srec", NULL};
static char *cpu32bug_loadprotos[] = {"none", NULL};
static char *cpu32bug_inits[] = {"\r", NULL};
static struct monitor_ops cpu32bug_cmds =
{
MO_CLR_BREAK_USES_ADDR,
cpu32bug_inits, /* Init strings */
"g\r", /* continue command */
"t\r", /* single step */
NULL, /* interrupt command */
"br %x\r", /* set a breakpoint */
"nobr %x\r", /* clear a breakpoint */
"nobr\r", /* clear all breakpoints */
"bf %x:%x %x;b\r", /* fill (start count val) */
{
"ms %x %02x\r", /* setmem.cmdb (addr, value) */
"ms %x %04x\r", /* setmem.cmdw (addr, value) */
"ms %x %08x\r", /* setmem.cmdl (addr, value) */
NULL, /* setmem.cmdll (addr, value) */
NULL, /* setreg.resp_delim */
NULL, /* setreg.term */
NULL, /* setreg.term_cmd */
},
{
"md %x:%x;b\r", /* getmem.cmdb (addr, len) */
"md %x:%x;b\r", /* getmem.cmdw (addr, len) */
"md %x:%x;b\r", /* getmem.cmdl (addr, len) */
NULL, /* getmem.cmdll (addr, len) */
" ", /* getmem.resp_delim */
NULL, /* getmem.term */
NULL, /* getmem.term_cmd */
},
{
"rs %s %x\r", /* setreg.cmd (name, value) */
NULL, /* setreg.resp_delim */
NULL, /* setreg.term */
NULL /* setreg.term_cmd */
},
{
"rs %s\r", /* getreg.cmd (name) */
"=", /* getreg.resp_delim */
NULL, /* getreg.term */
NULL /* getreg.term_cmd */
},
"rd\r", /* dump_registers */
"\\(\\w+\\) +=\\([0-9a-fA-F]+\\b\\)", /* register_pattern */
cpu32bug_supply_register, /* supply_register */
NULL, /* load_routine (defaults to SRECs) */
"lo\r", /* download command */
"lo\r\n", /* load response */
"CPU32Bug>", /* monitor command prompt */
NULL, /* end-of-command delimitor */
NULL, /* optional command terminator */
&cpu32bug_ops, /* target operations */
cpu32bug_loadtypes, /* loadtypes */
cpu32bug_loadprotos, /* loadprotos */
"9600", /* supported baud rates */
SERIAL_1_STOPBITS, /* number of stop bits */
cpu32bug_regnames, /* registers names */
MONITOR_OPS_MAGIC /* magic */
};
void
cpu32bug_open(args, from_tty)
char *args;
int from_tty;
{
monitor_open (args, &cpu32bug_cmds, from_tty);
}
void
_initialize_cpu32bug_rom ()
{
init_monitor_ops (&cpu32bug_ops);
cpu32bug_ops.to_shortname = "cpu32bug";
cpu32bug_ops.to_longname = "CPU32Bug monitor";
cpu32bug_ops.to_doc = "Debug via the CPU32Bug monitor.\n\
Specify the serial device it is connected to (e.g. /dev/ttya).";
cpu32bug_ops.to_open = cpu32bug_open;
add_target (&cpu32bug_ops);
}

View File

@ -22,6 +22,8 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "serial.h"
struct rom_cmd_data {
char *cmd; /* command to send */
char *delim; /* the delimiter */
@ -98,6 +100,7 @@ struct monitor_ops
char *dump_registers; /* Command to dump all regs at once */
char *register_pattern; /* Pattern that picks out register from reg dump */
void (*supply_register) PARAMS ((char *name, int namelen, char *val, int vallen));
void (*load_routine) PARAMS ((serial_t desc, char *file, int hashmark)); /* Download routine */
char *load; /* load command */
char *loadresp; /* Response to load command */
char *prompt; /* monitor command prompt */
@ -167,8 +170,9 @@ extern struct monitor_ops *current_monitor;
#define MEM_DIS_CMD (current_monitor->getmem)
#define REG_DELIM (current_monitor->regset.delim)
extern void monitor_open PARAMS ((char *args, struct monitor_ops *ops, int from_tty));
extern char *monitor_supply_register PARAMS ((int regno, char *valstr));
extern int monitor_expect PARAMS ((char *prompt, char *buf, int buflen));
extern int monitor_expect_prompt PARAMS ((char *buf, int buflen));
extern void monitor_printf ();
extern void init_monitor_ops PARAMS ((struct target_ops *));
extern void monitor_open PARAMS ((char *, struct monitor_ops *, int));
extern char *monitor_supply_register PARAMS ((int, char *));

View File

@ -1,25 +1,25 @@
/* Remote debugging interface for EST-300 ICE, for GDB
Copyright 1994 Free Software Foundation, Inc.
Copyright 1995 Free Software Foundation, Inc.
Contributed by Cygnus Support.
Written by Steve Chamberlain for Cygnus Support.
Re-written by Stu Grossman of Cygnus Support
This file is part of GDB.
This file is part of GDB.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "defs.h"
#include "gdbcore.h"
@ -142,6 +142,7 @@ static struct monitor_ops est_cmds =
"dr\r", /* dump_registers */
"\\(\\w+\\) = \\([0-9a-fA-F]+\\)", /* register_pattern */
est_supply_register, /* supply_register */
NULL, /* load_routine (defaults to SRECs) */
"dl\r", /* download command */
"+", /* load response */
">BKM>", /* monitor command prompt */

View File

@ -23,7 +23,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "monitor.h"
#include "serial.h"
static void rom68k_open PARAMS ((char *, int));
static void rom68k_open PARAMS ((char *args, int from_tty));
static void
rom68k_supply_register (regname, regnamelen, val, vallen)
@ -39,40 +39,36 @@ rom68k_supply_register (regname, regnamelen, val, vallen)
regno = -1;
if (regnamelen == 2)
{
switch (regname[0])
{
case 'S':
if (regname[1] == 'R')
regno = PS_REGNUM;
switch (regname[0])
{
case 'S':
if (regname[1] == 'R')
regno = PS_REGNUM;
break;
case 'P':
if (regname[1] == 'C')
regno = PC_REGNUM;
break;
case 'D':
if (regname[1] != 'R')
break;
case 'P':
if (regname[1] == 'C')
regno = PC_REGNUM;
regno = D0_REGNUM;
numregs = 8;
break;
case 'A':
if (regname[1] != 'R')
break;
case 'D':
if (regname[1] != 'R')
break;
regno = D0_REGNUM;
numregs = 8;
break;
case 'A':
if (regname[1] != 'R')
break;
regno = A0_REGNUM;
numregs = 7;
break;
}
}
regno = A0_REGNUM;
numregs = 7;
break;
}
else if (regnamelen == 3)
{
switch (regname[0])
{
case 'I':
if (regname[1] == 'S' && regname[2] == 'P')
regno = SP_REGNUM;
}
}
switch (regname[0])
{
case 'I':
if (regname[1] == 'S' && regname[2] == 'P')
regno = SP_REGNUM;
}
if (regno >= 0)
while (numregs-- > 0)
@ -145,6 +141,7 @@ static struct monitor_ops rom68k_cmds =
/* register_pattern */
"\\(\\w+\\)=\\([0-9a-fA-F]+\\( +[0-9a-fA-F]+\\b\\)*\\)",
rom68k_supply_register, /* supply_register */
NULL, /* load_routine (defaults to SRECs) */
"dc\r", /* download command */
"Waiting for S-records from host... ", /* Load response */
"ROM68K :->", /* monitor command prompt */

View File

@ -24,6 +24,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "target.h"
#include "monitor.h"
#include "serial.h"
#include "xmodem.h"
static void w89k_open PARAMS ((char *args, int from_tty));
@ -154,6 +155,82 @@ w89k_supply_register (regname, regnamelen, val, vallen)
val = monitor_supply_register (regno++, val);
}
static int hashmark = 1; /* flag set by "set hash" */
extern struct monitor_ops w89k_cmds; /* fwd decl */
static void
w89k_load (desc, file, hashmark)
serial_t desc;
char *file;
int hashmark;
{
bfd *abfd;
asection *s;
char *buffer;
int i;
buffer = alloca (XMODEM_PACKETSIZE);
abfd = bfd_openr (file, 0);
if (!abfd)
{
printf_filtered ("Unable to open file %s\n", file);
return;
}
if (bfd_check_format (abfd, bfd_object) == 0)
{
printf_filtered ("File is not an object file\n");
return;
}
for (s = abfd->sections; s; s = s->next)
if (s->flags & SEC_LOAD)
{
bfd_size_type section_size;
printf_filtered ("%s\t: 0x%4x .. 0x%4x ", s->name, s->vma,
s->vma + s->_raw_size);
gdb_flush (gdb_stdout);
monitor_printf (w89k_cmds.load, s->vma);
if (w89k_cmds.loadresp)
monitor_expect (w89k_cmds.loadresp, NULL, 0);
xmodem_init_xfer (desc);
section_size = bfd_section_size (abfd, s);
for (i = 0; i < section_size; i += XMODEM_DATASIZE)
{
int numbytes;
numbytes = min (XMODEM_DATASIZE, section_size - i);
bfd_get_section_contents (abfd, s, buffer + XMODEM_DATAOFFSET, i,
numbytes);
xmodem_send_packet (desc, buffer, numbytes, hashmark);
if (hashmark)
{
putchar_unfiltered ('#');
gdb_flush (gdb_stdout);
}
} /* Per-packet (or S-record) loop */
xmodem_finish_xfer (desc);
monitor_expect_prompt (NULL, 0);
putchar_unfiltered ('\n');
} /* Loadable sections */
if (hashmark)
putchar_unfiltered ('\n');
}
/*
* Define the monitor command strings. Since these are passed directly
* through to a printf style function, we need can include formatting
@ -162,7 +239,7 @@ w89k_supply_register (regname, regnamelen, val, vallen)
static struct target_ops w89k_ops;
static char *w89k_loadtypes[] = {"srec", NULL};
static char *w89k_loadtypes[] = {"binary", NULL};
static char *w89k_loadprotos[] = {"xmodem", NULL};
static char *w89k_inits[] = {"\r", NULL};
@ -211,8 +288,9 @@ static struct monitor_ops w89k_cmds =
"r\r", /* dump_registers */
"\\(\\w+\\)\\( +[0-9a-fA-F]+\\b\\)+",
w89k_supply_register, /* supply_register */
"u\r", /* download command */
"u\n\r", /* load response */
w89k_load, /* load routine */
"u %x\r", /* download command */
"\r", /* load response */
"ROM>", /* monitor command prompt */
NULL, /* end-of-command delimitor */
NULL, /* optional command terminator */

284
gdb/xmodem.c Normal file
View File

@ -0,0 +1,284 @@
/* XMODEM support for GDB, the GNU debugger.
Copyright 1995 Free Software Foundation, Inc.
This file is part of GDB.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "defs.h"
#include "serial.h"
#include "target.h"
#include "xmodem.h"
/* These definitions are for xmodem protocol. */
#define SOH 0x01
#define STX 0x02
#define ACK 0x06
#define NAK 0x15
#define EOT 0x04
#define CANCEL 0x18
static int blknum; /* XMODEM block number */
static int crcflag; /* Sez we are using CRC's instead of cksums */
static int
readchar (desc, timeout)
serial_t desc;
int timeout;
{
int c;
c = SERIAL_READCHAR (desc, timeout);
if (remote_debug > 0)
fputc_unfiltered (c, gdb_stderr);
if (c >= 0)
return c;
if (c == SERIAL_TIMEOUT)
error ("Timeout reading from remote system.");
perror_with_name ("xmodem.c:readchar()");
}
#define CRC16 0x1021 /* Generator polynomial (X^16 + X^12 + X^5 + 1) */
static unsigned short *crctab;
/* Call this to init the fast CRC-16 calculation table. */
static void
crcinit ()
{
static int crctab_inited = 0;
int val;
if (crctab_inited == 1)
return;
crctab = xmalloc (256 * sizeof (short));
for (val = 0; val <= 255; val++)
{
int i;
unsigned int crc;
crc = val << 8;
for (i = 0; i < 8; ++i)
{
crc <<= 1;
if (crc & 0x10000)
crc ^= CRC16;
}
crctab [val] = crc;
}
crctab_inited = 1;
}
/* Calculate a CRC-16 for the LEN byte message pointed at by P. */
static unsigned short
docrc (p, len)
unsigned char *p;
int len;
{
unsigned short crc = 0;
while (len-- > 0)
crc = (crc << 8) ^ crctab [(crc >> 8) ^ *p++];
return crc;
}
/* Start up the transmit process. Reset state variables. Wait for receiver to
send NAK or CRC request. */
int
xmodem_init_xfer (desc)
serial_t desc;
{
int c;
int i;
blknum = 1;
crcflag = 0;
crcinit ();
for (i = 1; i <= 10; i++)
{
c = readchar (desc, 6);
switch (c)
{
case 'C':
crcflag = 1;
case NAK:
return 0;
default:
fprintf_unfiltered (gdb_stderr, "xmodem_init_xfer: Got unexpected character %c (0%o)\n", c, c);
continue;
case CANCEL: /* target aborted load */
fprintf_unfiltered (gdb_stderr, "Got a CANCEL from the target.\n");
continue;
}
}
error ("xmodem_init_xfer: Too many unexpected characters.");
}
/* Take 128 bytes of data and make a packet out of it.
*
* Each packet looks like this:
* +-----+-------+-------+------+-----+
* | SOH | Seq1. | Seq2. | data | SUM |
* +-----+-------+-------+------+-----+
* SOH = 0x01
* Seq1 = The sequence number.
* Seq2 = The complement of the sequence number.
* Data = A 128 bytes of data.
* SUM = Add the contents of the 128 bytes and use the low-order
* 8 bits of the result.
*
* send_xmodem_packet fills in the XMODEM fields of PACKET and sends it to the
* remote system. PACKET must be XMODEM_PACKETSIZE bytes long. The data must
* start 3 bytes after the beginning of the packet to leave room for the
* XMODEM header. LEN is the length of the data portion of the packet (and
* must be <= 128 bytes). If it is < 128 bytes, ^Z padding will be added.
*/
void
xmodem_send_packet (desc, packet, len, hashmark)
serial_t desc;
unsigned char *packet;
int len;
int hashmark;
{
int i;
int retries;
int pktlen;
int datasize;
/* build the packet header */
packet[1] = blknum;
packet[2] = ~blknum;
blknum++;
if (len <= XMODEM_DATASIZE)
{
packet[0] = SOH;
datasize = XMODEM_DATASIZE;
}
else if (len <= XMODEM_1KDATASIZE)
{
packet[0] = STX;
datasize = XMODEM_1KDATASIZE;
}
else
abort (); /* Packet way too large */
/* Add ^Z padding if packet < 128 (or 1024) bytes */
memset (packet + 3 + len, '\026', datasize - len);
if (crcflag)
{
int crc;
crc = docrc (packet + 3, datasize);
packet[3 + datasize] = crc >> 8;
packet[3 + datasize + 1] = crc;
pktlen = datasize + 5;
}
else
{
int sum;
sum = 0;
for (i = 3; i < datasize + 3; i++)
sum += packet[i];
packet[3 + datasize] = sum; /* add the checksum */
pktlen = datasize + 4;
}
for (retries = 3; retries >= 0; retries--)
{
int c;
SERIAL_WRITE (desc, packet, pktlen);
c = readchar (desc, 3);
switch (c)
{
case ACK:
return;
case NAK:
if (!hashmark)
continue;
putchar_unfiltered ('-');
gdb_flush (gdb_stdout);
continue;
case CANCEL:
error ("xmodem_send_packet: Transfer aborted by receiver.");
default:
fprintf_unfiltered (gdb_stderr, "xmodem_send_packet: Got unexpected character %c (0%o)\n", c, c);
continue;
}
}
SERIAL_WRITE (desc, "\004", 1); /* Send an EOT */
error ("xmodem_send_packet: Excessive retries.");
}
/* Finish off the transfer. Send out the EOT, and wait for an ACK. */
void
xmodem_finish_xfer (desc)
serial_t desc;
{
int retries;
for (retries = 10; retries >= 0; retries--)
{
int c;
SERIAL_WRITE (desc, "\004", 1); /* Send an EOT */
c = readchar (desc, 3);
switch (c)
{
case ACK:
return;
case NAK:
continue;
case CANCEL:
error ("xmodem_finish_xfer: Transfer aborted by receiver.");
default:
fprintf_unfiltered (gdb_stderr, "xmodem_send_packet: Got unexpected character %c (0%o)\n", c, c);
continue;
}
}
error ("xmodem_finish_xfer: Excessive retries.");
}

29
gdb/xmodem.h Normal file
View File

@ -0,0 +1,29 @@
/* XMODEM support for GDB, the GNU debugger.
Copyright 1995 Free Software Foundation, Inc.
This file is part of GDB.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
int xmodem_init_xfer PARAMS ((serial_t desc));
void send_xmodem_packet PARAMS ((serial_t desc, unsigned char *packet, int len,
int hashmark));
void xmodem_finish_xfer PARAMS ((serial_t desc));
#define XMODEM_DATASIZE 128 /* The data size is ALWAYS 128 */
#define XMODEM_1KDATASIZE 1024 /* Unless it's 1024!!! */
#define XMODEM_PACKETSIZE 133 /* data + packet headers and crc */
#define XMODEM_1KPACKETSIZE 1024 + 5 /* data + packet headers and crc */
#define XMODEM_DATAOFFSET 3 /* Offset to start of actual data */