/* 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 %f 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*/