1 | /* |
2 | * Copyright (c) 2007-2015 Freescale Semiconductor, Inc. |
3 | * Copyright 2018-2021 NXP |
4 | * |
5 | * License: NXP LA_OPT_NXP_Software_License |
6 | * |
7 | * NXP Confidential. This software is owned or controlled by NXP and may |
8 | * only be used strictly in accordance with the applicable license terms. |
9 | * By expressly accepting such terms or by downloading, installing, |
10 | * activating and/or otherwise using the software, you are agreeing that |
11 | * you have read, and that you agree to comply with and are bound by, |
12 | * such license terms. If you do not agree to be bound by the applicable |
13 | * license terms, then you may not retain, install, activate or otherwise |
14 | * use the software. This code may only be used in a microprocessor, |
15 | * microcontroller, sensor or digital signal processor ("NXP Product") |
16 | * supplied directly or indirectly from NXP. See the full NXP Software |
17 | * License Agreement in license/LA_OPT_NXP_Software_License.pdf |
18 | * |
19 | * FreeMASTER Communication Driver - Serial communication |
20 | */ |
21 | |
22 | #include "freemaster.h" |
23 | #include "freemaster_private.h" |
24 | |
25 | /* Numeric identifier to help pre-processor to identify whether our transport is used or not. */ |
26 | #define FMSTR_SERIAL_ID 1 |
27 | |
28 | #if (FMSTR_MK_IDSTR(FMSTR_TRANSPORT) == FMSTR_SERIAL_ID) && FMSTR_DISABLE == 0 |
29 | |
30 | #if FMSTR_SESSION_COUNT != 1 |
31 | /* Serial transport only supports a single session */ |
32 | #warning Please set FMSTR_SESSION_COUNT to 1. |
33 | #endif |
34 | |
35 | #include "freemaster_protocol.h" |
36 | #include "freemaster_serial.h" |
37 | #include "freemaster_utils.h" |
38 | |
39 | /*********************************** |
40 | * local variables |
41 | ***********************************/ |
42 | |
43 | /* FreeMASTER communication buffer (in/out) plus the STS, LEN(LEB) and CRC bytes */ |
44 | static FMSTR_BCHR fmstr_pCommBuffer[FMSTR_COMM_BUFFER_SIZE + 1 + 4 + 2]; |
45 | |
46 | /* FreeMASTER runtime flags */ |
47 | /*lint -e{960} using union */ |
48 | typedef volatile union |
49 | { |
50 | FMSTR_FLAGS all; |
51 | |
52 | struct |
53 | { |
54 | unsigned bTxActive : 1; /* response is being transmitted */ |
55 | unsigned bTxWaitTC : 1; /* response sent, wait for transmission complete */ |
56 | unsigned bTxLastCharSOB : 1; /* last transmitted char was equal to SOB */ |
57 | unsigned bRxLastCharSOB : 1; /* last received character was SOB */ |
58 | unsigned bRxMsgLengthNext : 1; /* expect the length byte next time */ |
59 | } flg; |
60 | |
61 | } FMSTR_SERIAL_FLAGS; |
62 | |
63 | static FMSTR_SERIAL_FLAGS _fmstr_wFlags; |
64 | |
65 | /* receive and transmit buffers and counters */ |
66 | static FMSTR_SIZE8 fmstr_nTxTodo; /* transmission to-do counter (0 when tx is idle) */ |
67 | static FMSTR_SIZE8 fmstr_nRxTodo; /* reception to-do counter (0 when rx is idle) */ |
68 | static FMSTR_BPTR fmstr_pTxBuff; /* pointer to next byte to transmit */ |
69 | static FMSTR_BPTR fmstr_pRxBuff; /* pointer to next free place in RX buffer */ |
70 | static FMSTR_BCHR fmstr_nRxCrc8; /* checksum of data being received for short messages */ |
71 | |
72 | /* Maximal length of message to use 8 bit CRC8. */ |
73 | #define FMSTR_SHORT_MSG_LEN 128 |
74 | |
75 | #if FMSTR_DEBUG_TX > 0 |
76 | /* The poll counter is used to roughly measure duration of test frame transmission. |
77 | * The test frame will be sent once per N.times this measured period. */ |
78 | static FMSTR_S32 fmstr_nDebugTxPollCount; |
79 | /* the N factor for multiplying the transmission time to get the wait time */ |
80 | #define FMSTR_DEBUG_TX_POLLCNT_XFACTOR 32 |
81 | #define FMSTR_DEBUG_TX_POLLCNT_MIN (-1 * 0x4000000L) |
82 | #endif |
83 | |
84 | /*********************************** |
85 | * local function prototypes |
86 | ***********************************/ |
87 | |
88 | static void _FMSTR_Listen(void); |
89 | static void _FMSTR_SendError(FMSTR_BCHR nErrCode); |
90 | static FMSTR_BOOL _FMSTR_Tx(FMSTR_BCHR *getTxChar); |
91 | static FMSTR_BOOL _FMSTR_Rx(FMSTR_BCHR rxChar); |
92 | |
93 | /*********************************** |
94 | * local variables |
95 | ***********************************/ |
96 | |
97 | /* SHORT_INTR receive queue (circular buffer) */ |
98 | #if FMSTR_SHORT_INTR > 0 |
99 | static FMSTR_BCHR fmstr_rxBuff[FMSTR_COMM_RQUEUE_SIZE]; |
100 | static FMSTR_RING_BUFFER fmstr_rxQueue; |
101 | #endif |
102 | |
103 | /*********************************** |
104 | * local function prototypes |
105 | ***********************************/ |
106 | |
107 | #if FMSTR_SHORT_INTR > 0 |
108 | static void _FMSTR_RxDequeue(void); |
109 | #endif |
110 | |
111 | /* Interface function - Initialization of serial transport */ |
112 | static FMSTR_BOOL _FMSTR_SerialInit(void); |
113 | /* Interface function - Poll function of serial transport */ |
114 | static void _FMSTR_SerialPoll(void); |
115 | /* Interface function - Send Response function of serial transport */ |
116 | static void _FMSTR_SerialSendResponse(FMSTR_BPTR pResponse, |
117 | FMSTR_SIZE nLength, |
118 | FMSTR_U8 statusCode, |
119 | void *identification); |
120 | |
121 | /*********************************** |
122 | * global variables |
123 | ***********************************/ |
124 | |
125 | /* Interface of this serial driver */ |
126 | const FMSTR_TRANSPORT_INTF FMSTR_SERIAL = { |
127 | FMSTR_C99_INIT(Init) _FMSTR_SerialInit, |
128 | FMSTR_C99_INIT(Poll) _FMSTR_SerialPoll, |
129 | FMSTR_C99_INIT(SendResponse) _FMSTR_SerialSendResponse, |
130 | }; |
131 | |
132 | /*lint -esym(752,_FMSTR_RxQueue) this may be unreferenced in some cases */ |
133 | /*lint -esym(752,_FMSTR_RxDequeue) this may be unreferenced in some cases */ |
134 | |
135 | /******************************************************************************* |
136 | * |
137 | * @brief Routine to quick-receive a character (put to a queue only) |
138 | * |
139 | * This function puts received character into a queue and exits as soon as possible. |
140 | * |
141 | *******************************************************************************/ |
142 | |
143 | #if FMSTR_SHORT_INTR > 0 |
144 | |
145 | /******************************************************************************* |
146 | * |
147 | * @brief Late processing of queued characters |
148 | * |
149 | * This function takes the queued characters and calls FMSTR_Rx() for each of them, |
150 | * just like as the characters would be received from SCI one by one. |
151 | * |
152 | *******************************************************************************/ |
153 | |
154 | static void _FMSTR_RxDequeue(void) |
155 | { |
156 | FMSTR_BCHR nChar = 0U; |
157 | |
158 | /* get all queued characters */ |
159 | while (_FMSTR_RingBuffHasData(&fmstr_rxQueue) != FMSTR_FALSE) |
160 | { |
161 | nChar = _FMSTR_RingBuffGet(&fmstr_rxQueue); |
162 | |
163 | /* emulate the SCI receive event */ |
164 | if (_fmstr_wFlags.flg.bTxActive == 0U) |
165 | { |
166 | (void)_FMSTR_Rx(nChar); |
167 | } |
168 | } |
169 | } |
170 | |
171 | #endif /* FMSTR_SHORT_INTR */ |
172 | |
173 | /****************************************************************************** |
174 | * |
175 | * @brief Handle SCI communication (both TX and RX) |
176 | * |
177 | * This function checks the SCI flags and calls the Rx and/or Tx functions |
178 | * |
179 | * @note This function can be called either from SCI ISR or from the polling routine |
180 | * |
181 | ******************************************************************************/ |
182 | |
183 | void FMSTR_ProcessSerial(void) |
184 | { |
185 | FMSTR_BOOL endOfPacket = FMSTR_FALSE; |
186 | |
187 | /* transmitter active and empty? */ |
188 | if (_fmstr_wFlags.flg.bTxActive != 0U) |
189 | { |
190 | /* able to accept another character? */ |
191 | while (FMSTR_SERIAL_DRV.IsTransmitRegEmpty() != FMSTR_FALSE) |
192 | { |
193 | FMSTR_BCHR ch; |
194 | /* just put the byte into the SCI transmit buffer */ |
195 | endOfPacket = _FMSTR_Tx(&ch); |
196 | if (endOfPacket == FMSTR_FALSE) |
197 | { |
198 | #if FMSTR_DEBUG_LEVEL >= 3 |
199 | FMSTR_DEBUG_PRINTF("FMSTR Tx: %02x\n", (FMSTR_U8)ch); |
200 | #endif |
201 | FMSTR_SERIAL_DRV.PutChar((FMSTR_U8)ch); |
202 | } |
203 | else |
204 | { |
205 | break; |
206 | } |
207 | } |
208 | |
209 | /* Flush data */ |
210 | if (endOfPacket != FMSTR_FALSE) |
211 | { |
212 | #if FMSTR_DEBUG_LEVEL >= 3 |
213 | FMSTR_DEBUG_PRINTF("FMSTR Tx Flush\n"); |
214 | #endif |
215 | FMSTR_SERIAL_DRV.Flush(); |
216 | _fmstr_wFlags.flg.bTxWaitTC = 1U; |
217 | |
218 | #if FMSTR_SHORT_INTR || FMSTR_LONG_INTR |
219 | /* Enable UART Transfer Complete interrupt in case of interrupt mode of communication. */ |
220 | if (FMSTR_SERIAL_DRV.IsTransmitterActive() != FMSTR_FALSE) |
221 | { |
222 | /* Enable Trasmit complete interrupt */ |
223 | FMSTR_SERIAL_DRV.EnableTransmitCompleteInterrupt(FMSTR_TRUE); |
224 | } |
225 | #endif |
226 | } |
227 | |
228 | /* when SCI TX buffering is enabled, we must first wait until all |
229 | characters are physically transmitted (before disabling transmitter) */ |
230 | if (_fmstr_wFlags.flg.bTxWaitTC != 0U && FMSTR_SERIAL_DRV.IsTransmitterActive() == FMSTR_FALSE) |
231 | { |
232 | /* after TC, we can switch to listen mode safely */ |
233 | _FMSTR_Listen(); |
234 | } |
235 | } |
236 | /* transmitter not active, able to receive */ |
237 | else |
238 | { |
239 | /* data byte received? */ |
240 | while (FMSTR_SERIAL_DRV.IsReceiveRegFull() != FMSTR_FALSE) |
241 | { |
242 | FMSTR_BCHR rxChar = 0U; |
243 | rxChar = FMSTR_SERIAL_DRV.GetChar(); |
244 | |
245 | #if FMSTR_DEBUG_LEVEL >= 3 |
246 | FMSTR_DEBUG_PRINTF("FMSTR Rx: %02x\n", (FMSTR_U8)rxChar); |
247 | #endif |
248 | |
249 | #if FMSTR_SHORT_INTR > 0 |
250 | _FMSTR_RingBuffPut(&fmstr_rxQueue, rxChar); // TODO: if queue is lower than received data |
251 | #else |
252 | (void)_FMSTR_Rx(rxChar); |
253 | #endif |
254 | } |
255 | #if FMSTR_DEBUG_TX > 0 |
256 | /* time to send another test frame? */ |
257 | if (fmstr_doDebugTx != 0U && fmstr_nDebugTxPollCount == 0) |
258 | { |
259 | /* yes, start sending it now */ |
260 | if (FMSTR_SendTestFrame(&fmstr_pCommBuffer[2], NULL) != FMSTR_FALSE) |
261 | { |
262 | /* measure how long it takes to transmit it */ |
263 | fmstr_nDebugTxPollCount = -1; |
264 | } |
265 | } |
266 | #endif |
267 | } |
268 | } |
269 | |
270 | /****************************************************************************** |
271 | * |
272 | * @brief Start listening on a serial line |
273 | * |
274 | * Reset the receiver machine and start listening on a serial line |
275 | * |
276 | ******************************************************************************/ |
277 | |
278 | static void _FMSTR_Listen(void) |
279 | { |
280 | fmstr_nRxTodo = 0U; |
281 | |
282 | /* disable transmitter state machine */ |
283 | _fmstr_wFlags.flg.bTxActive = 0U; |
284 | _fmstr_wFlags.flg.bTxWaitTC = 0U; |
285 | |
286 | /* disable transmitter, enable receiver (enables single-wire connection) */ |
287 | FMSTR_SERIAL_DRV.EnableTransmit(FMSTR_FALSE); |
288 | FMSTR_SERIAL_DRV.EnableReceive(FMSTR_TRUE); |
289 | |
290 | /* disable transmit, enable receive interrupts */ |
291 | #if FMSTR_SHORT_INTR || FMSTR_LONG_INTR |
292 | FMSTR_SERIAL_DRV.EnableTransmitInterrupt(FMSTR_FALSE); /* disable Serial transmit interrupt */ |
293 | FMSTR_SERIAL_DRV.EnableTransmitCompleteInterrupt(FMSTR_FALSE); /* disable Serial transmit complete interrupt */ |
294 | FMSTR_SERIAL_DRV.EnableReceiveInterrupt(FMSTR_TRUE); /* enable Serial receive interrupt */ |
295 | #endif /* FMSTR_SHORT_INTR || FMSTR_LONG_INTR */ |
296 | |
297 | #if FMSTR_DEBUG_TX > 0 |
298 | /* we have just finished the transmission of the test frame, now wait the 32x times the sendtime |
299 | to receive any command from PC (count<0 is measurement, count>0 is waiting, count=0 is send trigger) */ |
300 | if (fmstr_nDebugTxPollCount < 0) |
301 | { |
302 | fmstr_nDebugTxPollCount *= -(FMSTR_DEBUG_TX_POLLCNT_XFACTOR); |
303 | } |
304 | #endif |
305 | |
306 | #if FMSTR_DEBUG_LEVEL >= 2 |
307 | FMSTR_DEBUG_PRINTF("FMSTR Listening...\n"); |
308 | #endif |
309 | } |
310 | |
311 | /****************************************************************************** |
312 | * |
313 | * @brief Send response of given error code (no data) |
314 | * |
315 | * @param nErrCode - error code to be sent |
316 | * |
317 | ******************************************************************************/ |
318 | |
319 | static void _FMSTR_SendError(FMSTR_BCHR nErrCode) |
320 | { |
321 | #if FMSTR_DEBUG_LEVEL >= 1 |
322 | FMSTR_DEBUG_PRINTF("FMSTR SendError code: 0x%x\n", (FMSTR_U8)nErrCode); |
323 | #endif |
324 | |
325 | /* fill & send single-byte response */ |
326 | _FMSTR_SerialSendResponse(&fmstr_pCommBuffer[2], 0U, nErrCode, NULL); |
327 | } |
328 | |
329 | /****************************************************************************** |
330 | * |
331 | * @brief Finalize transmit buffer before transmitting |
332 | * |
333 | * @param nLength - response length (1 for status + data length) |
334 | * |
335 | * |
336 | * This Function takes the data already prepared in the transmit buffer |
337 | * (inlcuding the status byte). It computes the check sum and kicks on tx. |
338 | * |
339 | ******************************************************************************/ |
340 | |
341 | static void _FMSTR_SerialSendResponse(FMSTR_BPTR pResponse, |
342 | FMSTR_SIZE nLength, |
343 | FMSTR_U8 statusCode, |
344 | void *identification) |
345 | { |
346 | FMSTR_SIZE8 i; |
347 | FMSTR_U8 c; |
348 | |
349 | FMSTR_UNUSED(identification); |
350 | |
351 | if (nLength > 254U || pResponse != &fmstr_pCommBuffer[2]) |
352 | { |
353 | /* The Serial driver doesn't support bigger responses than 254 bytes, change the response to status error */ |
354 | statusCode = FMSTR_STC_RSPBUFFOVF; |
355 | nLength = 0U; |
356 | } |
357 | |
358 | /* remember the buffer to be sent */ |
359 | fmstr_pTxBuff = fmstr_pCommBuffer; |
360 | /* Send the message with status, length and checksum. SOB is not counted as it is sent right here. */ |
361 | fmstr_nTxTodo = (FMSTR_SIZE8)(nLength + 3U); |
362 | |
363 | if ((statusCode & FMSTR_STSF_VARLEN) != 0U) |
364 | { |
365 | fmstr_pCommBuffer[0] = (FMSTR_BCHR)statusCode; |
366 | fmstr_pCommBuffer[1] = (FMSTR_BCHR)nLength; |
367 | } |
368 | else |
369 | { |
370 | fmstr_pCommBuffer[1] = (FMSTR_BCHR)statusCode; |
371 | fmstr_pTxBuff++; |
372 | fmstr_nTxTodo--; |
373 | } |
374 | |
375 | /* Initialize CRC algorithms */ |
376 | FMSTR_Crc8Init(&fmstr_nRxCrc8); |
377 | |
378 | /* status byte and data are already there, compute checksum only */ |
379 | pResponse = fmstr_pTxBuff; |
380 | for (i = 1U; i < fmstr_nTxTodo; i++) |
381 | { |
382 | pResponse = FMSTR_ValueFromBuffer8(&c, pResponse); |
383 | /* add character to checksum */ |
384 | FMSTR_Crc8AddByte(&fmstr_nRxCrc8, c); |
385 | } |
386 | |
387 | /* store checksum after the message */ |
388 | pResponse = FMSTR_ValueToBuffer8(pResponse, fmstr_nRxCrc8); |
389 | |
390 | /* now transmitting the response */ |
391 | _fmstr_wFlags.flg.bTxActive = 1U; |
392 | _fmstr_wFlags.flg.bTxWaitTC = 0U; |
393 | |
394 | /* do not replicate the initial SOB */ |
395 | _fmstr_wFlags.flg.bTxLastCharSOB = 0U; |
396 | |
397 | /* disable receiver, enable transmitter (single-wire communication) */ |
398 | FMSTR_SERIAL_DRV.EnableReceive(FMSTR_FALSE); |
399 | FMSTR_SERIAL_DRV.EnableTransmit(FMSTR_TRUE); |
400 | |
401 | #if FMSTR_DEBUG_LEVEL >= 3 |
402 | FMSTR_DEBUG_PRINTF("FMSTR Tx: %02x\n", (FMSTR_U8)FMSTR_SOB); |
403 | #endif |
404 | |
405 | /* kick on the SCI transmission (also clears TX Empty flag on some platforms) */ |
406 | (void)FMSTR_SERIAL_DRV.IsTransmitRegEmpty(); |
407 | FMSTR_SERIAL_DRV.PutChar(FMSTR_SOB); |
408 | |
409 | /* TX interrupt enable, RX interrupt disable */ |
410 | #if FMSTR_LONG_INTR > 0 || FMSTR_SHORT_INTR > 0 |
411 | FMSTR_SERIAL_DRV.EnableReceiveInterrupt(FMSTR_FALSE); /* disable SCI receive interrupt */ |
412 | FMSTR_SERIAL_DRV.EnableTransmitInterrupt(FMSTR_TRUE); /* enable SCI transmit interrupt */ |
413 | #endif /* FMSTR_LONG_INTR || FMSTR_SHORT_INTR */ |
414 | } |
415 | |
416 | /****************************************************************************** |
417 | * |
418 | * @brief Output buffer transmission |
419 | * |
420 | * @param getTxChar Return character to be transmitted |
421 | * |
422 | * @return Non-zero when transmission is complete |
423 | * |
424 | * get ready buffer(prepare data to send) |
425 | * |
426 | ******************************************************************************/ |
427 | |
428 | static FMSTR_BOOL _FMSTR_Tx(FMSTR_BCHR *getTxChar) |
429 | { |
430 | if (fmstr_nTxTodo > 0U) |
431 | { |
432 | /* fetch & send character ready to transmit */ |
433 | /*lint -e{534} ignoring return value */ |
434 | (void)FMSTR_ValueFromBuffer8(getTxChar, fmstr_pTxBuff); |
435 | |
436 | /* first, handle the replicated SOB characters */ |
437 | if (*getTxChar == FMSTR_SOB) |
438 | { |
439 | _fmstr_wFlags.flg.bTxLastCharSOB = _fmstr_wFlags.flg.bTxLastCharSOB != 0U ? 0U : 1U; |
440 | |
441 | if (_fmstr_wFlags.flg.bTxLastCharSOB != 0U) |
442 | { |
443 | /* yes, repeat the SOB next time */ |
444 | return FMSTR_FALSE; |
445 | } |
446 | } |
447 | |
448 | /* no, advance tx buffer pointer */ |
449 | fmstr_nTxTodo--; |
450 | fmstr_pTxBuff = FMSTR_SkipInBuffer(fmstr_pTxBuff, 1U); |
451 | return FMSTR_FALSE; |
452 | } |
453 | |
454 | return FMSTR_TRUE; |
455 | } |
456 | |
457 | /****************************************************************************** |
458 | * |
459 | * @brief Handle received character |
460 | * |
461 | * @param rxChar The character to be processed |
462 | * |
463 | * Handle the character received and -if the message is complete- call the |
464 | * protocol decode routine. |
465 | * |
466 | ******************************************************************************/ |
467 | |
468 | static FMSTR_BOOL _FMSTR_Rx(FMSTR_BCHR rxChar) |
469 | { |
470 | FMSTR_SERIAL_FLAGS *pflg = &_fmstr_wFlags; |
471 | /* first, handle the replicated SOB characters */ |
472 | if (rxChar == FMSTR_SOB) |
473 | { |
474 | pflg->flg.bRxLastCharSOB = pflg->flg.bRxLastCharSOB != 0U ? 0U : 1U; |
475 | if (pflg->flg.bRxLastCharSOB != 0U) |
476 | { |
477 | /* this is either the first byte of replicated SOB or a */ |
478 | /* real Start-of-Block mark - we will decide next time in FMSTR_Rx */ |
479 | return FMSTR_FALSE; |
480 | } |
481 | } |
482 | |
483 | /* we have got a common character preceded by the SOB - */ |
484 | /* this is the command code! */ |
485 | if (pflg->flg.bRxLastCharSOB != 0U) |
486 | { |
487 | #if FMSTR_DEBUG_LEVEL >= 3 |
488 | FMSTR_DEBUG_PRINTF("FMSTR Rx Frame start. Cmd: 0x%x\n", rxChar); |
489 | #endif |
490 | |
491 | /* reset receiving process */ |
492 | fmstr_pRxBuff = fmstr_pCommBuffer; |
493 | |
494 | FMSTR_Crc8Init(&fmstr_nRxCrc8); |
495 | FMSTR_Crc8AddByte(&fmstr_nRxCrc8, rxChar); |
496 | |
497 | *(fmstr_pRxBuff++) = rxChar; |
498 | fmstr_nRxTodo = 0; |
499 | |
500 | /* if the standard command was received, the message length will come in next byte */ |
501 | pflg->flg.bRxMsgLengthNext = 1U; |
502 | |
503 | /* command code stored & processed */ |
504 | pflg->flg.bRxLastCharSOB = 0U; |
505 | return FMSTR_FALSE; |
506 | } |
507 | |
508 | /* we are waiting for the length byte */ |
509 | if (pflg->flg.bRxMsgLengthNext != 0U) |
510 | { |
511 | #if FMSTR_DEBUG_LEVEL >= 3 |
512 | FMSTR_DEBUG_PRINTF("FMSTR Rx Frame length: 0x%x\n", rxChar); |
513 | #endif |
514 | /* total data length and the checksum */ |
515 | fmstr_nRxTodo = (FMSTR_SIZE8)(rxChar + 1U); |
516 | FMSTR_Crc8AddByte(&fmstr_nRxCrc8, rxChar); |
517 | |
518 | *(fmstr_pRxBuff++) = rxChar; |
519 | |
520 | /* now read the data bytes */ |
521 | pflg->flg.bRxMsgLengthNext = 0U; |
522 | |
523 | return FMSTR_FALSE; |
524 | } |
525 | |
526 | /* waiting for a data byte? */ |
527 | if (fmstr_nRxTodo > 0U) |
528 | { |
529 | /* decrease number of expected bytes */ |
530 | fmstr_nRxTodo--; |
531 | /* was it the last byte of the message (checksum)? */ |
532 | if (fmstr_nRxTodo == 0U) |
533 | { |
534 | #if FMSTR_DEBUG_LEVEL >= 3 |
535 | FMSTR_DEBUG_PRINTF("FMSTR Rx Checksum: 0x%x, expected: 0x%x\n", rxChar, fmstr_nRxCrc8); |
536 | #endif |
537 | |
538 | /* receive buffer overflow? */ |
539 | if (fmstr_pRxBuff == NULL) |
540 | { |
541 | _FMSTR_SendError(FMSTR_STC_CMDTOOLONG); |
542 | } |
543 | /* checksum error? */ |
544 | else if (fmstr_nRxCrc8 != rxChar) |
545 | { |
546 | _FMSTR_SendError(FMSTR_STC_CMDCSERR); |
547 | } |
548 | /* message is okay */ |
549 | else |
550 | { |
551 | FMSTR_BPTR pMessageIO = fmstr_pCommBuffer; |
552 | FMSTR_BOOL processed; |
553 | FMSTR_U8 cmd, size; |
554 | |
555 | /* command code comes first in the message */ |
556 | /*lint -e{534} return value is not used */ |
557 | pMessageIO = FMSTR_ValueFromBuffer8(&cmd, pMessageIO); |
558 | /* length of command follows */ |
559 | /*lint -e{534} return value is not used */ |
560 | pMessageIO = FMSTR_ValueFromBuffer8(&size, pMessageIO); |
561 | |
562 | /* do decode now! use "serial" as a globally unique pointer value as our identifier */ |
563 | processed = FMSTR_ProtocolDecoder(pMessageIO, size, cmd, (void *)"serial"); |
564 | FMSTR_UNUSED(processed); |
565 | } |
566 | |
567 | return FMSTR_TRUE; |
568 | } |
569 | /* not the last character yet */ |
570 | else |
571 | { |
572 | /* add this byte to checksum */ |
573 | FMSTR_Crc8AddByte(&fmstr_nRxCrc8, rxChar); |
574 | |
575 | /* is there still a space in the buffer? */ |
576 | if (fmstr_pRxBuff != NULL) |
577 | { |
578 | /*lint -e{946} pointer arithmetic is okay here (same array) */ |
579 | if (fmstr_pRxBuff < (fmstr_pCommBuffer + FMSTR_COMM_BUFFER_SIZE)) |
580 | { |
581 | /* store byte */ |
582 | *fmstr_pRxBuff++ = rxChar; |
583 | } |
584 | /* buffer is full! */ |
585 | else |
586 | { |
587 | /* NULL rx pointer means buffer overflow - but we still need */ |
588 | /* to receive all message characters (for the single-wire mode) */ |
589 | /* so keep "receiving" - but throw away all characters from now */ |
590 | fmstr_pRxBuff = NULL; |
591 | } |
592 | } |
593 | } |
594 | } |
595 | |
596 | return FMSTR_FALSE; |
597 | } |
598 | |
599 | /****************************************************************************** |
600 | * |
601 | * @brief Serial communication initialization |
602 | * |
603 | ******************************************************************************/ |
604 | |
605 | static FMSTR_BOOL _FMSTR_SerialInit(void) |
606 | { |
607 | /* initialize all state variables */ |
608 | _fmstr_wFlags.all = 0U; |
609 | fmstr_nTxTodo = 0U; |
610 | |
611 | #if FMSTR_DEBUG_LEVEL >= 2 |
612 | FMSTR_DEBUG_PRINTF("FMSTR SerialInit\n"); |
613 | #endif |
614 | |
615 | /* Check the interface if it's valid */ |
616 | FMSTR_ASSERT_RETURN(FMSTR_SERIAL_DRV.Init != NULL, FMSTR_FALSE); |
617 | FMSTR_ASSERT_RETURN(FMSTR_SERIAL_DRV.EnableTransmit != NULL, FMSTR_FALSE); |
618 | FMSTR_ASSERT_RETURN(FMSTR_SERIAL_DRV.EnableReceive != NULL, FMSTR_FALSE); |
619 | FMSTR_ASSERT_RETURN(FMSTR_SERIAL_DRV.IsTransmitRegEmpty != NULL, FMSTR_FALSE); |
620 | FMSTR_ASSERT_RETURN(FMSTR_SERIAL_DRV.IsReceiveRegFull != NULL, FMSTR_FALSE); |
621 | FMSTR_ASSERT_RETURN(FMSTR_SERIAL_DRV.IsTransmitterActive != NULL, FMSTR_FALSE); |
622 | FMSTR_ASSERT_RETURN(FMSTR_SERIAL_DRV.PutChar != NULL, FMSTR_FALSE); |
623 | FMSTR_ASSERT_RETURN(FMSTR_SERIAL_DRV.GetChar != NULL, FMSTR_FALSE); |
624 | FMSTR_ASSERT_RETURN(FMSTR_SERIAL_DRV.Flush != NULL, FMSTR_FALSE); |
625 | |
626 | #if FMSTR_SHORT_INTR || FMSTR_LONG_INTR |
627 | FMSTR_ASSERT_RETURN(FMSTR_SERIAL_DRV.EnableTransmitInterrupt != NULL, FMSTR_FALSE); |
628 | FMSTR_ASSERT_RETURN(FMSTR_SERIAL_DRV.EnableTransmitCompleteInterrupt != NULL, FMSTR_FALSE); |
629 | FMSTR_ASSERT_RETURN(FMSTR_SERIAL_DRV.EnableReceiveInterrupt != NULL, FMSTR_FALSE); |
630 | #endif |
631 | |
632 | /* Call initialization of serial driver */ |
633 | if (FMSTR_SERIAL_DRV.Init() == FMSTR_FALSE) |
634 | { |
635 | return FMSTR_FALSE; |
636 | } |
637 | |
638 | /* Initialize Serial interface */ |
639 | FMSTR_SERIAL_DRV.EnableReceive(FMSTR_TRUE); /* enable SCI receive interrupt */ |
640 | FMSTR_SERIAL_DRV.EnableTransmit(FMSTR_TRUE); /* enable SCI transmit interrupt */ |
641 | |
642 | #if FMSTR_SHORT_INTR > 0 |
643 | _FMSTR_RingBuffCreate(&fmstr_rxQueue, fmstr_rxBuff, FMSTR_COMM_RQUEUE_SIZE); |
644 | #endif |
645 | |
646 | #if FMSTR_DEBUG_TX > 0 |
647 | /* this zero will initiate the test frame transmission |
648 | * as soon as possible during Listen */ |
649 | fmstr_nDebugTxPollCount = 0; |
650 | #endif |
651 | |
652 | /* start listening for commands */ |
653 | _FMSTR_Listen(); |
654 | |
655 | #if FMSTR_DEBUG_LEVEL >= 2 |
656 | FMSTR_DEBUG_PRINTF("FMSTR SerialInit done\n"); |
657 | #endif |
658 | |
659 | return FMSTR_TRUE; |
660 | } |
661 | |
662 | /******************************************************************************* |
663 | * |
664 | * @brief API: Serial Transport "Polling" call from the application main loop |
665 | * |
666 | * This function either handles all the SCI communication (polling-only mode = |
667 | * FMSTR_POLL_DRIVEN) or decodes messages received on the background by SCI interrupt |
668 | * (short-interrupt mode = FMSTR_SHORT_INTR). |
669 | * |
670 | *******************************************************************************/ |
671 | |
672 | static void _FMSTR_SerialPoll(void) |
673 | { |
674 | /* invoke low-level driver's poll if needed */ |
675 | if (FMSTR_SERIAL_DRV.Poll != NULL) |
676 | { |
677 | FMSTR_SERIAL_DRV.Poll(); |
678 | } |
679 | |
680 | #if FMSTR_POLL_DRIVEN > 0 |
681 | |
682 | /* polled SCI mode */ |
683 | FMSTR_ProcessSerial(); |
684 | |
685 | #elif FMSTR_SHORT_INTR > 0 |
686 | /* process queued SCI characters */ |
687 | _FMSTR_RxDequeue(); |
688 | #endif |
689 | |
690 | #if FMSTR_DEBUG_TX > 0 |
691 | /* down-counting the polls for heuristic time measurement */ |
692 | if (fmstr_nDebugTxPollCount != 0 && fmstr_nDebugTxPollCount > FMSTR_DEBUG_TX_POLLCNT_MIN) |
693 | { |
694 | fmstr_nDebugTxPollCount--; |
695 | } |
696 | #endif |
697 | } |
698 | |
699 | #endif /* !(FMSTR_DISABLE) */ |
700 | |