| /* |
| * Copyright (C) 1995 Advanced RISC Machines Limited. All rights reserved. |
| * |
| * This software may be freely used, copied, modified, and distributed |
| * provided that the above copyright notice is preserved in all copies of the |
| * software. |
| */ |
| |
| /*-*-C-*- |
| * |
| * $Revision$ |
| * $Date$ |
| * |
| * Project: ANGEL |
| * |
| * Title: Character based packet transmission engine |
| */ |
| |
| #include <stdarg.h> /* ANSI varargs support */ |
| #include "angel.h" /* Angel system definitions */ |
| #include "angel_endian.h" /* Endian independant memory access macros */ |
| #include "crc.h" /* crc generation definitions and headers */ |
| #include "rxtx.h" |
| #include "channels.h" |
| #include "buffers.h" |
| #include "logging.h" |
| |
| /* definitions to describe the engines state */ |
| #define N_STX 0x0 /* first 2 bits for N_ */ |
| #define N_BODY 0x1 |
| #define N_ETX 0x2 |
| #define N_IDLE 0x3 |
| #define N_MASK 0x3 /* mask for the Encapsulator state */ |
| |
| #define E_PLAIN (0x0 << 2) /* 3rd bit for E_ */ |
| #define E_ESC (0x1 << 2) /* 3rd bit for E_ */ |
| #define E_MASK (0x1 << 2) /* mask for the Escaper state */ |
| |
| #define F_HEAD (0x0 << 3) /* 4th and 5th bits for F_ */ |
| #define F_DATA (0x1 << 3) |
| #define F_CRC (0x1 << 4) |
| #define F_MASK (0x3 << 3) /* mask for the Escaper state */ |
| |
| 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){ |
| /* TODO: gaurd on long/bad packets */ |
| /* |
| * encapsulate the packet, framing has been moved from a seperate |
| * function into the encapsulation routine as it needed too much |
| * inherited state for it to be sensibly located elsewhere |
| */ |
| 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; /* set up for the header */ |
| txstate->crc = startCRC32; /* set up basic crc */ |
| 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) { |
| /* send type */ |
| *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) { |
| /* move on to the next state */ |
| 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) { |
| /* move on to the next state */ |
| 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 |
| /* move on to the next state */ |
| 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; |
| } |
| /* stop a silly -Wall warning */ |
| return (te_status)-1; |
| } |
| |
| /* |
| * crc generation occurs in the escape function because it is the only |
| * place where we know that we're putting a real char into the buffer |
| * rather than an escaped one. |
| * We must be careful here not to update the crc when we're sending it |
| */ |
| static unsigned char escape(unsigned char ch_in, struct te_state *txstate) { |
| if (((txstate->tx_state) & E_MASK) == E_ESC) { |
| /* char has been escaped so send the real char */ |
| #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)) { |
| /* char needs escaping */ |
| #ifdef DO_TRACE |
| __rt_trace("txe-esc "); |
| #endif |
| txstate->tx_state = (txstate->tx_state & ~E_MASK) | E_ESC; |
| return txstate->config->esc; |
| } |
| /* must be a char that can be sent plain */ |
| txstate->field_c--; |
| if ((txstate->tx_state & F_MASK) != F_CRC) |
| txstate->crc = crc32(&ch_in, 1, txstate->crc); |
| return ch_in; |
| } |
| |
| /* EOF tx.c */ |