Имя usbdrv Проект драйвер AVR USB Автор Christian Starkjohann Перевод

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
/* Имя: usbdrv.h
* Проект: драйвер AVR USB
* Автор: Christian Starkjohann
* Перевод: microsin.ru
* Дата создания: 2004-12-29
* Табуляция: 4
* Copyright: (c) 2005 by OBJECTIVE DEVELOPMENT Software GmbH
* Лицензия: GNU GPL v2 (see License.txt) or proprietary (CommercialLicense.txt)
* Ревизия: $Id: usbdrv.h 607 2008-05-13 15:57:28Z cs $
*/
#ifndef __usbdrv_h_included__
#define __usbdrv_h_included__
#include "usbconfig.h"
#include "iarcompat.h"
/*
Требования к железу:
====================
Сигналы USB D+ и D- ДОЛЖНЫ быть подсоединены на один и тот же I/O порт (A, B, C или D).
Мы рекомендуем, чтобы сигнал D+ вызывал прерывание (лучший выбор - использовать INT0
для D+), однако возможно, чтобы прерывание срабатывало не от D+, а от D-. Если
используется D-, прерывания будут происходить каждый раз при получении пакетов SOF
(Start-Of-Frame). D- требует нагрузочный (pull-up) резистор 1.5k, подключенный к +3.5V
(и устройство должно быть запитано от 3.5V) для идентификации USB устройства как
low-speed. Резистор pull-down или pull-up 1M ДОЛЖЕН быть SHOULD подсоединен между D+
и +3.5V для предотвращения помех, конгда отсутствует USB мастер. Если Вы используете
диоды Зенера (по-русски - стабилитроны) для ограничения напряжения на сигналах D+ и D-,
Вы должны использовать резистор pull-down, а не pull-up. Мы используем D+ как источник
прерывания, не D-, потому что он не вызывает прерывание на состояния keep-alive
и RESET. Если Вы хотите подсчитывать события keep-alive с USB_COUNT_SOF, Вы ДОЛЖНЫ
использовать D- как источник прерываний.
Как опция этапа компиляции, 1.5k pull-up резистор на D- можнос сделать отключаемым,
чтобы реализовать программное отключение устройства от шины USB. См. установки
usbDeviceConnect() и usbDeviceDisconnect() далее в этом файле.
Пожалуйста, приведите величины в файле usbconfig.h в соответствие Вашему железу!
Микроконтроллер в Вашем USB-устройстве ДОЛЖЕН тактироваться от частот 12, 15 или 16 МГц
(при использовании кварца) или 16.5 МГц (использование внутреннего RC-генератора,
точность частоты +/- 1%). Детали см. в usbconfig-prototype.h.
Ограничения:
============
Устойчивость к ошибкам в коммуникации:
Драйвер предполагает, что при передаче данных ошибки отсутствуют. Он ДЕЛАЕТ проверку
ошибок в PID, но НЕ проверяет ошибки вставки битов, SE0 в середине байта,
CRC токена (5 бит) и CRC данных (16 бит). Проверки CRC не могут быть выполнены из-за
ограничений по времени: мы должны начать отправку ответа внутри 7-битного интервала
времени. Битовые ошибки и неправильно вставленный SE0 по спецификации должны проверяться
в режиме реального времени, но возможности универсального CPU AVR не допускают это.
Драйвер не проверяет переключение Data0/Data1, но приложение, с которым работает драйвер,
может реализовать такую проверку.
Входные характеристики:
Поскольку используется схема недифференциального приемника, чуствительность
к электрическим помехам повышенная. Драйвер опрашивает только одну линию ъ
данных с обычными входными характеристиками ножки I/O. Однако поскольку здесь
реализована низкоскоростная спецификация USB, то возможностей AVR оказывается
достаточно. Также спецификация требует обнаружения асимметрических состояний
на высоких скоростях для обнаружения SE0.
Количество конечных точек:
Драйвер поддерживает следующие конечные точки:
- Endpoint 0, по умолчанию управляющая конечная точка (default control endpoint).
- Любое количество interrupt- или bulk-out конечных точек. Данные передаются
в usbFunctionWriteOut() и USB_CFG_IMPLEMENT_FN_WRITEOUT должен быть задан
в 1 для активирования этой возможности. Номер конечной точки может быть
найден в глобальной переменной 'usbRxToken'.
- По умолчанию одна interrupt- или bulk-in конечная точка. Эта конечная точка
используется для interrupt- или bulk-in передач, которые не обрабатываются
другой конечной точкой. Вы можете задать USB_CFG_HAVE_INTRIN_ENDPOINT в порядке
активирования этой возможности и вызвать usbSetInterrupt() для отправки
данных interrupt/bulk.
- Одна добавочная interrupt- или bulk-in конечная точка. Это была endpoint 3 в
предыдущих версиях этого драйвера, но можно сконфигурировать любой номер
конечной точки. Вы должны задать USB_CFG_HAVE_INTRIN_ENDPOINT3 для активации
этой возможности и вызвать usbSetInterrupt3() для отправки данных interrupt/bulk.
Номер конечной точки указывается в USB_CFG_EP3_NUMBER.
Пожалуйста примите во внимание, что стандарт USB запрещает конечные точки bulk
для низкоскоростных устройств! Многие операционные системы однако все равно
разрешают использовать их, но AVR тратит 90% времени CPU в опросах прерываний
USB для данных bulk.
Максимальная полезная нагрузка данными:
Загрузка данными для управляющих входных (control in) и выходных (out) передач
может достигать до 254 байт. Чтобы принять данные полезной нагрузки выходных
передач (out transfers), Вы должны реализовать 'usbFunctionWrite()'.
Потребление тока в режиме USB Suspend Mode:
Стандарт USB ограничивает энергопотребление величиной 500uA, когда шина
переходит в режим suspend mode. Это не проблема для устройств, которые
запитываются самостоятельно, от отдельного источника тока (питаются не от
шины USB). Устройства, питающиеся от шины USB, могут выполнить это требование
только в том случае, если CPU (в нашем случае микроконтроллер AVR) переходит
в режим сна (sleep mode). Самостоятельно драйвер не поддерживает обработку
режима suspend. Однако приложение может реализовать мониторинг активности
и пробуждение от сна. Хост регулярно отправляет состояния SE0 для поддержания
шины в активном состоянии. Эти состояния SE0 могут детектироваться при
использовании сигнала D- в качестве источника прерывания. Задайте USB_COUNT_SOF
в 1 и используйте глобальную переменную usbSofCount для проверки активности шины.
Работа без мастера USB:
Драйвер ведет себя нейтрально без подключения к мастеру USB, если D- читается
как 1. Чтобы избежать фальшивых прерываний, мы рекомендуем на сигнал D+
(прерывание) подключить резистор высокого сопротивления (например 1M) как
pull-down ("нижний" резистор, подключенный между землей и D+) или pull-up
("верхний" резистор, подключенный между шиной питания +3.3 В и D+).
Если используются диоды Зенера (стабилитроны), используйте pull-down.
Если D- становится статически в 0, драйвер может заблокировать подпрограмму
прерывания.
Время задержки обработки прерывания (Interrupt latency):
Приложение должно удостовериться, что USB прерывание не запрещено для более чем
25 циклов (это число для 12 МГц, для бОльшей тактовой частоты допустимо
бОльшее количество циклов, что и называется latency). Это подразумевает, что
все обработчики прерывания должны быть либо задекларированы как "INTERRUPT"
вместо "SIGNAL" (см. "avr/signal.h") либо написаны на ассемблере с первой
инструкцией "sei".
Максимальная длительность прерывания / потребление циклов CPU:
Драйвер обрабатывает все соединения USB внутри обработчика прерывания. Выход
из обработчика прерывания не произойдет, пока не будет принято все USB-сообщение
целиком и отправится подтверждение. Это будет сделано примерно за 1200 циклов на
частоте 12 MHz (= 100us), если хост отвечает требованиям стандарта. Драйвер
будет потреблять циклы CPU для всех сообщений USB, даже если они обращаются
к другому (low-speed) устройству на той же шине.
*/
/* ------------------------------------------------------------------------- */
/* --------------------------- Интерфейс модуля ---------------------------- */
/* ------------------------------------------------------------------------- */
#define USBDRV_VERSION 20080513
/* Здесь задается уникальный идентификатор версии драйвера. Это десятичный номер,
* составленный из даты релиза драйвера в форме YYYYMMDD. Если поведение интерфейса
* драйвера меняется, Вы можете использовать эту константу, чтобы отличить версии.
* Если не указано, то дата релиза драйвера старее чем 2006-01-25.
*/
#ifndef USB_PUBLIC
#define USB_PUBLIC
#endif
/* USB_PUBLIC используется как атрибут декларации для всех функций, экспортируемых
* драйвером USB. По умолчанию атрибут не задан (см. выше). Вы можете задать
* атрибут static либо в usbconfig.h или из командной строки, если Вы включаете
* usbdrv.c вместо его линковки. Включение модуля C драйвера напрямую в Ваш код
* экономит несколько байт пямяти flash (память программ).
*/
#ifndef __ASSEMBLER__
#ifndef uchar
#define uchar unsigned char
#endif
#ifndef schar
#define schar signed char
#endif
/* шорткаты 8 бит целых типов */
#if USB_CFG_LONG_TRANSFERS /* если требуется для передачи больше, чем 254 байта */
# define usbMsgLen_t unsigned
#else
# define usbMsgLen_t uchar
#endif
/* usbMsgLen_t определяет тип данных, используемый для длин передачи. По умолчанию
* задано uchar, что позволяет передать максимум 254 байт (число 255 зарезервировано
* для USB_NO_MSG далее). Если в файле usbconfig.h задано USB_CFG_LONG_TRANSFERS в 1,
* будет использоваться тип данных 16 бит, что разрешает до 16384 байт (остаток
* используется для флагов в конфигурации дескриптора).
*/
#define USB_NO_MSG ((usbMsgLen_t)-1) /* константа, которая означает "нет сообщения" */
struct usbRequest; /* предварительная декларация */
USB_PUBLIC void usbInit(void);
/* Эта функция должна быть вызвана перед разрешением прерываний и заходом в основной
* цикл main.
*/
USB_PUBLIC void usbPoll(void);
/* Эта функция должна быть вызвана через регулярные интервалы внутри главного цикла main.
* Максимальная задержка между вызовами должна быть несколько меньше 50 мс (таймаут USB для
* принятия сообщения Setup). Иначе устройство не будет распознано.
* Пожалуйста примите во внимание, что отладочный вывод через UART отнимает ~ 0.5 мс на байт
* при скорости 19200 bps.
*/
extern uchar *usbMsgPtr;
/* Эта переменная может использоваться для передачи отправляемых данных драйверу
* от реализации usbFunctionWrite(). Она также используется внутренне драйвером
* для стандартных управляющих запросов.
*/
USB_PUBLIC usbMsgLen_t usbFunctionSetup(uchar data[8]);
/* Эта функция вызывается, когда драйвер принимает транзакцию SETUP от хоста,
* которому не отвечает драйвер непосредственно (на практике: запросы класса
* и вендора). Все управляющие передачи стартуют с транзакции SETUP, где хост
* сообщает параметры следующтих (опционально) передач данных. Данные SETUP
* доступны в параметре 'data', который может (и должен) быть преобразован
* в 'usbRequest_t *' для лучшего дружественного для пользователя доступа
* к параметрам.
*
* Если SETUP показывает передачу control-in, Вы должны обеспечить для драйвера
* запрошенные данные. Есть два пути для передачи этих данных:
* (1) установить глобальный указатель 'usbMsgPtr' на начало блока данных
* static RAM и возвратить длину данных в 'usbFunctionSetup()'. Драйвер
* обработает остаток. Или (2) возвратить USB_NO_MSG в 'usbFunctionSetup()'.
* Драйвер будет вызывать 'usbFunctionRead()', когда понадобятся данные. Для
* подробностей см. документацию usbFunctionRead().
*
* Если SETUP показывает передачу control-out, есть только один путь для приема
* данных от хоста - через вызов 'usbFunctionWrite()'. Если Вы реализовали эту
* функцию, Вы должны возвратить USB_NO_MSG в 'usbFunctionSetup()', чтобы
* показать необходимость использования 'usbFunctionWrite()'. Для большей
* информации см. документацию по этой функции. Если Вы просто хотите игнорировать
* данные, отправленные хостом, верните 0 'usbFunctionSetup()'.
*
* Примите во внимание, что вызовы функций usbFunctionRead() и usbFunctionWrite()
* работают только если они разрешены конфигурацией в usbconfig.h.
*/
USB_PUBLIC usbMsgLen_t usbFunctionDescriptor(struct usbRequest *rq);
/* Вам нужно реализовать эту функцию ТОЛЬКО если Вы предоставляете дескрипторы USB
* во время выполнения - runtime (особенность для экспертов). Это очень подобно
* usbFunctionSetup() выше, но она вызывается только для запроса данных дескриптора
* USB data. Подробнее см. документацию usbFunctionSetup() выше.
*/
#if USB_CFG_HAVE_INTRIN_ENDPOINT
USB_PUBLIC void usbSetInterrupt(uchar *data, uchar len);
/* Эта функция устанавливает сообщение, которое будет отправлено при следующей
* передаче IN по прерыванию. Сообщение копируется во внутренний буфер и не должно
* превышать по длине 8 байт. Сообщение может быть длиной в 0 байт просто для
* индикации статуса прерывания для хоста.
* Если Вам нужно передать бОльшее количество байт, используйте контрольное чтение
* после прерывания.
*/
#define usbInterruptIsReady() (usbTxLen1 & 0x10)
/* Этот макрос индицирует, было ли ужет послано последнее сообщение прерывания.
* Если Вы установили новое сообщение прерывания перед тем, как старое было
* отправлено, то уже буферизированое сообщение будет потеряно.
*/
#if USB_CFG_HAVE_INTRIN_ENDPOINT3
USB_PUBLIC void usbSetInterrupt3(uchar *data, uchar len);
#define usbInterruptIsReady3() (usbTxLen3 & 0x10)
/* То же самое, как ранее, но для конечной точки 3 */
#endif
#endif /* USB_CFG_HAVE_INTRIN_ENDPOINT */
#if USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH /* упрощенный интерфейс для обратной совместимости */
#define usbHidReportDescriptor usbDescriptorHidReport
/* должен быть декларирован так: PROGMEM char usbHidReportDescriptor[]; */
/* Если Вы реализуете устройство HID, Вам нужно предоставить дескриптор репорта.
* HID репорт дескриптор имеет несколько усложненный синтаксис. Если Вы понимаете,
* как конструировать репорт дескрипторы, мы рекомендуем использовать
* HID Descriptor Tool от usb.org, см. http://www.usb.org/developers/hidpage/.
* В другом случае Вам нужно начать с рабочего примера.
*/
#endif /* USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH */
#if USB_CFG_IMPLEMENT_FN_WRITE
USB_PUBLIC uchar usbFunctionWrite(uchar *data, uchar len);
/* Эта функция вызывается драйвером для обеспечения управляющих передач
* (control transfer's) данных полезной нагрузки (control-out). Она вызывается
* в кусках до 8 байт. Общее количество, предоставляемое в текущей управляющей
* передаче, может быть получено из свойства 'length' данных setup. Если
* во время обработки произошла ошибка, возвращается 0xff (== -1). В этом
* случае драйвер будет отвечать для всей передачи токеном STALL. Если Вы
* успешно приняли всю полезную нагрузку, возвращается 1. Если Вы ожидаете
* больше данных, возврат 0. Если Вы не знаете, будет ли хост посылать еще
* данные (Вы должны знать общее количество предоставляется вызовом
* usbFunctionSetup()!), возвращается 1.
* ЗАМЕЧАНИЕ: Если Вы вернули 0xff для STALL, 'usbFunctionWrite()' будет все
* равно вызываться для оставшихся данных. Вы должны продолжить возвращать 0xff
* для STALL в этих вызовах.
* Для того, чтобы добиться вызовов usbFunctionWrite(), задайте
* USB_CFG_IMPLEMENT_FN_WRITE на 1 в usbconfig.h и возвратите 0xff в usbFunctionSetup().
*/
#endif /* USB_CFG_IMPLEMENT_FN_WRITE */
#if USB_CFG_IMPLEMENT_FN_READ
USB_PUBLIC uchar usbFunctionRead(uchar *data, uchar len);
/* Эта функция вызывается драйвером для запроса у приложения управляющих передач
* данных полезной нагрузки (control-in). Вызывается кусками до 8 байт каждый.
* Вы должны скопировать данные в место, указанное параметром 'data' и
* возвратить действительно скопированное количество байт. Если Вы вернете return
* число меньшее, чем запрашивается, передача control-in будет прервана. Если
* Вы возвратите 0xff, драйвер прервет передачу с токеном STALL.
* Для того, чтобы вызывалась usbFunctionRead(), задайте USB_CFG_IMPLEMENT_FN_READ
* на 1 в usbconfig.h и верните 0xff в usbFunctionSetup().
*/
#endif /* USB_CFG_IMPLEMENT_FN_READ */
#if USB_CFG_IMPLEMENT_FN_WRITEOUT
USB_PUBLIC void usbFunctionWriteOut(uchar *data, uchar len);
/* Эта функция вызывается драйвером когда данные принимаются конечной точкой
* interrupt или bulk-out. Номер конечной точки можно найти в глобальной
* переменной usbRxToken. Вы должны задать USB_CFG_IMPLEMENT_FN_WRITEOUT на 1
* в usbconfig.h, чтобы добиться вызова этой функции.
*/
#endif /* USB_CFG_IMPLEMENT_FN_WRITEOUT */
#ifdef USB_CFG_PULLUP_IOPORTNAME
#define usbDeviceConnect() ((USB_PULLUP_DDR |= (1<<USB_CFG_PULLUP_BIT)), \
(USB_PULLUP_OUT |= (1<<USB_CFG_PULLUP_BIT)))
#define usbDeviceDisconnect() ((USB_PULLUP_DDR &= ~(1<<USB_CFG_PULLUP_BIT)), \
(USB_PULLUP_OUT &= ~(1<<USB_CFG_PULLUP_BIT)))
#else /* USB_CFG_PULLUP_IOPORTNAME */
#define usbDeviceConnect() (USBDDR &= ~(1<<USBMINUS))
#define usbDeviceDisconnect() (USBDDR |= (1<<USBMINUS))
#endif /* USB_CFG_PULLUP_IOPORTNAME */
/* Макрос usbDeviceConnect() и usbDeviceDisconnect() (предназначенный напоминать
* функцию) соединяет и соединяет устройство с шиной USB хоста. Если константы
* USB_CFG_PULLUP_IOPORT и USB_CFG_PULLUP_BIT заданы в usbconfig.h, отсоединение
* заключается в удалении резистора pull-up от D-, иначе отсоединение происходит
* при грубом притягивании D- к GND (D- программно устанавливается как выход 0).
* Это не удовлетворяет спецификации, но работает.
* Пожалуйста примите во внимание, что прерывание USB должно быть запрещено,
* когда устройство переходит в отключенное состояние, или обработчик прерывания
* зависнет! Вы можете либо выключить прерывание USB селективно:
* USB_INTR_ENABLE &= ~(1 << USB_INTR_ENABLE_BIT)
* или выполнить cli() для глобального запрета всех прерываний.
*/
extern unsigned usbCrc16(unsigned data, uchar len);
#define usbCrc16(data, len) usbCrc16((unsigned)(data), len)
/* Эта функция вычисляет двоичное дополнение CRC данных, используемое в пакетах
* данных USB. Величина используется для постороения сырых (raw) передаваемых
* пакетов. Вы можете пожелать использовать эту функцию для контрольных сумм
* данных или проверки принятых данных. Мы принудительно установили 16 бит
* соглашение о вызовах для совместимости с tiny моделью памяти IAR.
*/
extern unsigned usbCrc16Append(unsigned data, uchar len);
#define usbCrc16Append(data, len) usbCrc16Append((unsigned)(data), len)
/* Эта функция вычисляет эквивалентна usbCrc16() выше, отличие только в том,
* что она добавляет 2 байта CRC (первым младший байт) в буфер 'data' после
* чтения 'len' байт.
*/
#if USB_CFG_HAVE_MEASURE_FRAME_LENGTH
extern unsigned usbMeasureFrameLength(void);
/* Эта функция ДОЛЖНА быть вызвана НЕМЕДЛЕННО СРАЗУ ПОСЛЕ сброса USB и она
* измеряет 1/7 количества циклов CPU во время фрейма USB минус один бит длины
* низкоскоростного бита. Другими словами: возвращаемая величина
* = 1499 * (F_CPU / 10.5 MHz).
* Во время этого активного ожидания, Вы ДОЛЖНЫ запретить все прерывания,
* используя cli() перед вызовом этой функции. Функция может использоваться
* для калибровки RC-генератора AVR.
*/
#endif
extern uchar usbConfiguration;
/* Эта переменная содержит номер текущей конфигурации, установленной хостом.
* Драйвер позволяет установку и опрос этой переменной с запросами USB
* SET_CONFIGURATION и GET_CONFIGURATION, но не использует её иначе.
* Вы можете отразить "сконфигурированное" состояние светодиодом (LED)
* на устройстве или включить узлы схемы, потребляющие большую мощность,
* только если устройство сконфигурировано.
*/
#if USB_COUNT_SOF
extern volatile uchar usbSofCount;
/* Эта переременная инкрементируется каждым пакетом SOF (Start-Of-Frame, начало
* фрейма). Это доступно только в том случае, если макро USB_COUNT_SOF задан
* в величину != 0.
*/
#endif
#define USB_STRING_DESCRIPTOR_HEADER(stringLength) ((2*(stringLength)+2) | (3<<8))
/* Этот макро строит заголовок дескриптора для строкового дескриптора,
* по указанной длине строки. См. для примера использования usbdrv.c.
*/
#if USB_CFG_HAVE_FLOWCONTROL
extern volatile schar usbRxLen;
#define usbDisableAllRequests() usbRxLen = -1
/* Должно быть вызвано из usbFunctionWrite(). Этот макрос запрещает все входные
* данные от интерфейса USB. На запросы от хоста посылаются ответы NAK, пока
* действует такой запрет.
*/
#define usbEnableAllRequests() usbRxLen = 0
/* Может быть вызвано только если запросы запрещены. Этот макрос разрешает ввод
* от интерфейса USB после того, как он был запрещен вызовом usbDisableAllRequests().
*/
#define usbAllRequestsAreDisabled() (usbRxLen < 0)
/* Этот макрос возвращает TRUE, если запросы были запрещены. Он может понадобиться
* для того, чтобы убедиться в том, что usbEnableAllRequests() не вызывалась,
* когда запросы разрешены.
*/
#endif
#define USB_SET_DATATOKEN1(token) usbTxBuf1[0] = token
#define USB_SET_DATATOKEN3(token) usbTxBuf3[0] = token
/* Эти два макроса могут использоваться программой приложения для сброса переключения
* данных для конечных точек interrupt-in с номерами 1 и 3. Поскольку токен
* переключается ПЕРЕД отправкой данных, Вы должны установить противоположное
* значение токена, который должен прийти первым.
*/
#endif /* __ASSEMBLER__ */
/* ------------------------------------------------------------------------- */
/* -------------------- Определение свойств дескриптора -------------------- */
/* ------------------------------------------------------------------------- */
/* Это особенный материал. См. usbconfig-prototype.h для подробностей
* о различных методах определения дескрипторов USB. Если Вы ничего не сделаете,
* будут использоваться дескрипторы по умолчанию.
*/
#define USB_PROP_IS_DYNAMIC (1 << 14)
/* Если это свойство установлено для дескриптора, usbFunctionDescriptor() будет
* использоваться для получения частного дескриптора.
*/
#define USB_PROP_IS_RAM (1 << 15)
/* Если это свойство установлено для дескриптора, данные читаются из памяти RAM
* вместо Flash. Свойство используется всеми методами для предоставления
* внешних дескрипторов.
*/
#define USB_PROP_LENGTH(len) ((len) & 0x3fff)
/* Если используется статический внешний дескриптор, это общая длина дескриптора
* в байтах.
*/
/* все дескрипторы, которые могут иметь свойства: */
#ifndef USB_CFG_DESCR_PROPS_DEVICE
#define USB_CFG_DESCR_PROPS_DEVICE 0
#endif
#ifndef USB_CFG_DESCR_PROPS_CONFIGURATION
#define USB_CFG_DESCR_PROPS_CONFIGURATION 0
#endif
#ifndef USB_CFG_DESCR_PROPS_STRINGS
#define USB_CFG_DESCR_PROPS_STRINGS 0
#endif
#ifndef USB_CFG_DESCR_PROPS_STRING_0
#define USB_CFG_DESCR_PROPS_STRING_0 0
#endif
#ifndef USB_CFG_DESCR_PROPS_STRING_VENDOR
#define USB_CFG_DESCR_PROPS_STRING_VENDOR 0
#endif
#ifndef USB_CFG_DESCR_PROPS_STRING_PRODUCT
#define USB_CFG_DESCR_PROPS_STRING_PRODUCT 0
#endif
#ifndef USB_CFG_DESCR_PROPS_STRING_SERIAL_NUMBER
#define USB_CFG_DESCR_PROPS_STRING_SERIAL_NUMBER 0
#endif
#ifndef USB_CFG_DESCR_PROPS_HID
#define USB_CFG_DESCR_PROPS_HID 0
#endif
#if !(USB_CFG_DESCR_PROPS_HID_REPORT)
# undef USB_CFG_DESCR_PROPS_HID_REPORT
# if USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH /* некоторые ухищрения для обратной совместимости */
# define USB_CFG_DESCR_PROPS_HID_REPORT USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH
# else
# define USB_CFG_DESCR_PROPS_HID_REPORT 0
# endif
#endif
#ifndef USB_CFG_DESCR_PROPS_UNKNOWN
#define USB_CFG_DESCR_PROPS_UNKNOWN 0
#endif
/* ------------------ предварительная декларация дескрипторов ------------------- */
/* Если Вы используете внешние статические дескрипторы, они должны быть запомнены
* в глобальных массивах, как объявлено ниже:
*/
#ifndef __ASSEMBLER__
extern
#if !(USB_CFG_DESCR_PROPS_DEVICE & USB_PROP_IS_RAM)
PROGMEM
#endif
char usbDescriptorDevice[];
extern
#if !(USB_CFG_DESCR_PROPS_CONFIGURATION & USB_PROP_IS_RAM)
PROGMEM
#endif
char usbDescriptorConfiguration[];
extern
#if !(USB_CFG_DESCR_PROPS_HID_REPORT & USB_PROP_IS_RAM)
PROGMEM
#endif
char usbDescriptorHidReport[];
extern
#if !(USB_CFG_DESCR_PROPS_STRING_0 & USB_PROP_IS_RAM)
PROGMEM
#endif
char usbDescriptorString0[];
extern
#if !(USB_CFG_DESCR_PROPS_STRING_VENDOR & USB_PROP_IS_RAM)
PROGMEM
#endif
int usbDescriptorStringVendor[];
extern
#if !(USB_CFG_DESCR_PROPS_STRING_PRODUCT & USB_PROP_IS_RAM)
PROGMEM
#endif
int usbDescriptorStringDevice[];
extern
#if !(USB_CFG_DESCR_PROPS_STRING_SERIAL_NUMBER & USB_PROP_IS_RAM)
PROGMEM
#endif
int usbDescriptorStringSerialNumber[];
#endif /* __ASSEMBLER__ */
/* ------------------------------------------------------------------------- */
/* ----------------------- Макросы общего назначения ----------------------- */
/* ------------------------------------------------------------------------- */
#define USB_CONCAT(a, b) a ## b
#define USB_CONCAT_EXPANDED(a, b) USB_CONCAT(a, b)
#define USB_OUTPORT(name) USB_CONCAT(PORT, name)
#define USB_INPORT(name) USB_CONCAT(PIN, name)
#define USB_DDRPORT(name) USB_CONCAT(DDR, name)
/* Метод, заданный дважды выше позволяет нам сращивать строки, заданные макросом.
*/
/* ------------------------------------------------------------------------- */
/* ------------------------- Определения констант -------------------------- */
/* ------------------------------------------------------------------------- */
#if !defined __ASSEMBLER__ && (!defined USB_CFG_VENDOR_ID || !defined USB_CFG_DEVICE_ID)
#warning "You should define USB_CFG_VENDOR_ID and USB_CFG_DEVICE_ID in usbconfig.h"
/* Если пользователь не задал идентификаторы ID, мы используем по умолчанию
* свободные obdev ID. Детали см. в USBID-License.txt.
*/
#endif
/* убедитесь, что мы имеем заданные VID и PID, порядок байт младший байт (lowbyte),
старший байт (highbyte) */
#ifndef USB_CFG_VENDOR_ID
# define USB_CFG_VENDOR_ID 0xc0, 0x16 /* 5824 десятичное, используется для VOTI */
#endif
#ifndef USB_CFG_DEVICE_ID
# if USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH
# define USB_CFG_DEVICE_ID 0xdf, 0x05 /* 1503 десятичное, предоставленный в общий доступ PID для HID-ов */
# elif USB_CFG_INTERFACE_CLASS == 2
# define USB_CFG_DEVICE_ID 0xe1, 0x05 /* 1505 десятичное, предоставленный в общий доступ PID для модемов CDC */
# else
# define USB_CFG_DEVICE_ID 0xdc, 0x05 /* 1500 десятичное, свободный obdev PID */
# endif
#endif
/* Наследование Output, Input и DataDirection порты от имен портов */
#ifndef USB_CFG_IOPORTNAME
#error "You must define USB_CFG_IOPORTNAME in usbconfig.h, see usbconfig-prototype.h"
#endif
#define USBOUT USB_OUTPORT(USB_CFG_IOPORTNAME)
#define USB_PULLUP_OUT USB_OUTPORT(USB_CFG_PULLUP_IOPORTNAME)
#define USBIN USB_INPORT(USB_CFG_IOPORTNAME)
#define USBDDR USB_DDRPORT(USB_CFG_IOPORTNAME)
#define USB_PULLUP_DDR USB_DDRPORT(USB_CFG_PULLUP_IOPORTNAME)
#define USBMINUS USB_CFG_DMINUS_BIT
#define USBPLUS USB_CFG_DPLUS_BIT
#define USBIDLE (1<<USB_CFG_DMINUS_BIT) /* величина, представляющая состояние J */
#define USBMASK ((1<<USB_CFG_DPLUS_BIT) | (1<<USB_CFG_DMINUS_BIT)) /* маска для USB битов I/O */
/* определения для обратной совместимости со старыми версиями драйвера: */
#define USB_CFG_IOPORT USB_OUTPORT(USB_CFG_IOPORTNAME)
#ifdef USB_CFG_PULLUP_IOPORTNAME
#define USB_CFG_PULLUP_IOPORT USB_OUTPORT(USB_CFG_PULLUP_IOPORTNAME)
#endif
#ifndef USB_CFG_EP3_NUMBER /* если не задано в usbconfig.h */
#define USB_CFG_EP3_NUMBER 3
#endif
#define USB_BUFSIZE 11 /* PID, 8 байт данных, 2 байта CRC */
/* ----- Попытка найти регистры и биты, отвечающие за внешнее прерывание 0 ----- */
#ifndef USB_INTR_CFG /* пользователь может перезадать наши умолчания */
# if defined EICRA
# define USB_INTR_CFG EICRA
# else
# define USB_INTR_CFG MCUCR
# endif
#endif
#ifndef USB_INTR_CFG_SET /* пользователь может перезадать наши значения по умолчанию */
# define USB_INTR_CFG_SET ((1 << ISC00) | (1 << ISC01)) /* конфигурируем на фронт (нарастание) сигнала */
#endif
#ifndef USB_INTR_CFG_CLR /* пользователь может перезадать наши значения по умолчанию */
# define USB_INTR_CFG_CLR 0 /* нет битов для очистки */
#endif
#ifndef USB_INTR_ENABLE /* пользователь может перезадать наши значения по умолчанию */
# if defined GIMSK
# define USB_INTR_ENABLE GIMSK
# elif defined EIMSK
# define USB_INTR_ENABLE EIMSK
# else
# define USB_INTR_ENABLE GICR
# endif
#endif
#ifndef USB_INTR_ENABLE_BIT /* пользователь может перезадать наши значения по умолчанию */
# define USB_INTR_ENABLE_BIT INT0
#endif
#ifndef USB_INTR_PENDING /* пользователь может перезадать наши значения по умолчанию */
# if defined EIFR
# define USB_INTR_PENDING EIFR
# else
# define USB_INTR_PENDING GIFR
# endif
#endif
#ifndef USB_INTR_PENDING_BIT /* пользователь может перезадать наши значения по умолчанию */
# define USB_INTR_PENDING_BIT INTF0
#endif
/*
Определения выше не работают для следующих чипов:
at90c8534: нет ISC0?, нет PORTB, невозможно найти даташит
at86rf401: нет PORTB, нет MCUCR и т. д., низкая частота тактов
atmega103: нет ISC0? (может быть пропущено в заголовке, невозможно найти даташит)
atmega603: не задано в avr-libc
at43usb320, at43usb355, at76c711: уже имеется USB
at94k: это другой тип...
at90s1200, attiny11, attiny12, attiny15, attiny28: эти микроконтроллеры не имеют RAM
*/
/* ------------------------------------------------------------------------- */
/* ------------------- Константы и типы спецификации USB ------------------- */
/* ------------------------------------------------------------------------- */
/* значения токенов USB */
#define USBPID_SETUP 0x2d
#define USBPID_OUT 0xe1
#define USBPID_IN 0x69
#define USBPID_DATA0 0xc3
#define USBPID_DATA1 0x4b
#define USBPID_ACK 0xd2
#define USBPID_NAK 0x5a
#define USBPID_STALL 0x1e
#ifndef USB_INITIAL_DATATOKEN
#define USB_INITIAL_DATATOKEN USBPID_DATA1
#endif
#ifndef __ASSEMBLER__
typedef struct usbTxStatus{
volatile uchar len;
uchar buffer[USB_BUFSIZE];
}usbTxStatus_t;
extern usbTxStatus_t usbTxStatus1, usbTxStatus3;
#define usbTxLen1 usbTxStatus1.len
#define usbTxBuf1 usbTxStatus1.buffer
#define usbTxLen3 usbTxStatus3.len
#define usbTxBuf3 usbTxStatus3.buffer
typedef union usbWord{
unsigned word;
uchar bytes[2];
}usbWord_t;
typedef struct usbRequest{
uchar bmRequestType;
uchar bRequest;
usbWord_t wValue;
usbWord_t wIndex;
usbWord_t wLength;
}usbRequest_t;
/* Эта структура соответствует 8-байтному запросу setup */
#endif
/* поле bmRequestType в USB setup:
* d t t r r r r r, где
* d ..... направление: 0=хост->устройство, 1=устройство->хост
* t ..... тип: 0=стандартный, 1=класс, 2=вендор, 3=зарезервировано
* r ..... получатель: 0=устройство, 1=интерфейс, 2=конечная точка, 3=другое
*/
/* Значения получателя USB setup */
#define USBRQ_RCPT_MASK 0x1f
#define USBRQ_RCPT_DEVICE 0
#define USBRQ_RCPT_INTERFACE 1
#define USBRQ_RCPT_ENDPOINT 2
/* Значения типа запроса USB */
#define USBRQ_TYPE_MASK 0x60
#define USBRQ_TYPE_STANDARD (0<<5)
#define USBRQ_TYPE_CLASS (1<<5)
#define USBRQ_TYPE_VENDOR (2<<5)
/* Значения направления USB: */
#define USBRQ_DIR_MASK 0x80
#define USBRQ_DIR_HOST_TO_DEVICE (0<<7)
#define USBRQ_DIR_DEVICE_TO_HOST (1<<7)
/* Стандартные запросы USB */
#define USBRQ_GET_STATUS 0
#define USBRQ_CLEAR_FEATURE 1
#define USBRQ_SET_FEATURE 3
#define USBRQ_SET_ADDRESS 5
#define USBRQ_GET_DESCRIPTOR 6
#define USBRQ_SET_DESCRIPTOR 7
#define USBRQ_GET_CONFIGURATION 8
#define USBRQ_SET_CONFIGURATION 9
#define USBRQ_GET_INTERFACE 10
#define USBRQ_SET_INTERFACE 11
#define USBRQ_SYNCH_FRAME 12
/* Константы дескриптора USB */
#define USBDESCR_DEVICE 1
#define USBDESCR_CONFIG 2
#define USBDESCR_STRING 3
#define USBDESCR_INTERFACE 4
#define USBDESCR_ENDPOINT 5
#define USBDESCR_HID 0x21
#define USBDESCR_HID_REPORT 0x22
#define USBDESCR_HID_PHYS 0x23
#define USBATTR_BUSPOWER 0x80
#define USBATTR_SELFPOWER 0x40
#define USBATTR_REMOTEWAKE 0x20
/* Запросы USB HID */
#define USBRQ_HID_GET_REPORT 0x01
#define USBRQ_HID_GET_IDLE 0x02
#define USBRQ_HID_GET_PROTOCOL 0x03
#define USBRQ_HID_SET_REPORT 0x09
#define USBRQ_HID_SET_IDLE 0x0a
#define USBRQ_HID_SET_PROTOCOL 0x0b
/* ------------------------------------------------------------------------- */
#endif /* __usbdrv_h_included__ */