#include <stdarg.h>
#include "angel.h"
#include "angel_endian.h"
#include "crc.h"
#include "rxtx.h"
#include "channels.h"
#include "buffers.h"
#ifdef TARGET
# include "devdriv.h"
#endif
#include "logging.h"
static re_status unexp_stx(struct re_state *rxstate);
static re_status unexp_etx(struct re_state *rxstate);
typedef enum rx_state_flag{
RST_STX,
RST_TYP,
RST_LEN,
RST_DAT,
RST_CRC,
RST_ETX,
RST_ESC = (0x1 << 0x3)
} rx_state_flag;
void Angel_RxEngineInit(const struct re_config *rxconfig,
struct re_state *rxstate)
{
rxstate->rx_state = RST_STX;
rxstate->field_c = 0;
rxstate->index = 0;
rxstate->crc = 0;
rxstate->error = RE_OKAY;
rxstate->config = rxconfig;
}
re_status Angel_RxEngine(unsigned char new_ch, struct data_packet *packet,
struct re_state *rxstate)
{
if ((rxstate->rx_state & RST_ESC) == RST_ESC)
{
new_ch &= ~serial_ESCAPE;
#ifdef DO_TRACE
__rt_trace("rxe-echar-%2x ", new_ch);
#endif
rxstate->rx_state &= ~RST_ESC;
}
else if ( (1 << new_ch) & rxstate->config->esc_set )
{
if (new_ch == rxstate->config->esc)
{
#ifdef DO_TRACE
__rt_trace("rxe-esc ");
#endif
rxstate->rx_state |= RST_ESC;
return RS_IN_PKT;
}
else
{
if ((new_ch == (rxstate->config->stx)) && (rxstate->rx_state != RST_STX))
return unexp_stx(rxstate);
if ((new_ch == (rxstate->config->etx)) && (rxstate->rx_state != RST_ETX))
return unexp_etx(rxstate);
}
}
if (rxstate->rx_state == RST_DAT)
{
#ifdef DO_TRACE
__rt_trace("rxe-dat ");
#endif
rxstate->crc = crc32(&new_ch, 1, rxstate->crc);
(packet->data)[rxstate->index++] = (unsigned int)new_ch & 0xff;
if (rxstate->index == packet->len)
rxstate->rx_state = RST_CRC;
return RS_IN_PKT;
}
switch (rxstate->rx_state)
{
case RST_STX:
if (new_ch == rxstate->config->stx)
{
rxstate->rx_state = RST_TYP;
rxstate->error = RE_OKAY;
rxstate->crc = startCRC32;
rxstate->index = 0;
return RS_IN_PKT;
}
else
{
rxstate->error = RE_OKAY;
return RS_WAIT_PKT;
}
case RST_TYP:
packet->type = (DevChanID)new_ch;
rxstate->rx_state = RST_LEN;
rxstate->error = RE_OKAY;
rxstate->field_c = 0;
#ifdef DO_TRACE
__rt_trace("rxe-type-%2x ", packet->type);
#endif
rxstate->crc = crc32(&new_ch, 1, rxstate->crc);
return RS_IN_PKT;
case RST_LEN:
rxstate->crc = crc32(&new_ch, 1, rxstate->crc);
if (rxstate->field_c++ == 0)
{
packet->len = ((unsigned int)new_ch) << 8;
return RS_IN_PKT;
}
else
{
packet->len |= new_ch;
#ifdef DO_TRACE
__rt_trace("rxe-len-%4x\n", packet->len);
#endif
if (packet->len == 0)
{
rxstate->field_c = 0;
rxstate->rx_state = RST_CRC;
return RS_IN_PKT;
}
else
{
if (packet->data == NULL)
{
if (!rxstate->config->ba_callback(
packet, rxstate->config->ba_data)) {
rxstate->rx_state = RST_STX;
rxstate->error = RE_INTERNAL;
return RS_BAD_PKT;
}
}
if (packet->len > packet->buf_len)
{
rxstate->field_c = 0;
rxstate->rx_state = RST_STX;
rxstate->error = RE_LEN;
return RS_BAD_PKT;
}
else
{
rxstate->field_c = 0;
rxstate->rx_state = RST_DAT;
return RS_IN_PKT;
}
}
}
case RST_DAT:
#ifdef ASSERTIONS_ENABLED
__rt_warning("ERROR: hit RST_dat in switch\n");
#endif
rxstate->rx_state = RST_STX;
rxstate->error = RE_INTERNAL;
return RS_BAD_PKT;
case RST_CRC:
if (rxstate->field_c == 0)
packet->crc = 0;
packet->crc |= (new_ch & 0xFF) << ((3 - rxstate->field_c) * 8);
rxstate->field_c++;
if (rxstate->field_c == 4)
{
rxstate->field_c = 0;
rxstate->rx_state = RST_ETX;
#ifdef DO_TRACE
__rt_trace("rxe-rcrc-%8x ", packet->crc);
#endif
}
return RS_IN_PKT;
case RST_ETX:
if (new_ch == rxstate->config->etx)
{
#if defined(DEBUG) && !defined(NO_PKT_DATA)
{
int c;
# ifdef DO_TRACE
__rt_trace("\n");
# endif
__rt_info("RXE Data =");
for (c=0; c < packet->len; c++)
__rt_info("%02x", packet->data[c]);
__rt_info("\n");
}
#endif
if (rxstate->crc == packet->crc)
{
rxstate->rx_state = RST_STX;
rxstate->field_c = 0;
return RS_GOOD_PKT;
}
else
{
#ifdef ASSERTIONS_ENABLED
__rt_warning("Bad crc, rx calculates it should be 0x%x\n", rxstate->crc);
#endif
rxstate->rx_state = RST_STX;
rxstate->error = RE_CRC;
return RS_BAD_PKT;
}
}
else if (new_ch == rxstate->config->stx)
return unexp_stx(rxstate);
else
{
rxstate->rx_state = RST_STX;
rxstate->error = RE_NETX;
return RS_BAD_PKT;
}
default:
#ifdef ASSERTIONS_ENABLED
__rt_warning("ERROR fell through rxengine\n");
#endif
rxstate->rx_state = RST_STX;
rxstate->error = RE_INTERNAL;
return RS_BAD_PKT;
}
}
static re_status unexp_stx(struct re_state *rxstate)
{
#ifdef ASSERTIONS_ENABLED
__rt_warning("Unexpected stx\n");
#endif
rxstate->crc = startCRC32;
rxstate->index = 0;
rxstate->rx_state = RST_TYP;
rxstate->error = RE_U_STX;
rxstate->field_c = 0;
return RS_BAD_PKT;
}
static re_status unexp_etx(struct re_state *rxstate)
{
#ifdef ASSERTIONS_ENABLED
__rt_warning("Unexpected etx, rxstate: index= 0x%2x, field_c=0x%2x, state=0x%2x\n", rxstate->index, rxstate->field_c, rxstate->rx_state);
#endif
rxstate->crc = 0;
rxstate->index = 0;
rxstate->rx_state = RST_STX;
rxstate->error = RE_U_ETX;
rxstate->field_c = 0;
return RS_BAD_PKT;
}
bool angel_DD_RxEng_BufferAlloc( struct data_packet *packet, void *cb_data )
{
#ifdef TARGET
DeviceID devid = (DeviceID)cb_data;
#else
IGNORE(cb_data);
#endif
if ( packet->type < DC_NUM_CHANNELS )
{
#ifdef TARGET
packet->data = angel_DD_GetBuffer( devid, packet->type,
packet->len );
#else
packet->data = malloc(packet->len);
#endif
if ( packet->data == NULL )
return FALSE;
else
{
packet->buf_len = packet->len;
return TRUE;
}
}
else
{
return FALSE;
}
}