1 /* -------------------------------------------------------------------------- */
2 /* Copyright 2021-2024 NXP */
3 /* All rights reserved. */
4 /* SPDX-License-Identifier: BSD-3-Clause */
5 /* -------------------------------------------------------------------------- */
6
7 /* -------------------------------------------------------------------------- */
8 /* Includes */
9 /* -------------------------------------------------------------------------- */
10
11 #include <stdint.h>
12 #include <stdbool.h>
13
14 #include "fwk_platform_coex.h"
15 #include "fwk_platform_ble.h"
16 #include "fwk_platform_hdlc.h"
17 #include "fwk_platform_ot.h"
18 #include "fsl_adapter_rfimu.h"
19 #include "fsl_adapter_rpmsg.h"
20 #include "fsl_os_abstraction.h"
21
22 /* -------------------------------------------------------------------------- */
23 /* Private macros */
24 /* -------------------------------------------------------------------------- */
25
26 #ifndef PLATFORM_HDLC_RPMSG_LOCAL_ADDR
27 #define PLATFORM_HDLC_RPMSG_LOCAL_ADDR 10
28 #endif
29
30 #ifndef PLATFORM_HDLC_RPMSG_REMOTE_ADDR
31 #define PLATFORM_HDLC_RPMSG_REMOTE_ADDR 20
32 #endif
33
34 #ifndef PLATFORM_HDLC_RPMSG_ALLOC_FAILED_DELAY_MS
35 #define PLATFORM_HDLC_RPMSG_ALLOC_FAILED_DELAY_MS 2U
36 #endif
37
38 #ifndef PLATFORM_HDLC_RPMSG_LINK_READY_CHECK_RETRY
39 #define PLATFORM_HDLC_RPMSG_LINK_READY_CHECK_RETRY 100
40 #endif
41
42 #ifndef PLATFORM_HDLC_RPMSG_LINK_READY_DELAY_MS
43 #define PLATFORM_HDLC_RPMSG_LINK_READY_DELAY_MS 100
44 #endif
45
46 /* -------------------------------------------------------------------------- */
47 /* Private types */
48 /* -------------------------------------------------------------------------- */
49
50 /* -------------------------------------------------------------------------- */
51 /* Private prototypes */
52 /* -------------------------------------------------------------------------- */
53
54 /*!
55 * \brief Initialize HDLC RPMSG channel
56 *
57 * \return int return status: >=0 for success, <0 for errors
58 */
59 static int PLATFORM_InitHdlcRpmsg(void);
60
61 /*!
62 * \brief Terminate HDLC RPMSG channel
63 *
64 * \return int return status: >=0 for success, <0 for errors
65 */
66 static int PLATFORM_TerminateHdlcRpmsg(void);
67
68 /*!
69 * \brief RPMSG Rx callback used to receive HDLC messages from Controller
70 *
71 * \param[in] param Usually NULL
72 * \param[in] data pointer to data buffer
73 * \param[in] len size of the data
74 * \return hal_rpmsg_return_status_t tells RPMSG to free or hold the buffer
75 */
76 static hal_rpmsg_return_status_t PLATFORM_HdlcRpmsgRxCallback(void *param, uint8_t *data, uint32_t len);
77
78 /*!
79 * \brief Checks if the IMU link is ready - used before sending a message
80 *
81 * \return true link is ready
82 * \return false link is not ready yet
83 */
84 static bool PLATFORM_IsHdlcLinkReady(void);
85
86 /* -------------------------------------------------------------------------- */
87 /* Private memory */
88 /* -------------------------------------------------------------------------- */
89
90 static platform_hdlc_rx_callback_t hdlcRxCallback;
91 static void * callbackParam = NULL;
92
93 static RPMSG_HANDLE_DEFINE(hdlcRpmsgHandle);
94 static const hal_rpmsg_config_t hdlcRpmsgConfig = {
95 .local_addr = PLATFORM_HDLC_RPMSG_LOCAL_ADDR,
96 .remote_addr = PLATFORM_HDLC_RPMSG_REMOTE_ADDR,
97 .imuLink = kIMU_LinkCpu2Cpu3,
98 .callback = PLATFORM_HdlcRpmsgRxCallback,
99 .param = NULL,
100 };
101
102 /* -------------------------------------------------------------------------- */
103 /* Public functions */
104 /* -------------------------------------------------------------------------- */
105
PLATFORM_InitHdlcInterface(platform_hdlc_rx_callback_t callback,void * param)106 int PLATFORM_InitHdlcInterface(platform_hdlc_rx_callback_t callback, void *param)
107 {
108 int ret = 0;
109
110 hdlcRxCallback = callback;
111 callbackParam = param;
112
113 do
114 {
115 /* RPMSG/IMU requires 15.4 controller to be started */
116 if (PLATFORM_InitOt() != 0)
117 {
118 ret = -1;
119 break;
120 }
121
122 /* Init RPMSG interface */
123 if (PLATFORM_InitHdlcRpmsg() != 0)
124 {
125 ret = -2;
126 break;
127 }
128 } while (false);
129
130 if (ret != 0)
131 {
132 hdlcRxCallback = NULL;
133 callbackParam = NULL;
134 }
135
136 return ret;
137 }
138
PLATFORM_TerminateHdlcInterface(void)139 int PLATFORM_TerminateHdlcInterface(void)
140 {
141 int ret = 0;
142
143 do
144 {
145 /* Make sure the controller is awake */
146 ret = PLATFORM_RequestBleWakeUp();
147 if (ret != 0)
148 {
149 ret = -1;
150 break;
151 }
152
153 if (HAL_ImuDeinit(kIMU_LinkCpu2Cpu3, 0) != kStatus_HAL_RpmsgSuccess)
154 {
155 ret = -2;
156 break;
157 }
158
159 if (PLATFORM_TerminateHdlcRpmsg() != 0)
160 {
161 ret = -3;
162 break;
163 }
164
165 if (PLATFORM_TerminateControllers((uint32_t)conn802_15_4_c) != 0)
166 {
167 ret = -4;
168 break;
169 }
170
171 /* Release the wake up request now */
172 ret = PLATFORM_ReleaseBleWakeUp();
173 if (ret != 0)
174 {
175 ret = -5;
176 break;
177 }
178 } while (false);
179
180 return ret;
181 }
182
PLATFORM_ResetHdlcInterface(void)183 int PLATFORM_ResetHdlcInterface(void)
184 {
185 int ret = 0;
186
187 /* Init RPMSG interface */
188 if (PLATFORM_InitHdlcRpmsg() != 0)
189 {
190 ret = -1;
191 }
192
193 return ret;
194 }
195
PLATFORM_SendHdlcMessage(uint8_t * msg,uint32_t len)196 int PLATFORM_SendHdlcMessage(uint8_t *msg, uint32_t len)
197 {
198 hal_rpmsg_status_t rpmsgStatus;
199 int ret = 0;
200 int hdlcLinkReadyRetry = 0;
201 uint32_t remainingBytes = len;
202 uint8_t * pMsg = msg;
203 uint8_t * pRpmsgBuffer = NULL;
204
205 do
206 {
207 /* Make sure the link is ready before sending a message */
208 while (PLATFORM_IsHdlcLinkReady() == false)
209 {
210 if (hdlcLinkReadyRetry >= PLATFORM_HDLC_RPMSG_LINK_READY_CHECK_RETRY)
211 {
212 ret = -1;
213 break;
214 }
215 hdlcLinkReadyRetry++;
216 OSA_TimeDelay(PLATFORM_HDLC_RPMSG_LINK_READY_DELAY_MS);
217 }
218
219 if (ret != 0)
220 {
221 break;
222 }
223
224 (void)PLATFORM_RequestBleWakeUp();
225
226 /* Send HDLC Packet through RPMSG channel
227 * If the size if larger than the maximum RPMSG buffer size, we have to send chunks of the packet */
228 while (remainingBytes > 0)
229 {
230 uint32_t sizeToSend;
231
232 if (remainingBytes > RPMSG_TXQ23_BUFLENGTH)
233 {
234 sizeToSend = RPMSG_TXQ23_BUFLENGTH;
235 }
236 else
237 {
238 sizeToSend = remainingBytes;
239 }
240
241 /* Allocate a RPMSG buffer in shared memory */
242 pRpmsgBuffer = HAL_RpmsgAllocTxBuffer(hdlcRpmsgHandle, sizeToSend);
243 assert(pRpmsgBuffer != NULL);
244
245 /* Copy the message to the RPMSG buffer */
246 (void)memcpy(pRpmsgBuffer, pMsg, sizeToSend);
247
248 /* Send the message without any copy as it's already stored in the shared memory */
249 rpmsgStatus = HAL_RpmsgNoCopySend(hdlcRpmsgHandle, pRpmsgBuffer, sizeToSend);
250 if (rpmsgStatus != kStatus_HAL_RpmsgSuccess)
251 {
252 /* An error here means the IMU link is not ready yet, we can assert here as it shouldn't happen
253 * because we wait for the IMU link to be ready in PLATFORM_InitHdlcRpmsg() */
254 assert(0);
255 ret = -1;
256 break;
257 }
258
259 pMsg += sizeToSend;
260 remainingBytes -= sizeToSend;
261 }
262
263 (void)PLATFORM_ReleaseBleWakeUp();
264
265 } while (false);
266
267 return ret;
268 }
269
270 /* -------------------------------------------------------------------------- */
271 /* Private functions */
272 /* -------------------------------------------------------------------------- */
273
PLATFORM_InitHdlcRpmsg(void)274 static int PLATFORM_InitHdlcRpmsg(void)
275 {
276 hal_rpmsg_status_t rpmsgStatus;
277 int ret = 0;
278
279 do
280 {
281 /* Init RPMSG/IMU Channel */
282 rpmsgStatus = HAL_RpmsgInit((hal_rpmsg_handle_t)hdlcRpmsgHandle, (hal_rpmsg_config_t *)&hdlcRpmsgConfig);
283 if (rpmsgStatus != kStatus_HAL_RpmsgSuccess)
284 {
285 ret = -1;
286 break;
287 }
288 } while (false);
289
290 return ret;
291 }
292
PLATFORM_TerminateHdlcRpmsg(void)293 static int PLATFORM_TerminateHdlcRpmsg(void)
294 {
295 hal_rpmsg_status_t rpmsgStatus;
296 int ret = 0;
297
298 rpmsgStatus = HAL_RpmsgDeinit((hal_rpmsg_handle_t)hdlcRpmsgHandle);
299 if (rpmsgStatus != kStatus_HAL_RpmsgSuccess)
300 {
301 ret = -1;
302 }
303
304 return ret;
305 }
306
PLATFORM_HdlcRpmsgRxCallback(void * param,uint8_t * data,uint32_t len)307 static hal_rpmsg_return_status_t PLATFORM_HdlcRpmsgRxCallback(void *param, uint8_t *data, uint32_t len)
308 {
309 (void)PLATFORM_HandleControllerPowerState();
310
311 if (hdlcRxCallback != NULL)
312 {
313 hdlcRxCallback(data, len, callbackParam);
314 }
315
316 return kStatus_HAL_RL_RELEASE;
317 }
318
PLATFORM_IsHdlcLinkReady(void)319 static bool PLATFORM_IsHdlcLinkReady(void)
320 {
321 return (HAL_ImuLinkIsUp(hdlcRpmsgConfig.imuLink) == kStatus_HAL_RpmsgSuccess);
322 }
323