1 /*
2 * Copyright 2019 NXP
3 * All rights reserved.
4 *
5 * SPDX-License-Identifier: BSD-3-Clause
6 */
7
8 #include "tfa_device_hal.h"
9 #include "usb.h"
10 #include "usb_device_descriptor.h"
11
12 /*******************************************************************************
13 * Variables
14 *******************************************************************************/
15 tfa_hal_msg_status_t g_TfaDeviceMessageStatus = {.msgComplete = 0, .totalSend = 0};
16
17 /*******************************************************************************
18 * Code
19 ******************************************************************************/
20
21 /*!
22 * @brief Collect a message chuck into a internal buffer.
23 *
24 * @param handle TFA9XXX handle structure.
25 * @param chunk The message chunk.
26 * @param length Length of the message to be collected.
27 * @return uint8_t returns 1 when a complete message is collected, returns 0 when there is still remaining to be
28 * collected.
29 */
TFA_Hal_CollectMsg(tfa9xxx_handle_t * handle,uint8_t * chunk,uint32_t length)30 uint8_t TFA_Hal_CollectMsg(tfa9xxx_handle_t *handle, uint8_t *chunk, uint32_t length)
31 {
32 static uint8_t rcvBuffer[TFA_BUFFERSIZE];
33 struct _tfa_hal_msg *msg = (struct _tfa_hal_msg *)rcvBuffer;
34 static uint32_t totalRcv = 0;
35 uint8_t *prcv = &rcvBuffer[totalRcv];
36
37 if (length > USB_HID_GENERIC_OUT_BUFFER_LENGTH)
38 return 0;
39
40 // collect msg chunks
41 memcpy(prcv, chunk, length);
42 totalRcv += length;
43 prcv += length;
44 if (totalRcv < sizeof(struct _tfa_hal_msg))
45 {
46 // TODO validate msg here
47 // get the rest, if needed
48 return 0;
49 }
50 else if (totalRcv < sizeof(struct _tfa_hal_msg) + msg->wlength)
51 {
52 return 0;
53 }
54 else
55 {
56 memcpy(g_TfaDeviceMessageStatus.sndBuffer, msg, totalRcv);
57 TFA_Hal_ProcessMsg(handle, msg, g_TfaDeviceMessageStatus.sndBuffer);
58 totalRcv = 0;
59 g_TfaDeviceMessageStatus.totalSend = USB_HID_GENERIC_OUT_BUFFER_LENGTH; // TODO errorcheck
60 g_TfaDeviceMessageStatus.msgComplete = 1;
61 return 1;
62 }
63
64 return 0;
65 }
66
67 /*!
68 * @brief Process the message collected.
69 *
70 * @param handle TFA9XXX handle structure.
71 * @param inBuffer Input message buffer.
72 * @param outBuffer Output (return) message buffer.
73 * @retval 0 Message is processed successfully.
74 * @retval EIO I2C error.
75 * @retval EINVAL Message CRC check failed or command inside the message is invalid.
76 */
TFA_Hal_ProcessMsg(tfa9xxx_handle_t * handle,void * inBuffer,void * outBuffer)77 int32_t TFA_Hal_ProcessMsg(tfa9xxx_handle_t *handle, void *inBuffer, void *outBuffer)
78 {
79 struct _tfa_hal_msg *msg = (struct _tfa_hal_msg *)inBuffer;
80 struct _tfa_hal_msg *rmsg = (struct _tfa_hal_msg *)outBuffer;
81 int32_t ret;
82 uint32_t msgSize;
83 uint8_t address = 0;
84
85 #ifdef TFA_HAL_DEBUG
86 TFA_Hal_DumpMsg(msg, 1);
87 #endif
88
89 /* crc32 check of arrived message, only a write message contains a payload */
90 msgSize = (int16_t)msg->wlength + sizeof(struct _tfa_hal_msg);
91 ret = TFA_Hal_CheckMsgCRC(msg, msgSize);
92 memcpy(rmsg, msg, sizeof(struct _tfa_hal_msg));
93
94 if (ret >= 0)
95 {
96 switch (msg->cmd)
97 {
98 case TFA_HAL_MSG_I2C:
99 {
100 address = msg->data[0] >> 1;
101 uint8_t *in_buf = &msg->data[1];
102 size_t in_bytes = msg->wlength - 1;
103 uint8_t *out_buf = rmsg->data;
104 size_t out_bytes = rmsg->rlength;
105 ret = TFA_I2C_WriteReadRaw(handle, address, in_bytes, in_buf, out_bytes, out_buf) ? -EIO : 0;
106 }
107 break;
108 case TFA_HAL_MSG_VERSION:
109 break;
110 default:
111 /* Unsupported command */
112 ret = -EINVAL;
113 break;
114 }
115 }
116
117 /* set return message ID + server error code */
118 rmsg->cmd_lsb = 'r';
119 rmsg->error = ret;
120
121 /* add crc32 to outgoing message, only a read contains extra bytes */
122 msgSize = (int16_t)msg->rlength + sizeof(struct _tfa_hal_msg);
123
124 TFA_Hal_AddMsgCRC(rmsg, msgSize);
125
126 #ifdef TFA_HAL_DEBUG
127 TFA_Hal_DumpMsg(rmsg, 0);
128 #endif
129
130 return ret;
131 }
132
133 /*!
134 * @brief Get the length of the next message chunk for the device to sent. If the length is 0, it means the whole
135 * message has been sent.
136 *
137 * @param maxChunkLength Max length to be sent.
138 * @return uint32_t The length of next message chunk to be sent.
139 */
TFA_Hal_GetNextChunkLength(uint32_t maxChunkLength)140 uint32_t TFA_Hal_GetNextChunkLength(uint32_t maxChunkLength)
141 {
142 struct _tfa_hal_msg *rmsg = (struct _tfa_hal_msg *)(g_TfaDeviceMessageStatus.sndBuffer);
143 int32_t remaining = rmsg->rlength + sizeof(struct _tfa_hal_msg) - g_TfaDeviceMessageStatus.totalSend;
144 uint32_t chunkLength = remaining > maxChunkLength ? maxChunkLength : remaining;
145
146 if (chunkLength)
147 {
148 g_TfaDeviceMessageStatus.totalSend += chunkLength;
149 }
150 else
151 {
152 g_TfaDeviceMessageStatus.totalSend = 0; // done
153 }
154
155 // return max or the tail
156 return chunkLength;
157 }
158
159 /*!
160 * @brief I2C write read function. It's a wrapper over tfa9xxx driver I2C function.
161 *
162 * @param handle TFA9XXX handle structure.
163 * @param slave Slave address.
164 * @param wrLength Length of data to write.
165 * @param wrData Data to write.
166 * @param rdLength Length of data to read.
167 * @param rdData Pointer to read data buffer.
168 * @return int32_t It returns kStatus_Success if I2C operation finishes successfully. It returns negative value of
169 * _lpi2c_status error code if I2C operation fails.
170 */
TFA_I2C_WriteReadRaw(tfa9xxx_handle_t * handle,uint8_t slave,uint32_t wrLength,uint8_t * wrData,uint32_t rdLength,uint8_t * rdData)171 int32_t TFA_I2C_WriteReadRaw(
172 tfa9xxx_handle_t *handle, uint8_t slave, uint32_t wrLength, uint8_t *wrData, uint32_t rdLength, uint8_t *rdData)
173 {
174 struct i2c_client i2cClient = {
175 .addr = slave,
176 .hal = &(handle->i2cHandle),
177 };
178 return tfa2_i2c_write_read_raw(&i2cClient, wrLength, wrData, rdLength, rdData);
179 }
180
181 /*!
182 * @brief I2C write only function to control TFA. It's a wrapper over TFA_I2C_WriteReadRaw().
183 *
184 * @param handle TFA9XXX handle structure.
185 * @param slave Slave address
186 * @param length Length of data to write.
187 * @param data Data to write.
188 * @return int32_t
189 */
TFA_I2C_WriteRaw(tfa9xxx_handle_t * handle,uint8_t slave,uint32_t len,const uint8_t * data)190 int32_t TFA_I2C_WriteRaw(tfa9xxx_handle_t *handle, uint8_t slave, uint32_t len, const uint8_t *data)
191 {
192 return TFA_I2C_WriteReadRaw(handle, slave, len, (uint8_t *)data, 0, NULL);
193 }
194
195 /*!
196 * @brief Display the data in hex with certain length.
197 *
198 * @param str str to print
199 * @param data data to print
200 * @param length data size
201 */
TFA_Hal_DumpHex(char * str,uint8_t * data,uint32_t length)202 void TFA_Hal_DumpHex(char *str, uint8_t *data, uint32_t length)
203 {
204 int i;
205
206 if (str == NULL)
207 str = "";
208
209 TFA9XXX_Printf("%s [%d]:", str, length);
210 for (i = 0; i < length; i++)
211 {
212 TFA9XXX_Printf("%02x ", data[i]);
213 }
214 TFA9XXX_Printf("\n\r");
215 }
216
217 /*!
218 * @brief Display the contents of the message buffer.
219 *
220 * @param msg Message.
221 * @param rcv Received message or sent message.
222 */
TFA_Hal_DumpMsg(struct _tfa_hal_msg * msg,uint8_t rcv)223 void TFA_Hal_DumpMsg(struct _tfa_hal_msg *msg, uint8_t rcv)
224 {
225 /* header */
226 TFA9XXX_Printf(
227 "cmd(1) = %c, cmd_lsb(1) = 0x%x, seq(2) = %d, index(4) = %d, crc32(4) = 0x%x, error(2) = 0x%x, wlength(2) = "
228 "%d, rlength(2) = %d",
229 msg->cmd, msg->cmd_lsb, msg->seq, msg->index, msg->crc32, msg->error, msg->wlength, msg->rlength);
230
231 /* data depends in rcv=write or sdn=read */
232 if (rcv)
233 TFA_Hal_DumpHex(", wdata", (uint8_t *)&msg->data, msg->wlength);
234 else
235 TFA_Hal_DumpHex(", rdata", (uint8_t *)&msg->data, msg->rlength);
236 TFA9XXX_Printf("\n");
237 }
238
TFA_Hal_CheckMsgCRC(struct _tfa_hal_msg * msg,uint32_t msgSize)239 int32_t TFA_Hal_CheckMsgCRC(struct _tfa_hal_msg *msg, uint32_t msgSize)
240 {
241 uint8_t *base;
242 uint32_t size;
243 uint32_t crc_in = 0;
244
245 /* store, calculate and compare crc32 */
246 crc_in = msg->crc32;
247 msg->crc32 = 0x0;
248 base = (uint8_t *)msg;
249 size = msgSize;
250
251 if (crc_in != ~crc32_le(~0u, base, size))
252 return -EINVAL; // EPROTO;
253
254 return 0;
255 }
256
257 /*!
258 * @brief Calculate CRC of the message and add it to the message structure.
259 *
260 * @param msg Message.
261 * @param msgSize Message size.
262 */
TFA_Hal_AddMsgCRC(struct _tfa_hal_msg * msg,uint32_t msgSize)263 void TFA_Hal_AddMsgCRC(struct _tfa_hal_msg *msg, uint32_t msgSize)
264 {
265 uint8_t *base;
266 uint32_t size;
267
268 msg->crc32 = 0x0;
269 base = (uint8_t *)msg;
270 size = msgSize;
271 msg->crc32 = ~crc32_le(~0u, base, size);
272
273 return;
274 }
275