source: azure_iot_hub_f767zi/trunk/asp_baseplatform/usb/host/SERIAL/tusbh_serial.c@ 457

Last change on this file since 457 was 457, checked in by coas-nagasima, 4 years ago

ファイルを追加

  • Property svn:eol-style set to native
  • Property svn:mime-type set to text/x-csrc;charset=UTF-8
File size: 15.5 KB
Line 
1/*
2 * TOPPERS BASE PLATFORM MIDDLEWARE
3 *
4 * Copyright (C) 2017-2018 by TOPPERS PROJECT
5 * Educational Working Group.
6 *
7 * 上記著作権者は,以下の(1)~(4)の条件を満たす場合に限り,本ソフトウェ
8 * ア(本ソフトウェアを改変したものを含む.以下同じ)を使用・複製・改
9 * 変・再配布(以下,利用と呼ぶ)することを無償で許諾する.
10 * (1) 本ソフトウェアをソースコードの形で利用する場合には,上記の著作
11 * 権表示,この利用条件および下記の無保証規定が,そのままの形でソー
12 * スコード中に含まれていること.
13 * (2) 本ソフトウェアを,ライブラリ形式など,他のソフトウェア開発に使
14 * 用できる形で再配布する場合には,再配布に伴うドキュメント(利用
15 * 者マニュアルなど)に,上記の著作権表示,この利用条件および下記
16 * の無保証規定を掲載すること.
17 * (3) 本ソフトウェアを,機器に組み込むなど,他のソフトウェア開発に使
18 * 用できない形で再配布する場合には,次のいずれかの条件を満たすこ
19 * と.
20 * (a) 再配布に伴うドキュメント(利用者マニュアルなど)に,上記の著
21 * 作権表示,この利用条件および下記の無保証規定を掲載すること.
22 * (b) 再配布の形態を,別に定める方法によって,TOPPERSプロジェクトに
23 * 報告すること.
24 * (4) 本ソフトウェアの利用により直接的または間接的に生じるいかなる損
25 * 害からも,上記著作権者およびTOPPERSプロジェクトを免責すること.
26 * また,本ソフトウェアのユーザまたはエンドユーザからのいかなる理
27 * 由に基づく請求からも,上記著作権者およびTOPPERSプロジェクトを
28 * 免責すること.
29 *
30 * 本ソフトウェアは,無保証で提供されているものである.上記著作権者お
31 * よびTOPPERSプロジェクトは,本ソフトウェアに関して,特定の使用目的
32 * に対する適合性も含めて,いかなる保証も行わない.また,本ソフトウェ
33 * アの利用により直接的または間接的に生じたいかなる損害に関しても,そ
34 * の責任を負わない.
35 *
36 * @(#) $Id$
37 */
38/*
39 * USB Host Middleware CDC:SERIAL CLASS部
40 */
41
42#include "tusbh_serial.h"
43
44
45#define CDC_REQUEST_GETLINE(d, b) tusbhControlRequest((d), (b), CDC_REQUEST_GETLINE_TYPE, CDC_GET_LINE_CODING, 0, 0, LINE_CODING_STRUCTURE_SIZE)
46#define CDC_REQUEST_SETLINE(d, b) tusbhControlRequest((d), (b), CDC_REQUEST_SETLINE_TYPE, CDC_SET_LINE_CODING, 0, 0, LINE_CODING_STRUCTURE_SIZE)
47
48
49static TUSBH_ERCODE tusbhCDCInit(TUSBH_Device_t *pdevice);
50static TUSBH_ERCODE tusbhCDCDeInit(TUSBH_Device_t *pdevice);
51static TUSBH_ERCODE tusbhCDCProcess(TUSBH_Device_t *pdevice, uint8_t *mes);
52
53static TUSBH_Class_t SERAIL_Class = {
54 NULL,
55 "CDC",
56 CDC_CLASS,
57 tusbhCDCInit,
58 tusbhCDCDeInit,
59 tusbhCDCProcess,
60 NULL
61};
62
63/*
64 * SERIALクラスセットアップ関数
65 */
66void tusbhLinkSERIAL(TUSBH_Handle_t *phost)
67{
68 tusbhLinkClass(phost, &SERAIL_Class);
69}
70
71/*
72 * CDCクラス初期設定
73 * parameter1 pdevice: デバイスハンドラ
74 * return TUSBH_ERCODE
75 */
76static TUSBH_ERCODE
77tusbhCDCInit(TUSBH_Device_t *pdevice)
78{
79 uint8_t interface = 0;
80 CDC_Handle_t *hcdc;
81 TUSBH_Handle_t *phost = pdevice->pHost;
82 uint8_t max_ep, i;
83
84 interface = tusbhFindInterface(pdevice, pdevice->pClass->classCode, ABSTRACT_CONTROL_MODEL, CDC_ITU_T_V_250);
85
86 if(interface == NO_INTERFACE){
87 syslog_1(LOG_ERROR, "[CDC] Cannot Find the interface for %s class.", pdevice->pClass->Name);
88 return TUSBH_E_ERR;
89 }
90 tusbhSelectInterface(pdevice, interface);
91
92 hcdc = (CDC_Handle_t *)tusbmalloc(sizeof(CDC_Handle_t));
93 pdevice->pData = hcdc;
94 memset(hcdc, 0, sizeof(CDC_Handle_t));
95 max_ep = ((pdevice->ItfDesc[interface].bNumEndpoints <= 2) ?
96 pdevice->ItfDesc[interface].bNumEndpoints : 2);
97#if 1 /* ROI DEBUG */
98 syslog_3(LOG_NOTICE, "## tusbhCDCInit hmsc[%08x] max_ep(%d) csw(%d) ##", hcdc, max_ep, 0);
99#endif /* ROI DEBUG */
100 if(max_ep == 0 || (pdevice->EpDesc[interface][0].bEndpointAddress & 0x80) == 0)
101 return TUSBH_E_ERR;
102
103 hcdc->CommInEp = pdevice->EpDesc[interface][0].bEndpointAddress;
104 hcdc->CommInEpSize = pdevice->EpDesc[interface][0].wMaxPacketSize;
105 hcdc->CommInPipe = tusbhAllocPipe(phost, hcdc->CommInEp);
106
107 /*
108 * COMMNUCATION IN ENDPOINT OPEN
109 */
110 tusbhOpenPipe(pdevice, hcdc->CommInPipe, hcdc->CommInEp, USB_EP_TYPE_INTR, hcdc->CommInEpSize);
111 tusbhHDSetToggle(phost, hcdc->CommInPipe, 0);
112
113 interface = tusbhFindInterface(pdevice, DATA_INTERFACE_CLASS, 0x00, DIC_NO_SPECIFIC_PROTOCOL_CODE);
114 if(interface == NO_INTERFACE){
115 syslog_1(LOG_ERROR, "[CDC] Cannot Find the interface for %s class.", pdevice->pClass->Name);
116 return TUSBH_E_ERR;
117 }
118 max_ep = ((pdevice->ItfDesc[interface].bNumEndpoints <= 2) ?
119 pdevice->ItfDesc[interface].bNumEndpoints : 2);
120
121 for(i = 0 ; i < max_ep; i++){
122 if(pdevice->EpDesc[interface][i].bEndpointAddress & 0x80){
123 hcdc->InEp = (pdevice->EpDesc[interface][i].bEndpointAddress);
124 hcdc->InEpSize = pdevice->EpDesc[interface][i].wMaxPacketSize;
125 hcdc->InPipe = tusbhAllocPipe(phost, hcdc->InEp);
126 }
127 else{
128 hcdc->OutEp = (pdevice->EpDesc[interface][i].bEndpointAddress);
129 hcdc->OutEpSize = pdevice->EpDesc[interface][i].wMaxPacketSize;
130 hcdc->OutPipe = tusbhAllocPipe(phost, hcdc->OutEp);
131 }
132 }
133 if(hcdc->OutPipe == 0 || hcdc->InPipe == 0)
134 return TUSBH_E_ERR;
135
136 hcdc->state = CDC_PROCESS_INIT;
137 hcdc->timer = 0;
138 hcdc->pDev = pdevice;
139
140 /*
141 * NSCチャネルオープン
142 */
143 tusbhOpenPipe(pdevice, hcdc->OutPipe, hcdc->OutEp, USB_EP_TYPE_BULK, hcdc->OutEpSize);
144 tusbhHDSetToggle(phost, hcdc->OutPipe, 0);
145 tusbhOpenPipe(pdevice, hcdc->InPipe, hcdc->InEp, USB_EP_TYPE_BULK, hcdc->InEpSize);
146 tusbhHDSetToggle(phost, hcdc->InPipe, 0);
147
148 /* タイマースタート */
149 pdevice->timeid = pdevice->timecount = 100;
150 return TUSBH_E_OK;
151}
152
153/*
154 * CDCクラス終了設定
155 * parameter1 pdevice: デバイスハンドラ
156 * return TUSBH_ERCODE
157 */
158static TUSBH_ERCODE
159tusbhCDCDeInit(TUSBH_Device_t *pdevice)
160{
161 CDC_Handle_t *hcdc;
162 TUSBH_Handle_t *phost = pdevice->pHost;
163
164 hcdc = (CDC_Handle_t *)pdevice->pData;
165 if(hcdc->CommInPipe != 0){
166 tusbhClosePipe(pdevice, hcdc->CommInPipe);
167 tusbFreePipe(phost, hcdc->CommInPipe);
168 hcdc->CommInPipe = 0;
169 }
170
171 if(hcdc->OutPipe != 0){
172 tusbhClosePipe(pdevice, hcdc->OutPipe);
173 tusbFreePipe(phost, hcdc->OutPipe);
174 hcdc->OutPipe = 0;
175 }
176
177 if(hcdc->InPipe != 0){
178 tusbhClosePipe(pdevice, hcdc->InPipe);
179 tusbFreePipe(phost, hcdc->InPipe);
180 hcdc->InPipe = 0;
181 }
182
183 if(pdevice->pData != NULL){
184 tusbfree(pdevice->pData);
185 pdevice->pData = NULL;
186 }
187 return TUSBH_E_OK;
188}
189
190/*
191 * CDCクラスプロセス実行
192 * parameter1 pdevice: デバイスハンドラ
193 * parameter2 mes: 通信メッセージへのポインタ
194 * return TUSBH_ERCODE
195 */
196static TUSBH_ERCODE
197tusbhCDCProcess(TUSBH_Device_t *pdevice, uint8_t *mes)
198{
199 CDC_Handle_t *hcdc = (CDC_Handle_t *)pdevice->pData;
200 TUSBH_Handle_t *phost = pdevice->pHost;
201 void (*func)(TUSBH_Device_t *, uint8_t) = pdevice->pClass->subfunc;
202 TUSBH_URBState_t URB_Status = mes[3];
203 TUSBH_ERCODE ercd = TUSBH_E_BUSY;
204 TUSBH_ERCODE status;
205 int32_t length;
206 uint8_t cmd = CDC_LINE_STATUS_CHANGED;
207
208 if(mes[0] == TUSBH_URB_EVENT)
209 hcdc->urb_wait = 0;
210 else if(mes[0] == TUSBH_TIME_EVENT){
211 hcdc->timer += mes[3];
212 pdevice->timecount = mes[3];
213 }
214 else if(mes[0] == TUSBH_CLASS_EVENT && mes[2] != 0)
215 hcdc->state = mes[2];
216 switch (hcdc->state){
217 case CDC_PROCESS_INIT:
218 CDC_REQUEST_GETLINE(pdevice, (uint8_t *)(&hcdc->oLineCoding));
219 hcdc->state = CDC_PROCESS_INIT_WAIT;
220 break;
221 case CDC_PROCESS_INIT_WAIT:
222 status = tusbhControlWait(pdevice, mes);
223 if(status == TUSBH_E_OK){
224 if(phost->usrcallback != NULL)
225 phost->usrcallback(phost, pdevice, HOST_USER_CLASS_ACTIVE);
226 hcdc->state = CDC_PROCESS_IDLE;
227 }
228 else if(status != TUSBH_E_BUSY && status != TUSBH_E_BUSY_URB)
229 hcdc->state = CDC_PROCESS_ERROR;
230 break;
231 case CDC_PROCESS_IDLE:
232 if(mes[0] != TUSBH_URB_EVENT){
233 ercd = TUSBH_E_OK;
234 break;
235 }
236 if(mes[2] == pdevice->cntl_pipe_in || mes[2] == pdevice->cntl_pipe_out){
237 status = tusbhControlWait(pdevice, mes);
238 if(status == TUSBH_E_OK){
239 hcdc->state = CDC_PROCESS_IDLE;
240 if((hcdc->oLineCoding.stop_bits != hcdc->uLineCoding.stop_bits) ||
241 (hcdc->oLineCoding.data_bits != hcdc->uLineCoding.data_bits) ||
242 (hcdc->oLineCoding.parity != hcdc->uLineCoding.parity) ||
243 (hcdc->oLineCoding.baudrate != hcdc->uLineCoding.baudrate)){
244 if(func != NULL)
245 func(pdevice, CDC_LINE_STATUS_CHANGED);
246 }
247 }
248 else if(status != TUSBH_E_BUSY && status != TUSBH_E_BUSY_URB)
249 hcdc->state = CDC_PROCESS_ERROR;
250 }
251 else if(hcdc->rw_status != TUSBH_E_BUSY)
252 hcdc->state = CDC_PROCESS_ERROR;
253 else if(URB_Status == TUSBH_URB_DONE){
254 if(mes[2] == hcdc->InPipe){
255 hcdc->RxTrnPktSize = tusbhHDTrasLength(phost, hcdc->InPipe);
256 cmd = CDC_LINE_STATUS_RECEIVED;
257 hcdc->RxTrnLength += hcdc->RxTrnPktSize;
258 hcdc->pRxTrnBuff += hcdc->RxTrnPktSize;
259 hcdc->state = CDC_PROCESS_IDLE;
260 }
261 else{
262 cmd = CDC_LINE_STATUS_SENDED;
263 hcdc->TxTrnLength += hcdc->TxTrnPktSize;
264 hcdc->pTxTrnBuff += hcdc->TxTrnPktSize;
265 if(hcdc->TxTrnSize > hcdc->TxTrnLength)
266 hcdc->state = CDC_PROCESS_SEND;
267 else
268 hcdc->state = CDC_PROCESS_IDLE;
269 }
270 if(hcdc->state == CDC_PROCESS_IDLE){
271 hcdc->rw_status = TUSBH_E_OK;
272 if(func != NULL)
273 func(pdevice, cmd);
274 if(hcdc->rw_taskid != 0)
275 tusbWakeup(hcdc->rw_taskid);
276 }
277 }
278 else if(URB_Status == TUSBH_URB_NOTREADY){
279 if(mes[2] == hcdc->InPipe)
280 hcdc->state = CDC_PROCESS_RECEIVE;
281 else
282 hcdc->state = CDC_PROCESS_SEND;
283 }
284 else{
285 hcdc->state = CDC_PROCESS_ERROR;
286 hcdc->rw_status = TUSBH_E_ERR;
287 if(func != NULL)
288 func(pdevice, cmd);
289 if(hcdc->rw_taskid != 0)
290 tusbWakeup(hcdc->rw_taskid);
291 }
292 tusbSendData(phost->process_event, TUSBH_CLASS_EVENT, pdevice->idx, 0, 0);
293 break;
294 case CDC_PROCESS_SET_LINE_CODING:
295 CDC_REQUEST_SETLINE(pdevice, (uint8_t *)&hcdc->uLineCoding);
296 hcdc->state = CDC_PROCESS_SET_LINE_CODING_WAIT;
297 break;
298 case CDC_PROCESS_SET_LINE_CODING_WAIT:
299 status = tusbhControlWait(pdevice, mes);
300 if(status == TUSBH_E_OK)
301 hcdc->state = CDC_PROCESS_GET_LINE_CODING;
302 else if(status != TUSBH_E_BUSY && status != TUSBH_E_BUSY_URB)
303 hcdc->state = CDC_PROCESS_ERROR;
304 break;
305 case CDC_PROCESS_GET_LINE_CODING:
306 CDC_REQUEST_GETLINE(pdevice, (uint8_t *)&hcdc->uLineCoding);
307 hcdc->state = CDC_PROCESS_IDLE;
308 break;
309 case CDC_PROCESS_SEND:
310 length = hcdc->TxTrnSize - hcdc->TxTrnLength;
311 if(length > hcdc->OutEpSize)
312 hcdc->TxTrnPktSize = hcdc->OutEpSize;
313 else
314 hcdc->TxTrnPktSize = length;
315 tusbhBulkWrite(pdevice, hcdc->pTxTrnBuff, hcdc->TxTrnPktSize, hcdc->OutPipe);
316 hcdc->state = CDC_PROCESS_IDLE;
317 break;
318 case CDC_PROCESS_RECEIVE:
319 length = hcdc->RxTrnSize - hcdc->RxTrnLength;
320 if(length > hcdc->InEpSize)
321 hcdc->RxTrnPktSize = hcdc->InEpSize;
322 else
323 hcdc->RxTrnPktSize = length;
324 tusbhBulkRead(pdevice, hcdc->pRxTrnBuff, hcdc->RxTrnPktSize, hcdc->InPipe);
325 hcdc->state = CDC_PROCESS_IDLE;
326 break;
327 case CDC_PROCESS_ERROR:
328 tusbhClearFeature(pdevice, 0x00);
329 hcdc->state = CDC_PROCESS_ERROR_WAIT;
330 break;
331 case CDC_PROCESS_ERROR_WAIT:
332 if(tusbhControlWait(pdevice, mes) == TUSBH_E_OK)
333 hcdc->state = CDC_PROCESS_IDLE;
334 break;
335 default:
336 break;
337 }
338 return ercd;
339}
340
341/*
342 * SERIAL LINE CODINGデータ領域を設定
343 * parameter1 phost: ホストハンドラ
344 * parameter2 unit: UNIT#
345 * parameter3 linecod: ユーザのLINE CODING格納領域へのポインタ
346 * return TUSBH_ERCODE
347 */
348TUSBH_ERCODE
349tusbhCdcSetLineCoding(TUSBH_Handle_t *phost, uint8_t unit, Line_Coding_t *linecod)
350{
351 TUSBH_Device_t *pdevice = tusbhSearchDevice(phost, SERAIL_Class.classCode, &unit);
352 CDC_Handle_t *hcdc;
353
354 if(pdevice == NULL)
355 return TUSBH_E_OBJ;
356 hcdc = (CDC_Handle_t *)pdevice->pData;
357 if(pdevice->dstate == DEVICE_CLASS){
358 tusbmemcpy(&hcdc->uLineCoding, linecod, sizeof(Line_Coding_t));
359 tusbSendData(phost->process_event, TUSBH_CLASS_EVENT, pdevice->idx, CDC_PROCESS_SET_LINE_CODING, 0);
360 }
361 return TUSBH_E_OK;
362}
363
364/*
365 * SERIAL LINE CODINGデータ取得
366 * parameter1 phost: ホストハンドラ
367 * parameter2 unit: UNIT#
368 * parameter3 linecod: LINE CODING格納領域へのポインタ
369 * return TUSBH_ERCODE
370*/
371TUSBH_ERCODE
372tusbhCdcGetLineCoding(TUSBH_Handle_t *phost, uint8_t unit, Line_Coding_t *linecod)
373{
374 TUSBH_Device_t *pdevice = tusbhSearchDevice(phost, SERAIL_Class.classCode, &unit);
375 CDC_Handle_t *hcdc;
376
377 if(pdevice == NULL)
378 return TUSBH_E_OBJ;
379 hcdc = pdevice->pData;
380 *linecod = hcdc->oLineCoding;
381 return TUSBH_E_OK;
382}
383
384
385/*
386 * CDC DATA RECEIVE
387 * parameter1 phost: ホストハンドラ
388 * parameter2 unit: UNIT#
389 * parameter3 pbuf: 受信データ領域へのポインタ
390 * parameter4 length: 受信ブロック長
391 * return TUSBH_ERCODE
392 */
393TUSBH_ERCODE
394tusbhCdcReceive(TUSBH_Handle_t *phost, uint8_t unit, uint8_t *pbuf, uint32_t *length, uint32_t timeout)
395{
396 TUSBH_Device_t *pdevice = tusbhSearchDevice(phost, SERAIL_Class.classCode, &unit);
397 CDC_Handle_t *hcdc;
398 TUSBH_ERCODE status = TUSBH_E_BUSY;
399 uint32_t i;
400
401 if(pdevice != NULL){
402 hcdc = pdevice->pData;
403 if(pdevice->dstate != DEVICE_CLASS)
404 return TUSBH_E_OBJ;
405 if(hcdc->state == CDC_PROCESS_ERROR)
406 return TUSBH_E_ERR;
407 }
408 else
409 return TUSBH_E_OBJ;
410
411 /*
412 * 受信データ設定
413 */
414 hcdc->RxTrnSize = *length;
415 hcdc->RxTrnLength = 0;
416 hcdc->pRxTrnBuff = pbuf;
417 hcdc->rw_status = TUSBH_E_BUSY;
418 hcdc->rw_taskid = tusbGetTaskID();
419 tusbSendData(phost->process_event, TUSBH_CLASS_EVENT, pdevice->idx, CDC_PROCESS_RECEIVE, 0);
420
421 if(timeout != 0)
422 timeout += 9;
423 timeout /= 10;
424 for(i = 0 ; i < timeout ; i++){
425 tusbSleep(10);
426 if((status = hcdc->rw_status) != TUSBH_E_BUSY)
427 break;
428 }
429 if(status == TUSBH_E_BUSY){
430 hcdc->rw_status = TUSBH_E_TMOUT;
431 status = TUSBH_E_TMOUT;
432 }
433 *length = hcdc->RxTrnLength;
434 hcdc->rw_taskid = 0;
435 return status;
436}
437
438/*
439 * CDC DATA SEND
440 * parameter1 phost: ホストハンドラ
441 * parameter2 unit: UNIT#
442 * parameter3 pbuf: 送信データ領域へのポインタ
443 * parameter4 length: 送信データ長
444 * return TUSBH_ERCODE
445 */
446TUSBH_ERCODE
447tusbhCdcSend(TUSBH_Handle_t *phost, uint8_t unit, uint8_t *pbuf, uint32_t length)
448{
449 TUSBH_Device_t *pdevice = tusbhSearchDevice(phost, SERAIL_Class.classCode, &unit);
450 CDC_Handle_t *hcdc;
451 TUSBH_ERCODE status = TUSBH_E_BUSY;
452 uint32_t i;
453
454 if(pdevice != NULL){
455 hcdc = pdevice->pData;
456 if(pdevice->dstate != DEVICE_CLASS)
457 return TUSBH_E_OBJ;
458 if(hcdc->state == CDC_PROCESS_ERROR)
459 return TUSBH_E_ERR;
460 }
461 else
462 return TUSBH_E_OBJ;
463
464 /*
465 * 送信データ設定
466 */
467 hcdc->TxTrnSize = length;
468 hcdc->TxTrnLength = 0;
469 hcdc->pTxTrnBuff = pbuf;
470 hcdc->rw_status = TUSBH_E_BUSY;
471 hcdc->rw_taskid = tusbGetTaskID();
472 tusbSendData(phost->process_event, TUSBH_CLASS_EVENT, pdevice->idx, CDC_PROCESS_SEND, 0);
473
474 for(i = 0 ; i < (length * 10) ; i++){
475 tusbSleep(50);
476 if((status = hcdc->rw_status) != TUSBH_E_BUSY)
477 break;
478 }
479 if(status == TUSBH_E_BUSY){
480 hcdc->rw_status = TUSBH_E_TMOUT;
481 status = TUSBH_E_TMOUT;
482 }
483 hcdc->rw_taskid = 0;
484 return status;
485}
486
487/*
488 * SERIALコールバック関数
489 * parameter1 phost: ホストハンドラ
490 * parameter2 func: 関数ポインタ
491 */
492void
493tusbhSetCdcCallBack(TUSBH_Handle_t *phost, void (*func)(TUSBH_Device_t *p, uint8_t))
494{
495 SERAIL_Class.subfunc = func;
496}
497
498
Note: See TracBrowser for help on using the repository browser.