1 /**
2 ******************************************************************************
3 * @file shci.c
4 * @author MCD Application Team
5 * @brief System HCI command implementation
6 ******************************************************************************
7 * @attention
8 *
9 * <h2><center>© Copyright (c) 2019 STMicroelectronics.
10 * All rights reserved.</center></h2>
11 *
12 * This software component is licensed by ST under BSD 3-Clause license,
13 * the "License"; You may not use this file except in compliance with the
14 * License. You may obtain a copy of the License at:
15 * opensource.org/licenses/BSD-3-Clause
16 *
17 ******************************************************************************
18 */
19
20
21 /* Includes ------------------------------------------------------------------*/
22 #include "stm32_wpan_common.h"
23
24 #include "stm_list.h"
25 #include "shci_tl.h"
26
27
28 /* Private typedef -----------------------------------------------------------*/
29 /* Private defines -----------------------------------------------------------*/
30 /**
31 * The default System HCI layer timeout is set to 33s
32 */
33 #define SHCI_TL_DEFAULT_TIMEOUT (33000)
34
35 /* Private macros ------------------------------------------------------------*/
36 /* Public variables ---------------------------------------------------------*/
37 /* Private variables ---------------------------------------------------------*/
38 /**
39 * START of Section SYSTEM_DRIVER_CONTEXT
40 */
41 PLACE_IN_SECTION("SYSTEM_DRIVER_CONTEXT") static tListNode SHciAsynchEventQueue;
42 PLACE_IN_SECTION("SYSTEM_DRIVER_CONTEXT") static volatile SHCI_TL_CmdStatus_t SHCICmdStatus;
43 PLACE_IN_SECTION("SYSTEM_DRIVER_CONTEXT") static TL_CmdPacket_t *pCmdBuffer;
44 PLACE_IN_SECTION("SYSTEM_DRIVER_CONTEXT") SHCI_TL_UserEventFlowStatus_t SHCI_TL_UserEventFlow;
45 /**
46 * END of Section SYSTEM_DRIVER_CONTEXT
47 */
48
49 static tSHciContext shciContext;
50 static void (* StatusNotCallBackFunction) (SHCI_TL_CmdStatus_t status);
51
52 /* Private function prototypes -----------------------------------------------*/
53 static void Cmd_SetStatus(SHCI_TL_CmdStatus_t shcicmdstatus);
54 static void TlCmdEvtReceived(TL_EvtPacket_t *shcievt);
55 static void TlUserEvtReceived(TL_EvtPacket_t *shcievt);
56 static void TlInit( TL_CmdPacket_t * p_cmdbuffer );
57
58 /* Interface ------- ---------------------------------------------------------*/
shci_init(void (* UserEvtRx)(void * pData),void * pConf)59 void shci_init(void(* UserEvtRx)(void* pData), void* pConf)
60 {
61 StatusNotCallBackFunction = ((SHCI_TL_HciInitConf_t *)pConf)->StatusNotCallBack;
62 shciContext.UserEvtRx = UserEvtRx;
63
64 shci_register_io_bus (&shciContext.io);
65
66 TlInit((TL_CmdPacket_t *)(((SHCI_TL_HciInitConf_t *)pConf)->p_cmdbuffer));
67
68 return;
69 }
70
shci_user_evt_proc(void)71 void shci_user_evt_proc(void)
72 {
73 TL_EvtPacket_t *phcievtbuffer;
74 tSHCI_UserEvtRxParam UserEvtRxParam;
75
76 /**
77 * Up to release version v1.2.0, a while loop was implemented to read out events from the queue as long as
78 * it is not empty. However, in a bare metal implementation, this leads to calling in a "blocking" mode
79 * shci_user_evt_proc() as long as events are received without giving the opportunity to run other tasks
80 * in the background.
81 * From now, the events are reported one by one. When it is checked there is still an event pending in the queue,
82 * a request to the user is made to call again shci_user_evt_proc().
83 * This gives the opportunity to the application to run other background tasks between each event.
84 */
85
86 /**
87 * It is more secure to use LST_remove_head()/LST_insert_head() compare to LST_get_next_node()/LST_remove_node()
88 * in case the user overwrite the header where the next/prev pointers are located
89 */
90 if((LST_is_empty(&SHciAsynchEventQueue) == FALSE) && (SHCI_TL_UserEventFlow != SHCI_TL_UserEventFlow_Disable))
91 {
92 LST_remove_head ( &SHciAsynchEventQueue, (tListNode **)&phcievtbuffer );
93
94 SHCI_TL_UserEventFlow = SHCI_TL_UserEventFlow_Enable;
95
96 if (shciContext.UserEvtRx != NULL)
97 {
98 UserEvtRxParam.pckt = phcievtbuffer;
99 shciContext.UserEvtRx((void *)&UserEvtRxParam);
100 SHCI_TL_UserEventFlow = UserEvtRxParam.status;
101 }
102
103 if(SHCI_TL_UserEventFlow != SHCI_TL_UserEventFlow_Disable)
104 {
105 TL_MM_EvtDone( phcievtbuffer );
106 }
107 else
108 {
109 /**
110 * put back the event in the queue
111 */
112 LST_insert_head ( &SHciAsynchEventQueue, (tListNode *)phcievtbuffer );
113 }
114 }
115
116 if((LST_is_empty(&SHciAsynchEventQueue) == FALSE) && (SHCI_TL_UserEventFlow != SHCI_TL_UserEventFlow_Disable))
117 {
118 shci_notify_asynch_evt((void*) &SHciAsynchEventQueue);
119 }
120
121
122 return;
123 }
124
shci_resume_flow(void)125 void shci_resume_flow( void )
126 {
127 SHCI_TL_UserEventFlow = SHCI_TL_UserEventFlow_Enable;
128
129 /**
130 * It is better to go through the background process as it is not sure from which context this API may
131 * be called
132 */
133 shci_notify_asynch_evt((void*) &SHciAsynchEventQueue);
134
135 return;
136 }
137
shci_send(uint16_t cmd_code,uint8_t len_cmd_payload,uint8_t * p_cmd_payload,TL_EvtPacket_t * p_rsp)138 void shci_send( uint16_t cmd_code, uint8_t len_cmd_payload, uint8_t * p_cmd_payload, TL_EvtPacket_t * p_rsp )
139 {
140 Cmd_SetStatus(SHCI_TL_CmdBusy);
141
142 pCmdBuffer->cmdserial.cmd.cmdcode = cmd_code;
143 pCmdBuffer->cmdserial.cmd.plen = len_cmd_payload;
144
145 memcpy(pCmdBuffer->cmdserial.cmd.payload, p_cmd_payload, len_cmd_payload );
146
147 shciContext.io.Send(0,0);
148
149 shci_cmd_resp_wait(SHCI_TL_DEFAULT_TIMEOUT);
150
151 /**
152 * The command complete of a system command does not have the header
153 * It starts immediately with the evtserial field
154 */
155 memcpy( &(p_rsp->evtserial), pCmdBuffer, ((TL_EvtSerial_t*)pCmdBuffer)->evt.plen + TL_EVT_HDR_SIZE );
156
157 Cmd_SetStatus(SHCI_TL_CmdAvailable);
158
159 return;
160 }
161
162 /* Private functions ---------------------------------------------------------*/
TlInit(TL_CmdPacket_t * p_cmdbuffer)163 static void TlInit( TL_CmdPacket_t * p_cmdbuffer )
164 {
165 TL_SYS_InitConf_t Conf;
166
167 pCmdBuffer = p_cmdbuffer;
168
169 LST_init_head (&SHciAsynchEventQueue);
170
171 Cmd_SetStatus(SHCI_TL_CmdAvailable);
172
173 SHCI_TL_UserEventFlow = SHCI_TL_UserEventFlow_Enable;
174
175 /* Initialize low level driver */
176 if (shciContext.io.Init)
177 {
178
179 Conf.p_cmdbuffer = (uint8_t *)p_cmdbuffer;
180 Conf.IoBusCallBackCmdEvt = TlCmdEvtReceived;
181 Conf.IoBusCallBackUserEvt = TlUserEvtReceived;
182 shciContext.io.Init(&Conf);
183 }
184
185 return;
186 }
187
Cmd_SetStatus(SHCI_TL_CmdStatus_t shcicmdstatus)188 static void Cmd_SetStatus(SHCI_TL_CmdStatus_t shcicmdstatus)
189 {
190 if(shcicmdstatus == SHCI_TL_CmdBusy)
191 {
192 if(StatusNotCallBackFunction != 0)
193 {
194 StatusNotCallBackFunction( SHCI_TL_CmdBusy );
195 }
196 SHCICmdStatus = SHCI_TL_CmdBusy;
197 }
198 else
199 {
200 SHCICmdStatus = SHCI_TL_CmdAvailable;
201 if(StatusNotCallBackFunction != 0)
202 {
203 StatusNotCallBackFunction( SHCI_TL_CmdAvailable );
204 }
205 }
206
207 return;
208 }
209
TlCmdEvtReceived(TL_EvtPacket_t * shcievt)210 static void TlCmdEvtReceived(TL_EvtPacket_t *shcievt)
211 {
212 shci_cmd_resp_release(0); /**< Notify the application the Cmd response has been received */
213
214 return;
215 }
216
TlUserEvtReceived(TL_EvtPacket_t * shcievt)217 static void TlUserEvtReceived(TL_EvtPacket_t *shcievt)
218 {
219 LST_insert_tail(&SHciAsynchEventQueue, (tListNode *)shcievt);
220 shci_notify_asynch_evt((void*) &SHciAsynchEventQueue); /**< Notify the application a full HCI event has been received */
221
222 return;
223 }
224
225