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