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