Created
March 9, 2023 13:20
-
-
Save cpq/0410a30a178f551ccaa150e6e34a3a5a to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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