198aaae75095ec166b8da00b1a717c00f26d7542
1 /*\r
2 * rpc.c\r
3 *\r
4 * This module contains the RPC (Remote Procedure Call) API for the\r
5 * ZigBee Network Processor (ZNP) Host Interface.\r
6 *\r
7 * Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/\r
8 *\r
9 *\r
10 * Redistribution and use in source and binary forms, with or without\r
11 * modification, are permitted provided that the following conditions\r
12 * are met:\r
13 *\r
14 * Redistributions of source code must retain the above copyright\r
15 * notice, this list of conditions and the following disclaimer.\r
16 *\r
17 * Redistributions in binary form must reproduce the above copyright\r
18 * notice, this list of conditions and the following disclaimer in the\r
19 * documentation and/or other materials provided with the\r
20 * distribution.\r
21 *\r
22 * Neither the name of Texas Instruments Incorporated nor the names of\r
23 * its contributors may be used to endorse or promote products derived\r
24 * from this software without specific prior written permission.\r
25 *\r
26 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\r
27 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\r
28 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\r
29 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\r
30 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\r
31 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\r
32 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\r
33 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\r
34 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r
35 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\r
36 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
37 *\r
38 */\r
39 \r
40 /*********************************************************************\r
41 * INCLUDES\r
42 */\r
43 \r
44 #include <stdio.h>\r
45 #include <stdlib.h>\r
46 #include <string.h>\r
47 #include <unistd.h>\r
48 #include <ctype.h>\r
50 #include <signal.h>\r
51 #include "semaphore.h"\r
52 #include "queue.h"\r
53 //#include <mqueue.h>\r
54 #include <time.h>\r
55 \r
56 #include "rpc.h"\r
57 #include "rpcTransport.h"\r
58 #include "mtParser.h"\r
59 #include "dbgPrint.h"\r
60 \r
61 /*********************************************************************\r
62 * MACROS\r
63 */\r
64 \r
65 /*********************************************************************\r
66 * CONSTANTS\r
67 */\r
68 \r
69 #define SB_FORCE_BOOT (0xF8)\r
70 #define SB_FORCE_RUN (SB_FORCE_BOOT ^ 0xFF)\r
71 \r
72 #define SRSP_TIMEOUT_MS (2000) // 2000ms timeout\r
73 /*********************************************************************\r
74 * GLOBAL VARIABLES\r
75 */\r
76 \r
77 /*********************************************************************\r
78 * LOCAL VARIABLES\r
79 */\r
80 \r
81 // semaphore for sending RPC frames (used for mutual exclusion for\r
82 // calling rpcSendFrame() function - from application thread(s) )\r
83 static sem_t rpcSem;\r
84 \r
85 // semaphore for SRSP (Synchronous Response) used by application thread\r
86 // to wait for any response from the ZNP. The RPC thread will post\r
87 // the semaphore if any incoming message exists\r
88 static sem_t srspSem;\r
89 \r
90 // expected SRSP command ID\r
91 static uint8_t expectedSrspCmdId;\r
92 \r
93 // RPC message queue for passing RPC frame from RPC process to APP process\r
94 //static mqd_t rpcQueue = (mqd_t) -1;\r
95 static que_t rpcQueue;\r
96 \r
97 /*********************************************************************\r
98 * EXTERNAL VARIABLES\r
99 */\r
100 \r
101 /*********************************************************************\r
102 * LOCAL FUNCTIONS DECLARATION\r
103 */\r
104 \r
105 // function for calculating FCS in RPC UART frame\r
106 static uint8_t calcFcs(uint8_t *msg, uint8_t len);\r
107 \r
108 // function for printing out RPC frames\r
109 static void printRpcMsg(char* preMsg, uint8_t sof, uint8_t len, uint8_t *msg);\r
110 \r
111 /*********************************************************************\r
112 * API FUNCTIONS\r
113 */\r
114 \r
115 /*********************************************************************\r
116 * @fn rpcOpen\r
117 *\r
118 * @brief opens the serial port to the CC253x.\r
119 *\r
120 * @param devicePath - path to the UART device\r
121 *\r
122 * @return status\r
123 */\r
124 int32_t rpcOpen(char *_devicePath, uint32_t port)\r
125 {\r
126 int fd;\r
127 \r
128 // open RPC transport\r
129 fd = rpcTransportOpen(_devicePath, port);\r
130 if (fd < 0)\r
131 {\r
132 perror(_devicePath);\r
133 dbg_print(PRINT_LEVEL_ERROR, "rpcOpen: %s device open failed\n",\r
134 _devicePath);\r
135 return (-1);\r
136 }\r
137 \r
138 sem_init(&rpcSem, 0, 1); // initialize mutex to 1 - binary semaphore\r
139 sem_init(&srspSem, 0, 0); // initialize mutex to 0 - binary semaphore\r
140 \r
141 //rpcForceRun();\r
142 \r
143 return fd;\r
144 }\r
145 \r
146 /*********************************************************************\r
147 * @fn rpcInitMq\r
148 *\r
149 * @brief init message queue\r
150 *\r
151 * @param -\r
152 *\r
153 * @return status\r
154 */\r
155 int32_t rpcInitMq(void)\r
156 {\r
157 //char qname[32];\r
158 //struct mq_attr attr;\r
159 \r
160 // initialize the queue attributes\r
161 //attr.mq_flags = 0;\r
162 //attr.mq_maxmsg = 10;\r
163 //attr.mq_msgsize = RPC_MAX_LEN;\r
164 //attr.mq_curmsgs = 0;\r
165 //sprintf(qname, "/mquec%d", getpid());\r
166 \r
167 // create the message queue\r
168 //rpcQueue = mq_open((const char*)qname, O_CREAT | O_RDWR,\r
169 queInit(&rpcQueue); // 0644, &attr);\r
170 //dbg_print(PRINT_LEVEL_INFO, "rpcInitMqClient: rpcQueue = %s - %d\n",\r
171 //qname, rpcQueue);\r
172 \r
173 //return ((int32_t)rpcQueue);\r
174 return 0;\r
175 }\r
176 \r
177 /*********************************************************************\r
178 * @fn rpcGetMqClientMsg\r
179 *\r
180 * @brief wait (blocking function) for incoming message and process\r
181 * it\r
182 *\r
183 * @param -\r
184 *\r
185 * @return status\r
186 */\r
187 int32_t rpcGetMqClientMsg(void)\r
188 {\r
189 uint8_t rpcFrame[RPC_MAX_LEN + 1];\r
190 int32_t rpcLen;\r
191 \r
192 dbg_print(PRINT_LEVEL_INFO, "rpcWaitMqClient: waiting on queue\n");\r
193 \r
194 // wait for incoming message queue\r
195 rpcLen = receive(&rpcQueue, rpcFrame, RPC_MAX_LEN + 1); //mq_receive(rpcQueue, (char*) rpcFrame,\r
196 //RPC_MAX_LEN + 1, NULL);\r
197 if (rpcLen != -1)\r
198 {\r
199 dbg_print(PRINT_LEVEL_VERBOSE, "rpcWaitMqClient: processing MT[%d]\n",\r
200 rpcLen);\r
201 \r
202 // process incoming message\r
203 mtProcess(rpcFrame, rpcLen);\r
204 }\r
205 else\r
206 {\r
207 dbg_print(PRINT_LEVEL_WARNING, "rpcWaitMqClient: Timeout\n");\r
208 return -1;\r
209 }\r
210 \r
211 return 0;\r
212 }\r
213 \r
214 /*********************************************************************\r
215 * @fn rpcWaitMqClientMsg\r
216 *\r
217 * @brief wait (with timeout) for incoming message and process\r
218 * it\r
219 *\r
220 * @param -\r
221 *\r
222 * @return status\r
223 */\r
224 int32_t rpcWaitMqClientMsg(uint32_t timeout)\r
225 {\r
226 uint8_t rpcFrame[RPC_MAX_LEN + 1];\r
227 int32_t rpcLen;\r
228 struct timespec to;\r
229 \r
230 // calculate timeout\r
231 to.tv_sec = time(0) + (timeout / 1000);\r
232 to.tv_nsec = (long) ((long) timeout % 1000) * 1000000L;\r
233 \r
234 //dbg_print(PRINT_LEVEL_INFO, "rpcWaitMqClientMsg: timeout=%d\n", timeout);\r
235 //dbg_print(PRINT_LEVEL_INFO, "rpcWaitMqClientMsg: waiting on queue %d:%d:%d\n", timeout, to.tv_sec, to.tv_nsec);\r
236 rpcLen = timedReceive(&rpcQueue, rpcFrame, RPC_MAX_LEN + 1, &to);\r
237 if (rpcLen != -1)\r
238 {\r
239 dbg_print(PRINT_LEVEL_INFO, "rpcWaitMqClientMsg: processing MT[%d]\n",\r
240 rpcLen);\r
241 \r
242 // process incoming message\r
243 mtProcess(rpcFrame, rpcLen);\r
244 }\r
245 else\r
246 {\r
247 //dbg_print(PRINT_LEVEL_INFO, "rpcWaitMqClientMsg: Timed out [%d] - %s\n", rpcLen, strerror (errno));\r
248 return -1;\r
249 }\r
250 \r
251 return 0;\r
252 }\r
253 \r
254 /*********************************************************************\r
255 * @fn rpcForceRun\r
256 *\r
257 * @brief send force run bootloader command\r
258 *\r
259 * @param -\r
260 *\r
261 * @return -\r
262 */\r
263 void rpcForceRun(void)\r
264 {\r
265 uint8_t forceBoot = SB_FORCE_RUN;\r
266 \r
267 // send the bootloader force boot incase we have a bootloader that waits\r
268 rpcTransportWrite(&forceBoot, 1);\r
269 }\r
270 \r
271 /*************************************************************************************************\r
272 * @fn rpcProcess()\r
273 *\r
274 * @brief Read bytes from transport layer and form an RPC frame\r
275 *\r
276 * @param none\r
277 *\r
278 * @return length of current Rx Buffer\r
279 *************************************************************************************************/\r
280 int32_t rpcProcess(void)\r
281 {\r
282 uint8_t rpcLen, rpcTempLen, bytesRead, sofByte, rpcBuffIdx;\r
283 uint8_t retryAttempts = 0, len, rpcBuff[RPC_MAX_LEN];\r
284 \r
286 bytesRead = rpcTransportRead(&sofByte, 1);\r
287 \r
288 if ((sofByte == MT_RPC_SOF) && (bytesRead == 1))\r
289 #endif\r
290 {\r
291 // clear retry counter\r
292 retryAttempts = 0;\r
293 \r
294 // read length byte\r
295 bytesRead = rpcTransportRead(&rpcLen, 1);\r
296 \r
297 if (bytesRead == 1)\r
298 {\r
299 len = rpcLen;\r
300 \r
302 rpcLen += RPC_CMD0_FIELD_LEN + RPC_CMD1_FIELD_LEN;\r
303 #else\r
304 //allocating RPC payload (+ cmd0, cmd1 and fcs)\r
305 rpcLen +=\r
306 RPC_CMD0_FIELD_LEN + RPC_CMD1_FIELD_LEN + RPC_UART_FCS_LEN;\r
307 #endif\r
308 \r
309 //non blocking read, so we need to wait for the rpc to be read\r
310 rpcBuffIdx = 0;\r
311 rpcTempLen = rpcLen;\r
312 while (rpcTempLen > 0)\r
313 {\r
314 // read RPC frame\r
315 bytesRead = rpcTransportRead(&(rpcBuff[rpcBuffIdx]),\r
316 rpcTempLen);\r
317 \r
318 // check for error\r
319 if (bytesRead > rpcTempLen)\r
320 {\r
321 //there was an error\r
322 dbg_print(PRINT_LEVEL_WARNING,\r
323 "rpcProcess: read of %d bytes failed - %s\n",\r
324 rpcTempLen, strerror(errno));\r
325 \r
326 // check whether retry limits has been reached\r
327 if (retryAttempts++ < 5)\r
328 {\r
329 // sleep for 10ms\r
330 usleep(10000);\r
331 \r
332 // try again\r
333 bytesRead = 0;\r
334 }\r
335 else\r
336 {\r
337 // something went wrong, abort\r
338 dbg_print(PRINT_LEVEL_ERROR,\r
339 "rpcProcess: transport read failed too many times\n");\r
340 \r
341 return -1;\r
342 }\r
343 }\r
344 \r
345 // update counters\r
346 if (rpcTempLen > bytesRead)\r
347 {\r
348 rpcTempLen -= bytesRead;\r
349 }\r
350 else\r
351 {\r
352 rpcTempLen = 0;\r
353 }\r
354 rpcBuffIdx += bytesRead;\r
355 }\r
356 \r
357 // print out incoming RPC frame\r
358 printRpcMsg("SOC IN <--", MT_RPC_SOF, len, rpcBuff);\r
359 \r
360 // TODO: verify FCS of incoming MT frames\r
361 \r
362 if ((rpcBuff[0] & MT_RPC_CMD_TYPE_MASK) == MT_RPC_CMD_SRSP)\r
363 {\r
364 // SRSP command ID deteced\r
365 if (expectedSrspCmdId == (rpcBuff[0] & MT_RPC_SUBSYSTEM_MASK))\r
366 {\r
367 dbg_print(PRINT_LEVEL_INFO,\r
368 "rpcProcess: processing expected srsp [%02X]\n",\r
369 rpcBuff[0] & MT_RPC_SUBSYSTEM_MASK);\r
370 \r
371 //unblock waiting sreq\r
372 sem_post(&srspSem);\r
373 \r
374 dbg_print(PRINT_LEVEL_INFO,\r
375 "rpcProcess: writing %d bytes SRSP to head of the queue\n",\r
376 rpcLen);\r
377 \r
378 // send message to queue\r
379 addToHead(&rpcQueue, rpcBuff, rpcLen);//mq_send(rpcQueue, (char*) rpcBuff, rpcLen, 1);\r
380 //printf("------------>>>>>>>>>>>QUEUEUE %d",rpcQueue.head->data[0]);\r
381 }\r
382 else\r
383 {\r
384 // unexpected SRSP discard\r
385 dbg_print(PRINT_LEVEL_WARNING,\r
386 "rpcProcess: UNEXPECTED SREQ!: %02X%s:%02X%s",\r
387 expectedSrspCmdId,\r
388 (rpcBuff[0] & MT_RPC_SUBSYSTEM_MASK));\r
389 return 0;\r
390 }\r
391 }\r
392 else\r
393 {\r
394 // should be AREQ frame\r
395 dbg_print(PRINT_LEVEL_INFO,\r
396 "rpcProcess: writing %d bytes AREQ to tail of the que\n",\r
397 rpcLen);\r
398 \r
399 // send message to queue\r
400 addToTail(&rpcQueue, rpcBuff, rpcLen);//mq_send(rpcQueue, (char*) rpcBuff, rpcLen, 0);\r
401 }\r
402 \r
403 return 0;\r
404 }\r
405 else\r
406 {\r
407 dbg_print(PRINT_LEVEL_WARNING, "rpcProcess: Len Not read [%x]\n",\r
408 bytesRead);\r
409 }\r
410 }\r
411 else\r
412 {\r
413 dbg_print(PRINT_LEVEL_WARNING,\r
414 "rpcProcess: No valid Start Of Frame found [%x:%x]\n", sofByte,\r
415 bytesRead);\r
416 }\r
417 \r
418 return -1;\r
419 }\r
420 \r
421 /*************************************************************************************************\r
422 * @fn sendRpcFrame()\r
423 *\r
424 * @brief builds the Frame and sends it to the transport layer - usually called by the\r
425 * application thread(s)\r
426 *\r
427 * @param cmd0 System, cmd1 subsystem, ptr to payload, lenght of payload\r
428 *\r
429 * @return length of current Rx Buffer\r
430 *************************************************************************************************/\r
431 uint8_t rpcSendFrame(uint8_t cmd0, uint8_t cmd1, uint8_t *payload,\r
432 uint8_t payload_len)\r
433 {\r
434 uint8_t buf[RPC_MAX_LEN];\r
435 int32_t status = MT_RPC_SUCCESS;\r
436 \r
437 // block here if SREQ is in progress\r
438 dbg_print(PRINT_LEVEL_INFO, "rpcSendFrame: Blocking on RPC sem\n");\r
439 sem_wait(&rpcSem);\r
440 dbg_print(PRINT_LEVEL_INFO, "rpcSendFrame: Sending RPC\n");\r
441 \r
442 // fill in header bytes\r
443 buf[0] = MT_RPC_SOF;\r
444 buf[1] = payload_len;\r
445 buf[2] = cmd0;\r
446 buf[3] = cmd1;\r
447 \r
448 if ((cmd0 & MT_RPC_CMD_TYPE_MASK) == MT_RPC_CMD_SREQ)\r
449 {\r
450 // calculate expected SRSP\r
451 expectedSrspCmdId = (cmd0 & MT_RPC_SUBSYSTEM_MASK);\r
452 }\r
453 \r
454 if (payload_len > 0)\r
455 {\r
456 // copy payload to buffer\r
457 memcpy(buf + RPC_UART_HDR_LEN, payload, payload_len);\r
458 }\r
459 \r
460 // calculate FCS field\r
461 buf[payload_len + RPC_UART_HDR_LEN] = calcFcs(\r
462 &buf[RPC_UART_FRAME_START_IDX], payload_len + RPC_HDR_LEN);\r
463 \r
464 #ifdef HAL_UART_IP\r
465 // No SOF or FCS\r
466 rpcTransportWrite(buf+1, payload_len + RPC_HDR_LEN + RPC_UART_FCS_LEN);\r
467 #else\r
468 // send out RPC message\r
469 rpcTransportWrite(buf, payload_len + RPC_UART_HDR_LEN + RPC_UART_FCS_LEN);\r
470 #endif\r
471 \r
472 // print out message to be sent\r
473 printRpcMsg("SOC OUT -->", buf[0], payload_len, &buf[2]);\r
474 \r
475 // wait for SRSP if necessary\r
476 if ((cmd0 & MT_RPC_CMD_TYPE_MASK) == MT_RPC_CMD_SREQ)\r
477 {\r
478 // calculate timeout\r
479 struct timespec srspTimeOut =\r
480 { time(0) + (SRSP_TIMEOUT_MS / 1000), (long) ((long) SRSP_TIMEOUT_MS\r
481 % 1000) * 1000000 };\r
482 \r
483 dbg_print(PRINT_LEVEL_INFO, "rpcSendFrame: waiting for SRSP [%02x]\n",\r
484 expectedSrspCmdId);\r
485 \r
486 //Wait for the SRSP\r
487 status = sem_timedwait(&srspSem, &srspTimeOut);\r
488 if (status == -1)\r
489 {\r
490 dbg_print(PRINT_LEVEL_WARNING, "rpcSendFrame: SRSP Error - %x\n",\r
491 expectedSrspCmdId);\r
492 status = MT_RPC_ERR_SUBSYSTEM;\r
493 }\r
494 else\r
495 {\r
496 dbg_print(PRINT_LEVEL_INFO, "rpcSendFrame: Receive SRSP\n");\r
497 status = MT_RPC_SUCCESS;\r
498 }\r
499 \r
500 //set expected SRSP to invalid\r
501 expectedSrspCmdId = 0xFF;\r
502 }\r
503 \r
504 //Unlock RPC sem\r
505 sem_post(&rpcSem);\r
506 \r
507 return status;\r
508 }\r
509 \r
510 /*********************************************************************\r
511 * LOCAL FUNCTIONS\r
512 */\r
513 \r
514 /*********************************************************************\r
515 * @fn calcFcs\r
516 *\r
517 * @brief calculate the FCS (Frame Check Sequence) of the RPC payload.\r
518 *\r
519 * @param msg - pointer to the RPC general format frame message\r
520 * @param size - RPC general format frame size\r
521 *\r
522 * @return FCS value\r
523 */\r
524 static uint8_t calcFcs(uint8_t *msg, uint8_t size)\r
525 {\r
526 uint8_t result = 0;\r
527 \r
528 // calculate FCS by XORing all bytes\r
529 while (size--)\r
530 {\r
531 result ^= *msg++;\r
532 }\r
533 \r
534 return result;\r
535 }\r
536 \r
537 /*********************************************************************\r
538 * @fn printRpcMsg\r
539 *\r
540 * @brief print out RPC message\r
541 *\r
542 * @param preMsg - initial string\r
543 * @param sof - SOF (Start of Frame) bytes\r
544 * @param len - length byte\r
545 * @param msg - pointer to the RPC message starting from Cmd0 byte\r
546 *\r
547 * @return FCS value\r
548 */\r
549 static void printRpcMsg(char* preMsg, uint8_t sof, uint8_t len, uint8_t *msg)\r
550 {\r
551 uint8_t i;\r
552 \r
553 // print headers\r
554 dbg_print(PRINT_LEVEL_INFO_LOWLEVEL,\r
555 "%s %d Bytes: SOF:%02X, Len:%02X, CMD0:%02X, CMD1:%02X, Payload:",\r
556 preMsg, len + 5, sof, len, msg[0], msg[1]);\r
557 \r
558 // print frame payload\r
559 for (i = 2; i < len + 2; i++)\r
560 {\r
561 dbg_print(PRINT_LEVEL_INFO_LOWLEVEL, "%02X%s", msg[i],\r
562 i < (len + 2 - 1) ? ":" : ",");\r
563 }\r
564 \r
565 // print FCS\r
566 dbg_print(PRINT_LEVEL_INFO_LOWLEVEL, " FCS:%02X\n", msg[i]);\r
567 \r
568 }\r