libslip-c

C SLIP-encoding library
git clone https://git.sinitax.com/sinitax/libslip-c
Log | Files | Refs | LICENSE | sfeed.txt

commit 21b0708ce5d2f0e1cafb28c1b9e739c7ba1e8f36
Author: Louis Burda <quent.burda@gmail.com>
Date:   Sat, 18 Feb 2023 17:59:47 +0100

Initial version

Diffstat:
A.gitignore | 3+++
AMakefile | 34++++++++++++++++++++++++++++++++++
Ainclude/slip.h | 54++++++++++++++++++++++++++++++++++++++++++++++++++++++
Alibslip.abi | 7+++++++
Alibslip.lds | 11+++++++++++
Asrc/slip.c | 173+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
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; +}