Информационный сайт

 

Реклама
bulletinsite.net -> Книги на сайте -> Программисту -> Агуров П.В. -> "Интерфейсы USB. Практика использования и программирования" -> 121

Интерфейсы USB. Практика использования и программирования - Агуров П.В.

Агуров П.В. Интерфейсы USB. Практика использования и программирования — СПб.: БХВ-Петербург, 2004. — 576 c.
ISBN 5-94157-202-6
Скачать (прямая ссылка): interface2004.djvu
Предыдущая << 1 .. 115 116 117 118 119 120 < 121 > 122 123 124 125 126 127 .. 166 >> Следующая

Использование INPUT-репортов
Репорты типа input используются в случае, когда время доставки и обработки данных не критично. Чтение данных со стороны приложения производится С ПОМОЩЬЮ обЫЧНЫХ фуНКЦИЙ ReadFile ИЛИ ReadFileEx (ЄЩЄ ОДИН
способ чтения для Windows XP данных мы рассмотрим в разд. 13.7).
Передача данных через конечную точку состоит из двух операций: заполнения FIFO-буфера этой конечной точки и собственно передачи (листинг 13.37). Заполнять буфер можно в любом месте программы, а передача данных должна производиться при получении запроса от хоста. Для
382
Часть IV. Создание USB-устройств
HID-устройств важно заполнить FIFO-буфер данными, соответствующими структуре, декларированной в дескрипторе репорта (в дескрипторе конечной точки описывается максимальное число байт передачи, а в дескрипторе репорта — структура самих данных).
void main () {
/* основной цикл программы */ for (;;> {
Fill EPl FIFO();
/* обнаружено прерывание от конечной точки */
if (Usb_endpoint_interrupt())
{
/* переключиться на 1 конечную точку */
Osb_select_ep(l);
if (Usb_tx_complete()){
Usb_clear_tx_complete();
end_pointl_ready - FALSE;
}
)
}
} /* end for ;; */
void Fill_EPl_FIFO() {
/* устройство не готово к передаче данных */ if ((usb_configuration_nb — 0) II (usb_suspend())) return;
if (!endjx>intl_ready) /* предыдущий пахет отправлен */ {
Usb_select_ep(l)I
^Листинг 13.37,'Передача данных через конечную точку
Глава 13. HID-устройство на основе Atmel АТ89С5131
383
Usb_write_byte(0x01); Usb_write_byte(0x02); Usb_write_byte(pointl_state); Usb_write_byte(0x04); Usb_write_byte(0x05); usb_write_byte(0x06); Usb_write_byte(0x07); Usb_set_tx_ready();
pointl_state++; endjpointl_ready - TRUE; return;
}
}
Флаг endpointlready позволяет заполнять буфер новыми данными только после передачи предыдущего пакета. Переменная pointi_state является простым счетчиком отправленных пакетов, введенная исключительно для того, чтобы данные не были статическими и хоть немного менялись.
Важно понимать еще одну тонкость работы HID-устройства в случае использования INPUT-репортов. Добавим в функцию передачи данных переключение светодиодного индикатора, подключенного к контакту РЗ.З:
usb_select_ep(1);
if (Usb_tx_complete()){
usb_clear_tx_complete();
end_pointl_ready = FALSE;
P3.3-p_test; p_test=!p_test;
I
Подключив устройство, мы увидим, что обмен данными происходит постоянно, хотя мы со стороны Windows никакие данные не запрашивали! Запустим USB Monitor. Легко увидеть, что HID-драйвер Windows читает данные с устройства каждый раз, когда устройство сообщает о появлении нового пакета данных, т. е. каждый цикл программы. Что же произойдет, если данных не будет? Добавим еще одну строку, позволяющую управлять появлением новых пакетов:
void Fill_EPl_FlFO() (
/* устройство не готово x передаче данных */
384
Часть IV. Создание USB-устройств
if ((usb_configuration_nb — O) It (Usb_suspend()))
return; if (P3.2 — 0)
return;
}
Теперь, нажимая кнопку, соответствующую контакту Р3.2, мы будем прерывать генерацию новых пакетов. Разумеется, при отсутствии новых пакетов HID-драйвер не производит чтения данных с устройства, однако, как мы покажем в следующем разделе, функция чтения данных ReadFile "зависает" до тех пор, пока не сможет получить требуемый пакет.
Таким образом, при использовании INPUT-репортов предпочтительнее генерировать пакеты данных всегда (еще лучше делать это не в цикле программы, а по прерыванию), а при отсутствии новых данных либо посылать предыдущие, либо специальным флагом отмечать, что данные отсутствуют (в Windows XP можно использовать другой механизм чтения данных, см. разд. 13.7).
Оптимальный вариант — выделение чтения данных в отдельный поток и использование асинхронных функций (листинг 13.38)1.
!«Листинг 13.38. Использование асинхронного чтения
ReadOL : TOverLapped; {структура для асинхронного чтения} ReadFlag : Boolean;
HidHandle:= CreateFiie(PChar(SHidName[1]),
GENERIC_READ or GENERICJiRITE, FILE-SHARE-REAd or FILE_SHARE_WRITE, nil,
OFENJSXISTING,
FILE-FLAG-OvERLAPPED, Il открыть для асинхронного доступа О
);
// инициализация буфера
FillChar(InputReport, SizeOf(InputReport), #0);
Более подробно о создании потоков асинхронного чтения можно прочитать в [1].
Глава 13. HID-устройство на основе Atmel АТ89С5131
385
11 создание события для асинхронного чтения
FillChar(ReadOL, SizeOf(ReadOL), 0);
ReadOL.hEvent:= CreateEvent(nil, True, True, nil);
ReadFlag:= False;
Il если не удалось прочитать сразу - операция еще длится,
// или произошла ошибка
If not ReadFile(HidHandle, InputReport,
Capabilities.InputReportByteLength, BytesRead, бReadOL) then begin Il если операция еще длится, то ждем If GetLastErrorJ) = ERROR_IO_PENDING then begin Il ждем 2 cex, если не получилось, выходим
If WaitForSingleObject(ReadOL.hEvent, 2000) = WAIT-OBJECT_0 then ReadFlag:= True; End else begin
lbLog.Items.Add С Ошибка ReadFile'); End; End else begin
ReadFlag:» True; Il прочитали данные сразу End;
Il если данные прочитаны... If ReadFlag then begin
Предыдущая << 1 .. 115 116 117 118 119 120 < 121 > 122 123 124 125 126 127 .. 166 >> Следующая
Реклама
Авторские права © 2009 AdsNet. Все права защищены.
Rambler's Top100