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 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 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 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 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 */ 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