1 /*
2  * Copyright (c) 2016, Freescale Semiconductor, Inc.
3  * Copyright 2016-2017 NXP
4  * All rights reserved.
5  *
6  * SPDX-License-Identifier: BSD-3-Clause
7  */
8 
9 /**
10  * @file host_io_uart.c
11  * @brief The host_io_uart.c file contains definitions for UART based streaming interface
12  * for sending and reseiving messages to and from Host using ISSDK Host Protocol.
13  */
14 
15 /*******************************************************************************
16  * Standard C Includes
17  ******************************************************************************/
18 #include <stdlib.h>
19 
20 /*******************************************************************************
21  * SDK Includes
22  ******************************************************************************/
23 #include "fsl_common.h"
24 
25 /*******************************************************************************
26  * ISSDK Includes
27  ******************************************************************************/
28 #include "host_io_uart.h"
29 #include "register_io_i2c.h"
30 #include "register_io_spi.h"
31 #include "data_format_hdlc.h"
32 #include "data_format_json.h"
33 
34 /*******************************************************************************
35  * Global Variables
36  ******************************************************************************/
37 host_interface_handle_t gHostHandle = {0};
38 uint8_t gUartRxBuff, gHostRxBuff[HOST_RX_BUF_LEN];
39 host_rx_packet_t gHostRxPkt = {.pRxbuf = gHostRxBuff};
40 host_channel_params_t gHostChannelParams[MAX_HOST_STREAMS];
41 volatile bool bUartTxComplete, bUartRxPendingMsg, bUartErrorMsg;
42 
43 /*******************************************************************************
44  * Functions
45  ******************************************************************************/
46 /* Callback functions to handle incomming messages form the Host over UART. */
HOST_SignalEvent_t(uint32_t event)47 void HOST_SignalEvent_t(uint32_t event)
48 {
49     switch (event)
50     {
51         case ARM_USART_EVENT_RECEIVE_COMPLETE:
52             bUartRxPendingMsg = true;
53             break;
54         case ARM_USART_EVENT_SEND_COMPLETE:
55             bUartTxComplete = true;
56             break;
57         default:
58             bUartErrorMsg = true;
59             break;
60     }
61 }
62 
63 /* Function to lookup slave handle. */
getSlaveIndex(uint8_t slaveAddress)64 uint8_t getSlaveIndex(uint8_t slaveAddress)
65 {
66     for (uint8_t stream = 0; stream < MAX_HOST_STREAMS; stream++)
67     {
68         if (gHostChannelParams[stream].slaveAddress == slaveAddress)
69         {
70             return stream;
71         }
72     }
73 
74     /* If Address in not recognised, default to the first stream. */
75     return 0;
76 }
77 
78 /* Function to populate Streaming Packet Header.
79  * Outgoing  Iso Packet Format: (As per ISSDK Host Protocol Definition)
80  * Byte 0 : (Start Byte) HDLC Frame START MARKER. (Will be added by HDLC_Process_Tx_Msg())
81  * Byte 1 : Frame TAG (Interface)
82  * Byte 2 : Length    (Payload Length)
83  * Byte 3+: Payload   (Depending upon sensor sample length + 1 for Stream ID)
84  * Byte E : (End Byte) HDLC Frame STOP MARKER. (Will be added by HDLC_Process_Tx_Msg())
85  */
Host_IO_Add_ISO_Header(uint8_t streamID,uint8_t * pStreamingPacket,size_t sizePayload)86 void Host_IO_Add_ISO_Header(uint8_t streamID, uint8_t *pStreamingPacket, size_t sizePayload)
87 {
88     if (pStreamingPacket == NULL)
89     {
90         return;
91     }
92 
93     pStreamingPacket[HOST_MSG_HDR_TAG_OFFSET] = HOST_PRO_INT_ISO_TAG;
94     pStreamingPacket[HOST_ISO_LEN_MSB_OFFSET] = (sizePayload + 1) >> 8;     /* Size of Sample + Stream ID */
95     pStreamingPacket[HOST_ISO_LEN_LSB_OFFSET] = (sizePayload + 1) & 0x00FF; /* Size of Sample + Stream ID */
96     pStreamingPacket[HOST_ISO_PAYLOAD_OFFSET] = streamID;
97 }
98 
99 /* Function to get Stream ID, set Encoding and configure RLI related parameters. */
Host_IO_Init(ARM_DRIVER_USART * pDrv,void * pBus,void * pDevInfo,void * spiSlaveParams,uint16_t slaveAddress)100 uint8_t Host_IO_Init(ARM_DRIVER_USART *pDrv, void *pBus, void *pDevInfo, void *spiSlaveParams, uint16_t slaveAddress)
101 {
102     static uint8_t streamID = 0;
103 
104     /* Configure the UART callback if not already configured. */
105     if (gHostHandle.pCommInterface == NULL)
106     {
107         HOST_Initialize(&gHostHandle, COMM_UART, (void *)pDrv, COMM_NONBLOCKING, HOST_SignalEvent_t, NULL);
108         do /* Flush RX buffer. */
109         {
110             bUartRxPendingMsg = false;
111             HOST_Receive(&gHostHandle, &gUartRxBuff, NULL, 1, NULL);
112         } while (bUartRxPendingMsg);
113         bUartTxComplete = true; /* Reset TX Flag. */
114         bUartErrorMsg = false;  /* Reset Error Flag. */
115     }
116 
117     /* Host has to be accesible by 1 UART interface for all subscriptions
118      * and Number of streams less than MAX. */
119     if (gHostHandle.commHandle.pComm != pDrv || streamID == MAX_HOST_STREAMS)
120     {
121         return 0;
122     }
123 
124     /* Save the I2C/SPI Bus handle. */
125     gHostChannelParams[streamID].pCommDrv = pBus;
126     gHostChannelParams[streamID].deviceInfo = pDevInfo;
127     gHostChannelParams[streamID].slaveAddress = slaveAddress;
128 
129     /* If device type is I2C, Slave Handle will be NULL. */
130     gHostChannelParams[streamID].pSPIparams = spiSlaveParams;
131 
132     return ++streamID;
133 }
134 
135 /* Function to send bytes to Host over UART. */
Host_IO_Send(uint8_t * pMsg,size_t size,uint8_t encoding)136 void Host_IO_Send(uint8_t *pMsg, size_t size, uint8_t encoding)
137 {
138     size_t encodedSize = 0;
139     static uint8_t *pMsgEncoded = NULL;
140 
141     while (bUartTxComplete == false)
142     {
143         __NOP(); /* Wait if the previous Tx is still Pending. */
144     }
145     free(pMsgEncoded);
146 
147     switch (encoding)
148     {
149         case HOST_FORMAT_HDLC:
150             pMsgEncoded = malloc(size * 2); /* Allocate 2x the size to compensate for escape characters. */
151             encodedSize = HDLC_Process_Tx_Msg(pMsg, pMsgEncoded, size); /* Get the Encoded Message. */
152             break;
153         case HOST_FORMAT_JSON:
154             pMsgEncoded = malloc(size * 4); /* Allocate 4x the size to compensate for string character encoding. */
155             encodedSize = JSON_Process_Tx_Msg(pMsg, pMsgEncoded, size); /* Get the Encoded Message. */
156             break;
157         case HOST_FORMAT_PLAIN:
158         default:
159             pMsgEncoded = malloc(size);
160             memcpy(pMsgEncoded, pMsg, size);
161             encodedSize = size;
162             break;
163     }
164 
165     /* Send message to Host. */
166     bUartTxComplete = false;
167     HOST_Send(&gHostHandle, pMsgEncoded, encodedSize);
168 }
169 
170 /*  Function to check Rx and process received bytes and (re)enable UART Rx.
171  *  Command Types Supported :
172  *  1) Write App Data - Start/Stop Streaming.
173  *  2) Write Register Data - Register Address and Value.
174  *  3) Read Register Data - Start Address and Number of Bytes.
175  *  4) Read Device Info - Return Major/Minor + Board and Shield Names.
176  *
177  * Incoming Message Format (Host Commands): (As per ISSDK Host Protocol Definition)
178  * Byte 0 : Frame TAG   (Interface|Command)
179  * Byte 1 : Sequence ID (Random Txn Identifier)
180  * Byte 2 : Length MSB  (Payload Length MSB)
181  * Byte 3 : Length LSB  (Payload Length LSB)
182  * Byte 4+: Payload
183  *
184  * Outgoing Respone Format (Host Commands): (As per ISSDK Host Protocol Definition)
185  * Byte 0 : Frame TAG   (Status|Interface|Command)
186  * Byte 1 : Sequence ID (Random Txn Identifier)
187  * Byte 2 : Length MSB  (Payload Length MSB)
188  * Byte 3 : Length LSB  (Payload Length LSB)
189  * Byte 4+: Payload (Optional, depending upon requested operation)
190  *
191  * Incoming Message Format (ISO Command): (As per ISSDK Host Protocol Definition)
192  * Byte 0 : Frame TAG   (Interface)
193  * Byte 1 : Length MSB  (Payload Length MSB)
194  * Byte 2 : Length LSB  (Payload Length LSB)
195  * Byte 3+: Payload
196  *
197  * Incoming Message Format (Device Info): (As per ISSDK Host Protocol Definition)
198  * Byte 0 : Frame TAG   (Interface)
199  *
200  * Outgoing Respone Format (Device Info): (As per ISSDK Host Protocol Definition)
201  * Byte 0 : Frame TAG   (Interface)
202  * Byte 1 : Version ID  (ISSDK : Major | Minor Numbers)
203  * Byte 2 : Length of Board Name (Optional : populated by user callback)
204  * Byte 3 : Length of Shield Name (Optional : populated by user callback)
205  * Byte 4+: Payload (Board Name + Board Name) (Optional : populated by user callback)
206  */
Host_IO_Receive(host_cmd_proc_fn_t process_host_command,uint8_t encoding)207 void Host_IO_Receive(host_cmd_proc_fn_t process_host_command, uint8_t encoding)
208 {
209     uint8_t responseTag = gHostRxBuff[HOST_MSG_HDR_TAG_OFFSET] & HOST_PRO_CMD_WR_NAK_TAG;
210     comm_control_t rxAbort = {.control = ARM_USART_ABORT_RECEIVE, .arg = 0};
211     size_t dataLength, responseSize = HOST_RSP_HDR_LEN;
212     bool bCmdSuccess = false, bMessageReceived = false;
213     uint8_t *pMsgResponse = NULL;
214 
215     /* If error flag is set ABORT and RESTART transaction. */
216     if (bUartErrorMsg)
217     {
218         bUartErrorMsg = false;
219         bUartRxPendingMsg = false;
220         HOST_Configure(&gHostHandle, &rxAbort);
221         HOST_Receive(&gHostHandle, &gUartRxBuff, NULL, 1, NULL);
222     }
223 
224     if (bUartRxPendingMsg)
225     {
226         switch (encoding)
227         {
228             case HOST_FORMAT_HDLC:
229                 bMessageReceived = HDLC_Process_Rx_Byte(gUartRxBuff, &gHostRxPkt);
230                 break;
231             case HOST_FORMAT_JSON:
232                 bMessageReceived = JSON_Process_Rx_Byte(gUartRxBuff, &gHostRxPkt);
233                 break;
234             default:
235                 break;
236         }
237 
238         bUartErrorMsg = false;
239         bUartRxPendingMsg = false;
240         HOST_Receive(&gHostHandle, &gUartRxBuff, NULL, 1, NULL);
241     }
242 
243     if (bMessageReceived)
244     {
245         do
246         {
247             dataLength = gHostRxPkt.mIndex;
248             /* Check if it is a 1-byte Device Info Message from Host. */
249             if ((gHostRxBuff[HOST_MSG_HDR_TAG_OFFSET] & HOST_PRO_INT_DEV_TAG) && (dataLength == 1))
250             { /* Allocate memory for response packet for this command and populate the payload. */
251                 pMsgResponse = malloc(HOST_DEV_RSP_LEN);
252                 dataLength = 0; /* Incoming Payload is Zero. */
253                 if (process_host_command)
254                 { /* Call the user callback to proces the user specific payload. */
255                     bCmdSuccess = process_host_command(gHostRxBuff[HOST_MSG_HDR_TAG_OFFSET], NULL,
256                                                        pMsgResponse + HOST_DEV_LEN_STR_OFFSET, &dataLength,
257                                                        HOST_DEV_RSP_LEN - HOST_DEV_LEN_STR_OFFSET);
258                 }
259                 if (bCmdSuccess == false)
260                 {
261                     dataLength = 0;
262                 }
263 
264                 responseTag = HOST_PRO_INT_DEV_TAG;
265                 responseSize = HOST_DEV_LEN_STR_OFFSET + dataLength;
266                 break;
267             }
268             dataLength = (((uint16_t)gHostRxBuff[HOST_ISO_LEN_MSB_OFFSET] << 8) | gHostRxBuff[HOST_ISO_LEN_LSB_OFFSET]);
269             /* Check if it is an ISO Message from Host and has > 0 Byte payload. */
270             if ((gHostRxBuff[HOST_MSG_HDR_TAG_OFFSET] & HOST_PRO_INT_ISO_TAG) && (dataLength > 0))
271             {
272                 if (dataLength == (gHostRxPkt.mIndex - HOST_ISO_PAYLOAD_OFFSET) && process_host_command)
273                 { /* Call the user callback to proces the user specific payload if packet integrity is valid. */
274                     process_host_command(gHostRxBuff[HOST_MSG_HDR_TAG_OFFSET], gHostRxBuff + HOST_ISO_PAYLOAD_OFFSET,
275                                          NULL, /* No buffer since no response for ISO Messages. */
276                                          &dataLength, 0);
277                 }
278                 return; /* No response for ISO Messages. */
279             }
280 
281             dataLength = (((uint16_t)gHostRxBuff[HOST_MSG_LEN_MSB_OFFSET] << 8) | gHostRxBuff[HOST_MSG_LEN_LSB_OFFSET]);
282             if (dataLength != (gHostRxPkt.mIndex - HOST_MSG_CMD_OPC_OFFSET)) /* Ensure packet integrity */
283             {
284                 return; /* Drop corrupted and duplicate packets */
285             }
286             /* Allocate memory for response packet for this command. */
287             pMsgResponse = malloc(responseSize);
288 
289             /* Check if it is a Command from Host to Write Register Data and has 3+ Byte payload (SlaveAddress,
290              * RegisterAddress and ValuesToWrite). */
291             if ((gHostRxBuff[HOST_MSG_HDR_TAG_OFFSET] == (HOST_PRO_INT_CMD_TAG | HOST_PRO_CMD_W_REG_TAG)) &&
292                 (dataLength >= 3))
293             {
294                 int32_t status = ARM_DRIVER_ERROR;
295                 /* Fetch the slave bus handle using known Slave Address. */
296                 uint8_t deviceID = getSlaveIndex(gHostRxBuff[HOST_MSG_CMD_SLAVE_ADDR_OFFSET]);
297                 if (process_host_command)
298                 { /* Call the user callback to enable user pre-proces the register write payload (if required). */
299                     process_host_command(gHostRxBuff[HOST_MSG_HDR_TAG_OFFSET],
300                                          gHostRxBuff + HOST_MSG_CMD_SLAVE_ADDR_OFFSET, NULL, &dataLength, 0);
301                 }
302                 /* Confirm payload has enough number of bytes to write. */
303                 if (gHostChannelParams[deviceID].pCommDrv &&
304                     gHostRxPkt.mIndex - HOST_MSG_CMD_SLAVE_ADDR_OFFSET >= dataLength)
305                 {
306                     if (gHostChannelParams[deviceID].pSPIparams)
307                     {
308                         status = Register_SPI_BlockWrite(
309                             gHostChannelParams[deviceID].pCommDrv, gHostChannelParams[deviceID].deviceInfo,
310                             gHostChannelParams[deviceID].pSPIparams, gHostRxBuff[HOST_MSG_CMD_REGIS_ADDR_OFFSET],
311                             gHostRxBuff + HOST_MSG_CMD_VALUE_OFFSET, dataLength - 2);
312                     }
313                     else
314                     {
315                         status = Register_I2C_BlockWrite(
316                             gHostChannelParams[deviceID].pCommDrv, gHostChannelParams[deviceID].deviceInfo,
317                             gHostRxBuff[HOST_MSG_CMD_SLAVE_ADDR_OFFSET], gHostRxBuff[HOST_MSG_CMD_REGIS_ADDR_OFFSET],
318                             gHostRxBuff + HOST_MSG_CMD_VALUE_OFFSET, dataLength - 2);
319                     }
320                 }
321                 if (ARM_DRIVER_OK == status)
322                 {
323                     responseTag |= HOST_PRO_CMD_WR_ACK_TAG;
324                 }
325                 break;
326             }
327             /* Check if it is a Command from Host to Read Register Data and has 3 Byte payload (SlaveAddress,
328              * RegisterAddress and BytesToRead). */
329             if ((gHostRxBuff[HOST_MSG_HDR_TAG_OFFSET] == (HOST_PRO_INT_CMD_TAG | HOST_PRO_CMD_R_REG_TAG)) &&
330                 (dataLength == 3))
331             {
332                 int32_t status = ARM_DRIVER_ERROR;
333                 /* Fetch the slave bus handle using known Slave Address. */
334                 uint8_t deviceID = getSlaveIndex(gHostRxBuff[HOST_MSG_CMD_SLAVE_ADDR_OFFSET]);
335                 /* Allocate memory as per updated size of response packet for this command. */
336                 free(pMsgResponse);
337                 pMsgResponse = malloc(responseSize + gHostRxBuff[HOST_MSG_CMD_LENGTH_OFFSET]);
338                 if (gHostChannelParams[deviceID].pCommDrv)
339                 {
340                     if (gHostChannelParams[deviceID].pSPIparams)
341                     {
342                         status = Register_SPI_Read(
343                             gHostChannelParams[deviceID].pCommDrv, gHostChannelParams[deviceID].deviceInfo,
344                             gHostChannelParams[deviceID].pSPIparams, gHostRxBuff[HOST_MSG_CMD_REGIS_ADDR_OFFSET],
345                             gHostRxBuff[HOST_MSG_CMD_LENGTH_OFFSET], pMsgResponse + responseSize);
346                     }
347                     else
348                     {
349                         status = Register_I2C_Read(
350                             gHostChannelParams[deviceID].pCommDrv, gHostChannelParams[deviceID].deviceInfo,
351                             gHostRxBuff[HOST_MSG_CMD_SLAVE_ADDR_OFFSET], gHostRxBuff[HOST_MSG_CMD_REGIS_ADDR_OFFSET],
352                             gHostRxBuff[HOST_MSG_CMD_LENGTH_OFFSET], pMsgResponse + responseSize);
353                     }
354                 }
355                 if (process_host_command)
356                 { /* Call the user callback to enable user post-process the register read payload (if required). */
357                     process_host_command(gHostRxBuff[HOST_MSG_HDR_TAG_OFFSET],
358                                          gHostRxBuff + HOST_MSG_CMD_SLAVE_ADDR_OFFSET, pMsgResponse + responseSize,
359                                          &dataLength, gHostRxBuff[HOST_MSG_CMD_LENGTH_OFFSET]);
360                 }
361                 if (ARM_DRIVER_OK == status)
362                 {
363                     responseTag |= HOST_PRO_CMD_WR_ACK_TAG;
364                     responseSize += gHostRxBuff[HOST_MSG_CMD_LENGTH_OFFSET];
365                 }
366                 break;
367             }
368             /* Check if it is a Command from Host for Read/Write Configuration or User defined and has > 0 Byte payload.
369              */
370             if ((gHostRxBuff[HOST_MSG_HDR_TAG_OFFSET] & HOST_PRO_INT_CMD_TAG) && (dataLength > 0))
371             { /* Allocate memory for max possible response packet size for this command and populate the payload. */
372                 free(pMsgResponse);
373                 pMsgResponse = malloc(HOST_CMD_RSP_LEN);
374                 if (process_host_command)
375                 { /* Call the user callback to proces the user specific payload. */
376                     bCmdSuccess = process_host_command(gHostRxBuff[HOST_MSG_HDR_TAG_OFFSET],
377                                                        gHostRxBuff + HOST_MSG_CMD_OPC_OFFSET,
378                                                        pMsgResponse + HOST_MSG_CMD_OPC_OFFSET, &dataLength,
379                                                        HOST_CMD_RSP_LEN - HOST_MSG_CMD_OPC_OFFSET);
380                 }
381                 if (bCmdSuccess)
382                 {
383                     responseTag |= HOST_PRO_CMD_WR_ACK_TAG;
384                 }
385                 else
386                 {
387                     dataLength = 0;
388                 }
389 
390                 responseSize = HOST_MSG_CMD_OPC_OFFSET + dataLength;
391                 break;
392             }
393         } while (false);
394 
395         /* Populate the response packet header. */
396         pMsgResponse[HOST_MSG_HDR_TAG_OFFSET] = responseTag;
397         if (responseTag == HOST_PRO_INT_DEV_TAG)
398         {
399             pMsgResponse[HOST_DEV_HDR_VER_OFFSET] = HOST_INTERFACE_VERSION;
400         }
401         else
402         {
403             pMsgResponse[HOST_MSG_HDR_SEQ_OFFSET] = gHostRxBuff[HOST_MSG_HDR_SEQ_OFFSET];
404             pMsgResponse[HOST_MSG_LEN_MSB_OFFSET] = (responseSize - HOST_RSP_HDR_LEN) >> 8;
405             pMsgResponse[HOST_MSG_LEN_LSB_OFFSET] = (responseSize - HOST_RSP_HDR_LEN) & 0xFF;
406         }
407 
408         /* Send response to Host. */
409         Host_IO_Send(pMsgResponse, responseSize, encoding);
410         free(pMsgResponse);
411     }
412 }
413