#include <stdarg.h>
#include "angel.h"
#include "angel_endian.h"
#include "crc.h"
#include "rxtx.h"
#include "channels.h"
#include "buffers.h"
#include "logging.h"
#define N_STX 0x0
#define N_BODY 0x1
#define N_ETX 0x2
#define N_IDLE 0x3
#define N_MASK 0x3
#define E_PLAIN (0x0 << 2)
#define E_ESC (0x1 << 2)
#define E_MASK (0x1 << 2)
#define F_HEAD (0x0 << 3)
#define F_DATA (0x1 << 3)
#define F_CRC (0x1 << 4)
#define F_MASK (0x3 << 3)
static unsigned char escape(unsigned char ch_in, struct te_state *txstate);
void Angel_TxEngineInit(const struct re_config *txconfig,
const struct data_packet *packet,
struct te_state *txstate){
IGNORE(packet);
txstate->tx_state = N_STX | E_PLAIN | F_HEAD;
txstate->field_c = 0;
txstate->encoded = 0;
txstate->config = txconfig;
txstate->crc = 0;
}
te_status Angel_TxEngine(const struct data_packet *packet,
struct te_state *txstate,
unsigned char *tx_ch){
switch ((txstate->tx_state) & N_MASK){
case N_STX:
#ifdef DO_TRACE
__rt_trace("txe-stx ");
#endif
txstate->tx_state = (txstate->tx_state & ~N_MASK) | N_BODY;
*tx_ch = txstate->config->stx;
txstate->field_c = 3;
txstate->crc = startCRC32;
return TS_IN_PKT;
case N_BODY:{
switch (txstate->tx_state & F_MASK) {
case F_HEAD:
#ifdef DO_TRACE
__rt_trace("txe-head ");
#endif
if (txstate->field_c == 3) {
*tx_ch = escape(packet->type, txstate);
return TS_IN_PKT;
}
else {
*tx_ch = escape((packet->len >> (txstate->field_c - 1) * 8) & 0xff,
txstate);
if (txstate->field_c == 0) {
txstate->tx_state = (txstate->tx_state & ~F_MASK) | F_DATA;
txstate->field_c = packet->len;
}
return TS_IN_PKT;
}
case F_DATA:
#ifdef DO_TRACE
__rt_trace("txe-data ");
#endif
*tx_ch = escape(packet->data[packet->len - txstate->field_c], txstate);
if (txstate->field_c == 0) {
txstate->tx_state = (txstate->tx_state & ~F_MASK) | F_CRC;
txstate->field_c = 4;
}
return TS_IN_PKT;
case F_CRC:
#ifdef DO_TRACE
__rt_trace("txe-crc ");
#endif
*tx_ch = escape((txstate->crc >> ((txstate->field_c - 1) * 8)) & 0xff,
txstate);
if (txstate->field_c == 0) {
#ifdef DO_TRACE
__rt_trace("txe crc = 0x%x\n", txstate->crc);
#endif
txstate->tx_state = (txstate->tx_state & ~N_MASK) | N_ETX;
}
return TS_IN_PKT;
}
}
case N_ETX:
#ifdef DO_TRACE
__rt_trace("txe-etx\n");
#endif
txstate->tx_state = (txstate->tx_state & ~N_MASK) | N_IDLE;
*tx_ch = txstate->config->etx;
return TS_DONE_PKT;
default:
#ifdef DEBUG
__rt_info("tx default\n");
#endif
txstate->tx_state = (txstate->tx_state & ~N_MASK) | N_IDLE;
return TS_IDLE;
}
return (te_status)-1;
}
static unsigned char escape(unsigned char ch_in, struct te_state *txstate) {
if (((txstate->tx_state) & E_MASK) == E_ESC) {
#ifdef DO_TRACE
__rt_trace("txe-echar ");
#endif
txstate->tx_state = (txstate->tx_state & ~E_MASK) | E_PLAIN;
txstate->field_c--;
if ((txstate->tx_state & F_MASK) != F_CRC)
txstate->crc = crc32( &ch_in, 1, txstate->crc);
return ch_in | serial_ESCAPE;
}
if ((ch_in < 32) && ((txstate->config->esc_set & (1 << ch_in)) != 0)) {
#ifdef DO_TRACE
__rt_trace("txe-esc ");
#endif
txstate->tx_state = (txstate->tx_state & ~E_MASK) | E_ESC;
return txstate->config->esc;
}
txstate->field_c--;
if ((txstate->tx_state & F_MASK) != F_CRC)
txstate->crc = crc32(&ch_in, 1, txstate->crc);
return ch_in;
}