semf
stm32f4usbvcp.cpp
Go to the documentation of this file.
1
11
12#if defined(STM32F4) && defined(HAL_PCD_MODULE_ENABLED)
13#include <usbd_desc.h>
14#include <usbd_cdc_if.h>
15#include <algorithm>
16namespace semf
17{
18Stm32F4UsbVcp::CallbackList* Stm32F4UsbVcp::m_callbackList = nullptr;
19Stm32F4UsbVcp::Stm32F4UsbVcp(USBD_HandleTypeDef& usbHandle, uint8_t usbRxCache[], size_t usbRxCacheSize):
20 m_handle(&usbHandle), m_usbRxCache(usbRxCache), m_usbRxCacheSize(usbRxCacheSize)
21{
22 m_listMember.member = this;
23 m_listMember.next = nullptr;
24
25 if (m_callbackList == nullptr)
26 {
27 m_callbackList =&m_listMember;
28 }
29 else
30 {
31 CallbackList* curr = m_callbackList;
32 while (curr->next !=nullptr)
33 {
34 curr = curr->next;
35 }
36 curr->next = &m_listMember;
37 }
38}
39
40void Stm32F4UsbVcp::init()
41{
42 m_interfaceCallbackClass = USBD_CDC;
43
44 // replace some pointers
45 m_interfaceCallbackClass.Init = cdcInitCallback;
46 m_interfaceCallbackClass.DeInit = cdcDeInitCallback;
47 m_interfaceCallbackClass.DataIn = cdcTxCallback;
48 m_interfaceCallbackClass.DataOut = cdcRxCallback;
49 reinterpret_cast<USBD_CDC_ItfTypeDef *>(m_handle->pUserData)->Control = cdcControlCallback;
50
51 // stop if it is started to register the correct interfaces, it is recommended not to initiate it in the main.c
52 if (USBD_Stop(m_handle) != USBD_OK)
53 {
54 onError(Error(kSemfClassId, static_cast<uint8_t>(ErrorCode::Init_Stop)));
55 }
56 if (USBD_DeInit(m_handle) != USBD_OK)
57 {
58 onError(Error(kSemfClassId, static_cast<uint8_t>(ErrorCode::Init_Deinit)));
59 }
60 if (USBD_Init(m_handle, &FS_Desc, DEVICE_FS) != USBD_OK)
61 {
62 onError(Error(kSemfClassId, static_cast<uint8_t>(ErrorCode::Init_Init)));
63 }
64 if (USBD_RegisterClass(m_handle, &m_interfaceCallbackClass) != USBD_OK)
65 {
66 onError(Error(kSemfClassId, static_cast<uint8_t>(ErrorCode::Init_RegisterClass)));
67 }
68 if (USBD_CDC_RegisterInterface(m_handle, &USBD_Interface_fops_FS) != USBD_OK)
69 {
70 onError(Error(kSemfClassId, static_cast<uint8_t>(ErrorCode::Init_RegisterInterface)));
71 }
72 if (USBD_Start(m_handle) != USBD_OK)
73 {
74 onError(Error(kSemfClassId, static_cast<uint8_t>(ErrorCode::Init_Start)));
75 }
76}
77
78void Stm32F4UsbVcp::deinit()
79{
80 // TODO(AA) not implemented
81 return;
82}
83void Stm32F4UsbVcp::stopRead()
84{
85 // TODO(AA) not implemented
86 return;
87}
88void Stm32F4UsbVcp::stopWrite()
89{
90 // TODO(AA) not implemented
91 return;
92}
93
94void Stm32F4UsbVcp::setFormat(uint8_t bits, WireMode wire, Parity par, StopBits stop, FlowControl flow)
95{
96 // TODO(AA) not implemented
97 return;
98}
99
100void Stm32F4UsbVcp::setBaud(uint32_t baud)
101{
102 // TODO(AA) not implemented
103 return;
104}
105
106uint8_t Stm32F4UsbVcp::cdcInitCallback(USBD_HandleTypeDef* usb, uint8_t cfgidx)
107{
108 uint8_t ret = 0U;
109 USBD_CDC_HandleTypeDef *hcdc;
110
111 if (usb->dev_speed == USBD_SPEED_HIGH)
112 {
113 /* Open EP IN */
114 USBD_LL_OpenEP(usb, CDC_IN_EP, USBD_EP_TYPE_BULK,
115 CDC_DATA_HS_IN_PACKET_SIZE);
116
117 usb->ep_in[CDC_IN_EP & 0xFU].is_used = 1U;
118
119 /* Open EP OUT */
120 USBD_LL_OpenEP(usb, CDC_OUT_EP, USBD_EP_TYPE_BULK,
121 CDC_DATA_HS_OUT_PACKET_SIZE);
122
123 usb->ep_out[CDC_OUT_EP & 0xFU].is_used = 1U;
124 }
125 else
126 {
127 /* Open EP IN */
128 USBD_LL_OpenEP(usb, CDC_IN_EP, USBD_EP_TYPE_BULK,
129 CDC_DATA_FS_IN_PACKET_SIZE);
130
131 usb->ep_in[CDC_IN_EP & 0xFU].is_used = 1U;
132
133 /* Open EP OUT */
134 USBD_LL_OpenEP(usb, CDC_OUT_EP, USBD_EP_TYPE_BULK,
135 CDC_DATA_FS_OUT_PACKET_SIZE);
136
137 usb->ep_out[CDC_OUT_EP & 0xFU].is_used = 1U;
138 }
139 /* Open Command IN EP */
140 USBD_LL_OpenEP(usb, CDC_CMD_EP, USBD_EP_TYPE_INTR, CDC_CMD_PACKET_SIZE);
141 usb->ep_in[CDC_CMD_EP & 0xFU].is_used = 1U;
142
143 for(auto i = m_callbackList; i != nullptr; i = i->next)
144 {
145 if (i->member->m_handle == usb)
146 {
147 usb->pClassData = reinterpret_cast<void*>(&i->member->m_cdcHandle);
148 USBD_CDC_SetRxBuffer(i->member->m_handle, i->member->m_usbRxCache);
149 break;
150 }
151 }
152
153 if (usb->pClassData == NULL)
154 {
155 ret = 1U;
156 }
157 else
158 {
159 hcdc = reinterpret_cast<USBD_CDC_HandleTypeDef*>(usb->pClassData);
160
161 /* Init physical Interface components */
162 reinterpret_cast<USBD_CDC_ItfTypeDef *>(usb->pUserData)->Init();
163
164 CallbackList* curr = m_callbackList;
165 while(curr != nullptr)
166 {
167 curr->member->cdcInit(usb);
168 curr = curr->next;
169 }
170
171 /* Init Xfer states */
172 hcdc->TxState = 0U;
173 hcdc->RxState = 0U;
174
175 if (usb->dev_speed == USBD_SPEED_HIGH)
176 {
177 /* Prepare Out endpoint to receive next packet */
178 USBD_LL_PrepareReceive(usb, CDC_OUT_EP, hcdc->RxBuffer,
179 CDC_DATA_HS_OUT_PACKET_SIZE);
180 }
181 else
182 {
183 /* Prepare Out endpoint to receive next packet */
184 USBD_LL_PrepareReceive(usb, CDC_OUT_EP, hcdc->RxBuffer,
185 CDC_DATA_FS_OUT_PACKET_SIZE);
186 }
187 }
188 return ret;
189}
190
191uint8_t Stm32F4UsbVcp::cdcDeInitCallback(USBD_HandleTypeDef *usb, uint8_t cfgidx)
192{
193 /* Close EP IN */
194 USBD_LL_CloseEP(usb, CDC_IN_EP);
195 usb->ep_in[CDC_IN_EP & 0xFU].is_used = 0U;
196
197 /* Close EP OUT */
198 USBD_LL_CloseEP(usb, CDC_OUT_EP);
199 usb->ep_out[CDC_OUT_EP & 0xFU].is_used = 0U;
200
201 /* Close Command IN EP */
202 USBD_LL_CloseEP(usb, CDC_CMD_EP);
203 usb->ep_in[CDC_CMD_EP & 0xFU].is_used = 0U;
204
205 /* DeInit physical Interface components */
206 if(usb->pClassData != NULL)
207 {
208 (reinterpret_cast<USBD_CDC_ItfTypeDef*>(usb->pUserData))->DeInit();
209 usb->pClassData = NULL;
210 }
211
212 return 0;
213}
214
215uint8_t Stm32F4UsbVcp::cdcTxCallback(USBD_HandleTypeDef* usb, uint8_t epnum)
216{
217 uint8_t retVal = USBD_CDC.DataIn(usb, epnum);
218 if ( (retVal == USBD_OK) &&
219 ((reinterpret_cast<USBD_CDC_HandleTypeDef*>(usb->pClassData))->TxState == 0U)
220 )
221 {
222 CallbackList* curr = m_callbackList;
223 while(curr != nullptr)
224 {
225 curr->member->cdcTx(usb);
226 curr = curr->next;
227 }
228 }
229 return retVal;
230}
231
232uint8_t Stm32F4UsbVcp::cdcRxCallback(USBD_HandleTypeDef* usb, uint8_t epnum)
233{
234 CallbackList* curr = m_callbackList;
235 while(curr != nullptr)
236 {
237 curr->member->cdcRx(usb, epnum);
238
239 curr = curr->next;
240 }
241 return USBD_OK;
242}
243
244int8_t Stm32F4UsbVcp::cdcControlCallback(uint8_t cmd, uint8_t pbuf[], uint16_t size)
245{
246 CallbackList* curr = m_callbackList;
247 while(curr != nullptr)
248 {
249 curr->member->cdcControl(cmd, pbuf, size);
250 curr = curr->next;
251 }
252 return (USBD_OK);
253}
254
255void Stm32F4UsbVcp::cdcInit(USBD_HandleTypeDef* usb)
256{
257 if (m_handle == usb)
258 {
259 m_usbRxCacheWritePos = 0;
260 m_usbRxCacheReadPos = 0;
261 }
262}
263
264void Stm32F4UsbVcp::cdcTx(USBD_HandleTypeDef* usb)
265{
266 if (m_handle == usb)
267 {
268 onDataWritten();
269 }
270}
271
272void Stm32F4UsbVcp::cdcRx(USBD_HandleTypeDef* usb, uint8_t epnum)
273{
274 if (m_handle == usb)
275 {
276 size_t numOfRxData = USBD_LL_GetRxDataSize(usb, epnum);
277 if (numOfRxData > 0)
278 {
279 memcpy(&m_rxData[m_rxDataAvailable], &m_usbRxCache[m_usbRxCacheReadPos],
280 std::min(numOfRxData, m_rxDataSize - m_rxDataAvailable));
281 m_usbRxCacheReadPos += std::min(numOfRxData, m_rxDataSize - m_rxDataAvailable);
282 m_usbRxCacheWritePos += numOfRxData;
283 m_rxDataAvailable += std::min(numOfRxData, m_rxDataSize);
284 if (m_rxDataAvailable == m_rxDataSize)
285 onDataAvailable();
286 }
287
289 if(usb->dev_speed == USBD_SPEED_HIGH)
290 {
291 if (m_usbRxCacheSize < (m_usbRxCacheWritePos + CDC_DATA_HS_OUT_PACKET_SIZE))
292 {
293 m_usbRxCacheWritePos = 0;
294 m_usbRxCacheReadPos = 0;
295 }
296 }
297 else
298 {
299 if (m_usbRxCacheSize < (m_usbRxCacheWritePos + CDC_DATA_FS_OUT_PACKET_SIZE))
300 {
301 m_usbRxCacheWritePos = 0;
302 m_usbRxCacheReadPos = 0;
303 }
304 }
305
306 USBD_CDC_SetRxBuffer(m_handle, &m_usbRxCache[m_usbRxCacheWritePos]);
307 USBD_CDC_ReceivePacket(usb);
308 }
309}
310
311void Stm32F4UsbVcp::cdcControl(uint8_t cmd, uint8_t pbuf[], uint16_t size)
312{
313 switch (cmd)
314 {
315 case CDC_SEND_ENCAPSULATED_COMMAND:
316 break;
317 case CDC_GET_ENCAPSULATED_RESPONSE:
318 break;
319 case CDC_SET_COMM_FEATURE:
320 break;
321 case CDC_GET_COMM_FEATURE:
322 break;
323 case CDC_CLEAR_COMM_FEATURE:
324 break;
325 case CDC_SET_LINE_CODING:
326 m_lineCoding.bitrate = (uint32_t)(pbuf[0] | (pbuf[1] << 8) |\
327 (pbuf[2] << 16) | (pbuf[3] << 24));
328 m_lineCoding.format = pbuf[4];
329 m_lineCoding.paritytype = pbuf[5];
330 m_lineCoding.datatype = pbuf[6];
331 break;
332 case CDC_GET_LINE_CODING:
333 pbuf[0] = (uint8_t)(m_lineCoding.bitrate);
334 pbuf[1] = (uint8_t)(m_lineCoding.bitrate >> 8);
335 pbuf[2] = (uint8_t)(m_lineCoding.bitrate >> 16);
336 pbuf[3] = (uint8_t)(m_lineCoding.bitrate >> 24);
337 pbuf[4] = m_lineCoding.format;
338 pbuf[5] = m_lineCoding.paritytype;
339 pbuf[6] = m_lineCoding.datatype;
340 break;
341 case CDC_SET_CONTROL_LINE_STATE:
342 break;
343 case CDC_SEND_BREAK:
344 break;
345 default:
346 break;
347 }
348}
349
350void Stm32F4UsbVcp::writeHardware(const uint8_t data[], size_t size)
351{
352 // check if usb is connected
353 if (m_handle->dev_state == USBD_STATE_CONFIGURED)
354 {
355 if (CDC_Transmit_FS(const_cast<uint8_t*>(data), size) != USBD_OK)
356 {
357 // must called, while this is a uart simulation, and a uart has no connection state
358 onDataWritten();
359 }
360 }
361 else
362 {
363 // must called, while this is a uart simulation, and a uart has no connection state
364 onDataWritten();
365 }
366}
367
368void Stm32F4UsbVcp::readHardware(uint8_t data[], size_t size)
369{
370 m_rxData = data;
371 m_rxDataSize = size;
372 m_rxDataAvailable = 0;
373
374 if (m_usbRxCacheWritePos > m_usbRxCacheReadPos)
375 {
376 memcpy(m_rxData, &m_usbRxCache[m_usbRxCacheReadPos],
377 std::min(m_usbRxCacheWritePos - m_usbRxCacheReadPos, m_rxDataSize));
378 m_rxDataAvailable = std::min(m_usbRxCacheWritePos - m_usbRxCacheReadPos, m_rxDataSize);
379 m_usbRxCacheReadPos += std::min(m_usbRxCacheWritePos - m_usbRxCacheReadPos, m_rxDataSize);
380
381 if (m_rxDataAvailable == m_rxDataSize)
382 onDataAvailable();
383 }
384
385 if (m_usbRxCacheWritePos <= m_usbRxCacheReadPos)
386 {
387 m_usbRxCacheWritePos = 0;
388 m_usbRxCacheReadPos = 0;
389 USBD_CDC_SetRxBuffer(m_handle, m_usbRxCache);
390 }
391}
392} /* namespace semf */
393#endif