From: ian Date: Mon, 30 May 2005 15:29:56 +0000 (+0000) Subject: can send nmra, it seems X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ijackson/git?a=commitdiff_plain;h=e29d470d5d6a84408449180bf01e8d0b8a40e6dd;p=trains.git can send nmra, it seems --- diff --git a/hostside/Makefile b/hostside/Makefile index 763637f..f9ea034 100644 --- a/hostside/Makefile +++ b/hostside/Makefile @@ -10,7 +10,8 @@ all: $(TARGETS) hostside-old: serialio.o nmra.o main.o encode.o $(LINK) -hostside: hostside.o serialio.o client.o obc.o commands.c -loop +hostside: hostside.o serialio.o client.o obc.o commands.o \ + nmra.o encode.o retransmit.o -loop $(LINK) layoutinfo.h: ../layout/ours.layout-data.c Makefile diff --git a/hostside/client.c b/hostside/client.c index e30f8c7..f0ff758 100644 --- a/hostside/client.c +++ b/hostside/client.c @@ -19,9 +19,9 @@ void badcmd(ParseState *ps, const char *fmt, ...) { va_end(al); } -int ps_needword(ParseState *ps) { +int ps_word(ParseState *ps) { const char *space; - if (!ps->remain) { badcmd(ps,"too few args"); return 0; } + if (!ps->remain) return 0; space= strchr(ps->remain, ' '); ps->thisword= ps->remain; if (space) { @@ -34,6 +34,40 @@ int ps_needword(ParseState *ps) { return 1; } +int ps_needword(ParseState *ps) { + if (!ps_word(ps)) { badcmd(ps,"too few args"); return 0; } + return 1; +} + +int ps_needhextoend(ParseState *ps, Byte *d, int *remain_io) { + Byte *d_end; + char buf[3], *ep; + + d_end= d + *remain_io; + buf[2]= 0; + + if (!ps->remain) { badcmd(ps,"need hex data block"); return 0; } + for (;;) { + if (!ps_word(ps)) return 0; + while (ps->lthisword > 0) { + if (ps->lthisword & 1) { + badcmd(ps,"hex data block with odd number of digits in part"); + return 0; + } + buf[0]= ps->thisword[0]; + buf[1]= ps->thisword[1]; + if (d >= d_end) { badcmd(ps,"hex data block too long"); return 0; } + *d++= strtoul(buf,&ep,16); + if (*ep) { badcmd(ps,"invalid digit in hex data block"); return 0; } + ps->lthisword -= 2; + ps->thisword += 2; + } + } + + *remain_io= d_end - d; + return 1; +} + const CmdInfo *ps_lookup(ParseState *ps, const CmdInfo *inf) { for (; inf->name; diff --git a/hostside/commands.c b/hostside/commands.c index 57aaa99..13fea12 100644 --- a/hostside/commands.c +++ b/hostside/commands.c @@ -1,28 +1,165 @@ /**/ +#include +#include +#include +#include + #include "hostside.h" -#if 0 -static void cmd_nmra_c(ParseState *ps, const CmdInfo *ci) { +#define NMRA_MAX_NARGS 10 + +typedef struct ManualRetransmitNode ManualRetransmitNode; +struct ManualRetransmitNode { + ManualRetransmitNode *back, *next; + char *name; + int lname; + RetransmitNode rn; +}; + +#define bogus_volatile /*empty*/ +#ifdef __GNUC__ +#if __GNUC__ == 2 +#undef bogus_volatile +#define bogus_volatile volatile +#endif +#endif + +struct NmraParseEncodeCaller { + ParseState *ps; + unsigned long arg[NMRA_MAX_NARGS]; + jmp_buf jb; +}; + +unsigned long nmra_argnumber(NmraParseEncodeCaller *pec, int argi) { + return pec->arg[argi]; +} + +void nmra_problem(NmraParseEncodeCaller *pec, const char *problem) { + badcmd(pec->ps,problem); + longjmp(pec->jb, 1); +} + +static int cmd_nmra_command(ParseState *ps, RetransmitNode *rn) { + int hex; + const char *cmdarg; + int lcmdarg; + bogus_volatile int argc, checksum; + NmraParseEncodeCaller pec; + Nmra nmra; + char *ep; + + assert(ps->remain); + switch (ps->remain[0]) { + case '_': ps->remain++; return ps_needhextoend(ps, rn->d, &rn->l); + case '=': hex=1; checksum=1; break; + case ':': hex=1; checksum=0; break; + default: hex=0; checksum=1; break; + } + + if (hex) { + ps->remain++; + nmra.l= NMRA_PACKET_MAX - checksum; + if (!ps_needhextoend(ps, nmra.d, &nmra.l)) + return 0; + } else { + if (!ps_needword(ps)) return 0; + cmdarg= ps->thisword; + lcmdarg= ps->lthisword; + pec.ps= ps; + argc= 0; + + while (ps_word(ps)) { + if (argc >= NMRA_MAX_NARGS) { + badcmd(ps,"far too many nmra args"); + return 0; + } + + errno=0; pec.arg[argc++]= strtoul(ps->thisword, &ep, 0); + if (errno || ep != ps->thisword + ps->lthisword) + { badcmd(ps,"bad numeric argument for nmra"); return 0; } + } + if (setjmp(pec.jb)) + return 0; + nmra_parse_encode(&nmra, cmdarg,lcmdarg, argc, &pec); + } + if (checksum) + nmra_addchecksum(&nmra); + + nmra_encodeforpic(&nmra, rn->d, &rn->l); + return 1; +} + +static void cmd_nmra(ParseState *ps, const CmdInfo *ci) { + static struct { ManualRetransmitNode *head, *tail; } mrns; + + ManualRetransmitNode *mrn; + RetransmitNode *rn, rn_buf; + + if (ps->remain && ps->remain[0]=='*') { + const char *mrname; + int lmrname; + + ps_word(ps); + mrname= ps->thisword+1; + lmrname= ps->lthisword-1; + + for (mrn= mrns.head; + !(mrn->lname == lmrname && + !memcmp(mrn->name, mrname, lmrname)); + mrn= mrn->next); + if (mrn) { + retransmit_cancel(&mrn->rn); + } else { + mrn= mmalloc(sizeof(*mrn)); + mrn->name= mmalloc(lmrname); + memcpy(mrn->name, mrname, lmrname); + mrn->lname= lmrname; + } + } else { + mrn= 0; + } + + if (!ps->remain) { + if (!mrn) { + badcmd(ps,"nmra must have slot to cancel or data to send"); + return; + } + free(mrn->name); + free(mrn); + return; + } + + rn= mrn ? &mrn->rn : &rn_buf; + rn->l= sizeof(rn->d); + + if (!cmd_nmra_command(ps, rn)) { + if (mrn) { free(mrn->name); free(mrn); } + return; + } + + if (mrn) + retransmit_queue(&mrn->rn); + else + serial_transmit(rn->d, rn->l); } -#endif static void cmd_noop(ParseState *ps, const CmdInfo *ci) { oprintf(&ps->cl->ch,"noop successful\n"); } const CmdInfo toplevel_cmds[]= { + { "nmra", cmd_nmra, }, + /* eg nmra [*[slot]] speed28 3 13 1 */ + /* eg nmra [*[slot]] =0348 */ + /* eg nmra [*[slot]] :03484b */ + /* eg nmra [*[slot]] _7f7f00644197 */ + /* eg nmra [*[slot]] */ #if 0 - { "nmra-cx", cmd_nmra_c }, /* eg nmra-c1 speed28 3 13 1 */ - { "nmra-c1", cmd_nmra_c, 1 }, - { "nmra-hx", cmd_nmra_h }, - { "nmra-h1", cmd_nmra_h, 1 }, /* eg nmra-h1 0348 */ - { "nmra-rx", cmd_nmra_r }, - { "nmra-r1", cmd_nmra_r, 1 }, /* eg nmra-r1 03484b */ - { "pic", cmd_pic }, /* eg pic point 3 */ - { "pic-raw", cmd_pic_raw }, /* pic-raw 7f7f00644197, pic-raw a003 */ + { "pic-raw" , cmd_pic_raw, 1, }, + { "pic", cmd_pic }, /* eg pic point 3 */ #endif - { "noop", cmd_noop }, + { "noop", cmd_noop }, { 0 } }; diff --git a/hostside/common.h b/hostside/common.h new file mode 100644 index 0000000..66dd6f3 --- /dev/null +++ b/hostside/common.h @@ -0,0 +1,51 @@ +/* + * declarations common to simple test program and real controller daemon + */ + +#ifndef COMMON_H +#define COMMON_H + +#include + +/*---------- types ----------*/ + +typedef unsigned char Byte; + +#define COMMAND_ENCODED_MAX 16 +#define NMRA_PACKET_MAX ((COMMAND_ENCODED_MAX*7 - 14) / 8) + +typedef struct Nmra { + Byte d[NMRA_PACKET_MAX]; + int l; +} Nmra; + +/*---------- from serialio.c ----------*/ + +void vdie(const char *fmt, int ev, va_list al) + __attribute__((noreturn,format(printf,1,0))); +void die(const char *fmt, ...) __attribute__((noreturn,format(printf,1,2))); +void diee(const char *fmt, ...) __attribute__((noreturn,format(printf,1,2))); +void diem(void) __attribute__((noreturn)); + +void serial_open(const char *device); +void serial_transmit(const Byte *command, int length); + +void *mmalloc(size_t sz); + +extern int serial_fd, serial_fudge_delay; + +/*---------- nmra parsing, nmra.c et al ----------*/ + +typedef struct NmraParseEncodeCaller NmraParseEncodeCaller; +void nmra_parse_encode(Nmra *out, const char *arg, int argl, + int argc, NmraParseEncodeCaller *pec); + /* will call back to these, supplied by caller: */ + unsigned long nmra_argnumber(NmraParseEncodeCaller *pec, int argi); + void nmra_problem(NmraParseEncodeCaller *pec, const char *problem); + +void nmra_addchecksum(Nmra *packet); +void nmra_encodeforpic(const Nmra *packet, Byte *picdata, int *lpicdata_r); + /* picdata should point to COMMAND_ENCODED_MAX bytes */ + + +#endif /*COMMON_H*/ diff --git a/hostside/encode.c b/hostside/encode.c index a369299..26999a6 100644 --- a/hostside/encode.c +++ b/hostside/encode.c @@ -1,10 +1,13 @@ -/**/ +/* + * arranges for the definitions of + * enco_nmra_WHATEVER + */ #include #include #include -#include "hostside.h" +#include "common.h" #include "nmra.h" #define CONST(...) \ diff --git a/hostside/hostside.c b/hostside/hostside.c index 5c14f66..6b92d86 100644 --- a/hostside/hostside.c +++ b/hostside/hostside.c @@ -25,7 +25,8 @@ static void *serial_exception(oop_source *evts, int fd, static void *serial_readable(oop_source *evts, int fd, oop_event evt, void *u0) { - abort(); + events->cancel_fd(events, serial_fd, OOP_READ); + return OOP_CONTINUE; } const char *device; diff --git a/hostside/hostside.h b/hostside/hostside.h index 5075d7d..3066ade 100644 --- a/hostside/hostside.h +++ b/hostside/hostside.h @@ -1,20 +1,24 @@ -/**/ +/* + * declarations for hostside controller daemon + */ #ifndef HOSTSIDE_H #define HOSTSIDE_H -#include +#include "common.h" + #include #include -typedef unsigned char Byte; - -typedef struct OutBuffer OutBuffer; -typedef struct OutBufferChain OutBufferChain; typedef struct Client Client; typedef struct ParseState ParseState; typedef struct CmdInfo CmdInfo; +typedef struct RetransmitNode RetransmitNode; + +/*---------- from obc.c ----------*/ +typedef struct OutBuffer OutBuffer; +typedef struct OutBufferChain OutBufferChain; typedef void OutBufferError(OutBufferChain*, const char *e1, const char *e2); struct OutBufferChain { @@ -27,6 +31,19 @@ struct OutBufferChain { struct { OutBuffer *head, *tail; } obs; }; +void obc_init(OutBufferChain *ch); +void ovprintf(OutBufferChain *ch, const char *fmt, va_list al) + __attribute__((format(printf,2,0))); +void oprintf(OutBufferChain *ch, const char *msg, ...) + __attribute__((format(printf,2,3))); +void owrite(OutBufferChain *ch, const char *data, int l); + +/*---------- from hostside.c ----------*/ + +extern oop_source *events; + +/*---------- from client.c ----------*/ + struct Client { OutBufferChain ch; oop_read *rd; @@ -45,60 +62,32 @@ struct CmdInfo { int xarg; }; -extern oop_source *events; -void vdie(const char *fmt, int ev, va_list al) - __attribute__((noreturn,format(printf,1,0))); -void die(const char *fmt, ...) __attribute__((noreturn,format(printf,1,2))); -void diee(const char *fmt, ...) __attribute__((noreturn,format(printf,1,2))); -void diem(void) __attribute__((noreturn)); - -void vbadcmd(ParseState *ps, const char *fmt, va_list al) - __attribute__((format(printf,2,0))); -void badcmd(ParseState *ps, const char *fmt, ...) - __attribute__((format(printf,2,3))); +int ps_word(ParseState *ps); int ps_needword(ParseState *ps); +int ps_needhextoend(ParseState *ps, Byte *dbuf, int *len_io); const CmdInfo *ps_lookup(ParseState *ps, const CmdInfo *inf); const CmdInfo *ps_needword_lookup(ParseState *ps, const CmdInfo *infs); void ps_callword(ParseState *ps, const CmdInfo *infs, const char *what); -extern const CmdInfo toplevel_cmds[]; -void stdin_client(void); - - -void obc_init(OutBufferChain *ch); -void ovprintf(OutBufferChain *ch, const char *fmt, va_list al) +void vbadcmd(ParseState *ps, const char *fmt, va_list al) __attribute__((format(printf,2,0))); -void oprintf(OutBufferChain *ch, const char *msg, ...) +void badcmd(ParseState *ps, const char *fmt, ...) __attribute__((format(printf,2,3))); -void owrite(OutBufferChain *ch, const char *data, int l); -void *mmalloc(size_t sz); +void stdin_client(void); +extern const CmdInfo toplevel_cmds[]; /* defined in commands.c*/ -#define COMMAND_ENCODED_MAX 16 -#define NMRA_PACKET_MAX ((COMMAND_ENCODED_MAX*7 - 14) / 8) +/*---------- from retransmit.c ----------*/ -typedef struct Nmra { - Byte d[NMRA_PACKET_MAX]; +struct RetransmitNode { + /* set by caller: */ + Byte d[COMMAND_ENCODED_MAX]; int l; -} Nmra; - -typedef struct NmraParseEncodeCaller NmraParseEncodeCaller; -void nmra_parse_encode(Nmra *out, const char *arg, int argl, - int argc, NmraParseEncodeCaller *pec); -unsigned long nmra_argnumber(NmraParseEncodeCaller *pec, int argi); -void nmra_problem(const char *problem); - -void xmit_nmra_raw(const Byte *with_csum, int length); -void xmit_nmra_bytes(const Byte *without_csum, int length); -void xmit_nmra(const Nmra*); -void xmit_command(const Byte *command, int length); - -extern FILE *dump_stream; -void dump(const char *what, const Byte *data, int length); -void sysfatal(const char *m); -void serial_open(const char *device); + /* internal: */ +}; -extern int serial_fd, serial_fudge_delay; +void retransmit_queue(RetransmitNode *rn); +void retransmit_cancel(RetransmitNode *rn); #endif /*HOSTSIDE_H*/ diff --git a/hostside/main.c b/hostside/main.c index 138f563..320cb58 100644 --- a/hostside/main.c +++ b/hostside/main.c @@ -15,17 +15,14 @@ #include #include -#include "hostside.h" +#include "common.h" -FILE *dump_stream= 0; +static FILE *dump_stream= 0; static int repeat_delay= -1, iterations= -1; static const char *serial_port; -static struct { - Nmra nmra; - Byte buf[COMMAND_ENCODED_MAX]; /* padding prevents overruns */ -} buf; +static Nmra buf; static void badusage(const char *why) { fprintf(stderr,"bad usage: %s\n",why); exit(8); @@ -37,7 +34,7 @@ static void pahex(const char **argv) { int i, l; Byte *c; - c= buf.nmra.d; + c= buf.d; while ((data_string= *argv++)) { l= strlen(data_string); @@ -45,7 +42,7 @@ static void pahex(const char **argv) { l >>= 1; for (i=0; i= buf.nmra.d + sizeof(buf.nmra.d)) badusage("too much hex"); + if (c >= buf.d + sizeof(buf.d)) badusage("too much hex"); hbuf[0]= data_string[i*2]; hbuf[1]= data_string[i*2+1]; @@ -54,11 +51,10 @@ static void pahex(const char **argv) { if (ep!=&hbuf[2]) badusage("bad hex in hex argument"); } } - buf.nmra.l= c - buf.nmra.d; + buf.l= c - buf.d; } struct NmraParseEncodeCaller { - int argc; const char *const *argv; }; @@ -67,19 +63,48 @@ unsigned long nmra_argnumber(NmraParseEncodeCaller *pec, int argi) { char *ep; unsigned long l; - if (argi >= pec->argc) badusage("missing numeric arg value"); arg= pec->argv[argi]; errno=0; l= strtoul(arg,&ep,0); if (errno || *ep || ep==arg) badusage("bad numeric arg value"); return l; } -void nmra_problem(const char *problem) { +void nmra_problem(NmraParseEncodeCaller *pec, const char *problem) { badusage(problem); } +static void dump(const char *what, const Byte *data, int length) { + if (!dump_stream) return; + fprintf(dump_stream,"%-25s %3d ",what,length); + while (length>0) { + fprintf(dump_stream," %02x", *data); + data++; + length--; + } + fprintf(dump_stream,"\n"); +} + +static void xmit_command(void) { + dump("xmit_command", buf.d, buf.l); + serial_transmit(buf.d, buf.l); +} + +static void xmit_nmra_raw(void) { + Byte encoded[COMMAND_ENCODED_MAX]; + int lencoded; + + dump("xmit_nmra_raw", buf.d, buf.l); + nmra_encodeforpic(&buf, encoded, &lencoded); + serial_transmit(encoded, lencoded); +} + +static void xmit_nmra_bytes(void) { + nmra_addchecksum(&buf); + xmit_nmra_raw(); +} + int main(int argc, const char **argv) { - void (*xmitter)(const Byte *d, int l); + void (*xmitter)(void); const char *arg; if (!*argv++) badusage("need argv[0]"); @@ -117,15 +142,15 @@ int main(int argc, const char **argv) { { NmraParseEncodeCaller pec; pec.argv= argv; - for (pec.argc=0; argv[pec.argc]; pec.argc++); - nmra_parse_encode(&buf.nmra, arg, strlen(arg), pec.argc, &pec); + for (argc=0; argv[argc]; argc++); + nmra_parse_encode(&buf, arg, strlen(arg), argc, &pec); xmitter= xmit_nmra_bytes; } serial_open(serial_port); for (;;) { - xmitter(buf.nmra.d,buf.nmra.l); + xmitter(); if (repeat_delay < 0) break; if (iterations >= 0 && !iterations--) break; diff --git a/hostside/nmra.c b/hostside/nmra.c index e5bda79..bd2e916 100644 --- a/hostside/nmra.c +++ b/hostside/nmra.c @@ -3,16 +3,19 @@ #include #include -#include "hostside.h" +#include "common.h" #include "nmra.h" -void xmit_nmra_raw(const Byte *nmra_packet, int length) { - Byte encoded[COMMAND_ENCODED_MAX], *encp; +void nmra_encodeforpic(const Nmra *packet, Byte *encoded, int *lencoded_r) { + const Byte *bp; + int length; + Byte *encp; unsigned working, newbits; int working_qty; - dump("xmit_nmra_raw",nmra_packet,length); - + length= packet->l; + bp= packet->d; + assert(length > 0); assert(length <= NMRA_PACKET_MAX); encp= encoded; @@ -25,7 +28,7 @@ void xmit_nmra_raw(const Byte *nmra_packet, int length) { if (length > 0) { /* plonk new data bits just to right of old data bits */ length--; - newbits= *nmra_packet++; + newbits= *bp++; newbits <<= 1; newbits |= !length; /* 9 bits, bottom one is `end of packet' */ working |= (newbits << (7-working_qty)); @@ -46,36 +49,34 @@ void xmit_nmra_raw(const Byte *nmra_packet, int length) { } assert(encp > encoded); encp[-1] |= 0x80; /* `end of command' bit */ - - xmit_command(encoded, encp - encoded); + *lencoded_r= encp - encoded; } -void xmit_nmra_bytes(const Byte *without_csum, int length) { +void nmra_addchecksum(Nmra *packet) { /* calculates checksum, S9.2 B l.63 */ - Byte with_csum[NMRA_PACKET_MAX]; - const Byte *in; - Byte *out; int left; + Byte *bp; unsigned running; - dump("xmit_nmra",without_csum,length); + assert(packet->l >=0 && packet->l < NMRA_PACKET_MAX); - assert(length >=0 && length < sizeof(with_csum)); - for (left=length, running=0, in=without_csum, out=with_csum; - left>0; - in++, out++, left--) - running ^= (*out = *in); + for (left=packet->l, running=0, bp=packet->d; + left > 0; + bp++, left--) + running ^= *bp; - *out= running; - xmit_nmra_raw(with_csum, length+1); + *bp= running; + packet->l++; } static long argnumber(NmraParseEncodeCaller *pec, int argi, - unsigned long *au, + unsigned long *au, int argc, long min, long max) { long l; unsigned long abit; + if (argi >= argc) nmra_problem(pec,"missing numeric arg value"); + l= nmra_argnumber(pec, argi); abit= 1ul << argi; @@ -83,7 +84,7 @@ static long argnumber(NmraParseEncodeCaller *pec, int argi, *au |= abit; if (lLONG_MAX || l>max) - nmra_problem("numeric arg value out of range"); + nmra_problem(pec,"numeric arg value out of range"); return l; } @@ -91,9 +92,9 @@ void nmra_parse_encode(Nmra *out, const char *arg, int argl, int argc, NmraParseEncodeCaller *pec) { unsigned long au= 0; - #define Aint(x,i) , argnumber(pec,i,&au, INT_MIN,INT_MAX) - #define Abitmap(x,i) , argnumber(pec,i,&au, 0,~0u>>1) - #define Abyte(x,i) , argnumber(pec,i,&au, 0,0xff) + #define Aint(x,i) , argnumber(pec,i,&au,argc, INT_MIN,INT_MAX) + #define Abitmap(x,i) , argnumber(pec,i,&au,argc, 0,~0u>>1) + #define Abyte(x,i) , argnumber(pec,i,&au,argc, 0,0xff) #define Anone #define NMRA(n,al,body) \ if (argl == sizeof(#n)-1 && !memcmp(arg,#n,argl)) { \ @@ -101,8 +102,8 @@ void nmra_parse_encode(Nmra *out, const char *arg, int argl, } else #include "nmra-packets.h" { - nmra_problem("unknown instruction"); + nmra_problem(pec,"unknown instruction"); } if (au != (1ul << argc)-1) - nmra_problem("too many args for packet type"); + nmra_problem(pec,"too many args for packet type"); } diff --git a/hostside/nmra.h b/hostside/nmra.h index d54cf80..1150032 100644 --- a/hostside/nmra.h +++ b/hostside/nmra.h @@ -1,4 +1,7 @@ -/**/ +/* + * arranges for the declarations of + * enco_nmra_WHATEVER + */ #ifndef NMRA_H #define NMRA_H diff --git a/hostside/retransmit.c b/hostside/retransmit.c new file mode 100644 index 0000000..54c4fda --- /dev/null +++ b/hostside/retransmit.c @@ -0,0 +1,11 @@ +/* + * nmra retransmission + */ + +#include "hostside.h" + +void retransmit_queue(RetransmitNode *rn) { +} + +void retransmit_cancel(RetransmitNode *rn) { +} diff --git a/hostside/serialio.c b/hostside/serialio.c index 952698d..c481c23 100644 --- a/hostside/serialio.c +++ b/hostside/serialio.c @@ -1,4 +1,6 @@ -/**/ +/* + * general serial i/o and system interface etc. + */ #include #include @@ -11,7 +13,7 @@ #include #include -#include "hostside.h" +#include "common.h" int serial_fudge_delay= 0; int serial_fd= -1; @@ -45,23 +47,10 @@ void serial_open(const char *device) { if (serial_fd<0) diee(device); } -void dump(const char *what, const Byte *data, int length) { - if (!dump_stream) return; - fprintf(dump_stream,"%-25s %3d ",what,length); - while (length>0) { - fprintf(dump_stream," %02x", *data); - data++; - length--; - } - fprintf(dump_stream,"\n"); -} - -void xmit_command(const Byte *command, int length) { +void serial_transmit(const Byte *command, int length) { int r; assert(length <= COMMAND_ENCODED_MAX); - dump("xmit_command",command,length); - while (length > 0) { r= write(serial_fd, command, serial_fudge_delay ? 1 : length);