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