c2-utopia/linux-receiver/slip.c

198 lines
4.4 KiB
C

#include "slip.h"
/**
* @brief Internal SLIP character values.
**/
typedef enum {
END = 0xC0,
ESC = 0xDB,
ESC_END = 0xDC,
ESC_ESC = 0xDD
} slip_char_t;
/**
* @brief Internal SLIP encoder state.
**/
typedef enum {
STATE_MESSAGE,
STATE_ERROR,
STATE_ESCAPE
} slip_state_t;
/**
* @brief Initialise a SLIP encoder or decoder.
*
* @param[in] slip : Pointer to SLIP encoder or decoder.
* @param[in] buf : Buffer to hold encoded or decoded message.
* @param[in] len : Length of buffer
**/
void SLIP_init(slip_t *slip, uint8_t *buf, size_t len, slip_encoding_t encoding)
{
slip->buf = buf;
slip->len = len;
slip->state = STATE_MESSAGE;
slip->wp = 0;
slip->encoding = encoding;
}
/**
* @brief Reset SLIP encoder or decoder.
*
* @param[in] slip : Pointer to SLIP encoder or decoder.
**/
void SLIP_reset(slip_t *slip)
{
slip->state = STATE_MESSAGE;
slip->wp = 0;
}
/**
* @brief Gets the length of the encoded or decoded message so far.
*
* @param[in] slip : Pointer to SLIP encoder or decoder.
*
* @return Length of message.
*/
size_t SLIP_get_length(slip_t *slip)
{
return slip->wp;
}
/**
* @brief Consume byte for SLIP encoding.
*
* @param[in] slip : Pointer to SLIP encoder.
* @param[in] byte : Byte to be encoded.
*
* @return < 0 : Error
* = 0 : Encoded byte
* > 0 : Success/Finished (Length of encoded data)
**/
static int SLIP_encode_byte(slip_t *slip, uint8_t byte)
{
int remaining = slip->len - slip->wp;
int required = (byte == ESC || byte == END) ? 2 : 1;
if (remaining < required) {
return -1;
}
if (byte == ESC)
{
slip->buf[slip->wp++] = ESC;
slip->buf[slip->wp++] = ESC_ESC;
}
else if (byte == END) {
slip->buf[slip->wp++] = ESC;
slip->buf[slip->wp++] = ESC_END;
}
else {
slip->buf[slip->wp++] = byte;
}
return 0;
}
/**
* @brief SLIP encodes a given frame
*
* @param[in] slip : Pointer to SLIP encoder.
* @param[in] buf : Buffer containing frame.
* @param[in] len : Length of buffer
*
* @return > 0 : Success (Length of encoded data)
* = 0 : Failed
**/
size_t SLIP_encode(slip_t *slip, const uint8_t *buf, size_t len)
{
SLIP_reset(slip);
if(slip->encoding == SLIP_ENCODING_DOUBLE_ENDED && slip->wp == 0) {
/* Start of message */
/* Double encoded SLIP, where an END delimiter is also added to the beginning of the message */
slip->buf[slip->wp++] = END;
}
while(len--) {
if(SLIP_encode_byte(slip, *buf++) < 0) {
/* SLIP encoding failed */
return 0;
}
}
if((slip->len - slip->wp) < 1) {
/* No space for END delimiter */
return 0;
}
slip->buf[slip->wp++] = END;
return slip->wp;
}
/**
* @brief Consume byte for SLIP decoding.
*
* @param[in] slip : Pointer to SLIP decoder.
* @param[in] byte : Byte to be decoded.
*
* @return < 0 : Error
* = 0 : Decoded byte
* > 0 : Success/Finished (Length of decoded data)
**/
int SLIP_decode(slip_t *slip, uint8_t byte)
{
int retVal = 0;
if(byte == END)
{
if(slip->wp == 0) {
/* Double ended SLIP encoding. This indicatees the beginning of a SLIP message */
retVal = 0;
}
else if(slip->wp > 0 && slip->state == STATE_MESSAGE) {
retVal = slip->wp;
} else {
retVal = -1;
}
SLIP_reset(slip);
return retVal;
}
switch(slip->state)
{
case STATE_MESSAGE:
{
if(slip->wp == slip->len) {
/* ERROR: Ran out of buffer space */
SLIP_reset(slip);
return -1;
} else if(byte == ESC) {
slip->state = STATE_ESCAPE;
} else {
slip->buf[slip->wp++] = byte;
}
break;
}
case STATE_ESCAPE:
{
if(byte == ESC_END) {
slip->buf[slip->wp++] = END;
slip->state = STATE_MESSAGE;
} else if(byte == ESC_ESC) {
slip->buf[slip->wp++] = ESC;
slip->state = STATE_MESSAGE;
} else {
/* ERROR: Wrong character received */
SLIP_reset(slip);
return -1;
}
break;
}
case STATE_ERROR: {
SLIP_reset(slip);
return -1;
}
}
return 0;
}