diff options
author | Martin Peach <mrpeach@users.sourceforge.net> | 2010-05-03 23:23:46 +0000 |
---|---|---|
committer | Martin Peach <mrpeach@users.sourceforge.net> | 2010-05-03 23:23:46 +0000 |
commit | d12a97f73664e552caec2010a3405b3a381076a1 (patch) | |
tree | b002d482365abf844a78932c99350741f27d3544 /slipenc/slipenc.c | |
parent | 34a543355e6dd46d36a600a4ff082558e626bf7a (diff) |
slipenc encodes an input list of bytes-as-floats with the Serial Line Internet Protocol, suitable for transmission over a serial link. This is used in OSC 1.1.
svn path=/trunk/externals/mrpeach/; revision=13487
Diffstat (limited to 'slipenc/slipenc.c')
-rw-r--r-- | slipenc/slipenc.c | 144 |
1 files changed, 144 insertions, 0 deletions
diff --git a/slipenc/slipenc.c b/slipenc/slipenc.c new file mode 100644 index 0000000..fc2747b --- /dev/null +++ b/slipenc/slipenc.c @@ -0,0 +1,144 @@ +/* slipenc.c 20070711 Martin Peach */ +/**encode a list of bytes as SLIP / +/* +/* +From RFC 1055: +PROTOCOL + + The SLIP protocol defines two special characters: SLIP_END and SLIP_ESC. SLIP_END is + octal 300 (decimal 192) and SLIP_ESC is octal 333 (decimal 219) not to be + confused with the ASCII ESCape character; for the purposes of this + discussion, SLIP_ESC will indicate the SLIP SLIP_ESC character. To send a + packet, a SLIP host simply starts sending the data in the packet. If + a data byte is the same code as SLIP_END character, a two byte sequence of + SLIP_ESC and octal 334 (decimal 220) is sent instead. If it the same as + an SLIP_ESC character, an two byte sequence of SLIP_ESC and octal 335 (decimal + 221) is sent instead. When the last byte in the packet has been + sent, an SLIP_END character is then transmitted. + + Phil Karn suggests a simple change to the algorithm, which is to + begin as well as end packets with an SLIP_END character. This will flush + any erroneous bytes which have been caused by line noise. In the + normal case, the receiver will simply see two back-to-back SLIP_END + characters, which will generate a bad IP packet. If the SLIP + implementation does not throw away the zero-length IP packet, the IP + implementation certainly will. If there was line noise, the data + received due to it will be discarded without affecting the following + packet. + + Because there is no 'standard' SLIP specification, there is no real + defined maximum packet size for SLIP. It is probably best to accept + the maximum packet size used by the Berkeley UNIX SLIP drivers: 1006 + bytes including the IP and transport protocol headers (not including + the framing characters). Therefore any new SLIP implementations + should be prepared to accept 1006 byte datagrams and should not send + more than 1006 bytes in a datagram. +*/ + +#include "m_pd.h" + +/* -------------------------- slipenc -------------------------- */ +#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 *slipenc_class; + +typedef struct _slipenc +{ + t_object x_obj; + t_outlet *x_slipenc_out; + t_atom *x_slip_buf; + t_int x_slip_length; +} t_slipenc; + +static void *slipenc_new(t_symbol *s, int argc, t_atom *argv); +static void slipenc_list(t_slipenc *x, t_symbol *s, int ac, t_atom *av); +static void slipenc_free(t_slipenc *x); +void slipenc_setup(void); + +static void *slipenc_new(t_symbol *s, int argc, t_atom *argv) +{ + int i; + t_slipenc *x = (t_slipenc *)pd_new(slipenc_class); + + x->x_slip_buf = (t_atom *)getbytes(sizeof(t_atom)*MAX_SLIP); + if(x->x_slip_buf == NULL) + { + error("slipenc: unable to allocate %lu bytes for x_slip_buf", (long)sizeof(t_atom)*MAX_SLIP); + return NULL; + } + /* Initialize all the slip buf atoms to float type */ + for (i = 0; i < MAX_SLIP; ++i) x->x_slip_buf[i].a_type = A_FLOAT; + x->x_slipenc_out = outlet_new(&x->x_obj, &s_list); + return (x); +} + +static void slipenc_list(t_slipenc *x, t_symbol *s, int ac, t_atom *av) +{ + /* SLIP encode a list of bytes */ + float f; + int i, c; + + i = x->x_slip_length = 0; + /* send an initial SLIP_END character to flush out any data that may */ + /* have accumulated in the receiver due to line noise */ + x->x_slip_buf[x->x_slip_length++].a_w.w_float = SLIP_END; + + /* for each byte in the packet, send the appropriate character sequence */ + while((i < ac) && (x->x_slip_length < (MAX_SLIP-1))) + { + /* check each atom for byteness */ + f = atom_getfloat(&av[i++]); + c = (((int)f) & 0x0FF); + if (c != f) + { + /* abort, bad input character */ + pd_error (x, "slipenc: input %d out of range [0..255]", f); + return; + } + if(SLIP_END == c) + { + /* If it's the same code as a SLIP_END character, replace it with a */ + /* special two-character code so as not to make the receiver think we sent SLIP_END */ + x->x_slip_buf[x->x_slip_length++].a_w.w_float = SLIP_ESC; + x->x_slip_buf[x->x_slip_length++].a_w.w_float = SLIP_ESC_END; + } + else if (SLIP_ESC == c) + { + /* If it's the same code as a SLIP_ESC character, replace it with a special two-character code */ + /* so as not to make the receiver think we sent SLIP_ESC */ + x->x_slip_buf[x->x_slip_length++].a_w.w_float = SLIP_ESC; + x->x_slip_buf[x->x_slip_length++].a_w.w_float = SLIP_ESC_ESC; + } + else + { + /* Otherwise, pass the character */ + x->x_slip_buf[x->x_slip_length++].a_w.w_float = c; + } + } + /* Add the SLIP_END code to tell the receiver that the packet is complete */ + x->x_slip_buf[x->x_slip_length++].a_w.w_float = SLIP_END; + outlet_list(x->x_slipenc_out, &s_list, x->x_slip_length, x->x_slip_buf); +} + +static void slipenc_free(t_slipenc *x) +{ + if (x->x_slip_buf != NULL) freebytes((void *)x->x_slip_buf, sizeof(t_atom)*MAX_SLIP); +} + +void slipenc_setup(void) +{ + slipenc_class = class_new(gensym("slipenc"), + (t_newmethod)slipenc_new, (t_method)slipenc_free, + sizeof(t_slipenc), 0, A_GIMME, 0); + class_addlist(slipenc_class, slipenc_list); +} + +/* fin slipenc.c*/ |