|
8 | 8 | #if PBDRV_CONFIG_USB_STM32F4 |
9 | 9 |
|
10 | 10 | #include <stdbool.h> |
| 11 | +#include <string.h> |
11 | 12 |
|
12 | 13 | #include <contiki.h> |
13 | 14 | #include <stm32f4xx_hal.h> |
14 | 15 | #include <stm32f4xx_hal_pcd_ex.h> |
15 | 16 | #include <usbd_core.h> |
| 17 | +#include <usbd_pybricks.h> |
16 | 18 |
|
17 | 19 | #include <pbdrv/usb.h> |
18 | 20 | #include <pbio/util.h> |
| 21 | +#include <pbsys/command.h> |
19 | 22 |
|
20 | 23 | #include "../charger/charger.h" |
21 | 24 | #include "./usb_stm32.h" |
22 | 25 |
|
| 26 | +#define UUID_SZ (128 / 8) |
| 27 | + |
23 | 28 | PROCESS(pbdrv_usb_process, "USB"); |
24 | 29 |
|
| 30 | +static uint8_t usb_in_buf[USBD_PYBRICKS_MAX_PACKET_SIZE]; |
| 31 | +static uint8_t usb_out_buf[USBD_PYBRICKS_MAX_PACKET_SIZE]; |
| 32 | +static volatile uint32_t usb_in_sz; |
| 33 | +static volatile uint32_t usb_out_sz; |
| 34 | + |
25 | 35 | static USBD_HandleTypeDef husbd; |
26 | 36 | static PCD_HandleTypeDef hpcd; |
| 37 | + |
27 | 38 | static volatile bool vbus_active; |
28 | 39 | static pbdrv_usb_bcd_t pbdrv_usb_bcd; |
29 | 40 |
|
@@ -121,14 +132,87 @@ void pbdrv_usb_stm32_handle_vbus_irq(bool active) { |
121 | 132 | process_poll(&pbdrv_usb_process); |
122 | 133 | } |
123 | 134 |
|
| 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 int8_t Pybricks_Itf_Init(void) { |
| 142 | + USBD_Pybricks_SetTxBuffer(&husbd, usb_out_buf, sizeof(usb_out_buf)); |
| 143 | + USBD_Pybricks_SetRxBuffer(&husbd, usb_in_buf); |
| 144 | + usb_in_sz = 0; |
| 145 | + usb_out_sz = 0; |
| 146 | + |
| 147 | + return USBD_OK; |
| 148 | +} |
| 149 | + |
| 150 | +/** |
| 151 | + * @brief Pybricks_Itf_DeInit |
| 152 | + * DeInitializes the Pybricks media low layer |
| 153 | + * @param None |
| 154 | + * @retval Result of the operation: USBD_OK if all operations are OK else USBD_FAIL |
| 155 | + */ |
| 156 | +static int8_t Pybricks_Itf_DeInit(void) { |
| 157 | + return USBD_OK; |
| 158 | +} |
| 159 | + |
| 160 | +/** |
| 161 | + * @brief Pybricks_Itf_DataRx |
| 162 | + * Data received over USB OUT endpoint are sent over CDC interface |
| 163 | + * through this function. |
| 164 | + * @param Buf: Buffer of data to be transmitted |
| 165 | + * @param Len: Number of data received (in bytes) |
| 166 | + * @retval Result of the operation: USBD_OK if all operations are OK else USBD_FAIL |
| 167 | + */ |
| 168 | +static int8_t Pybricks_Itf_Receive(uint8_t *Buf, uint32_t *Len) { |
| 169 | + if (*Len > sizeof(usb_in_buf)) { |
| 170 | + return USBD_FAIL; |
| 171 | + } |
| 172 | + |
| 173 | + memcpy(usb_in_buf, Buf, *Len); |
| 174 | + usb_in_sz = *Len; |
| 175 | + process_poll(&pbdrv_usb_process); |
| 176 | + return USBD_OK; |
| 177 | +} |
| 178 | + |
| 179 | +/** |
| 180 | + * @brief Pybricks_Itf_TransmitCplt |
| 181 | + * Data transmitted callback |
| 182 | + * |
| 183 | + * @note |
| 184 | + * This function is IN transfer complete callback used to inform user that |
| 185 | + * the submitted Data is successfully sent over USB. |
| 186 | + * |
| 187 | + * @param Buf: Buffer of data to be received |
| 188 | + * @param Len: Number of data received (in bytes) |
| 189 | + * @retval Result of the operation: USBD_OK if all operations are OK else USBD_FAIL |
| 190 | + */ |
| 191 | +static int8_t Pybricks_Itf_TransmitCplt(uint8_t *Buf, uint32_t *Len, uint8_t epnum) { |
| 192 | + usb_out_sz = 0; |
| 193 | + process_poll(&pbdrv_usb_process); |
| 194 | + return USBD_OK; |
| 195 | +} |
| 196 | + |
| 197 | +static USBD_Pybricks_ItfTypeDef USBD_Pybricks_fops = { |
| 198 | + .Init = Pybricks_Itf_Init, |
| 199 | + .DeInit = Pybricks_Itf_DeInit, |
| 200 | + .Receive = Pybricks_Itf_Receive, |
| 201 | + .TransmitCplt = Pybricks_Itf_TransmitCplt, |
| 202 | +}; |
| 203 | + |
124 | 204 | // Common USB driver implementation. |
125 | 205 |
|
126 | 206 | void pbdrv_usb_init(void) { |
127 | 207 | // Link the driver data structures |
128 | 208 | husbd.pData = &hpcd; |
129 | 209 | hpcd.pData = &husbd; |
130 | 210 |
|
131 | | - USBD_Init(&husbd, NULL, 0); |
| 211 | + USBD_Init(&husbd, &Pybricks_Desc, 0); |
| 212 | + USBD_RegisterClass(&husbd, &USBD_Pybricks_ClassDriver); |
| 213 | + USBD_Pybricks_RegisterInterface(&husbd, &USBD_Pybricks_fops); |
| 214 | + USBD_Start(&husbd); |
| 215 | + |
132 | 216 | process_start(&pbdrv_usb_process); |
133 | 217 |
|
134 | 218 | // VBUS may already be active |
@@ -164,12 +248,27 @@ PROCESS_THREAD(pbdrv_usb_process, ev, data) { |
164 | 248 |
|
165 | 249 | PROCESS_BEGIN(); |
166 | 250 |
|
| 251 | + // Prepare to receive the first packet |
| 252 | + USBD_Pybricks_ReceivePacket(&husbd); |
| 253 | + |
167 | 254 | for (;;) { |
168 | 255 | PROCESS_WAIT_EVENT(); |
169 | 256 |
|
170 | 257 | if (bcd_busy) { |
171 | 258 | bcd_busy = PT_SCHEDULE(pbdrv_usb_stm32_bcd_detect(&bcd_pt)); |
172 | 259 | } |
| 260 | + |
| 261 | + if (usb_in_sz) { |
| 262 | + if ((usb_in_sz >= UUID_SZ) && |
| 263 | + pbio_uuid128_le_compare(usb_in_buf, pbio_pybricks_command_event_char_uuid)) { |
| 264 | + pbsys_command(usb_in_buf + UUID_SZ, usb_in_sz - UUID_SZ); |
| 265 | + } |
| 266 | + |
| 267 | + usb_in_sz = 0; |
| 268 | + |
| 269 | + // Prepare to receive the next packet |
| 270 | + USBD_Pybricks_ReceivePacket(&husbd); |
| 271 | + } |
173 | 272 | } |
174 | 273 |
|
175 | 274 | PROCESS_END(); |
|
0 commit comments