1/*
2 * Copyright (C) 1995 Advanced RISC Machines Limited. All rights reserved.
3 *
4 * This software may be freely used, copied, modified, and distributed
5 * provided that the above copyright notice is preserved in all copies of the
6 * software.
7 */
8
9/*-*-C-*-
10 *
11 * $Revision: 1.3 $
12 *     $Date: 1999/11/01 13:31:43 $
13 *
14 *   Project: ANGEL
15 *
16 *     Title: Character based packet transmission engine
17 */
18
19#include <stdarg.h>    /* ANSI varargs support */
20#include "angel.h"     /* Angel system definitions */
21#include "angel_endian.h"    /* Endian independant memory access macros */
22#include "crc.h"       /* crc generation definitions and headers */
23#include "rxtx.h"
24#include "channels.h"
25#include "buffers.h"
26#include "logging.h"
27
28/* definitions to describe the engines state */
29#define N_STX           0x0  /* first 2 bits for N_ */
30#define N_BODY          0x1
31#define N_ETX           0x2
32#define N_IDLE          0x3
33#define N_MASK          0x3 /* mask for the Encapsulator state */
34
35#define E_PLAIN         (0x0 << 2) /* 3rd bit for E_ */
36#define E_ESC           (0x1 << 2) /* 3rd bit for E_ */
37#define E_MASK          (0x1 << 2) /* mask for the Escaper state */
38
39#define F_HEAD          (0x0 << 3) /* 4th and 5th bits for F_ */
40#define F_DATA          (0x1 << 3)
41#define F_CRC           (0x1 << 4)
42#define F_MASK          (0x3 << 3) /* mask for the Escaper state */
43
44static unsigned char escape(unsigned char ch_in, struct te_state *txstate);
45
46void Angel_TxEngineInit(const struct re_config *txconfig,
47                        const struct data_packet *packet,
48                        struct te_state *txstate){
49  IGNORE(packet);
50  txstate->tx_state = N_STX | E_PLAIN | F_HEAD;
51  txstate->field_c = 0;
52  txstate->encoded = 0;
53  txstate->config = txconfig;
54  txstate->crc = 0;
55}
56
57te_status Angel_TxEngine(const struct data_packet *packet,
58                         struct te_state *txstate,
59                         unsigned char *tx_ch){
60  /* TODO: gaurd on long/bad packets */
61  /*
62   * encapsulate the packet, framing has been moved from a seperate
63   * function into the encapsulation routine as it needed too much
64   * inherited state for it to be sensibly located elsewhere
65   */
66  switch ((txstate->tx_state) & N_MASK){
67  case N_STX:
68#ifdef DO_TRACE
69    __rt_trace("txe-stx ");
70#endif
71    txstate->tx_state = (txstate->tx_state & ~N_MASK) | N_BODY;
72    *tx_ch = txstate->config->stx;
73    txstate->field_c = 3; /* set up for the header */
74    txstate->crc = startCRC32; /* set up basic crc */
75    return TS_IN_PKT;
76  case N_BODY:{
77    switch (txstate->tx_state & F_MASK) {
78    case F_HEAD:
79#ifdef DO_TRACE
80    __rt_trace("txe-head ");
81#endif
82      if (txstate->field_c == 3) {
83        /* send type */
84        *tx_ch = escape(packet->type, txstate);
85        return TS_IN_PKT;
86      }
87      else {
88        *tx_ch = escape((packet->len >> (txstate->field_c - 1) * 8) & 0xff,
89                      txstate);
90          if (txstate->field_c == 0) {
91            /* move on to the next state */
92            txstate->tx_state = (txstate->tx_state & ~F_MASK) | F_DATA;
93            txstate->field_c = packet->len;
94          }
95        return TS_IN_PKT;
96      }
97    case F_DATA:
98#ifdef DO_TRACE
99    __rt_trace("txe-data ");
100#endif
101      *tx_ch = escape(packet->data[packet->len - txstate->field_c], txstate);
102      if (txstate->field_c == 0) {
103        /* move on to the next state */
104        txstate->tx_state = (txstate->tx_state & ~F_MASK) | F_CRC;
105        txstate->field_c = 4;
106      }
107      return TS_IN_PKT;
108    case F_CRC:
109#ifdef DO_TRACE
110    __rt_trace("txe-crc ");
111#endif
112     *tx_ch = escape((txstate->crc >> ((txstate->field_c - 1) * 8)) & 0xff,
113                      txstate);
114
115      if (txstate->field_c == 0) {
116#ifdef DO_TRACE
117        __rt_trace("txe crc = 0x%x\n", txstate->crc);
118#endif
119        /* move on to the next state */
120        txstate->tx_state = (txstate->tx_state & ~N_MASK) | N_ETX;
121      }
122      return TS_IN_PKT;
123    }
124  }
125  case N_ETX:
126#ifdef DO_TRACE
127    __rt_trace("txe-etx\n");
128#endif
129    txstate->tx_state = (txstate->tx_state & ~N_MASK) | N_IDLE;
130    *tx_ch = txstate->config->etx;
131    return TS_DONE_PKT;
132  default:
133#ifdef DEBUG
134    __rt_info("tx default\n");
135#endif
136    txstate->tx_state = (txstate->tx_state & ~N_MASK) | N_IDLE;
137    return TS_IDLE;
138  }
139  /* stop a silly -Wall warning */
140  return (te_status)-1;
141}
142
143/*
144 * crc generation occurs in the escape function because it is the only
145 * place where we know that we're putting a real char into the buffer
146 * rather than an escaped one.
147 * We must be careful here not to update the crc when we're sending it
148 */
149static unsigned char escape(unsigned char ch_in, struct te_state *txstate) {
150   if (((txstate->tx_state) & E_MASK) == E_ESC) {
151      /* char has been escaped so send the real char */
152#ifdef DO_TRACE
153     __rt_trace("txe-echar ");
154#endif
155      txstate->tx_state = (txstate->tx_state & ~E_MASK) | E_PLAIN;
156      txstate->field_c--;
157      if ((txstate->tx_state & F_MASK) != F_CRC)
158        txstate->crc = crc32( &ch_in, 1, txstate->crc);
159      return ch_in | serial_ESCAPE;
160   }
161   if ((ch_in < 32) && ((txstate->config->esc_set & (1 << ch_in)) != 0)) {
162     /* char needs escaping */
163#ifdef DO_TRACE
164     __rt_trace("txe-esc ");
165#endif
166     txstate->tx_state = (txstate->tx_state & ~E_MASK) | E_ESC;
167     return txstate->config->esc;
168   }
169   /* must be a char that can be sent plain */
170   txstate->field_c--;
171   if ((txstate->tx_state & F_MASK) != F_CRC)
172     txstate->crc = crc32(&ch_in, 1, txstate->crc);
173   return ch_in;
174}
175
176/* EOF tx.c */
177