]> Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - znp-host-framework/znp-host-framework.git/blob - framework/rpcWindows/rpc.c
Added binaries, updated users guide, and added manifest
[znp-host-framework/znp-host-framework.git] / framework / rpcWindows / rpc.c
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
49 #include <fcntl.h>      // For O_* constants\r#include <errno.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
285 #ifndef HAL_UART_IP //No SOF for IP\r    //read first byte and check it is a SOF\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
301 #ifdef HAL_UART_IP //No FCS for IP\r                     //allocating RPC payload (+ cmd0, cmd1)\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