ISF  2.1
Intelligent Sensing Framework for Kinetis with Processor Expert
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Modules Pages
task_ci.c
Go to the documentation of this file.
1 /*
2  *
3  * Copyright (c) 2014, Freescale Semiconductor, Inc.
4  *
5 */
6 
7 /*!
8  * @file task_ci.c
9  *
10  * @brief Command Interpreter (CI) task source file that implements the top level
11  * CI protocol features and functionality. This file is internal ISF code.
12  *
13  */
14 
15 
16 
17 #include "isf_target.h"
18 #include "isf.h"
19 #include "lwevent.h"
20 #include "lwsem.h"
21 #include "mutex.h"
22 #include "lwmem.h"
23 
24 #include "isf_ci.h"
25 #include "task_ci.h"
26 #include "isf_ci_protocol.h"
27 #include "cortex.h"
28 #include "isf_devmsg.h"
29 #include "isf_ci_stream.h"
30 
31 extern uint32 get_ci_comm(void);
32 
34 
35 static LWSEM_STRUCT ci_sema_tx;
36 
37 static ci_rx_packet_t ci_rx_packet;
38 static ci_tx_packet_t ci_tx_packet;
39 static uint8 protocol_max = 0;
41 static uint32 ci_max_recv_size = 0;
42 
45 
46 
47 static inline void reset_rx_packet() { \
48  ci_rx_packet.mbIndex = 0; \
49  ci_rx_packet.packetSize = 0; \
50  ci_rx_packet.rxState = CI_RX_STATE_WAITFORPACKETMARKER1; \
51  }
52 
53 static inline void reset_tx_packet() { \
54  ci_tx_packet.bytesLeft = 0; \
55  ci_tx_packet.pTxbuf = NULL; \
56  ci_tx_packet.txState = CI_TX_STATE_NULL; \
57  }
58 
59 
60 extern const ci_protocol_t ci_protocol_table[];
62 extern uint32 isf_ci_get_recv_size(void);
63 
64 
65 // -------------------------------------------------------------------
66 // Debug only
67 
68 //#define DEBUG_TRACE_ENABLE
69 
70 #ifdef DEBUG_TRACE_ENABLE
71  volatile uint32 ci_debug_rx_packet_cnt = 0;
72  volatile uint32 ci_debug_tx_packet_cnt = 0;
73 
74  volatile uint32 ci_debug_trace[16];
75  volatile uint8 ci_debug_trace_index = 0;
76 
77 void debug_trace_set(uint8 step, uint32 data24)
78 {
79  ci_debug_trace[ci_debug_trace_index] = (uint32)( ((uint32)step << 24) | data24 );
80 
81  ++ci_debug_trace_index;
82  if (ci_debug_trace_index >= 16)
83  ci_debug_trace_index = 0; // Wrap around
84 }
85 #endif // DEBUG_TRACE_ENABLE
86 
87 // ---------------------------------------
88 //#define DEBUG_SAVE_RX_RAWCHARS
89 
90 #ifdef DEBUG_SAVE_RX_RAWCHARS
91 
92 void debug_rx_store(uint8 c);
93 void debug_rx_reset(void);
94 
95 // Circular buffer to store rx chars.
96 volatile uint8 debug_rx_buf[32];
97 volatile uint32 debug_rx_index;
98 
99 void debug_rx_store(uint8 c)
100 {
101  debug_rx_buf[debug_rx_index] = c;
102  ++debug_rx_index;
103  if (debug_rx_index >= 32)
104  debug_rx_index = 0; // Wrap around
105 }
106 
107 
108 void debug_rx_resetbuf(void)
109 {
110  debug_rx_index = 32;
111  do
112  {
113  debug_rx_buf[debug_rx_index-1] = 0;
114  } while(--debug_rx_index);
115  debug_rx_index = 0;
116 }
117 #endif
118 
119 
120 
121 /*!
122  *
123 * @brief Process data received over comm port. Perform CI packet
124 * processing and return to caller status.
125 *
126 * @param (in) c - character to process
127 *
128 * @return process_recv_byte() returns a value of type
129 * ::ci_packet_recv_status_t indicating the status of
130 * the packet received status.
131 *
132 * @retval ::CI_PACKET_RECV_STATUS_NO indicating no packet has been
133 * received.
134 *
135 * @retval ::CI_PACKET_RECV_STATUS_YES indicating a packet has been
136 * received.
137 *
138 * @see task_ci()
139 */
140 
142 {
143 
144  static boolean packetReceived = FALSE;
146 
147  bool bDone = FALSE;
148  bool bRxPacketerror = FALSE;
149 
150 
151 #ifdef DEBUG_SAVE_RX_RAWCHARS
152  debug_rx_store(c);
153 #endif
154 
155 
156  // Process the character.
157  {
158  switch(ci_rx_packet.rxState)
159  {
160 
162 
163  if (c == CI_PACKET_MARKER)
164  {
165  ci_rx_packet.mbIndex = 0;
166  ci_rx_packet.packetSize = 0;
167 
168  // Wait for packet data if any.
169  ci_rx_packet.rxState = CI_RX_STATE_GETTINGPACKETDATA2;
170  }
171  // Else ignore the data. It could be a fragment of a packet.
172 
173  break;
174 
175 
177  {
178  static volatile uint8 c_prev = 0;
179 
180  if (c != CI_PACKET_MARKER)
181  {
182  // Got some real data (non-marker char).
183 
184  // Do escape decode if needed.
185  if (c == 0x7D)
186  {
187  c_prev = c;
188 
189  // ------------------------------------------------------
190  // Exit the case statement. Waiting for 2nd escape char.
191  // ------------------------------------------------------
192  break;
193  }
194  else if (c_prev == 0x7D)
195  {
196  if (c == 0x5D) {
197  c = 0x7D;
198  }
199  else if (c == 0x5E) {
200  c = CI_PACKET_MARKER;
201  }
202  else {
203  // ENGR302687: Handle erroneous escape sequence.
204  // Illegal escape sequence. Reset and wait for next packet.
205  bRxPacketerror = TRUE;
206  }
207  c_prev = 0;
208  }
209 
210 
211  // Escape decode done.
212  if (ci_rx_packet.mbIndex < ci_max_recv_size)
213  {
214  // Just got data byte, save it.
215 
216  ci_rx_packet.pRxbuf[ci_rx_packet.mbIndex] = c;
217  ++ci_rx_packet.mbIndex;
218  }
219  else
220  {
221  // Error: receiving too many bytes.
222  // Reset and wait for next packet.
223  bRxPacketerror = TRUE;
224  }
225 
226  }
227  else
228  {
229  // Got packet marker while waiting for data.
230 
231  if (ci_rx_packet.mbIndex > 0)
232  {
233 
234  if (ci_rx_packet.mbIndex >= CI_MIN_RX_BYTES)
235  {
236  // Got minimum amount of bytes for CI packet.
237 
238  // Wait for next packet.
240 
241  // Set flag to process packet just received.
242  packetReceived = TRUE;
243 
244  // Quit looping.
245  bDone = TRUE;
246  }
247  else
248  {
249  // This case means that we did not receive enough data.
250  // Reset and wait for next packet.
251  bRxPacketerror = TRUE;
252  }
253  }
254  else
255  {
256  // We got back to back packet marker. This 2nd packet marker will
257  // then be treated as a start marker. Go back to wait for data.
258 
260  ci_rx_packet.mbIndex = 0;
261  ci_rx_packet.packetSize = 0;
262  }
263 
264  }
265 
266  }
267  break;
268 
269  default:
270 
271  // Unknown state.
272  bRxPacketerror = TRUE;
273 
274  break;
275 
276  } // switch
277 
278  // Handle packet error.
279  if (bRxPacketerror == TRUE)
280  {
281  reset_rx_packet();
282  packetReceived = FALSE;
283 
284 #ifdef DEBUG_SAVE_RX_RAWCHARS
285  debug_rx_resetbuf();
286 #endif
287 
288  // Quit looping.
289  bDone = TRUE;
290 
291  }
292  }
293 
294 
295 
296  if (packetReceived == TRUE)
297  {
298 
299  // TODO: IF this isr is being converted to SDK callback, return kStatus_UART_RxCallBackEnd
300  // here to indicate that all expected bytes have been received. Return 0 otherwise.
301 
302  // Tell caller packet has been received.
303  packet_status = CI_PACKET_RECV_STATUS_YES;
304 
305  // Reset
306  packetReceived = FALSE;
307 
308 #ifdef DEBUG_SAVE_RX_RAWCHARS
309  debug_rx_resetbuf();
310 #endif
311 
312  }
313 
314  return packet_status;
315 }
316 
317 
318 /*!
319  *
320  * @brief CI send packet - main function to send data to host.
321  *
322  * @param anumBytes - number of bytes to transmit.
323  *
324  * @param apSrc - pointer to source of data to transmit.
325  *
326  * @return See ci_response_enum type for possible return values
327  *
328  * @errors None \n
329  *
330  * @constraints Only one caller can have access to the transmit operation.
331  * Other callers will be blocked by a semaphore until the
332  * current transmit operation has completed.
333  *
334  * @reentrant Yes. \n
335  *
336  * @libs \n
337  *
338  * @see \n
339  *
340 */
341 
343 {
344 
345  isf_status_t ci_ret = !ISF_SUCCESS;
346  _mqx_uint ret = !MQX_OK;
347 
348  if (anumBytes > 0)
349  {
350 
351  ret = _lwsem_wait_ticks(&ci_sema_tx, 0);
352 
353  // For now try letting task switching in case comm speed is slow
354  // and let other tasks run.
355  //_task_stop_preemption();
356 
357  // While waiting for buffer to be transmitted, we allow preemption
358  // because the operation is interrupt driven.
359 
360  if (ret == MQX_OK)
361  {
362 
363  ci_tx_packet.txState = CI_TX_STATE_SEND_STARTMARKER1;
364  ci_tx_packet.bytesLeft = anumBytes;
365  ci_tx_packet.pTxbuf = apSrc;
366 
367 
368 
369  // If there are data to transmit, then do it.
370  if (ci_tx_packet.txState != CI_TX_STATE_NULL)
371  {
372  bool bDone = FALSE;
373 
374  // NOTE: Must keep sending until the transmitter is full so that it
375  // will clear its transmit empty flag. The transmitter is double
376  // buffered and if you don't fill them up, the transmit empty flag
377  // is still set and you won't get another transmit empty interrupt.
378 
379  while (bDone == FALSE)
380  {
381 
382  switch(ci_tx_packet.txState)
383  {
384 
385  case CI_TX_STATE_SEND_STARTMARKER1: // Send start marker
386 
387  dm_device_write(&dm_dev_desc, 0, (uint8*)&packet_marker, 1, 1);
388 
389  ci_tx_packet.txState = CI_TX_STATE_SEND_PACKETDATA2;
390  break;
391 
392  case CI_TX_STATE_SEND_PACKETDATA2: // Send MB
393  {
395  uint8 c = 0;
396  uint8 d;
397 
398  c = *ci_tx_packet.pTxbuf;
399 
400  if ((c == 0x7D) || (c == CI_PACKET_MARKER))
401  {
402  if (escapeState == CI_ESCAPE_STATE_WAIT_1ST_CHAR)
403  {
404  // Send first escape byte.
405  d = 0x7D;
406  dm_device_write(&dm_dev_desc, 0, (uint8*)&d, 1, 1);
407 
408  escapeState = CI_ESCAPE_STATE_WAIT_2ND_CHAR; // Send 2nd escape byte next time.
409  }
410  else
411  {
412  // Send second escape byte.
413  if (c == 0x7D)
414  d = 0x5D;
415  else
416  d = 0x5E;
417  dm_device_write(&dm_dev_desc, 0, (uint8*)&d, 1, 1);
418  escapeState = CI_ESCAPE_STATE_WAIT_1ST_CHAR;
419 
420  ++ci_tx_packet.pTxbuf;
421  --ci_tx_packet.bytesLeft;
422  }
423  }
424  else
425  {
426  // No escape encoding needed.
427  dm_device_write(&dm_dev_desc, 0, (uint8*)ci_tx_packet.pTxbuf++, 1, 1);
428 
429  --ci_tx_packet.bytesLeft;
430  }
431 
432  if (ci_tx_packet.bytesLeft == 0)
433  ci_tx_packet.txState = CI_TX_STATE_SEND_ENDMARKER4;
434  }
435 
436  break;
437 
439 
440  // All done transmitting packet. Wrap up.
441 
442  // Send end marker.
443  dm_device_write(&dm_dev_desc, 0, (uint8*)&packet_marker, 1, 1);
444 
445  // Reset state.
446  ci_tx_packet.txState = CI_TX_STATE_NULL;
447 
448  #ifdef DEBUG_TRACE_ENABLE
449  ++ci_debug_tx_packet_cnt;
450  #endif
451 
452  bDone = TRUE;
453 
454  break;
455 
456  default:
457  break;
458  }
459  }
460  }
461 
462  }
463 
464  _lwsem_post(&ci_sema_tx);
465 
466  }
467 
468  if (ret == MQX_OK)
469  ci_ret = (isf_status_t)ISF_SUCCESS;
470  else
471  ci_ret = (isf_status_t)ISF_CI_FAILURE;
472 
473  return ci_ret;
474 }
475 
476 
477 
478 
479 /*!
480  *
481  * @brief Command Interpreter Task - main task to handle communication \n
482  * via mailboxes with the host.
483  *
484  * @param initial_data - value passed in when task is created, not used.
485  *
486  * @return None
487  *
488  * @errors \n
489  *
490  * @constraints \n
491  *
492  * @reentrant No.
493  *
494  * @libs \n
495  *
496  * @see main.c/MQX_template_list[]\n
497  *
498 */
499 void task_ci(uint32 initial_data)
500 {
501 
502  ci_response_t callback_ret;
503 
504  while(1)
505  {
506 
507 #ifdef DEBUG_TRACE_ENABLE
508  debug_trace_set(1, ci_debug_rx_packet_cnt);
509 #endif
510 
511 
512  // Wait to receive data from host.
513  {
514  uint8 char_cnt = 0;
515  uint8 c;
516 
517  while(1)
518  {
519 
520  if (ISF_SUCCESS == dm_device_read(&dm_dev_desc, 0, &c, 1, 1)) {
521  ++char_cnt;
523  break;
524  }
525 
526  }
527  }
528 
529 
530 #ifdef DEBUG_TRACE_ENABLE
531  debug_trace_set(2, ci_debug_rx_packet_cnt);
532 #endif
533 
534 #ifdef DEBUG_TRACE_ENABLE
535  debug_trace_set(3, ci_debug_rx_packet_cnt);
536 #endif
537 
538 
539  // CI packet processing.
540  {
541 
542  // Number of bytes in packet minus CI wrapper.
543  uint32 size = ci_rx_packet.mbIndex - CI_PROTOCOL_ID_SIZE; // -1 for protocol id byte at beginning of packet.
544 
545 
546  // Set to failure so that if no matching protocol is defined we exit loop with error.
547  callback_ret = ISF_CI_FAILURE;
548 
549  uint8 protocol = 0;
550  uint8 id = ci_get_protocol_id();
551  while (protocol < protocol_max)
552  {
553  if ( (id > CI_PROTOCOL_ID_NULL) && (id <= CI_PROTOCOL_ID_MAX) && (ci_protocol_table[protocol].protcolID == id))
554  {
555  // Invoke the protocol.
556  if (ci_protocol_table[protocol].pProtocolCB != NULL)
557  {
558  callback_ret = ((*((ci_protocol_callback_funcp_t)
559  (ci_protocol_table[protocol].pProtocolCB)))(size, (uint8 *)&ci_rx_packet.pRxbuf[CI_PROTOCOL_DATA_OFFSET], 0, NULL));
560  break;
561  }
562  }
563  else
564  {
565  ++protocol;
566  }
567  }
568 
569  // For now, we do not send anything back if error conditions occur such as:
570  // - The protocol id specifies a protocol that has not been implemented
571  // - The protocol callback returns an error (such as CRC error). In case of
572  // CRC failure, the packet is corrupted so there we can't use any of its
573  // information to know what/who to send the error to.
574 
575  }
576 
577  } // while loop
578 
579 }
580 
581 
582 
583 // See isf_ci.h for documentation
585 {
586 
587  isf_status_t ret = ISF_SUCCESS;
588 
589  // Create semaphore for transmit operation.
590  _lwsem_create(&ci_sema_tx, 1);
591 
592 
593  // Init transmitter/receiver packet states.
594  reset_rx_packet();
595  reset_tx_packet();
596 
597  // Alloc mem for recv buffer.
598  ci_max_recv_size = isf_ci_get_recv_size();
599  ci_rx_packet.pRxbuf = CI_ALLOC_MEM_ZERO(ci_max_recv_size);
600 
601  if (ci_rx_packet.pRxbuf == NULL)
602  return ISF_ERR_LIB_INIT;
603 
604 
605  protocol_max = 0;
606 
607 
608  // Get the number of defined protocols. Count number of pointers in array until we reach NULL
609  // or max num of allowable protocols. It is expected that the array is NULL terminated in the
610  // last element.
611  do
612  {
613 
614  if ( (ci_protocol_table[protocol_max].pProtocolCB != NULL) &&
615  (ci_protocol_table[protocol_max].pProtocolInit != NULL) &&
616  (ci_protocol_table[protocol_max].protcolID > 0)
617  )
618  {
619  // Call the protocol's initialization and give it its ID.
620  ((*((ci_protocol_init_funcp_t)(ci_protocol_table[protocol_max].pProtocolInit)))
621  ( ci_protocol_table[protocol_max].protcolID, ci_protocol_initptr_table[protocol_max]));
622  }
623  else
624  {
625  break;
626  }
627 
628  } while (++protocol_max < CI_MAX_PROTOCOL);
629 
630 
631  // Initialize communication channel via device messaging.
633  return ISF_ERR_LIB_INIT;
634  }
635  if(COMM_STATE_OK != dm_channel_get_state(&dm_channel_desc)){
636  return ISF_ERR_LIB_INIT;
637  }
638  if(ISF_SUCCESS != dm_channel_start(&dm_channel_desc)){
639  return ISF_ERR_LIB_INIT;
640  }
641  if(ISF_SUCCESS != dm_device_open(&dm_channel_desc, NULL, &dm_dev_desc)){
642  return ISF_ERR_LIB_INIT;
643  }
644 
645 
646  return ret;
647 }
648 
649 
650 
651 
652 
653 
654 
655 
656 
657 
658 
659 
660 
isf_status_t dm_channel_start(dm_ChannelDescriptor_t *apChannelDescriptor)
This function starts a channel.
#define CI_PROTOCOL_DATA_OFFSET
Define offset to where protocol data begins of the send/receive buffer that skips pass the protocol i...
ISF board support header files.
#define CI_MAX_PROTOCOL
Define the maximum allowable CI protocols.
#define ci_get_protocol_id()
Retrieve the protocol ID.
Definition: task_ci.h:115
const uint8 packet_marker
Definition: task_ci.c:40
unsigned char uint8
This defines uint8 as unsigned char.
Definition: isf_types.h:18
ci_packet_recv_status_t
Packet received status.
Definition: task_ci.h:98
#define TRUE
Definition: isf_types.h:52
ISF Command Interpreter (CI) stream protocol header file.
volatile uint32 bytesLeft
Internal transmit state.
Definition: task_ci.h:63
isf_status_t(* ci_protocol_init_funcp_t)(uint8 aprotocolID, void *apInitData)
This is a CI protocol intialization callback function pointer.
isf_status_t dm_device_open(dm_ChannelDescriptor_t *apChannelDescriptor, void *apDevice, dm_DeviceDescriptor_t *apDeviceDescriptor)
This function creates a device handle for a device at a specified channel address.
void * ci_protocol_initdata_ptr_t
This is the pointer to the user defined data structure to be passed into the ci_protocol_init_funcp_t...
comm_State_t dm_channel_get_state(dm_ChannelDescriptor_t *apChannelDescriptor)
This function returns the channel state.
uint32 get_ci_comm(void)
#define CI_MIN_RX_BYTES
Define the minimum number of bytes for the CI wrapper that encapsulates the protocol data...
Command Interpreter (CI) Protocol header file.
#define FALSE
Definition: isf_types.h:56
Transmitter state: Send packet marker.
Definition: task_ci.h:44
This structure holds information to receive a packet of data to the host. CI will fill the structure ...
Definition: task_ci.h:75
Receiver state: Waiting for a packet marker.
Definition: task_ci.h:33
volatile uint8 * pRxbuf
Expected packet size.
Definition: task_ci.h:80
volatile uint8 packetSize
Mailbox index.
Definition: task_ci.h:79
volatile ci_tx_state_t txState
Definition: task_ci.h:62
unsigned long uint32
This defines uint32 as unsigned long.
Definition: isf_types.h:36
dm_DeviceDescriptor_t dm_dev_desc
Definition: task_ci.c:44
dm_ChannelDescriptor_t dm_channel_desc
Definition: task_ci.c:43
uint8 protcolID
Protocol destination buffer size.
isf_status_t dm_device_write(dm_DeviceDescriptor_t *apDeviceDescriptor, int32 aOffset, uint8 *apWriteBuffer, uint32 aBuffsize, uint32 aNbyteWrite)
This function writes to a device.
isf_status_t ci_send_packet(uint32 anumBytes, uint8 *apSrc)
CI send packet - main function to send data to host.
Definition: task_ci.c:342
volatile uint8 mbIndex
Internal receive state.
Definition: task_ci.h:78
Command interpreter task header file. This file is internal ISF code.
isf_status_t ci_init(void)
This API initializes the Command Interpreter.
Definition: task_ci.c:584
uint32 isf_ci_get_recv_size(void)
CI Receive buffer size.
#define CI_PROTOCOL_ID_SIZE
Define the number of bytes for the protocol ID. Do not modify.
ci_escape_state_enum
States for encoding/decoding escape characters.
Definition: task_ci.h:87
const ci_protocol_t ci_protocol_table[]
CI protocol routing table.
isf_status_t dm_channel_init(dm_ChannelId_t aChannelId, dm_ChannelDescriptor_t *apChannelDescriptor)
This function initializes a channel.
volatile uint8 * pTxbuf
How many bytes left to transfered.
Definition: task_ci.h:64
ci_packet_recv_status_t process_recv_byte(uint8 c)
Process data received over comm port. Perform CI packet processing and return to caller status...
Definition: task_ci.c:141
This structure holds information to send a packet of data to the host. A task will fill the structure...
Definition: task_ci.h:60
Main ISF header file. Contains code common to all ISF components.
Transmitter state: Send packet data.
Definition: task_ci.h:46
API definitions, types, and macros for the Intelligent Sensing Framework (ISF) Command Interpreter (C...
General library initialization failure status.
Definition: isf.h:36
ci_protocol_initdata_ptr_t ci_protocol_initptr_table[]
CI protocol user defined initialization data pointer table.
#define CI_PACKET_MARKER
Packet maker. Each packet is delineated by this character.
Definition: task_ci.h:25
isf_status_t dm_device_read(dm_DeviceDescriptor_t *apDeviceDescriptor, int32 aOffset, uint8 *apReadBuffer, uint32 aBuffsize, uint32 aNbyteRead)
This function reads from a device.
void task_ci(uint32 initial_data)
Command Interpreter Task - main task to handle communication via mailboxes with the host...
Definition: task_ci.c:499
int32 isf_status_t
ISF return status type.
Definition: isf.h:51
Transmitter state: Send end marker.
Definition: task_ci.h:48
#define CI_ALLOC_MEM_ZERO(x)
Memory allocation abstraction.
Definition: task_ci.h:108
This structure defines a handle for the device.
Definition: isf_devmsg.h:61
Receiver state: Receiving data payload.
Definition: task_ci.h:35
This structure binds a protocol ID to a set of related functions and data. When a packet is received ...
isf_devmsg.h defines the API definitions and types for the Intelligent Sensing (ISF) Device Messaging...
ci_response_enum
These are the CI errors provided to the host.
Definition: isf_ci.h:107
isf_status_t(* ci_protocol_callback_funcp_t)(uint32 anumSrcBytes, uint8 *apSrc, uint32 *apnumDestBytes, uint8 *apDest)
This is a CI protocol callback function pointer.
This structure is a declaration of a channel descriptor type.
Definition: isf_devmsg.h:50
volatile ci_recv_state_t rxState
Definition: task_ci.h:77