Skip to content

Instantly share code, notes, and snippets.

@cpq
Created March 9, 2023 13:20
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save cpq/0410a30a178f551ccaa150e6e34a3a5a to your computer and use it in GitHub Desktop.
Save cpq/0410a30a178f551ccaa150e6e34a3a5a to your computer and use it in GitHub Desktop.
// Copyright (c) Cesanta Software Limited
// All rights reserved
// SPDX-License-Identifier: MIT
// Usage example (Arduino):
// char buf[100];
// struct slip slip = {.buf = buf, .size = sizeof(buf) - 1};
// ...
// unsigned char c = Serial.read();
// size_t len = slip_recv(c, &slip);
// if (len > 0) {
// buf[len] = '\0';
// Serial.print("Received SLIP frame: ");
// Serial.println(buf);
// } else {
// Serial.write(c);
// }
// https://datatracker.ietf.org/doc/html/rfc1055
enum { END = 192, ESC = 219, ESC_END = 220, ESC_ESC = 221 };
// SLIP state machine
struct slip {
unsigned char *buf; // Buffer for the frame mode
size_t size; // Buffer size
size_t len; // Number of currently buffered bytes
int mode; // Operation mode. 0 - serial, 1 - frame
unsigned char prev; // Previously read character
};
// Encapsulate buf,len in a SLIP frame and send using function fn
static inline void slip_send(const void *buf, size_t len,
void (*fn)(unsigned char, void *), void *arg) {
const unsigned char *p = buf;
size_t i;
fn(END, arg);
for (i = 0; i < len; i++) {
if (p[i] == END) {
fn(ESC, arg);
fn(ESC_END, arg);
} else if (p[i] == ESC) {
fn(ESC, arg);
fn(ESC_ESC, arg);
} else {
fn(p[i], arg);
}
}
fn(END, arg);
}
// Process incoming byte `c`.
// In serial mode, do nothing, return 1.
// In frame mode, append a byte to the `buf` and increment `len`.
// Return size of the buffered packet when switching to serial mode, or 0
static inline size_t slip_recv(unsigned char c, struct slip *slip) {
size_t res = 0;
if (slip->mode) {
if (slip->prev == ESC && c == ESC_END) {
slip->buf[slip->len++] = END;
} else if (slip->prev == ESC && c == ESC_ESC) {
slip->buf[slip->len++] = ESC;
} else if (c == END) {
res = slip->len;
} else if (c != ESC) {
slip->buf[slip->len++] = c;
}
if (slip->len >= slip->size) slip->len = 0; // Overflow. Reset silently
}
slip->prev = c;
// The "END" character flips the mode
if (c == END) slip->len = 0, slip->mode = !slip->mode;
return res;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment