From 36bb415afd5dba7ce434976115c5899455690cd7 Mon Sep 17 00:00:00 2001 From: Martin Peach Date: Fri, 1 Oct 2010 18:58:55 +0000 Subject: Fixed bugs where incomplete packets with escapes were not decoded correctly. Added a help patch. svn path=/trunk/externals/mrpeach/; revision=14183 --- slipdec/slipdec-help.pd | 60 +++++++ slipdec/slipdec.c | 407 ++++++++++++++++++++++++------------------------ 2 files changed, 265 insertions(+), 202 deletions(-) create mode 100644 slipdec/slipdec-help.pd diff --git a/slipdec/slipdec-help.pd b/slipdec/slipdec-help.pd new file mode 100644 index 0000000..ff84873 --- /dev/null +++ b/slipdec/slipdec-help.pd @@ -0,0 +1,60 @@ +#N canvas 167 296 901 442 10; +#X obj 388 325 print decoded; +#X msg 319 159 192 192 192 192 192; +#X floatatom 339 182 5 0 0 0 - - -; +#X obj 382 238 cnv 15 60 30 empty empty empty 20 12 0 14 -4034 -66577 +0; +#X text -57 298 The motivation behind SLIP is the need to determine +the boundaries of a packet when it is received one byte at a time \, +as with a serial channel. Bytes are integers between 0 and 255; +#X msg 185 25 verbosity \$1; +#X obj 185 6 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 0 1 +; +#X text -57 355 SLIP (RFC 1055) is a simple encoding that prefixes +each packet with 192 \, and replaces 192s inside the packet with 219 +followed by 220 Any 219 will be replaced with 219 and 221 The packet +ends with 192; +#X text 443 160 Null packets are invisible; +#X obj 427 274 print valid; +#X text -57 193 Note that the SLIP specification limits the maximum +packet size to 1006...; +#X obj 388 245 slipdec; +#X text -57 221 ...but a float argument to slipdec or slipenc will +set another maximum packet size; +#X msg 229 69 192 \, 1.33 \, 192; +#X text 335 45 This should give 1 192; +#X text 321 69 Only bytes are permitted; +#X msg 275 115 192 219 5 6 7 192; +#X msg 253 93 1 43 5 6 7 192; +#X text 348 92 Missing 192 at start is OK; +#X text -58 139 [slipdec]; +#X text 548 404 Author: Martin Peach \, 2010/10/01; +#X msg 205 45 192 1 \, 219 \, 220 \, 192; +#X msg 297 137 1 25 5 6 7; +#X text -57 257 Input can be any combination of float and list of floats +as long as they are integers on [0...255]; +#X text 385 115 Bad escapes are invalid; +#X text 368 136 Unterminated input will be accumulated until end is +received; +#X text 636 368 See also:; +#X obj 695 370 slipenc; +#X text -58 153 Decodes bytes from SLIP to raw. Useful for receiving +OSC via [comport].; +#X text 427 290 Right outlet is one whenever a valid packet is output +\, zero if packet could not be decoded (bad packets are not output). +; +#X text 389 341 Left outlet gives lists of decoded bytes whenever valid += 1; +#X text 267 24 Verbosity might be useful if things don't seem to be +working; +#X connect 1 0 11 0; +#X connect 2 0 11 0; +#X connect 5 0 11 0; +#X connect 6 0 5 0; +#X connect 11 0 0 0; +#X connect 11 1 9 0; +#X connect 13 0 11 0; +#X connect 16 0 11 0; +#X connect 17 0 11 0; +#X connect 21 0 11 0; +#X connect 22 0 11 0; diff --git a/slipdec/slipdec.c b/slipdec/slipdec.c index e654b24..ce80cce 100644 --- a/slipdec/slipdec.c +++ b/slipdec/slipdec.c @@ -1,50 +1,49 @@ -/* slipdec.c 20100513 Martin Peach */ -/* decode a list of SLIP-encoded bytes */ -#include "m_pd.h" - -/* -------------------------- slipdec -------------------------- */ -#ifndef _SLIPCODES -/* SLIP special character codes */ -#define SLIP_END 0300 /* indicates end of packet */ -#define SLIP_ESC 0333 /* indicates byte stuffing */ -#define SLIP_ESC_END 0334 /* SLIP_ESC SLIP_ESC_END means SLIP_END data byte */ -#define SLIP_ESC_ESC 0335 /* SLIP_ESC SLIP_ESC_ESC means SLIP_ESC data byte */ -#define MAX_SLIP 1006 /* maximum SLIP packet size */ -#define _SLIPCODES -#endif // _SLIPCODES - -static t_class *slipdec_class; - -typedef struct _slipdec -{ - t_object x_obj; - t_outlet *x_slipdec_out; - t_outlet *x_status_out; - t_atom *x_slip_buf; - t_int x_slip_length; +/* slipdec.c 20100513 Martin Peach */ +/* decode a list of SLIP-encoded bytes */ +#include "m_pd.h" + +/* -------------------------- slipdec -------------------------- */ +#ifndef _SLIPCODES +/* SLIP special character codes */ +#define SLIP_END 0300 /* decimal 192 indicates end of packet */ +#define SLIP_ESC 0333 /* decimal 219 indicates byte stuffing */ +#define SLIP_ESC_END 0334 /* decimal 220 SLIP_ESC_END means SLIP_END as data byte */ +#define SLIP_ESC_ESC 0335 /* decimal 221 SLIP_ESC_ESC means SLIP_ESC as data byte */ +#define MAX_SLIP 1006 /* maximum SLIP packet size */ +#define _SLIPCODES +#endif /* _SLIPCODES */ + +static t_class *slipdec_class; + +typedef struct _slipdec +{ + t_object x_obj; + t_outlet *x_slipdec_out; + t_outlet *x_status_out; + t_atom *x_slip_buf; + t_int x_slip_length; t_int x_slip_max_length; - t_int x_packet_index; - t_int x_valid_SLIP; - t_int x_esced; - t_int x_verbose; -} t_slipdec; - -static void *slipdec_new(t_symbol *s, int argc, t_atom *argv); + t_int x_valid_SLIP; + t_int x_esced; + t_int x_verbose; +} t_slipdec; + +static void *slipdec_new(t_symbol *s, int argc, t_atom *argv); static void slipdec_dump(t_slipdec *x, int dosend); -static void slipdec_list(t_slipdec *x, t_symbol *s, int ac, t_atom *av); -static void slipdec_float(t_slipdec *x, t_float f); -static void slipdec_verbosity(t_slipdec *x, t_float f); -static void slipdec_free(t_slipdec *x); -void slipdec_setup(void); - -static void *slipdec_new(t_symbol *s, int argc, t_atom *argv) -{ - int i; +static void slipdec_list(t_slipdec *x, t_symbol *s, int ac, t_atom *av); +static void slipdec_float(t_slipdec *x, t_float f); +static void slipdec_verbosity(t_slipdec *x, t_float f); +static void slipdec_free(t_slipdec *x); +void slipdec_setup(void); + +static void *slipdec_new(t_symbol *s, int argc, t_atom *argv) +{ + int i; t_slipdec *x = (t_slipdec *)pd_new(slipdec_class); if (x == NULL) return x; - x->x_slip_max_length = MAX_SLIP;// default unless a float argument is given + x->x_slip_max_length = MAX_SLIP;// default unless a float argument is given for (i = 0; i < argc; ++i) { if (argv[i].a_type == A_FLOAT) @@ -55,177 +54,181 @@ static void *slipdec_new(t_symbol *s, int argc, t_atom *argv) } } - x->x_slip_buf = (t_atom *)getbytes(sizeof(t_atom)*x->x_slip_max_length); - if(x->x_slip_buf == NULL) - { - error("slipdec: unable to allocate %lu bytes for x_slip_buf", (long)sizeof(t_atom)*x->x_slip_max_length); - return NULL; - } - /* init the slip buf atoms to float type */ - for (i = 0; i < x->x_slip_max_length; ++i) x->x_slip_buf[i].a_type = A_FLOAT; - x->x_slipdec_out = outlet_new(&x->x_obj, &s_list); - x->x_status_out = outlet_new(&x->x_obj, &s_anything); - x->x_packet_index = 0; - x->x_valid_SLIP = 1; - return (x); -} + x->x_slip_buf = (t_atom *)getbytes(sizeof(t_atom)*x->x_slip_max_length); + if(x->x_slip_buf == NULL) + { + error("slipdec: unable to allocate %lu bytes for x_slip_buf", (long)sizeof(t_atom)*x->x_slip_max_length); + return NULL; + } + /* init the slip buf atoms to float type */ + for (i = 0; i < x->x_slip_max_length; ++i) x->x_slip_buf[i].a_type = A_FLOAT; + x->x_slipdec_out = outlet_new(&x->x_obj, &s_list); + x->x_status_out = outlet_new(&x->x_obj, &s_anything); + x->x_valid_SLIP = 1; + return (x); +} static void slipdec_dump(t_slipdec *x, int dosend) -{ +{ + outlet_float(x->x_status_out, x->x_valid_SLIP); if(dosend) - { - if ((0 != x->x_valid_SLIP) && (x->x_slip_length > 0)) - outlet_list(x->x_slipdec_out, &s_list, x->x_slip_length, x->x_slip_buf); - } - - x->x_slip_length = x->x_esced = x->x_packet_index = 0; - x->x_valid_SLIP = 1; -} - -static void slipdec_list(t_slipdec *x, t_symbol *s, int ac, t_atom *av) -{ - /* SLIP decode a list of bytes */ - float f; - int i = 0, c; - - /* x_slip_length will be non-zero if an incomplete packet is in the buffer */ + { + if ((0 != x->x_valid_SLIP) && (x->x_slip_length > 0)) + outlet_list(x->x_slipdec_out, &s_list, x->x_slip_length, x->x_slip_buf); + } + + x->x_slip_length = x->x_esced = 0; + x->x_valid_SLIP = 1; +} + +static void slipdec_list(t_slipdec *x, t_symbol *s, int ac, t_atom *av) +{ + /* SLIP decode a list of bytes */ + float f; + int i, c; + + if (x->x_verbose) post ("slipdec_list: buffer length %d, esc = %d", x->x_slip_length, x->x_esced); + /* x_slip_length will be non-zero if an incomplete packet is in the buffer */ if ((ac + x->x_slip_length) > x->x_slip_max_length) { - pd_error (x, "slipdec_list: input packet longer than %d", x->x_slip_max_length); - x->x_slip_length = x->x_esced = x->x_packet_index = 0; + pd_error (x, "slipdec_list: input packet longer than %d", x->x_slip_max_length); + x->x_valid_SLIP = 0; /* not valid SLIP */ + slipdec_dump(x,0);// reset return; - } - /* for each byte in the packet, send the appropriate character sequence */ - for(; ((i < ac) && (x->x_slip_length < x->x_slip_max_length)); ++i) - { - /* check each atom for byteness */ - f = atom_getfloat(&av[i]); - c = (((int)f) & 0x0FF); - if (c != f) - { - /* abort, input list needs to be fixed before this is gonna wuk */ - pd_error (x, "slipdec: input %d out of range [0..255]", f); - return; - } - if(SLIP_END == c) - { - if (x->x_verbose) post ("slipdec_list: SLIP_END packet index is %d", x->x_packet_index); - /* If it's the beginning of a packet, ignore it */ + } + /* for each byte in the packet, send the appropriate character sequence */ + for(i = 0; ((i < ac) && (x->x_slip_length < x->x_slip_max_length)); ++i) + { + /* check each atom for byteness */ + f = atom_getfloat(&av[i]); + c = (((int)f) & 0x0FF); + if (c != f) + { + /* abort, input list needs to be fixed before this is gonna wuk */ + pd_error (x, "slipdec: input %d out of range [0..255]", f); + x->x_valid_SLIP = 0; /* not valid SLIP */ + slipdec_dump(x,0);// reset + return; + } + if(SLIP_END == c) + { + if (x->x_verbose) post ("slipdec_list: SLIP_END at %d", x->x_slip_length); + /* If it's the beginning of a packet, ignore it */ if (x->x_slip_length) - { - if (x->x_verbose) post ("slipdec_list: end of packet"); - /* send the packet */ - slipdec_dump(x, 1); - } - continue; - } - if (SLIP_ESC == c) - { - if (x->x_verbose) post ("slipdec_list: SLIP_ESC %f = %d", f, c); - x->x_esced = 1; - continue; - } - if (1 == x->x_esced) - { - if (SLIP_ESC_END == c) c = SLIP_END; - else if (SLIP_ESC_ESC == c) c = SLIP_ESC; - else x->x_valid_SLIP = 0; /* not valid SLIP */ - if (x->x_verbose) post ("slipdec_list: ESCED %f = %d", f, c); - x->x_esced = 0; - } - /* Add the character to the list */ - x->x_slip_buf[x->x_slip_length++].a_w.w_float = c; - } - if (0 != x->x_slip_length) - { - if(SLIP_END != c) x->x_valid_SLIP = 0; - outlet_float(x->x_status_out, x->x_valid_SLIP); - if (0 != x->x_valid_SLIP) outlet_list(x->x_slipdec_out, &s_list, x->x_slip_length, x->x_slip_buf); - x->x_slip_length = x->x_esced = x->x_packet_index = 0; - x->x_valid_SLIP = 1; - /* any remaining data in the list is ignored for now... */ - if (i < ac-1) post("slipdec_list: dropped %d bytes after packet", ac-1-i); - } -} - -static void slipdec_float(t_slipdec *x, t_float f) -{ - /* SLIP decode a byte */ - int c; - /* for each byte in the packet, send the appropriate character sequence */ - /* check each atom for byteness */ - c = (((int)f) & 0x0FF); - if (c != f) - { - /* abort, input list needs to be fixed before this is gonna wuk */ - pd_error (x, "slipdec: input %d out of range [0..255]", f); - x->x_slip_length = x->x_esced = x->x_packet_index = 0; - x->x_valid_SLIP = 1; - return; - } - if(SLIP_END == c) - { - if (x->x_verbose) post ("slipdec_float: SLIP_END packet index is %d", x->x_packet_index); - /* If it's the beginning of a packet, ignore it */ - if (0 == x->x_packet_index) return; - /* send the packet */ - else - { - if (x->x_verbose) post ("slipdec_float: end of packet"); - outlet_float(x->x_status_out, x->x_valid_SLIP); - if ((0 != x->x_slip_length) && (0 != x->x_valid_SLIP)) - outlet_list(x->x_slipdec_out, &s_list, x->x_slip_length, x->x_slip_buf); - x->x_slip_length = x->x_esced = x->x_packet_index = 0; - x->x_valid_SLIP = 1; - return; - } - } - if (SLIP_ESC == c) - { - if (x->x_verbose) post ("slipdec_float: SLIP_ESC %f = %d", f, c); - x->x_esced = 1; - return; - } - if (1 == x->x_esced) - { - if (SLIP_ESC_END == c) c = SLIP_END; - else if (SLIP_ESC_ESC == c) c = SLIP_ESC; - else x->x_valid_SLIP = 0; /* not valid SLIP */ - if (x->x_verbose) post ("slipdec_float: ESCED %f = %d", f, c); - x->x_esced = 0; - } - /* Add the character to the list */ - if (0 == x->x_packet_index++) x->x_slip_length = 0; + { + if (x->x_verbose) post ("slipdec_list: end of packet"); + /* send the packet */ + slipdec_dump(x, 1); + } + continue; + } + if (SLIP_ESC == c) + { + if (x->x_verbose) post ("slipdec_list: SLIP_ESC %f = %d", f, c); + x->x_esced = 1; + continue; + } + if (1 == x->x_esced) + { + if (SLIP_ESC_END == c) c = SLIP_END; + else if (SLIP_ESC_ESC == c) c = SLIP_ESC; + else + { + pd_error (x, "slipdec_list: SLIP_ESC not followed by 220 or 221 (%d)", c); + x->x_valid_SLIP = 0; /* not valid SLIP */ + slipdec_dump(x,0);/* reset */ + return; + } + x->x_esced = 0; + } + /* Add the character to the buffer */ + if (x->x_verbose) post ("slipdec_list: adding character %d to buffer[%d]", c, x->x_slip_length); + x->x_slip_buf[x->x_slip_length++].a_w.w_float = c; + } +} + +static void slipdec_float(t_slipdec *x, t_float f) +{ + /* SLIP decode a byte */ + int c; + + if (x->x_verbose) post ("slipdec_float: buffer length %d, esc = %d", x->x_slip_length, x->x_esced); + /* for each byte in the packet, send the appropriate character sequence */ + /* check each atom for byteness */ + c = (((int)f) & 0x0FF); + if (c != f) + { + /* abort, input list needs to be fixed before this is gonna wuk */ + pd_error (x, "slipdec: input %d out of range [0..255]", f); + x->x_valid_SLIP = 0; /* not valid SLIP */ + slipdec_dump(x,0);/* reset */ + return; + } + if(SLIP_END == c) + { + if (x->x_verbose) post ("slipdec_float: SLIP_END at %d", x->x_slip_length); + /* If it's the beginning of a packet, ignore it */ + if (0 == x->x_slip_length) return; + /* send the packet */ + else + { + if (x->x_verbose) post ("slipdec_float: end of packet"); + slipdec_dump(x, 1); + return; + } + } + if (SLIP_ESC == c) + { + if (x->x_verbose) post ("slipdec_float: SLIP_ESC %f = %d", f, c); + x->x_esced = 1; + return; + } + if (1 == x->x_esced) + { + if (SLIP_ESC_END == c) c = SLIP_END; + else if (SLIP_ESC_ESC == c) c = SLIP_ESC; + else + { + x->x_valid_SLIP = 0; /* not valid SLIP */ + slipdec_dump(x,0);/* reset */ + pd_error (x, "slipdec_float: SLIP_ESC not followed by 220 or 221 (%d)", c); + return; + } + if (x->x_verbose) post ("slipdec_float: ESCED %f = %d", f, c); + x->x_esced = 0; + } + /* Add the character to the buffer */ if (x->x_slip_length < x->x_slip_max_length) { + if (x->x_verbose) post ("slipdec_float: adding character %d to buffer[%d]", c, x->x_slip_length); x->x_slip_buf[x->x_slip_length++].a_w.w_float = c; } else { - pd_error (x, "slipdec: input packet longer than %d", x->x_slip_length); - x->x_slip_length = x->x_esced = x->x_packet_index = 0; - } -} - -static void slipdec_verbosity(t_slipdec *x, t_float f) -{ - x->x_verbose = (0 != f)?1:0; -} - -static void slipdec_free(t_slipdec *x) -{ - if (x->x_slip_buf != NULL) freebytes((void *)x->x_slip_buf, sizeof(t_atom)*x->x_slip_max_length); -} - -void slipdec_setup(void) -{ - slipdec_class = class_new(gensym("slipdec"), - (t_newmethod)slipdec_new, (t_method)slipdec_free, - sizeof(t_slipdec), 0, A_GIMME, 0); - class_addlist(slipdec_class, slipdec_list); - class_addfloat(slipdec_class, slipdec_float); - class_addmethod(slipdec_class, (t_method)slipdec_verbosity, gensym("verbosity"), A_FLOAT, 0); - class_sethelpsymbol(slipdec_class, gensym("slipenc")); /* use slipenc-help.pd */ -} - -/* fin slipdec.c*/ + pd_error (x, "slipdec: input packet longer than %d", x->x_slip_length); + x->x_valid_SLIP = 0; /* not valid SLIP */ + slipdec_dump(x,0);/* reset */ + } +} + +static void slipdec_verbosity(t_slipdec *x, t_float f) +{ + x->x_verbose = (0 != f)?1:0; +} + +static void slipdec_free(t_slipdec *x) +{ + if (x->x_slip_buf != NULL) freebytes((void *)x->x_slip_buf, sizeof(t_atom)*x->x_slip_max_length); +} + +void slipdec_setup(void) +{ + slipdec_class = class_new(gensym("slipdec"), + (t_newmethod)slipdec_new, (t_method)slipdec_free, + sizeof(t_slipdec), 0, A_GIMME, 0); + class_addlist(slipdec_class, slipdec_list); + class_addfloat(slipdec_class, slipdec_float); + class_addmethod(slipdec_class, (t_method)slipdec_verbosity, gensym("verbosity"), A_FLOAT, 0); +} + +/* fin slipdec.c */ -- cgit v1.2.1