diff options
Diffstat (limited to 'slip.c')
-rw-r--r-- | slip.c | 141 |
1 files changed, 141 insertions, 0 deletions
@@ -0,0 +1,141 @@ +/* SLIP send/recv code, from RFC 1055 */ + +#include <stdio.h> /* perror */ + +#include "slip_internal.h" + +/* SLIP special character codes + */ +#define END 0300 /* indicates end of packet */ +#define ESC 0333 /* indicates byte stuffing */ +#define ESC_END 0334 /* ESC ESC_END means END data byte */ +#define ESC_ESC 0335 /* ESC ESC_ESC means ESC data byte */ + +/* SLIP_SEND: sends a packet of length "len", starting at + * location "p". + */ +int hal_slip_send(const uint8_t * const ptr, const size_t len) +{ + int i; + uint8_t *p = (uint8_t *)ptr; + +#define check_send_char(c) if (hal_slip_send_char(c) == -1) return perror("write"), -1; + + /* send an initial END character to flush out any data that may + * have accumulated in the receiver due to line noise + */ + check_send_char(END); + + /* for each byte in the packet, send the appropriate character + * sequence + */ + for (i = 0; i < len; ++i) { + switch (*p) { + /* if it's the same code as an END character, we send a + * special two character code so as not to make the + * receiver think we sent an END + */ + case END: + check_send_char(ESC); + check_send_char(ESC_END); + break; + + /* if it's the same code as an ESC character, + * we send a special two character code so as not + * to make the receiver think we sent an ESC + */ + case ESC: + check_send_char(ESC); + check_send_char(ESC_ESC); + break; + + /* otherwise, we just send the character + */ + default: + check_send_char(*p); + } + + p++; + } + + /* tell the receiver that we're done sending the packet + */ + check_send_char(END); + + return 0; +#undef check_send_char +} + +/* SLIP_RECV: receives a packet into the buffer located at "p". + * If more than len bytes are received, the packet will + * be truncated. + * Returns the number of bytes stored in the buffer. + */ +int hal_slip_recv(uint8_t * const p, const size_t len) +{ + uint8_t c; + size_t received = 0; + +#define check_recv_char(c) if (hal_slip_recv_char(&c) == -1) return perror("read"), -1; + + /* sit in a loop reading bytes until we put together + * a whole packet. + * Make sure not to copy them into the packet if we + * run out of room. + */ + while (1) { + /* get a character to process + */ + check_recv_char(c); + + /* handle bytestuffing if necessary + */ + switch (c) { + + /* if it's an END character then we're done with + * the packet + */ + case END: + /* a minor optimization: if there is no + * data in the packet, ignore it. This is + * meant to avoid bothering IP with all + * the empty packets generated by the + * duplicate END characters which are in + * turn sent to try to detect line noise. + */ + if (received) + return received; + else + break; + + /* if it's the same code as an ESC character, wait + * and get another character and then figure out + * what to store in the packet based on that. + */ + case ESC: + check_recv_char(c); + + /* if "c" is not one of these two, then we + * have a protocol violation. The best bet + * seems to be to leave the byte alone and + * just stuff it into the packet + */ + switch(c) { + case ESC_END: + c = END; + break; + case ESC_ESC: + c = ESC; + break; + } + + /* here we fall into the default handler and let + * it store the character for us + */ + default: + if (received < len) + p[received++] = c; + } + } +#undef check_recv_char +} |