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: 2004/12/27 14:00:54 $
13 *
14 *
15 * Project: ANGEL
16 *
17 * Title: Character reception engine
18 */
19
20 #include <stdarg.h> /* ANSI varargs support */
21 #include "angel.h" /* Angel system definitions */
22 #include "angel_endian.h" /* Endian independant memory access macros */
23 #include "crc.h" /* crc generation definitions and headers */
24 #include "rxtx.h"
25 #include "channels.h"
26 #include "buffers.h"
27 #ifdef TARGET
28 # include "devdriv.h"
29 #endif
30 #include "logging.h"
31
32 static re_status unexp_stx(struct re_state *rxstate);
33 static re_status unexp_etx(struct re_state *rxstate);
34
35 /* bitfield for the rx_engine state */
36 typedef enum rx_state_flag{
37 RST_STX,
38 RST_TYP,
39 RST_LEN,
40 RST_DAT,
41 RST_CRC,
42 RST_ETX,
43 RST_ESC = (0x1 << 0x3)
44 } rx_state_flag;
45
Angel_RxEngineInit(const struct re_config * rxconfig,struct re_state * rxstate)46 void Angel_RxEngineInit(const struct re_config *rxconfig,
47 struct re_state *rxstate)
48 {
49 rxstate->rx_state = RST_STX;
50 rxstate->field_c = 0;
51 rxstate->index = 0;
52 rxstate->crc = 0;
53 rxstate->error = RE_OKAY;
54 rxstate->config = rxconfig;
55 }
56
Angel_RxEngine(unsigned char new_ch,struct data_packet * packet,struct re_state * rxstate)57 re_status Angel_RxEngine(unsigned char new_ch, struct data_packet *packet,
58 struct re_state *rxstate)
59 {
60 /*
61 * TODO: add the flow control bits in
62 * Note: We test for the data field in a seperate case so we can
63 * completely avoid entering the switch for most chars
64 */
65
66 /* see if we're expecting a escaped char */
67 if ((rxstate->rx_state & RST_ESC) == RST_ESC)
68 {
69 /* unescape the char and unset the flag*/
70 new_ch &= ~serial_ESCAPE;
71 #ifdef DO_TRACE
72 __rt_trace("rxe-echar-%2x ", new_ch);
73 #endif
74 rxstate->rx_state &= ~RST_ESC;
75 }
76 else if ( (1 << new_ch) & rxstate->config->esc_set )
77 {
78 /* see if the incoming char is a special one */
79 if (new_ch == rxstate->config->esc)
80 {
81 #ifdef DO_TRACE
82 __rt_trace("rxe-esc ");
83 #endif
84 rxstate->rx_state |= RST_ESC;
85 return RS_IN_PKT;
86 }
87 else
88 {
89 /*
90 * must be a normal packet so do some unexpected etx/stx checking
91 * we haven't been told to escape or received an escape so unless
92 * we are expecting an stx or etx then we can take the unexpected
93 * stx/etx trap
94 */
95 if ((new_ch == (rxstate->config->stx)) && (rxstate->rx_state != RST_STX))
96 return unexp_stx(rxstate);
97 if ((new_ch == (rxstate->config->etx)) && (rxstate->rx_state != RST_ETX))
98 return unexp_etx(rxstate);
99 }
100 }
101
102 if (rxstate->rx_state == RST_DAT)
103 {
104 /*
105 * do this to speed up the common case, no real penalty for
106 * other cases
107 */
108 #ifdef DO_TRACE
109 __rt_trace("rxe-dat ");
110 #endif
111
112 rxstate->crc = crc32(&new_ch, 1, rxstate->crc);
113 (packet->data)[rxstate->index++] = (unsigned int)new_ch & 0xff;
114
115 if (rxstate->index == packet->len)
116 rxstate->rx_state = RST_CRC;
117
118 return RS_IN_PKT;
119 }
120
121 /*
122 * Now that the common case is out of the way we can test for everything
123 * else without worrying quite so much about the speed, changing the
124 * order to len,crc,stx,etx,typ might gain a tiny bit of speed but lets
125 * leave that for the moment
126 */
127 switch (rxstate->rx_state)
128 {
129 case RST_STX:
130 if (new_ch == rxstate->config->stx)
131 {
132 rxstate->rx_state = RST_TYP;
133 rxstate->error = RE_OKAY;
134 rxstate->crc = startCRC32;
135 rxstate->index = 0;
136 return RS_IN_PKT;
137 }
138 else
139 {
140 rxstate->error = RE_OKAY;
141 return RS_WAIT_PKT;
142 }
143
144 case RST_TYP:
145 packet->type = (DevChanID)new_ch;
146 rxstate->rx_state = RST_LEN;
147 rxstate->error = RE_OKAY;
148 rxstate->field_c = 0; /* set up here for the length that follows */
149 #ifdef DO_TRACE
150 __rt_trace("rxe-type-%2x ", packet->type);
151 #endif
152 rxstate->crc = crc32(&new_ch, 1, rxstate->crc);
153
154 return RS_IN_PKT;
155
156 case RST_LEN:
157 rxstate->crc = crc32(&new_ch, 1, rxstate->crc);
158
159 if (rxstate->field_c++ == 0)
160 {
161 /* first length byte */
162 packet->len = ((unsigned int)new_ch) << 8;
163 return RS_IN_PKT;
164 }
165 else
166 {
167 /* got the whole legth */
168 packet->len |= new_ch;
169 #ifdef DO_TRACE
170 __rt_trace("rxe-len-%4x\n", packet->len);
171 #endif
172
173 /* check that the length is ok */
174 if (packet->len == 0)
175 {
176 /* empty pkt */
177 rxstate->field_c = 0;
178 rxstate->rx_state = RST_CRC;
179 return RS_IN_PKT;
180 }
181 else
182 {
183 if (packet->data == NULL)
184 {
185 /* need to alloc the data buffer */
186 if (!rxstate->config->ba_callback(
187 packet, rxstate->config->ba_data)) {
188 rxstate->rx_state = RST_STX;
189 rxstate->error = RE_INTERNAL;
190 return RS_BAD_PKT;
191 }
192 }
193
194 if (packet->len > packet->buf_len)
195 {
196 /* pkt bigger than buffer */
197 rxstate->field_c = 0;
198 rxstate->rx_state = RST_STX;
199 rxstate->error = RE_LEN;
200 return RS_BAD_PKT;
201 }
202 else
203 {
204 /* packet ok */
205 rxstate->field_c = 0;
206 rxstate->rx_state = RST_DAT;
207 return RS_IN_PKT;
208 }
209 }
210 }
211
212 case RST_DAT:
213 /* dummy case (dealt with earlier) */
214 #ifdef ASSERTIONS_ENABLED
215 __rt_warning("ERROR: hit RST_dat in switch\n");
216 #endif
217 rxstate->rx_state = RST_STX;
218 rxstate->error = RE_INTERNAL;
219 return RS_BAD_PKT;
220
221 case RST_CRC:
222 if (rxstate->field_c == 0)
223 packet->crc = 0;
224
225 packet->crc |= (new_ch & 0xFF) << ((3 - rxstate->field_c) * 8);
226 rxstate->field_c++;
227
228 if (rxstate->field_c == 4)
229 {
230 /* last crc field */
231 rxstate->field_c = 0;
232 rxstate->rx_state = RST_ETX;
233 #ifdef DO_TRACE
234 __rt_trace("rxe-rcrc-%8x ", packet->crc);
235 #endif
236 }
237
238 return RS_IN_PKT;
239
240 case RST_ETX:
241 if (new_ch == rxstate->config->etx)
242 {
243 #if defined(DEBUG) && !defined(NO_PKT_DATA)
244 {
245 int c;
246 # ifdef DO_TRACE
247 __rt_trace("\n");
248 # endif
249 __rt_info("RXE Data =");
250 for (c=0; c < packet->len; c++)
251 __rt_info("%02x", packet->data[c]);
252 __rt_info("\n");
253 }
254 #endif
255
256 /* check crc */
257 if (rxstate->crc == packet->crc)
258 {
259 /* crc ok */
260 rxstate->rx_state = RST_STX;
261 rxstate->field_c = 0;
262 return RS_GOOD_PKT;
263 }
264 else
265 {
266 #ifdef ASSERTIONS_ENABLED
267 __rt_warning("Bad crc, rx calculates it should be 0x%x\n", rxstate->crc);
268 #endif
269 rxstate->rx_state = RST_STX;
270 rxstate->error = RE_CRC;
271 return RS_BAD_PKT;
272 }
273 }
274 else if (new_ch == rxstate->config->stx)
275 return unexp_stx(rxstate);
276 else
277 {
278 rxstate->rx_state = RST_STX;
279 rxstate->error = RE_NETX;
280 return RS_BAD_PKT;
281 }
282
283 default:
284 #ifdef ASSERTIONS_ENABLED
285 __rt_warning("ERROR fell through rxengine\n");
286 #endif
287 rxstate->rx_state = RST_STX;
288 rxstate->error = RE_INTERNAL;
289 return RS_BAD_PKT;
290 }
291 }
292
unexp_stx(struct re_state * rxstate)293 static re_status unexp_stx(struct re_state *rxstate)
294 {
295 #ifdef ASSERTIONS_ENABLED
296 __rt_warning("Unexpected stx\n");
297 #endif
298 rxstate->crc = startCRC32;
299 rxstate->index = 0;
300 rxstate->rx_state = RST_TYP;
301 rxstate->error = RE_U_STX;
302 rxstate->field_c = 0;
303 return RS_BAD_PKT;
304 }
305
unexp_etx(struct re_state * rxstate)306 static re_status unexp_etx(struct re_state *rxstate)
307 {
308 #ifdef ASSERTIONS_ENABLED
309 __rt_warning("Unexpected etx, rxstate: index= 0x%2x, field_c=0x%2x, state=0x%2x\n", rxstate->index, rxstate->field_c, rxstate->rx_state);
310 #endif
311 rxstate->crc = 0;
312 rxstate->index = 0;
313 rxstate->rx_state = RST_STX;
314 rxstate->error = RE_U_ETX;
315 rxstate->field_c = 0;
316 return RS_BAD_PKT;
317 }
318
319 /*
320 * This can be used as the buffer allocation callback for the rx engine,
321 * and makes use of angel_DD_GetBuffer() [in devdrv.h].
322 *
323 * Saves duplicating this callback function in every device driver that
324 * uses the rx engine.
325 *
326 * Note that this REQUIRES that the device id is installed as ba_data
327 * in the rx engine config structure for the driver.
328 */
angel_DD_RxEng_BufferAlloc(struct data_packet * packet,void * cb_data)329 bool angel_DD_RxEng_BufferAlloc( struct data_packet *packet, void *cb_data )
330 {
331 #ifdef TARGET
332 DeviceID devid = (DeviceID)cb_data;
333 #else
334 IGNORE(cb_data);
335 #endif
336
337 if ( packet->type < DC_NUM_CHANNELS )
338 {
339 /* request a buffer down from the channels layer */
340 #ifdef TARGET
341 packet->data = angel_DD_GetBuffer( devid, packet->type,
342 packet->len );
343 #else
344 packet->data = malloc(packet->len);
345 #endif
346 if ( packet->data == NULL )
347 return FALSE;
348 else
349 {
350 packet->buf_len = packet->len;
351 return TRUE;
352 }
353 }
354 else
355 {
356 /* bad type field */
357 return FALSE;
358 }
359 }
360
361 /* EOF rx.c */
362