1 /* -------------------------------------------------------------------------- */
2 /* Copyright 2021-2023 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_hdlc.h"
15 #include "fsl_component_serial_manager.h"
16 #include "board.h"
17 #include "fwk_platform_coex.h"
18
19 /* -------------------------------------------------------------------------- */
20 /* Private macros */
21 /* -------------------------------------------------------------------------- */
22
23 #ifndef SPINEL_UART_INSTANCE
24 #define SPINEL_UART_INSTANCE 3
25 #endif
26 #ifndef SPINEL_ENABLE_RX_RTS
27 #define SPINEL_ENABLE_RX_RTS 1
28 #endif
29 #ifndef SPINEL_ENABLE_TX_RTS
30 #define SPINEL_ENABLE_TX_RTS 1
31 #endif
32
33 #ifndef SPINEL_UART_BAUD_RATE
34 #define SPINEL_UART_BAUD_RATE 1000000
35 #endif
36
37 #ifndef SPINEL_UART_CLOCK_RATE
38 #define SPINEL_UART_CLOCK_RATE BOARD_BT_UART_CLK_FREQ
39 #endif
40
41 #define SPINEL_HDLC_MALLOC pvPortMalloc
42 #define SPINEL_HDLC_FREE vPortFree
43
44 /* -------------------------------------------------------------------------- */
45 /* Private types */
46 /* -------------------------------------------------------------------------- */
47
48 enum
49 {
50 /* Ring buffer size should be >= to the RCP max TX buffer size value which is 2048 */
51 kMaxRingBufferSize = 2048,
52 };
53
54 /* -------------------------------------------------------------------------- */
55 /* Private memory */
56 /* -------------------------------------------------------------------------- */
57
58 static SERIAL_MANAGER_HANDLE_DEFINE(otTransceiverSerialHandle);
59 static SERIAL_MANAGER_READ_HANDLE_DEFINE(otTransceiverSerialReadHandle);
60
61 static uint8_t s_ringBuffer[kMaxRingBufferSize];
62
63 static platform_hdlc_rx_callback_t hdlcRxCallback;
64 static void * callbackParam = NULL;
65
66 #if (defined(HAL_UART_DMA_ENABLE) && (HAL_UART_DMA_ENABLE > 0U))
67 static serial_port_uart_dma_config_t uartConfig = {
68 #else
69 static serial_port_uart_config_t uartConfig = {
70 #endif
71 .baudRate = SPINEL_UART_BAUD_RATE,
72 .parityMode = kSerialManager_UartParityDisabled,
73 .stopBitCount = kSerialManager_UartOneStopBit,
74 .enableRx = 1,
75 .enableTx = 1,
76 .enableRxRTS = SPINEL_ENABLE_RX_RTS,
77 .enableTxCTS = SPINEL_ENABLE_TX_RTS,
78 .instance = SPINEL_UART_INSTANCE,
79 .txFifoWatermark = 0,
80 .rxFifoWatermark = 0,
81 };
82
83 static const serial_manager_config_t serialManagerConfig = {
84 .ringBuffer = &s_ringBuffer[0],
85 .ringBufferSize = sizeof(s_ringBuffer),
86 .type = kSerialPort_Uart,
87 .blockType = kSerialManager_NonBlocking,
88 .portConfig = (serial_port_uart_config_t *)&uartConfig,
89 };
90
91 static bool hdlcUartInitialized = false;
92
93 /* -------------------------------------------------------------------------- */
94 /* Private prototypes */
95 /* -------------------------------------------------------------------------- */
96
97 int PLATFORM_InitHdlcUart(void);
98 static int PLATFORM_TerminateHdlcUart(void);
99 static void PLATFORM_HdlcSerialManagerTxCallback(void * pData,
100 serial_manager_callback_message_t *message,
101 serial_manager_status_t status);
102 static void PLATFORM_HdlcSerialManagerRxCallback(void * pData,
103 serial_manager_callback_message_t *message,
104 serial_manager_status_t status);
105
106 /* -------------------------------------------------------------------------- */
107 /* Public functions */
108 /* -------------------------------------------------------------------------- */
109
PLATFORM_InitHdlcInterface(platform_hdlc_rx_callback_t callback,void * param)110 int PLATFORM_InitHdlcInterface(platform_hdlc_rx_callback_t callback, void *param)
111 {
112 int ret = 0;
113
114 hdlcRxCallback = callback;
115 callbackParam = param;
116
117 do
118 {
119 /* Init controllers
120 * The hdlc interface will be initialized at the end of the controller initialization
121 * and before doing a reset.
122 */
123 if (PLATFORM_InitControllers(conn802_15_4_c) != 0)
124 {
125 ret = -1;
126 break;
127 }
128 if (PLATFORM_InitHdlcUart() != 0)
129 {
130 ret = -1;
131 break;
132 }
133 } while (false);
134
135 if (ret < 0)
136 {
137 hdlcRxCallback = NULL;
138 callbackParam = NULL;
139 }
140
141 return ret;
142 }
143
PLATFORM_TerminateHdlcInterface(void)144 int PLATFORM_TerminateHdlcInterface(void)
145 {
146 int ret = 0;
147
148 hdlcRxCallback = NULL;
149 callbackParam = NULL;
150
151 if (PLATFORM_TerminateHdlcUart() != 0)
152 {
153 ret = -1;
154 }
155
156 return ret;
157 }
158
PLATFORM_SendHdlcMessage(uint8_t * msg,uint32_t len)159 int PLATFORM_SendHdlcMessage(uint8_t *msg, uint32_t len)
160 {
161 serial_manager_status_t serialManagerStatus;
162 uint8_t * pWriteHandleAndFrame = NULL;
163 uint8_t * pNewFrameBuffer = NULL;
164 int ret = 0;
165
166 /* Disable IRQs to prevent concurrent accesses to class fields or
167 * serial manager global variables that could be accessed in the
168 * Write function
169 */
170 OSA_InterruptDisable();
171
172 do
173 {
174 pWriteHandleAndFrame = (uint8_t *)SPINEL_HDLC_MALLOC(SERIAL_MANAGER_WRITE_HANDLE_SIZE + len);
175 if (pWriteHandleAndFrame == NULL)
176 {
177 ret = -1;
178 break;
179 }
180
181 pNewFrameBuffer = pWriteHandleAndFrame + SERIAL_MANAGER_WRITE_HANDLE_SIZE;
182 memcpy(pNewFrameBuffer, msg, len);
183
184 serialManagerStatus = SerialManager_OpenWriteHandle((serial_handle_t)otTransceiverSerialHandle,
185 (serial_write_handle_t)pWriteHandleAndFrame);
186 if (serialManagerStatus != kStatus_SerialManager_Success)
187 {
188 ret = -2;
189 break;
190 }
191
192 serialManagerStatus = SerialManager_InstallTxCallback(
193 (serial_write_handle_t)pWriteHandleAndFrame, PLATFORM_HdlcSerialManagerTxCallback, pWriteHandleAndFrame);
194 if (serialManagerStatus != kStatus_SerialManager_Success)
195 {
196 ret = -3;
197 break;
198 }
199
200 serialManagerStatus =
201 SerialManager_WriteNonBlocking((serial_write_handle_t)pWriteHandleAndFrame, pNewFrameBuffer, len);
202 if (serialManagerStatus != kStatus_SerialManager_Success)
203 {
204 ret = -4;
205 break;
206 }
207 } while (false);
208
209 if (ret != 0)
210 {
211 SPINEL_HDLC_FREE(pWriteHandleAndFrame);
212 }
213
214 OSA_InterruptEnable();
215
216 return ret;
217 }
218
PLATFORM_InitHdlcUart(void)219 int PLATFORM_InitHdlcUart(void)
220 {
221 serial_manager_status_t status;
222 int ret = 0;
223
224 /*
225 * Make sure to disable interrupts while initializating the serial manager interface
226 * Some issues could happen a UART IRQ is fired during serial manager initialization
227 */
228 OSA_InterruptDisable();
229 do
230 {
231 if (hdlcUartInitialized)
232 break;
233 /* Retrieve the UART clock rate at runtime as it can depend on clock config */
234 uartConfig.clockRate = SPINEL_UART_CLOCK_RATE;
235
236 status = SerialManager_Init((serial_handle_t)otTransceiverSerialHandle, &serialManagerConfig);
237 if (status != kStatus_SerialManager_Success)
238 {
239 ret = -1;
240 break;
241 }
242
243 status = SerialManager_OpenReadHandle((serial_handle_t)otTransceiverSerialHandle,
244 (serial_read_handle_t)otTransceiverSerialReadHandle);
245 if (status != kStatus_SerialManager_Success)
246 {
247 ret = -2;
248 break;
249 }
250
251 status = SerialManager_InstallRxCallback((serial_read_handle_t)otTransceiverSerialReadHandle,
252 PLATFORM_HdlcSerialManagerRxCallback, NULL);
253 if (status != kStatus_SerialManager_Success)
254 {
255 ret = -3;
256 break;
257 }
258 hdlcUartInitialized = true;
259 } while (false);
260 OSA_InterruptEnable();
261 assert(status == kStatus_SerialManager_Success);
262
263 return ret;
264 }
265
266 /* -------------------------------------------------------------------------- */
267 /* Private functions */
268 /* -------------------------------------------------------------------------- */
269
PLATFORM_TerminateHdlcUart(void)270 static int PLATFORM_TerminateHdlcUart(void)
271 {
272 serial_manager_status_t status;
273 int ret = 0;
274
275 do
276 {
277 if (!hdlcUartInitialized)
278 break;
279 status = SerialManager_CloseReadHandle((serial_read_handle_t)otTransceiverSerialReadHandle);
280 if (status != kStatus_SerialManager_Success)
281 {
282 ret = -1;
283 break;
284 }
285
286 status = SerialManager_Deinit((serial_handle_t)otTransceiverSerialHandle);
287 if (status != kStatus_SerialManager_Success)
288 {
289 ret = -2;
290 break;
291 }
292 hdlcUartInitialized = false;
293 } while (false);
294
295 return ret;
296 }
297
PLATFORM_HdlcSerialManagerTxCallback(void * pData,serial_manager_callback_message_t * message,serial_manager_status_t status)298 static void PLATFORM_HdlcSerialManagerTxCallback(void * pData,
299 serial_manager_callback_message_t *message,
300 serial_manager_status_t status)
301 {
302 OSA_InterruptDisable();
303 /* Close the write handle */
304 SerialManager_CloseWriteHandle((serial_write_handle_t)pData);
305 OSA_InterruptEnable();
306 /* Free the buffer */
307 SPINEL_HDLC_FREE(pData);
308 }
309
PLATFORM_HdlcSerialManagerRxCallback(void * param,serial_manager_callback_message_t * message,serial_manager_status_t status)310 static void PLATFORM_HdlcSerialManagerRxCallback(void * param,
311 serial_manager_callback_message_t *message,
312 serial_manager_status_t status)
313 {
314 uint8_t mUartRxBuffer[256];
315 uint32_t bytesRead = 0U;
316 serial_manager_status_t smStatus;
317
318 do
319 {
320 OSA_InterruptDisable();
321 smStatus = SerialManager_TryRead((serial_read_handle_t)otTransceiverSerialReadHandle, mUartRxBuffer,
322 sizeof(mUartRxBuffer), &bytesRead);
323 OSA_InterruptEnable();
324
325 if ((hdlcRxCallback != NULL) && (bytesRead > 0U) && (smStatus == kStatus_SerialManager_Success))
326 {
327 hdlcRxCallback(mUartRxBuffer, bytesRead, callbackParam);
328 }
329 } while (bytesRead != 0U);
330 }
331