V-USB и libusb комуникират с USB HID устройство, използвайки USB контролни съобщения,
Статията се занимава с метода за използване на функциитеusbFunctionSetup(от библиотекатаV-USB) иusb_control_msg(от библиотекатаlibusb) за организиране на обмена между устройствотоUSB HID(работи на базата на библиотеката V-USB) от програма на компютъра (хост софтуер, работи на базата на libusb библиотека).
Накратко, библиотеките V-USB и libusb ви позволяват да разработвате USB устройства на конвенционални AtmelAVRмикроконтролери и да пишете междуплатформен (Windows, MAC OS, *nix) хост софтуер за тях. Вижте връзките за подробности.
Обменът на данни с помощта на контролни съобщения (контролни съобщения) е удобен, когато не е необходимо да прехвърляте голямо количество данни наведнъж (до 4 байта). Всички обмени на информация в двете посоки (както от USB HID устройството към хост софтуера, така и обратно от хост софтуера към USB HID устройството) се извършват само по инициатива на хоста. За да прехвърли данни от USB HID устройство, хост софтуерът използва заявка със стойностCUSTOM_RQ_GET_STATUS, а за да изпрати данни към USB устройство, заявка със стойностCUSTOM_RQ_SET_STATUS(за това хост софтуерът използва извикването на функцията usb_control_msg със съответните параметри). В отговор USB HID на фърмуера в своята функция usbFunctionSetup трябва да анализира стойността на входящата заявка и в зависимост от това или да получи данни (в отговор на заявка CUSTOM_RQ_SET_STATUS), или да подготви данни за изпращане (в отговор на заявка CUSTOM_RQ_GET_STATUS).
Нека анализираме метода на обмен, използвайки примера на hid-custom-rq (този пример може да бъде изтеглен от архива avr-usb-russian.rar [3]). В този пример софтуерът на хоста управлява светодиода, свързан към щифта на микроконтролера (вижте диаграмата на макетната платка AVR-USB-MEGA16 за пример) или чете неговото състояние. И в двата случая самоедин байт, което е напълно достатъчно за такава задача. Ще разгледам само онези части от примерния код, които ще трябва да бъдат модифицирани в случай на създаване на собствен софтуер.
[Изпращане на данни от хост софтуер към USB HID устройство]
В този случай ние контролираме състоянието на светодиода. Хост софтуерът използва извикването на функцията usb_control_msg с параметъра CUSTOM_RQ_SET_STATUS, за да изпрати байт (вижте модула examples\hid-custom-rq\commandline\set-led.c, основна функция):
Сега по-подробно за предназначението на всяка променлива.
handle- манипулатор на споделеното USB HID устройство. Кодът, който отваря USB HID устройството и получава ненулева стойност на променливата на манипулатора, не се разглежда тук, тъй като не променяме нищо в него - глупаво оставяме всичко както в примераcnt- броят байтове, получени от USB HID устройството в отговор на заявката CUSTOM_RQ_SET_STATUS. В този случай стойността на cnt просто сигнализира за грешка, ако cnt е отрицателен.isOnе байтът на полезния товар за изпращане. Ако е равно на 0, тогава светодиодът ще се изключи, ако е 1, тогава ще светне.bufferе просто тъпа променлива, която не се използва тук по никакъв начин. Когато изпращате заявка CUSTOM_RQ_SET_STATUS, състоянието на данните на буфера на входа на функцията usb_control_msg може да бъде произволно и тези данни нямат значение. При излизане от функцията usb_control_msg буферният буфер също не се анализира, в него няма полезни данни.
Присвояване на параметър на функцията usb_control_msg (вижте документацията за функцията usb_control_msg libusb Ръководство за разработчици сайт:libusb.sourceforge.net):
1. usb_dev_handle *dev. Тук се използва стойността на манипулаторната променлива - предава се идентификаторът на отвореното USB HID устройство. Вземете валиден манипулатор след товаедно извикване на функцията usbOpenDevice (от модула opendevice.c).2. int тип заявка, тип заявка. Стойността му е USB_TYPE_VENDOR USB_RECIP_DEVICE USB_ENDPOINT_OUT. Указва USB крайната точка на устройството USB_ENDPOINT_OUT.3. int заявка, стойността на заявката. Стойността на CUSTOM_RQ_SET_STATUS се замества тук, което означава, че предаваме данни в заявката.4. int стойност. Максимум два байта могат да бъдат предадени в този параметър (т.е. долните 16 бита на 32-битов параметър int). В нашия пример тук се предава стойността на променливата isOn, която носи информация, че светодиодът трябва да бъде изключен (isOn=0) или включен (isOn=1).5. int индекс. Тук се предава нула и в нашия пример този параметър не се използва, но тук могат да бъдат предадени още 2 байта данни за полезен товар. По този начин, като използвате заявката CUSTOM_RQ_SET_STATUS, можете да прехвърлите максимум 4 байта полезна информация от хост софтуера към USB HID на устройството (в стойностите на параметъра 4 стойност и 5 индекс).6. char*байтове. Указател към буфер, разпределен в паметта. В случай на заявка CUSTOM_RQ_SET_STATUS, този буфер не се използва по никакъв начин и няма начин да се използва за прехвърляне на информация.7. int размер. Размерът на буфера се предава тук. В случай на заявка CUSTOM_RQ_SET_STATUS винаги се изпраща 0, друга стойност няма ефект.8. int таймаут. Времето за изчакване, в рамките на което трябва да пристигне отговорът. Стойността е 5000, което вероятно означава 5000 милисекунди).
В USB HID устройство заявката CUSTOM_RQ_SET_STATUS обработва кода в тялото на функцията usbFunctionSetup. Този код включва или изключва светодиода:
От кода се вижда, че се анализират данните от полетоwValueна структуратаusbRequest_t. Стойността на wValue е равна на стойността на параметър 4 в извикването на функциятаusb_control_msg, в нашия пример тук се предава стойността на променливата isOn. Размерът на полето wValue е 16 бита, тук могат да се прехвърлят 2 байта полезна информация. Други 2 байта могат да бъдат предадени чрез полетоwIndex(съответства на параметъра 5 int index във функцията usb_control_msg). Възможно е още 2 байта да бъдат прекарани през полето wLength, но не съм го пробвал.
[Изпращане на данни от USB HID устройство към хост софтуер]
В този случай четем състоянието на светодиода. Хост софтуерът използва извикването на функцията usb_control_msg с параметъра CUSTOM_RQ_GET_STATUS, за да получи байта, който съдържа състоянието на светодиода (вижте модула examples\hid-custom-rq\commandline\set-led.c, основна функция):
Върнатата стойност на променливата cnt, равна на нула и по-малка от нула, сигнализира за грешка, в случай на връщане на 1 или повече, това означава, че заявката е обработена успешно. В действителност се връща един байт, така че cnt трябва да е равно на 1 (това е точно равно на стойността, която функцията usbFunctionSetup връща при обработка на заявката CUSTOM_RQ_GET_STATUS: return 1). Полезният товар се предава в първия байт на буфера. Присвояване на променливи в извикването на функцията usb_control_msg:
1. usb_dev_handle *dev. Тук нищо не се е променило, всичко е същото като при изпращане на заявката CUSTOM_RQ_SET_STATUS.2. int тип заявка, тип заявка. Стойността му е USB_TYPE_VENDOR USB_RECIP_DEVICE USB_ENDPOINT_IN. Единствената разлика тук е, че крайната точка USB_ENDPOINT_IN е указана, а не USB_ENDPOINT_OUT.3. int заявка, стойността на заявката. Стойността CUSTOM_RQ_GET_STATUS се замества тук, което означава, че изпращаме заявка за получаване на данни.4. int стойност. Изпраща се 0, параметърът не се използва.5. int индекс. Изпраща се 0, параметърът не се използва.6. char*байтове.Указател към буфер, разпределен в паметта. В случай на заявка CUSTOM_RQ_GET_STATUS, този буфер се използва за прехвърляне на данни от USB устройството към хост софтуера. В нашия пример се предава само един байт, който носи информация за състоянието на светодиода. Фактът, че има само един байт, се указва чрез връщане 1 при изход от usbFunctionSetup в случай на обработка на заявката CUSTOM_RQ_GET_STATUS (вижте USB HID код на устройство, main.c модул).7. int размер. Размерът на буфера се предава тук. В случай на заявка CUSTOM_RQ_GET_STATUS се предава стойност 4, отразяваща действителния размер на буфера.8. int таймаут. Тук всичко е същото.
От страната на USB HID на устройството, заявката CUSTOM_RQ_GET_STATUS обработва прост код в тялото на функцията usbFunctionSetup:
Всичко! Не е необходимо да знаете нищо друго, за да организирате прост работещ обмен на данни до 4 байта в двете посоки. Повтарям още веднъж, че данните се изпращат към USB устройството в заявката CUSTOM_RQ_SET_STATUS чрез параметри 4 стойност и 5 индекс на извикването на функцията usb_control_msg (в USB HID устройство тези данни влизат в съответните полета на структурата usbRequest_t), а данните се получават от USB устройството чрез заявката CUSTOM_RQ_GET_STATUS и специален буфер за данни.
[Промяна на параметрите на USB устройството - име на устройството, неговия VID и PID]