ISSDK  1.8
IoT Sensing Software Development Kit
host_io_uart.c
Go to the documentation of this file.
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  ******************************************************************************/
42 
43 /*******************************************************************************
44  * Functions
45  ******************************************************************************/
46 /* Callback functions to handle incomming messages form the Host over UART. */
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. */
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  */
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 
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. */
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. */
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  */
208 {
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. */
256  pMsgResponse + HOST_DEV_LEN_STR_OFFSET, &dataLength,
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. */
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). */
292  (dataLength >= 3))
293  {
294  int32_t status = ARM_DRIVER_ERROR;
295  /* Fetch the slave bus handle using known Slave Address. */
297  if (process_host_command)
298  { /* Call the user callback to enable user pre-proces the register write payload (if required). */
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). */
330  (dataLength == 3))
331  {
332  int32_t status = ARM_DRIVER_ERROR;
333  /* Fetch the slave bus handle using known Slave Address. */
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). */
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. */
378  pMsgResponse + HOST_MSG_CMD_OPC_OFFSET, &dataLength,
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  {
400  }
401  else
402  {
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 }
uint32_t size
volatile bool bUartRxPendingMsg
Definition: host_io_uart.c:41
uint8_t getSlaveIndex(uint8_t slaveAddress)
Definition: host_io_uart.c:64
uint8_t Host_IO_Init(ARM_DRIVER_USART *pDrv, void *pBus, void *pDevInfo, void *spiSlaveParams, uint16_t slaveAddress)
Definition: host_io_uart.c:100
void Host_IO_Receive(host_cmd_proc_fn_t process_host_command, uint8_t encoding)
Definition: host_io_uart.c:207
#define HOST_PRO_CMD_WR_ACK_TAG
Definition: host_io_uart.h:70
int32_t status
#define HOST_PRO_CMD_R_REG_TAG
Definition: host_io_uart.h:66
int32_t Register_I2C_Read(ARM_DRIVER_I2C *pCommDrv, registerDeviceInfo_t *devInfo, uint16_t slaveAddress, uint8_t offset, uint8_t length, uint8_t *pOutBuffer)
The interface function to read a sensor register.
The host_io_uart.h file contains the Host Protocol interface definitions and configuration.
#define HOST_PRO_CMD_WR_NAK_TAG
Bit aligned values for Host Protocol Command Interface Status IDs (Bit 7).
Definition: host_io_uart.h:69
The register_io_spi.h file declares low-level interface functions for reading and writing sensor regi...
int32_t HOST_Initialize(host_interface_handle_t *pHandle, comm_type_t type, void *pCommInstance, comm_instance_type_t inType, Host_Event_t event, void *pInData)
The function to Initialize the Host.
#define HOST_INTERFACE_VERSION
uint8_t gUartRxBuff
Definition: host_io_uart.c:38
#define MAX_HOST_STREAMS
Definition: host_io_uart.h:30
void HOST_SignalEvent_t(uint32_t event)
Defines the HOST UART signal event handler.
Definition: host_io_uart.c:47
This structure holds information to receive a packet of data to the host.
Definition: host_io_uart.h:49
typedef int32_t(DATA_FORMAT_Append_t))(void *pData
The interface function to append the data on the formated stream.
uint8_t * pRxbuf
Definition: host_io_uart.h:53
The format_json.h file describes the structures and definitions for the data-format standard JSON...
The register_io_i2c.h file declares low-level interface functions for reading and writing sensor regi...
bool process_host_command(uint8_t tag, uint8_t *hostCommand, uint8_t *hostResponse, size_t *hostMsgSize, size_t respBufferSize)
bool HDLC_Process_Rx_Byte(uint8_t c, host_rx_packet_t *pHostRxPkt)
void Host_IO_Add_ISO_Header(uint8_t streamID, uint8_t *pStreamingPacket, size_t sizePayload)
Definition: host_io_uart.c:86
#define HOST_PRO_CMD_W_REG_TAG
Definition: host_io_uart.h:65
#define HOST_RX_BUF_LEN
Definition: host_io_uart.h:26
This structure holds information regarding the Encoding and RLI interface parameters.
Definition: host_io_uart.h:36
size_t HDLC_Process_Tx_Msg(const uint8_t *pBuffer, uint8_t *pMsg, size_t size)
int32_t HOST_Receive(host_interface_handle_t *pHandle, uint8_t *pData, uint32_t *pRecvSize, uint32_t size, BlockRead_t process)
The function to receive data from the host.
#define HOST_DEV_RSP_LEN
Definition: host_io_uart.h:28
uint8_t gHostRxBuff[HOST_RX_BUF_LEN]
Definition: host_io_uart.c:38
void Host_IO_Send(uint8_t *pMsg, size_t size, uint8_t encoding)
Definition: host_io_uart.c:136
uint32_t control
The data_format_hdlc.h file contains the Host interface definitions and configuration.
#define HOST_PRO_INT_DEV_TAG
Definition: host_io_uart.h:59
#define HOST_PRO_INT_ISO_TAG
Definition: host_io_uart.h:58
host_channel_params_t gHostChannelParams[MAX_HOST_STREAMS]
Definition: host_io_uart.c:40
int32_t HOST_Send(host_interface_handle_t *pHandle, uint8_t *pData, uint32_t size)
The function to Send the data to the host.
size_t JSON_Process_Tx_Msg(const uint8_t *pBuffer, uint8_t *pMsg, size_t size)
int32_t HOST_Configure(host_interface_handle_t *pHandle, void *pConfigData)
The function to Configure the Host.
comm_interface_t * pCommInterface
int32_t Register_SPI_BlockWrite(ARM_DRIVER_SPI *pCommDrv, registerDeviceInfo_t *devInfo, void *pWriteParams, uint8_t offset, const uint8_t *pBuffer, uint8_t bytesToWrite)
The interface function to block write to a sensor register.
int32_t Register_I2C_BlockWrite(ARM_DRIVER_I2C *pCommDrv, registerDeviceInfo_t *devInfo, uint16_t slaveAddress, uint8_t offset, const uint8_t *pBuffer, uint8_t bytesToWrite)
The interface function to write a sensor register.
bool JSON_Process_Rx_Byte(uint8_t c, host_rx_packet_t *pHostRxPkt)
Function to handle incomming JSON encoded bytes form the Host over UART.
volatile bool bUartTxComplete
Definition: host_io_uart.c:41
host_rx_packet_t gHostRxPkt
Definition: host_io_uart.c:39
#define HOST_CMD_RSP_LEN
Definition: host_io_uart.h:29
#define HOST_RSP_HDR_LEN
Definition: host_io_uart.h:27
#define HOST_PRO_INT_CMD_TAG
Bit aligned values for Host Protocol Interface IDs (Bits 5-6).
Definition: host_io_uart.h:57
int32_t Register_SPI_Read(ARM_DRIVER_SPI *pCommDrv, registerDeviceInfo_t *devInfo, void *pReadParams, uint8_t offset, uint8_t length, uint8_t *pOutBuffer)
The interface function to read a sensor register.
volatile bool bUartErrorMsg
Definition: host_io_uart.c:41
bool(* host_cmd_proc_fn_t)(uint8_t, uint8_t *, uint8_t *, size_t *, size_t)
The Host Command Process Function ([IN]Command TAG, [IN]Commad Buffer, [OUT]Response Buffer...
Definition: host_io_uart.h:46
host_interface_handle_t gHostHandle
Definition: host_io_uart.c:37