- •Лабораторная работа
- •Структура usb.
- •Физический интерфейс.
- •Модель передачи данных.
- •Типы передачи данных.
- •Протокол.
- •Форматы пакетов.
- •Работа с мышью.
- •Листинг программы для работы с мышью через интерфейс usb (ос Dos):
- •Блок-схема алгоритма:
- •Работа с принтером.
- •Листинг программы: печать заштрихованного квадрата на струйном принтере epson Stylus с интерфейсом usb.
- •Блок-схема алгоритма программы: печать заштрихованного квадрата на струйном принтере epson Stylus с интерфейсом usb
- •Листинг программы для работы с принтером (ос Windows хр) через интерфейс usb.
- •Блок-схема алгоритма:
- •Результат работы программы:
- •Контрольные вопросы:
- •1. Опиши те все, что вы знаете о хост-контроллерах.
- •3. Опишите четыре базовых типа передачи данных, предусмотренных протоколом usb.
- •4. Опишите реализацию запросов к usb устройствам.
- •5. Что такое Human Interface Devices?
- •6. Опишите все, что вы знаете о рапортах.
- •7. Опишите разряды слова состояния конечной точки.
- •8. Опишите модель передачи данных.
- •9. Перечислите и опишите основные операции при работе с интерфейсом usb.
- •10. Опишите формат пакетов передаваемых данных.
- •11. Что вы знаете об однонаправленном и двунаправленном интерфейсах?
- •12. Как проверить принадлежность устройства к классу принтеров?
- •13. Опишите особенности и принцип работы с принтером через usb интерфейс.
- •14. Какие командные языки используются для управления процессом печати?
- •15. Как производится программный сброс принтера?
- •16. Опишите назначение полей bDeviceClass, bDeviceSubClass, bDeviceProtocol в дескрипторе устройства.
- •17. Что происходит по запросу Get Port Status?
- •18. Что происходит по запросу Get Device id?
Листинг программы для работы с мышью через интерфейс usb (ос Dos):
IDEAL
P386
LOCALS
MODEL MEDIUM
; Физический адрес области памяти для списка кадров USB
FrameListBaseAddr equ 200000h
; Параметры экрана в текстовом режиме
ScreenLength equ 80 ;количество символов в строке
ScreenHeigth equ 25 ;количество строк на экране
; Подключить файл мнемонических обозначений
; кодов управляющих клавиш и цветовых кодов
include "list1_03.inc"
; Подключить файл макросов
include "list1_04.inc"
DATASEG
; Старое значение фона символа
OldCharBackground DB 2 DUP(0Fh)
; Текущее состояние кнопок
ButtonsStatus DB 0
; Текущие координаты курсора мыши
XCoordinate DW 0
YCoordinate DW 0
; Предыдущая позиция курсора мыши
OldXCoordinate DW 0
OldYCoordinate DW 0
;>Счетчик перемещений мыщы (в любом направлении)
MovementCounter DD 0
; Режим курсора, нормальный или увеличеный на 2 клетки
CursorMode DB 0
;<
; Текстовые сообщения
Txt0 DB LIGHTBLUE,0,25,"ПОИСК И ТЕСТИРОВАНИЕ МЫШИ USB",0
DB LIGHTMAGENTA,12,9,"Отображение курсора "
DB "осуществляется инверсией атрибута символа",0
DB YELLOW,24,21
DB "Для выхода нажмите левую клавишу мыши",0
Txt1 DB 2,24,"Порядковый номер контроллера:",0
DB 4,8,"Базовый адрес набора регистров:",0
DB 5,8,"Номер используемого прерывания:",0
DB 7,23,"Регистр команды:",0
DB 8,21,"Регистр состояния:",0
DB 9,7,"Регистр управления прерываниями:",0
DB 10,27,"Номер кадра:",0
DB 11,11,"Базовый адрес списка кадров:",0
DB 12,14,"Модификация начала кадра:",0
DB 13,13,"Регистр состояния порта 1:",0
DB 14,13,"Регистр состояния порта 2:",0
DB 16,17,"Адрес активного порта:",0
AnyK DB YELLOW,24,29,"Нажмите любую клавишу",0; Сообщения об ошибках
NoMouse DB 12,31,"Мышь не обнаружена",0
; ДЕСКРИПТОРЫ КОМАНД
; Дескриптор команды "Get Device Descriptor"
GetDevDesc DB 80h,6
DW 100h,0,8
; Дескриптор команды "Set Address"
SetAddrDesc DB 0,5
DW 0,0,0
; Дескриптор команды "Get Configuration Descriptor"
GetConfDesc DB 80h,6
DW 200h,0,8
; Дескриптор команды "Set Configuration"
SetConfigur DB 00h,9
DW 1,0,0
ENDS
SEGMENT sseg para stack 'STACK'
DB 400h DUP(?)
ENDS
; Область памяти для хранения дескрипторов передачи
SEGMENT USB_DESCR para public 'DATA'
; Заголовок очереди дескрипторов
QH_Descriptor DD 00000003h ;единственный заголовок
DD 00000000h ;указатель на первый TD
DD 0,0,0,0,0,0 ;область данных ПО
; Список дескрипторов для одной транзакции
TD_Array DD 8*16 DUP(0)
ENDS
CODESEG
;*****************************
;* Основной модуль программы *
;*****************************
PROC USB_Mouse
mov AX,DGROUP
mov DS,AX
mov [CS:MainDataSeg],AX
; Установить текстовый режим и очистить экран
mov AX,3
int 10h
; Скрыть курсор - убрать за нижнюю границу экрана
mov [ScreenString],25
mov [ScreenColumn],0
call SetCursorPosition
; Проверить наличие PCI BIOS
mov AX,0B101h
int 1Ah
jc @@PCIBIOSNotFound
cmp EDX,20494350h
jne @@PCIBIOSNotFound
; Установить режим прямой адресации памяти
call Initialization
; Инициализировать дескрипторы USB
call InitializeDeascriptors
; ЦИКЛ ПОИСКА ХОСТ-КОНТРОЛЛЕРОВ
mov [SearchResult],0
mov [USB_HostIndex],0
@@NextHost:
; Найти контроллер USB
call FindUSBController
cmp [SearchResult],0
jne @@NoHost
; Произвести глобальный сброс контроллера
mov DX,[USB_BaseAddr]
mov AX,100b ;установить сигнал сброса
out DX,AX
; Ожидать не менее 10 мс
call Wait05s
; Снять сигнал сброса
mov AX,0
out DX,AX
; Ожидать не менее 10 мс
call Wait05s
; Обнулить счетчик номеров
mov [USB_Device_Number],0
; Загрузить указатель на список кадров в регистр
; адреса списка кадров
mov DX,[USB_BaseAddr]
add DX,6
mov AX,0
out DX,AX
add DX,2
mov EAX,FrameListBaseAddr
out DX,EAX
; Активизировать хост-контроллер
mov DX,[USB_BaseAddr]
mov AX,1
out DX,AX
; Проверить регистр состояния порта 1
mov [USB_PortNum],1
; Вычислить адрес регистра состояния порта
mov DX,[USB_BaseAddr]
add DX,10h
; Запомнить адрес регистра состояния порта
mov [USB_PortReg],DX
; Проверить наличие устройства
in AX,DX
test AX,000Fh
jz @@TestPort2
; Присвоить устройству порядковый номер
call Enumeration
; Получить дескриптор конфигурации
call GetConfigurationDescriptor
; Устройство является мышью?
cmp [byte ptr DataBuffer+9+5],03h
jne @@TestPort2
cmp [byte ptr DataBuffer+9+7],02h
je @@MouseFound
; Проверить регистр состояния порта 2
@@TestPort2:
mov [USB_PortNum],2
; Вычислить адрес регистра состояния порта
mov DX,[USB_BaseAddr]
add DX,12h
; Запомнить адрес регистра состояния порта
mov [USB_PortReg],DX
; Проверить наличие устройства
in AX,DX
test AX,000Fh
jz @@ContrStop
; Присвоить устройству порядковый номер
call Enumeration
; Получить дескриптор конфигурации
call GetConfigurationDescriptor
cmp [byte ptr DataBuffer+9+5],03h
jne @@TestPort2
cmp [byte ptr DataBuffer+9+7],02h
je @@MouseFound
; Остановить контроллер
@@ContrStop:
mov DX,[USB_BaseAddr]
mov AX,0
out DX,AX
jmp @@NextHost
@@MouseFound:
; Вывести текстовые сообщения на экран
MShowColorText 3,Txt0
; СКОНФИГУРИРОВАТЬ УСТРОЙСТВО
; Подать команду "Set Configuration"
mov SI,offset SetConfigur
call Setup_Transaction
; Определить адрес конечной точки и размер пакета
call IntEndpointDescriptor
; Отобразить курсор мыши первый раз
call ShowNewMouseCursorPosition
; Сбросить триггер данных
mov [dword ptr DataTrigger],0
@@NextInterrupt:
; Принять от мыши пакет данных
call InterruptIN_Transaction
; Прибавить перемещение по X к координате X
mov AL,[DataBuffer+1]
cbw
add AX,[XCoordinate]
js @@X1
cmp AX,ScreenLength
jb @@X2
mov AX,ScreenLength-1
jmp @@X2
@@X1: xor AX,AX
@@X2: mov [XCoordinate],AX
; Прибавить перемещение по Y к координате Y
mov AL,[DataBuffer+2]
cbw
add AX,[YCoordinate]
js @@Y1
cmp AX,ScreenHeigth
jb @@Y2
mov AX,ScreenHeigth-1
jmp @@Y2
@@Y1: xor AX,AX
@@Y2: mov [YCoordinate],AX
; Показать курсор в новой позиции
call ShowNewMouseCursorPosition
;>Если нажата левая кнопка показать сообщение "Left clicked"
test [DataBuffer],00000001b
jz @@RightClick
MShowColorText 1,Txt2
; Если нажата правая кнопка показать сообщение "Right clicked"
@@RightClick:
test [DataBuffer],00000010b
jz @@NoClick
MShowColorText 1,Txt3
@@NoClick:
; Проверить состояние буфера клавиатуры
mov AH,1
int 16h
jz @@Next
; Принять символ из буфера клавиатуры
mov AX,0
int 16h
; Завершить програму если нажа Escape
cmp AH,01h
je @@Exit
; Поменять форму курсора если нажат пробел
cmp AH,39h
jne @@Next
not [CursorMode]
; Продолжить прием событий
@@Next:
jmp @@NextInterrupt
@@Exit:
;<
; Остановить контроллер
mov DX,[USB_BaseAddr]
mov AX,0
out DX,AX
; Переустановить текстовый режим и очистить экран
mov AX,3
int 10h
; Выход в DOS
mov AH,4Ch
int 21h
; Обработка ошибок
@@NoHost:
cmp [USB_HostIndex],0
je @@HostNotFound
jmp short @@MouseNotFound
; Не поддерживается PCI BIOS
@@PCIBIOSNotFound:
MFatalError NoPCI
; Неверный номер регистра
@@BadRegisterNumber:
MFatalError BadRg
; Нет ни одного контроллера USB
@@HostNotFound:
MFatalError NoUSB
; Мышь USB не найдена
@@MouseNotFound:
MFatalError NoMouse
ENDP USB_Mouse
;*******************************************
;* ОТОБРАЖЕНИЕ КУРСОРА МЫШИ ПУТЕМ ИНВЕРСИИ *
;* АТРИБУТА СИМВОЛА В ПОЗИЦИИ КУРСОРА *
;*******************************************
PROC ShowNewMouseCursorPosition NEAR
pusha
push ES
;>Показать координаты курсора в верхнем правом углу
MShowHexWord 1,70,[YCoordinate]
MShowHexWord 1,75,[XCoordinate]
; Проверить сосотяние буфера клавиатуры
mov AH,02h
int 16h
mov AH,AL
; Если зажат Alt, перемещение только по горизонтали
test AL,04h
jz @@TestY
mov AX,[OldXCoordinate]
mov [XCoordinate],AX
jmp @@TestOk
@@TestY:
; Если зажат Cntl, перемещение только по вертикали
test AL,08h
jz @@TestOk
mov AX,[OldYCoordinate]
mov [YCoordinate],AX
; Посчитать общее количество пперемещений курсора по оси X и Y
@@TestOk:
push ECX
xor EAX,EAX
mov ECX,EAX
mov AX,[YCoordinate]
sub AX,[OldYCoordinate]
jns @AX_AbsValue
not AX
inc AX
@AX_AbsValue:
mov CX,[XCoordinate]
sub CX,[OldXCoordinate]
jns @@CX_AbsValue
not CX
inc CX
@@CX_AbsValue:
; Показать количество перемещений в верхнем правом углу
add EAX,ECX
add [MovementCounter],EAX
pop ECX
MShowHexDWord 1,60,[MovementCounter]
;<
; Настроить ES на видеопамять
mov AX,0B800h
mov ES,AX
; Вычислить старую координату курсора
mov AX,[OldYCoordinate]
mov DX,160
mul DX
add AX,[OldXCoordinate]
add AX,[OldXCoordinate]
inc AX
mov DI,AX
; Восстановить атрибут символа
mov AL,[OldCharBackground]
mov [ES:DI],AL
;> Восстановить атрибут символа для курсора большого размера
push DI
mov AL,[OldCharBackground+1]
add DI,2
mov [ES:DI],AL
pop DI
;<
; Вычислить новую координату курсора
mov AX,[YCoordinate]
mov DX,160
mul DX
add AX,[XCoordinate]
add AX,[XCoordinate]
inc AX
mov DI,AX
; Сохранить атрибут символа
mov AL,[ES:DI]
mov [OldCharBackground],AL
;>Сохранить атрибут символа для курсора большого размера
push DI
add DI,2
mov AL,[ES:DI]
mov [OldCharBackground+1],AL
pop DI
; Если включен режим большого курсора, инвертировать артибут
cmp [CursorMode],0
jz @@Xor1
push DI
add DI,2
xor [byte ptr ES:DI],1111111b
pop DI
@@Xor1:
;<
; Инвертировать атрибут
xor [byte ptr ES:DI],1111111b
; Запомнить координаты символа
mov AX,[XCoordinate]
mov [OldXCoordinate],AX
mov AX,[YCoordinate]
mov [OldYCoordinate],AX
pop ES
popa
ret
ENDP ShowNewMouseCursorPosition
;********************************************
;* ПРИНЯТЬ ПАКЕТ ПО ПРЕРЫВАНИЮ *
;* Передаваемые параметры: *
;* INT_DataSize - объем принимаемых данных. *
;********************************************
PROC InterruptIN_Transaction near
pushad
; Загрузить в ESI указатель на массив дескрипторов
mov ESI,[Addr_TD_Array]
; Загрузить в EBX указатель на буфер данных
mov EBX,[Addr_DataDescr]
; Сформировать дескриптор данных
; Указатель на следующий TD
mov [dword ptr GS:ESI],1b ;последний TD
; Слово управления
mov EAX,[ShDevType] ;тип устройства
or EAX,00800000h ;признак активности
mov [GS:ESI+4],EAX
; Маркер
mov EAX,69h ;прием данных
or EAX,[ShFuncNum] ;номер функции
or EAX,[ShEndpNum] ;конечная точка
or EAX,[DataTrigger]
or EAX,[ShPackSize] ;размер блока
mov [GS:ESI+8],EAX
; Переключить триггер данных
xor [dword ptr DataTrigger],80000h
mov [GS:ESI+12],EBX ;буфер данных
xor EAX,EAX
mov [GS:ESI+16],EAX
mov [GS:ESI+20],EAX
mov [GS:ESI+24],EAX
mov [GS:ESI+28],EAX
; Установить указатель на список дескрипторов
; (контроллер начинает передачу данных)
mov EAX,[Addr_TD_Array]
mov ESI,[Addr_QH]
add ESI,4
mov [GS:ESI],EAX
; Ожидать завершения операции
@@Wait_OpComplete:
cmp [dword ptr GS:ESI],1b
jne @@Wait_OpComplete
popad
ret
ENDP InterruptIN_Transaction
;*****************************************
;* ОПРЕДЕЛИТЬ МАКСИМАЛЬНЫЙ РАЗМЕР ПАКЕТА *
;* ДЛЯ ИСПОЛЬЗУЕМОЙ КОНЕЧНОЙ ТОЧКИ *
;*****************************************
PROC IntEndpointDescriptor near
pusha
; Поиск дескриптора конечной точки в списке дескрипторов
mov BX,0 ;счетчик байтов
@@NextDescriptor:
cmp [word ptr DataBuffer+BX],0507h
je @@Endpoint
@@NextDescOffset:
; Вычислить смещение следующего дескриптора
add BL,[DataBuffer+BX]
adc BH,0
; Проверка на превышение длины массива
cmp BX,[word ptr DataBuffer+2]
jb @@NextDescriptor
MFatalError NoDev
@@Endpoint:
; Точка передачи по прерываниям?
test [DataBuffer+BX+2],10000000b
jz @@NextDescOffset
cmp [DataBuffer+BX+3],3
jne @@NextDescOffset
; Запомнить адрес конечной точки
xor EAX,EAX
mov AL,[DataBuffer+BX+2]
and AL,00001111b
shl EAX,15
mov [ShEndpNum],EAX
; Запомнить размер пакета
xor EAX,EAX
mov AX,[word ptr DataBuffer+BX+4]
dec AX
shl EAX,21
mov [ShPackSize],EAX
popa
ret
ENDP IntEndpointDescriptor
ENDS
; Подключить процедуры ввода данных и вывода на экран
; в текстовом режиме
include "list1_02.inc"
; Подключить подпрограмму, переводящую сегментный
; регистр GS в режим линейной адресации
include "list2_01.inc"
; Подключить процедуры для работы с контроллером USB
include "list8_01.inc"
END
Блок-схема алгоритма программы:
Результат работы программы.
Листинг программы для работы с мышью (ОС Windows ХР)
через интерфейс USB.
//---------------------------------------------------------------------------
#include <vcl.h>
#pragma hdrstop
#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
RECT LR;
LR.left=100;
LR.top=100;
LR.right=500;
LR.bottom=500;
ClipCursor(&LR);// Ограничиваем в заданой области
}
// Освободить курсор можно, передав функции NULL:
//---------------------------------------------------------------------------
void __fastcall TForm1::Button2Click(TObject *Sender)
{
HWND i;
i=LoadImage(0,"3dgarro.cur",IMAGE_CURSOR,0,0,LR_LOADFROMFILE);
if (i==0) ShowMessage("Ошибка загрузки курсора!");
else
{
Screen->Cursors[1]=i;
Form1->Cursor=1;
}
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button3Click(TObject *Sender)
{
ClipCursor(NULL);
}
//---------------------------------------------------------------------------
void __fastcall TForm1::FormMouseMove(TObject *Sender, TShiftState Shift,
int X, int Y)
{
TPoint cPt;
GetCursorPos(&cPt);
Label1->Caption=cPt.y; //Возвращает y-позицию курсора мыши
GetCursorPos(&cPt);
Label2->Caption=cPt.x; //Возвращает x-позицию курсора мыши
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button4Click(TObject *Sender)
{
SetCursorPos(50,50);}