commit 21b0708ce5d2f0e1cafb28c1b9e739c7ba1e8f36
Author: Louis Burda <quent.burda@gmail.com>
Date: Sat, 18 Feb 2023 17:59:47 +0100
Initial version
Diffstat:
6 files changed, 282 insertions(+), 0 deletions(-)
diff --git a/.gitignore b/.gitignore
@@ -0,0 +1,3 @@
+build
+compile_commands.json
+.cache
diff --git a/Makefile b/Makefile
@@ -0,0 +1,34 @@
+PREFIX ?= /usr/local
+BINDIR ?= /bin
+
+CFLAGS = -I include
+
+ifeq "$(LIBSLIP_DEBUG)" "1"
+CFLAGS += -g -DLIBSLIP_ASSERT_ENABLE=1
+endif
+
+all: build/libslip.so build/libslip.a
+
+clean:
+ rm -rf build
+
+build:
+ mkdir build
+
+build/libslip.a: src/slip.c include/slip.h | build
+ $(CC) -o build/tmp.o src/slip.c $(CFLAGS) -r
+ objcopy --keep-global-symbols=libslip.abi build/tmp.o build/fixed.o
+ ar rcs $@ build/fixed.o
+
+build/libslip.so: src/slip.c include/slip.h | build
+ $(CC) -o $@ src/slip.c -fPIC $(CFLAGS) -shared -Wl,-version-script libslip.lds
+
+install:
+ install -m755 build/libslip.so -t "$(DESTDIR)$(PREFIX)$(BINDIR)"
+ install -m755 build/libslip.a -t "$(DESTDIR)$(PREFIX)$(BINDIR)"
+
+uninstall:
+ rm -f "$(DESTDIR)$(PREFIX)$(BINDIR)/libslip.so"
+ rm -f "$(DESTDIR)$(PREFIX)$(BINDIR)/libslip.a"
+
+.PHONY: all clean install uninstall
diff --git a/include/slip.h b/include/slip.h
@@ -0,0 +1,54 @@
+#pragma once
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <stdlib.h>
+
+#ifdef LIBSLIP_ASSERT_ENABLE
+
+#include <stdio.h>
+
+#define LIBSLIP_ASSERT(x) libslip_assert((x), __FILE__, __LINE__, #x)
+
+static inline void libslip_assert(int cond,
+ const char *file, int line, const char *condstr)
+{
+ if (cond) return;
+
+ fprintf(stderr, "libslip: Assertion failed at %s:%i (%s)\n",
+ file, line, condstr);
+ abort();
+}
+
+#else
+#define LIBSLIP_ASSERT(x)
+#endif
+
+struct slip {
+ int rx_state;
+
+ size_t rx_index;
+ size_t rx_buflen;
+ uint8_t *rx_buf;
+
+ void (*rx_restart)(struct slip *slip, uint8_t err_byte);
+ void (*rx_packet)(struct slip *slip, void *user,
+ uint8_t *data, size_t size);
+ void *rx_packet_userdata;
+
+ void *(*realloc)(void *buffer, size_t size);
+
+ uint8_t esc, start, end;
+ bool esc_active[256];
+ uint8_t esc_enc[256];
+ uint8_t esc_dec[256];
+};
+
+int slip_init(struct slip *slip);
+void slip_deinit(struct slip *slip);
+
+int slip_decode(struct slip *slip, uint8_t *data, size_t size);
+void slip_decode_store(struct slip *slip, uint8_t byte);
+
+int slip_encode(struct slip *slip, uint8_t *out, size_t *outlen, size_t outcap,
+ uint8_t *in, size_t inlen);
diff --git a/libslip.abi b/libslip.abi
@@ -0,0 +1,7 @@
+slip_init;
+slip_deinit;
+
+slip_set_rx_callback;
+slip_decode;
+
+slip_encode;
diff --git a/libslip.lds b/libslip.lds
@@ -0,0 +1,11 @@
+LIBSLIP_1.0 {
+ global:
+ slip_init;
+ slip_deinit;
+
+ slip_set_rx_callback;
+ slip_decode;
+
+ slip_encode;
+ local: *;
+};
diff --git a/src/slip.c b/src/slip.c
@@ -0,0 +1,173 @@
+#include "slip.h"
+
+#include <asm-generic/errno.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdint.h>
+
+enum {
+ SLIPDEC_START_STATE,
+ SLIPDEC_IN_FRAME_STATE,
+ SLIPDEC_ESC_STATE
+};
+
+static void slip_decode_start(struct slip *slip, uint8_t rx_byte);
+static void slip_decode_inframe(struct slip *slip, uint8_t rx_byte);
+static void slip_decode_escseq(struct slip *slip, uint8_t rx_byte);
+
+static inline void
+store(uint8_t **cur, uint8_t *end, uint8_t byte)
+{
+ if (*cur < end) *(*cur)++ = byte;
+}
+
+void
+slip_decode_start(struct slip *slip, uint8_t rx_byte)
+{
+ /* wait for packet start */
+ if (rx_byte == slip->start) {
+ slip->rx_index = 0;
+ slip->rx_state = SLIPDEC_IN_FRAME_STATE;
+ }
+}
+
+void
+slip_decode_inframe(struct slip *slip, uint8_t rx_byte)
+{
+ if (rx_byte == slip->end) {
+ /* end of packet */
+ slip->rx_packet(slip, slip->rx_packet_userdata,
+ slip->rx_buf, slip->rx_index);
+ slip->rx_state = SLIPDEC_START_STATE;
+ } else if (rx_byte == slip->start) {
+ /* malformed packet */
+ if (slip->rx_restart)
+ slip->rx_restart(slip, rx_byte);
+ slip->rx_index = 0;
+ slip->rx_state = SLIPDEC_START_STATE;
+ } else if (rx_byte == slip->esc) {
+ /* escape sequence */
+ slip->rx_state = SLIPDEC_ESC_STATE;
+ } else {
+ /* data byte */
+ slip_decode_store(slip, rx_byte);
+ }
+}
+
+void
+slip_decode_escseq(struct slip *slip, uint8_t rx_byte)
+{
+ uint8_t dec;
+
+ dec = slip->esc_dec[rx_byte];
+ if (!slip->esc_active[dec]) {
+ /* invalid contents, restart */
+ if (slip->rx_restart)
+ slip->rx_restart(slip, rx_byte);
+ slip->rx_state = SLIPDEC_START_STATE;
+ slip->rx_index = 0;
+ } else {
+ slip_decode_store(slip, dec);
+ slip->rx_state = SLIPDEC_IN_FRAME_STATE;
+ }
+}
+
+int
+slip_init(struct slip *slip)
+{
+ int i;
+
+ slip->rx_state = SLIPDEC_START_STATE;
+
+ slip->rx_index = 0;
+ slip->rx_buflen = 0;
+ slip->rx_buf = NULL;
+
+ LIBSLIP_ASSERT(slip->rx_packet != NULL);
+ LIBSLIP_ASSERT(slip->realloc != NULL);
+
+ LIBSLIP_ASSERT(slip->esc != slip->start);
+ LIBSLIP_ASSERT(slip->esc != slip->end);
+
+ /* build decode table */
+ for (i = 0; i < 256; i++)
+ slip->esc_dec[slip->esc_enc[i]] = i;
+
+ return 0;
+}
+
+void
+slip_deinit(struct slip *slip)
+{
+ free(slip->rx_buf);
+}
+
+void
+slip_decode_store(struct slip *slip, uint8_t byte)
+{
+ if (slip->rx_index >= slip->rx_buflen) {
+ if (!slip->rx_buflen)
+ slip->rx_buflen = 256;
+ else
+ slip->rx_buflen *= 2;
+ slip->rx_buf = slip->realloc(slip->rx_buf, slip->rx_buflen);
+ LIBSLIP_ASSERT(slip->rx_buf != NULL);
+ }
+ slip->rx_buf[slip->rx_index++] = byte;
+}
+
+int
+slip_decode(struct slip *slip, uint8_t* data, size_t size)
+{
+ uint8_t rx_byte;
+ size_t i;
+
+ for (i = 0; i < size; i++) {
+ rx_byte = data[i];
+ switch (slip->rx_state) {
+ case SLIPDEC_START_STATE:
+ slip_decode_start(slip, rx_byte);
+ break;
+ case SLIPDEC_IN_FRAME_STATE:
+ slip_decode_inframe(slip, rx_byte);
+ break;
+ case SLIPDEC_ESC_STATE:
+ slip_decode_escseq(slip, rx_byte);
+ break;
+ default:
+ LIBSLIP_ASSERT(false);
+ }
+ }
+
+ return 0;
+}
+
+int
+slip_encode(struct slip *slip, uint8_t* out, size_t *outlen, size_t outcap,
+ uint8_t* in, size_t inlen)
+{
+ uint8_t *pos, *end;
+ size_t i;
+
+ pos = out;
+ end = out + outcap;
+
+ store(&pos, end, slip->start);
+
+ for (i = 0; i < inlen && pos < end; i++) {
+ if (slip->esc_active[in[i]]) {
+ store(&pos, end, slip->esc);
+ store(&pos, end, slip->esc_enc[in[i]]);
+ } else {
+ store(&pos, end, in[i]);
+ }
+ }
+
+ store(&pos, end, slip->end);
+
+ if (pos >= end) return ENOBUFS;
+
+ *outlen = pos - out;
+
+ return 0;
+}