O dabar pasinersim į USB klavietūros gamybą. Pasinaudosim STM32CubeMX konservais, HID mouse pavyzdžiu, bet perdarysim savaip, kad gautusi klavietūra. Viską darom kaip USB-Peles pavyzdyje. Visiskai viską. Tačiau pakeisime įrenginio aprašymą (descriptor). Labai negudrausim, bet iš www.usb.org nusikrausim HID descriptorių generatorių ir jame pasirinksime klavietūra. Tai universalus ir perteklinis descriptorius, bet kol kas, paprastumo labui, naudosim taip kaip yra.
Programos sugeneruotą descriptorių eksportuojam į “h” tipo failą: keybrd.h (jis bus įdėtas į source code archyvą).
Tiesiogiai “inkliudinti” nesigaus. Todėl atsidarom “usbd_hid.c” failą iš “\Middlewares\ST\STM32_USB_Device_Library\Class\HID\Src” folderio.
Ten pilnas chaosas iš pirmo žvilgsnio. Tačiau taip nėra. USB deskriptorius yra hierarchinis failas kuriame aprašoma viskas- kokio USB tipo įrenginys, kiek valgo elektros, kas pagamino, koks serijinis numeris, kokia įrenginio klasė, kokius standartus (greičius) palaiko… Va jei palaiko kelis greičius, dar aprašomi atskirai kaip veikia ant skirtingo greičio. Gal net galima, jei tipo lėtas USB, tai bus klavietūra, o jei greitas- tai bus klavietūra ir koks nors diskasukis viename. (o gal ir ne). Tačiau svarbu- jei keli greičiai/tipai, tai reikės kelis kartus pakeitinėti iš pelės į klavietūrą (paboldinta):
/************** Descriptor of Joystick Mouse interface ****************/
/* 09 */
0x09, /*bLength: Interface Descriptor size*/
USB_DESC_TYPE_INTERFACE,/*bDescriptorType: Interface descriptor type*/
0x00, /*bInterfaceNumber: Number of Interface*/
0x00, /*bAlternateSetting: Alternate setting*/
0x01, /*bNumEndpoints*/
0x03, /*bInterfaceClass: HID*/
0x01, /*bInterfaceSubClass : 1=BOOT, 0=no boot*/
0x01, /*nInterfaceProtocol : 0=none, 1=keyboard, 2=mouse*/
0, /*iInterface: Index of string descriptor*/
/******************** Descriptor of Joystick Mouse HID ********************/
/* 18 */
0x09, /*bLength: HID Descriptor size*/
HID_DESCRIPTOR_TYPE, /*bDescriptorType: HID*/
0x11, /*bcdHID: HID Class Spec release number*/
0x01,
0x00, /*bCountryCode: Hardware target country*/
0x01, /*bNumDescriptors: Number of HID class descriptors to follow*/
0x22, /*bDescriptorType*/
HID_KEYBOARD_REPORT_DESC_SIZE,/*wItemLength: Total length of Report descriptor*/
0x00,
/******************** Descriptor of Mouse endpoint ********************/
O kur pats deskriptorius:
__ALIGN_BEGIN static uint8_t HID_MOUSE_ReportDesc[HID_MOUSE_REPORT_DESC_SIZE] __ALIGN_END = . . .
pakeičiam dėl grožio iš pelės į klavietūrą. Pačius masyvo beprasmius skaičiukus pakeičiam naujais, iš sugeneruoto failo “keybrd.h”. Kartu pastebim, kad masyvo ilgis 63 baitai. Tą reikia įrašyti į inc failą “usbd_hid.h”, konstanta HID_KEYBOARD_REPORT_DESC_SIZE, o susijusia su pele galime ištrinti. Šiaip, šiame procese labai padeda funcija “find” redaktoriuje.
Mūsų naujas deskriptorius prasideda taip:
__ALIGN_BEGIN static uint8_t HID_KEYBOARD_ReportDesc[HID_KEYBOARD_REPORT_DESC_SIZE] __ALIGN_END =
//char ReportDescriptor[63] = {
0x05, 0x01, // USAGE_PAGE (Generic Desktop)
0x09, 0x06, // USAGE (Keyboard)
. . . .
Teoriškai, dabar projektas turi kompiliuotis, kompas turi pamatyti klavietūrą, bet niekas daugiau neveiktu. Kitas, jau baisus reikalas- jei paspausim pas STM32Cube pergeneruoti kodą- visas USB descriptorių failas bus sunaikintas ir perdarytas atgal į pelės variantą.
Dabar reikia keisti “main.c” failą. Surašom nuorodas į reikiamus failus:
/* USER CODE BEGIN Includes */
#include "usbd_hid.h"
#include "PS2/PS2Keyboard.c"
/* USER CODE END Includes */
nuoroda į USB įrenginį:
/* USER CODE BEGIN PV */
extern USBD_HandleTypeDef hUsbDeviceFS;
/* USER CODE END PV */
O pagrindinėje dalyje (main() ) rašom visą esmę. Pirmiausia kintamieji ir klavietūros reporto struktūra. Kam nepatinka struktūros, galima paimti paprasčiausia 8 baitų buferį. Buferio/struktūros formatas: pirmas baitas- modifikatoriai (alt, šift, windows logo, control), antras baitas- niekas, rezervuota. O likutis, šeši baitai- klavietūros scan kodai. Vienu reportu galima perduoti 6 mygtukų ir 8 modifikatorių akordą. Męs naudosim tik vieną mygtuką.
/* USER CODE BEGIN 1 */
int scancode;
unsigned char passcode=0;
char c;// HID Keyboard
struct keyboardHID_t {
uint8_t modificator; // bitai: 0-LCTRL, 1-LSHIFT, 2-LALT, 3-LGUI, 4-RCTRL, 5-RSHIFT, 6-RALT, 7-RGUI
uint8_t res; // 0x00 nulis
uint8_t key[6];
};struct keyboardHID_t kbdHID;
kbdHID.modificator=0;
kbdHID.res=0;
kbdHID.key[0]=0;
kbdHID.key[1]=0;
kbdHID.key[2]=0;
kbdHID.key[3]=0;
kbdHID.key[4]=0;
kbdHID.key[5]=0;
/* USER CODE END 1 */
Pagrindiniam, amžinam cikle sukam PS2 dekoderį ir siunčiam per USB naujus, HID kodus.
/* USER CODE BEGIN WHILE */
while (1)
{
scancode=get_PS2scan_code();
if (scancode !=0) {
if(scancode==0xF0)
{ passcode=1;
kbdHID.key[0]= 0;
USBD_HID_SendReport(&hUsbDeviceFS, (uint8_t*)&kbdHID, sizeof(struct keyboardHID_t));
}
else
{
if(passcode==1)
{passcode=0;}
else
{
c=scan_decode(scancode);
kbdHID.key[0]= c;
USBD_HID_SendReport(&hUsbDeviceFS, (uint8_t*)&kbdHID, sizeof(struct keyboardHID_t));
}
}
}
/* USER CODE END WHILE */
Suprogramuojam į čipą, kišam į kompą ir veikia. O jei neveikia, neužmirštam išinstaliuoti senus HID pelės draiverius su geltonu šauktuku. USB įrenginio VID/PID tai nesikeitė ir windows atžvilgiu mūsų pelė pradėjo nekorektiškai veikti.
Visas STM32CubeMX projektas, sugeneruotas ir pertaisytas source kodas bei sukompiliuoti failai. Galima tiesiog įrašyti į bluepill ir viskas iškarto veiks.
Beja, jei naudosit mano source ar bin failą, tai nenustabkit, kad naujas įrenginys vadinsis “mygtukynas”. 🙂