88#if PBDRV_CONFIG_USB_STM32F4
99
1010#include <stdbool.h>
11+ #include <string.h>
1112
1213#include <contiki.h>
1314#include <stm32f4xx_hal.h>
1415#include <stm32f4xx_hal_pcd_ex.h>
1516#include <usbd_core.h>
17+ #include <usbd_desc.h>
18+ #include <usbd_pybricks.h>
1619
1720#include <pbdrv/usb.h>
1821#include <pbio/util.h>
22+ #include <pbsys/command.h>
23+ #include <pbsys/status.h>
1924
2025#include "../charger/charger.h"
2126#include "./usb_stm32.h"
2227
2328PROCESS (pbdrv_usb_process , "USB" );
2429
30+ // These buffers need to be 32-bit aligned because the USB driver moves data
31+ // to/from FIFOs in 32-bit chunks.
32+ static uint8_t usb_in_buf [USBD_PYBRICKS_MAX_PACKET_SIZE ] __aligned (4 );
33+ static volatile uint32_t usb_in_sz ;
34+
2535static USBD_HandleTypeDef husbd ;
2636static PCD_HandleTypeDef hpcd ;
37+
2738static volatile bool vbus_active ;
2839static pbdrv_usb_bcd_t pbdrv_usb_bcd ;
2940
@@ -121,14 +132,81 @@ void pbdrv_usb_stm32_handle_vbus_irq(bool active) {
121132 process_poll (& pbdrv_usb_process );
122133}
123134
135+ /**
136+ * @brief Pybricks_Itf_Init
137+ * Initializes the Pybricks media low layer
138+ * @param None
139+ * @retval Result of the operation: USBD_OK if all operations are OK else USBD_FAIL
140+ */
141+ static USBD_StatusTypeDef Pybricks_Itf_Init (void ) {
142+ USBD_Pybricks_SetRxBuffer (& husbd , usb_in_buf );
143+ usb_in_sz = 0 ;
144+
145+ return USBD_OK ;
146+ }
147+
148+ /**
149+ * @brief Pybricks_Itf_DeInit
150+ * DeInitializes the Pybricks media low layer
151+ * @param None
152+ * @retval Result of the operation: USBD_OK if all operations are OK else USBD_FAIL
153+ */
154+ static USBD_StatusTypeDef Pybricks_Itf_DeInit (void ) {
155+ return USBD_OK ;
156+ }
157+
158+ /**
159+ * @brief Pybricks_Itf_DataRx
160+ * Data received over USB OUT endpoint are sent over Pybricks interface
161+ * through this function.
162+ * @param Buf: Buffer of data to be transmitted
163+ * @param Len: Number of data received (in bytes)
164+ * @retval Result of the operation: USBD_OK if all operations are OK else USBD_FAIL
165+ */
166+ static USBD_StatusTypeDef Pybricks_Itf_Receive (uint8_t * Buf , uint32_t Len ) {
167+
168+ usb_in_sz = Len ;
169+ process_poll (& pbdrv_usb_process );
170+ return USBD_OK ;
171+ }
172+
173+ /**
174+ * @brief Pybricks_Itf_TransmitCplt
175+ * Data transmitted callback
176+ *
177+ * @note
178+ * This function is IN transfer complete callback used to inform user that
179+ * the submitted Data is successfully sent over USB.
180+ *
181+ * @param Buf: Buffer of data that was transmitted
182+ * @param Len: Number of data transmitted (in bytes)
183+ * @retval Result of the operation: USBD_OK if all operations are OK else USBD_FAIL
184+ */
185+ static USBD_StatusTypeDef Pybricks_Itf_TransmitCplt (uint8_t * Buf , uint32_t Len , uint8_t epnum ) {
186+ process_poll (& pbdrv_usb_process );
187+ return USBD_OK ;
188+ }
189+
190+ static USBD_Pybricks_ItfTypeDef USBD_Pybricks_fops = {
191+ .Init = Pybricks_Itf_Init ,
192+ .DeInit = Pybricks_Itf_DeInit ,
193+ .Receive = Pybricks_Itf_Receive ,
194+ .TransmitCplt = Pybricks_Itf_TransmitCplt ,
195+ };
196+
124197// Common USB driver implementation.
125198
126199void pbdrv_usb_init (void ) {
127200 // Link the driver data structures
128201 husbd .pData = & hpcd ;
129202 hpcd .pData = & husbd ;
130203
131- USBD_Init (& husbd , NULL , 0 );
204+ USBD_Pybricks_Desc_Init ();
205+ USBD_Init (& husbd , & USBD_Pybricks_Desc , 0 );
206+ USBD_RegisterClass (& husbd , & USBD_Pybricks_ClassDriver );
207+ USBD_Pybricks_RegisterInterface (& husbd , & USBD_Pybricks_fops );
208+ USBD_Start (& husbd );
209+
132210 process_start (& pbdrv_usb_process );
133211
134212 // VBUS may already be active
@@ -145,6 +223,7 @@ PROCESS_THREAD(pbdrv_usb_process, ev, data) {
145223 static struct pt bcd_pt ;
146224 static PBIO_ONESHOT (no_vbus_oneshot );
147225 static PBIO_ONESHOT (bcd_oneshot );
226+ static PBIO_ONESHOT (pwrdn_oneshot );
148227 static bool bcd_busy ;
149228
150229 PROCESS_POLLHANDLER ({
@@ -169,6 +248,34 @@ PROCESS_THREAD(pbdrv_usb_process, ev, data) {
169248
170249 if (bcd_busy ) {
171250 bcd_busy = PT_SCHEDULE (pbdrv_usb_stm32_bcd_detect (& bcd_pt ));
251+
252+ if (bcd_busy ) {
253+ // All other USB functions are halted if BCD is busy
254+ continue ;
255+ }
256+ }
257+
258+ if (pbsys_status_test (PBIO_PYBRICKS_STATUS_SHUTDOWN )) {
259+ if (pbio_oneshot (true, & pwrdn_oneshot )) {
260+ USBD_Stop (& husbd );
261+ USBD_DeInit (& husbd );
262+ }
263+
264+ // USB communication is stopped after a shutdown, but
265+ // the process is still needed to track the BCD state
266+ continue ;
267+ }
268+
269+ if (usb_in_sz ) {
270+ switch (usb_in_buf [0 ]) {
271+ case USBD_PYBRICKS_OUT_EP_MSG_COMMAND :
272+ pbsys_command (usb_in_buf + 1 , usb_in_sz - 1 );
273+ break ;
274+ }
275+
276+ // Prepare to receive the next packet
277+ usb_in_sz = 0 ;
278+ USBD_Pybricks_ReceivePacket (& husbd );
172279 }
173280 }
174281
0 commit comments