USB et PIC - WordPress.com · 2016-05-17 · ! 1! USB et PIC: guide rapide pour un cadre de HID USB...

29
1 USB et PIC: guide rapide pour un cadre de HID USB Comment utiliser un cadre open source USB avec les microcontrôleurs PIC Open source GPL2 firmware USB 2.0 haut débit Classe HID Fonctionne sur 18F2550, 2450, 2455, 2553, 4450, 4455, 4550, 4553 code C, à être compilé avec MCC18 (version d'évaluation aussi) Pas besoin de pilotes exemple de communication pour Windows et Linux Pas besoin de bibliothèques de DDK ou propriétaires Version Linux utilise hiddev, le gestionnaire natif HID Introduction Ce guide ne vise pas à être complet en aucune façon. Le but est de présenter et documenter un exemple rapide sur la façon de mettre en œuvre un dispositif USB à l'aide d'un microcontrôleur PIC18, sur la configuration du firmware et logiciel . Il est maintenant très facile de mettre en place un périphérique USB avec un PIC18, comme le montre le schéma ci-dessous (LED indiquent que l'état de connexion):

Transcript of USB et PIC - WordPress.com · 2016-05-17 · ! 1! USB et PIC: guide rapide pour un cadre de HID USB...

Page 1: USB et PIC - WordPress.com · 2016-05-17 · ! 1! USB et PIC: guide rapide pour un cadre de HID USB Comment utiliser un cadre open source USB avec les microcontrôleurs PIC Open source

  1  

USB et PIC: guide rapide pour un cadre de HID USB Comment utiliser un cadre open source USB avec les

microcontrôleurs PIC Open source GPL2 firmware USB 2.0 haut débit Classe HID Fonctionne sur 18F2550, 2450, 2455, 2553, 4450, 4455, 4550, 4553 code C, à être compilé avec MCC18 (version d'évaluation aussi) Pas besoin de pilotes exemple de communication pour Windows et Linux Pas besoin de bibliothèques de DDK ou propriétaires Version Linux utilise hiddev, le gestionnaire natif HID Introduction Ce guide ne vise pas à être complet en aucune façon. Le but est de présenter et documenter un exemple rapide sur la façon de mettre en œuvre un dispositif USB à l'aide d'un microcontrôleur PIC18, sur la configuration du firmware et logiciel . Il est maintenant très facile de mettre en place un périphérique USB avec un PIC18, comme le montre le schéma ci-dessous (LED indiquent que l'état de connexion):

Page 2: USB et PIC - WordPress.com · 2016-05-17 · ! 1! USB et PIC: guide rapide pour un cadre de HID USB Comment utiliser un cadre open source USB avec les microcontrôleurs PIC Open source

  2  

Contrairement aux interfaces série et parallèle, USB a besoin d'un processus de recensement compliqué pour établir un canal de communication. Les cadres dits USB sont des bibliothèques de code qui cachent les détails du protocole, de sorte qu'il est possible d'utiliser l'interface très rapidement pour communiquer avec un PC. L'une des plus utilisée provient de Microchip, mais possède une licence fermée et une structure peu compliquée; en plus plus ou moins tous les vendeurs de compilateurs donnent un cadre à leurs produits un prix élevé. Sur le front open source, il ya des exemples de cadres USB génériques, mais ici nous voulons documenter un projet qui est

Page 3: USB et PIC - WordPress.com · 2016-05-17 · ! 1! USB et PIC: guide rapide pour un cadre de HID USB Comment utiliser un cadre open source USB avec les microcontrôleurs PIC Open source

  3  

pratiquement inconnu et difficile à trouver, qui implémente également la classe HID. Certaines modifications ont été nécessaires pour compiler avec MCC18; il initialement requis CCSD. La classe HID Le protocole USB divise tous les périphériques dans différentes catégories, en fonction des besoins et des limites de transfert de données; il est même possible de spécifier une nouvelle classe, mais en utilisant un standard a l'avantage que tous les principaux systèmes d'exploitation incluent déjà le pilote logiciel approprié. En particulier, la classe HID (Human Interface Device), qui comprend les claviers et les souris, est parfaite pour l'interfaçage de petits microcontrôleurs: les données sont généralement échangées à l'aide des transferts d'interruption avec un maximum de 64 octets par paquet et une vitesse maximale de 64 Ko / s. Au cours de l'énumération des périphériques HID le système lit une structure de données appelée rapport HID descripteur, qui indique le nombre d'octets à transférer et la façon d'interpréter les données. Ce procédé est très souple et permet de définir tous les types de dispositifs, par exemple un clavier avec des touches supplémentaires ou avec pointeur intégré, et en général toutes les combinaisons qui ne serait pas explicitement décrite dans un système d'exploitation. Pour plus d'informations, consultez la spécification de classe HID . Cependant, dans les projets de l'électronique, nous sommes souvent pas intéressé à décrire ce que bits ou les octets signifient; si nous nous soucions seulement de transférer des données du rapport descripteur sera seulement spécifier la taille du paquet. Les données sont échangées par le biais d'un rapport de sortie et un rapport d'entrée, sous la direction respectivement de et vers le PC; il est également possible d'utiliser un rapport de fonction dans les deux sens.

Page 4: USB et PIC - WordPress.com · 2016-05-17 · ! 1! USB et PIC: guide rapide pour un cadre de HID USB Comment utiliser un cadre open source USB avec les microcontrôleurs PIC Open source

  4  

Configurer et utiliser le firmware La première chose à faire est d'installer MPLAB et MCC18 (; télécharger une fois du site de Microchip . Ici , nous mettons un exemple d'application; il inclut les fichiers sources C et un projet de MPLAB. Le dispositif résultant utilise le premier octet du paquet entrant pour contrôler le port B (PORTB <7: 2>); RB1 et RB0 indiquent la méthode de transfert utilisée: 01 = rapport de sortie via interruption, 10 = rapport de fonction, 11 = rapport de sortie via le contrôle final. La réponse est constituée par: l'état du port A (1 octet); le type de transfert, si 0xF0 interruption, 0xF1 si caractéristique, si 0xF2 contrôle; un horodatage de 2 octets incrémenté tous les 10,93 ms; les octets restants reçus. Le usb.c du fichier source contient les structures de données qui permettent d'identifier le périphérique; le premier à être lu est le descripteur de périphérique: octet rom deviceDescriptor [] = { 0x12, 0x01, // bLength, bDescriptorType 0x00, 0x02, // bcdUSB (octet de poids faible), bcdUSB (octet de poids fort) 0x00, 0x00, // bDeviceClass, bDeviceSubClass 0x00, E0SZ, // bDeviceProtocl, bMaxPacketSize 0xD8, 0x04, // idVendor (octet de poids faible), idVendor (octet haut) 0xFF, 0x01, // idProduct (octet de poids faible), idProduct (octet haut) 0x01, 0x00, // bcdDevice (octet de poids faible), bcdDevice (octet de poids fort) 0x01, 0x02, // iManufacturer, iProduct 0x00, 0x01 // iSerialNumber (none),

Page 5: USB et PIC - WordPress.com · 2016-05-17 · ! 1! USB et PIC: guide rapide pour un cadre de HID USB Comment utiliser un cadre open source USB avec les microcontrôleurs PIC Open source

  5  

bNumConfigurations }; Vid et Pid sont généralement affectés par le consortium USB sous paiement, mais bien sûr, pour les projets non commerciaux, il est possible d'utiliser un nombre quelconque, par exemple 4D8 1FF; 0x4D8 est l'ID de Microchip. Le rapport descripteur est un rapport de 64 octets avec une application réservée; cela signifie que le système ne tentera pas de décoder et utiliser, comme il le ferait avec des claviers et des souris; le rapport de fonctionnalité est également 64 octets de long: rom octet HIDReport [HID_REPORT_SIZE] = { 0x06, 0xa0, 0xff, // USAGE_PAGE (fournisseur défini Page 1) 0x09, 0x01, // UTILISATION (Vendor Utilisation 1) 0xA1, 0x01, // COLLECTION (Application) // Le rapport d'entrée 0x09, 0x03, // Utilisation ID - fournisseur défini 0x15, 0x00, // logique minimum (0) 0x26, 0xFF, 0x00, // logique maximale (255) 0x75, 0x08, // Rapport Taille (8 bits) 0x95, 0x40, // Rapport comte (64 domaines) 0x81, 0x02, // entrée (données, variables, Absolute) // Le rapport de sortie 0x09, 0x04, // Utilisation ID - fournisseur défini 0x15, 0x00, // logique minimum (0) 0x26, 0xFF, 0x00, // logique maximale (255) 0x75, 0x08, // Rapport Taille (8 bits) 0x95, 0x40, // Rapport comte (64 domaines) 0x91, 0x02, // Sortie (données, variables, Absolute) // Le rapport complet

Page 6: USB et PIC - WordPress.com · 2016-05-17 · ! 1! USB et PIC: guide rapide pour un cadre de HID USB Comment utiliser un cadre open source USB avec les microcontrôleurs PIC Open source

  6  

0x09, 0x01, // Utilisation ID - fournisseur défini 0x15, 0x00, // logique minimum (0) 0x26, 0xFF, 0x00, // logique maximale (255) 0x75, 0x08, // Rapport Taille (8 bits) 0x95, 0x40, // Rapport comte (64 domaines) 0xB1, 0x02, // Fonction (données, variables, Absolute) 0xc0 de la END_COLLECTION }; La différence entre / rapport d'entrée-sortie et rapport de caractéristique est que l’ ancien usage était généralement un transfert d'interruption (le max de 64Ko /) point d'extrémité 1, le dernier est toujours un transfert de contrôle au point final 0, qui est partagé avec le flux de messages standard USB; dans ce cas, à la différence des transferts d'interruption, le système d'exploitation ne garantit pas une latence maximale mais un équilibre entre le flux de données ; les transferts sont divisées en paquets de bMaxPacketSize0, qui est spécifié dans le descripteur de dispositif; dans usb.h ils sont définis comme E0SZ. Le rapport de fonction a été conçue pour transférer de façon sporadique options de configuration ou les attributs à d'autres données (par exemple l'état des voyants du clavier), les déclarations d'entrée / sortie porteraient les données réelles; le concepteur doit choisir celle (s) à utiliser. Si il n'y a pas besoin d'un rapport de fonctionnalité, il est possible de supprimer la section correspondante du rapport descripteur; supprimer également HIDFeatureBuffer [HID_FEATURE_REPORT_BYTES] et les fonctions SetupFeatureReport (octet reportID), SetFeatureReport (octet reportID), et GetFeatureReport (octet reportID); enfin supprimer les appels à ces fonctions dans ProcessControlTransfer (vide) et ProcessHIDRequest (void) Une autre façon d'accéder aux rapports d'entrée / sortie utilise les messages HID GET_REPORT et SET_REPORT dirigés vers l'endpoint 0 (mode de commande); il est similaire au transfert de

Page 7: USB et PIC - WordPress.com · 2016-05-17 · ! 1! USB et PIC: guide rapide pour un cadre de HID USB Comment utiliser un cadre open source USB avec les microcontrôleurs PIC Open source

  7  

rapport de fonction, et les mêmes considérations faite avant appliquer aussi; Mais la documentation du système d'exploitation conseille d'utiliser le mode d'interruption pour les transferts continus. Si il n'y a pas besoin d'utiliser GET_REPORT et SET_REPORT il est possible de supprimer des fonctions SetupOutputReport (octet reportID), SetOutputReport (octet reportID), et GetInputReport (octet reportID); également supprimer les appels à ProcessControlTransfer (vides) et ProcessHIDRequest (vides). Retour à la configuration, les descripteurs de chaîne sont lus par le système pour donner une description textuelle de fournisseur et du produit; ils doivent être de 2 octets unicode comme l'exemple suivant: octet rom stringDescriptor1 [] = { 18, STRING_DESCRIPTOR, // bLength, bDscType 'S', 0, 't', 0, 'r', 0, 'I', 0, 'n', 0, 'g', 0, '', 0, '1', 0, }; En usb.h est spécifié la taille de rapports de données; Celles-ci doivent être écrites dans le rapport descripteur: #define HID_INPUT_REPORT_BYTES 64 #define HID_OUTPUT_REPORT_BYTES 64 #define HID_FEATURE_REPORT_BYTES 64 Les routines de communication USB sont mises en œuvre sans interruption; cela est possible parce que le protocole précise des temps de réponse très longs (après énumération, il ya une deuxième limite de 5 pour les transferts de données) et le périphérique USB continue à envoyer des paquets Nack automatiquement si de nouvelles données ne sont pas disponibles. L'avantage est que les fonctions de l'utilisateur peuvent prendre le plein contrôle du microcontrôleur. Le cycle principal appelle à plusieurs reprises le gestionnaire de transactions USB et la fonction de l'utilisateur processio (): while (1) {

Page 8: USB et PIC - WordPress.com · 2016-05-17 · ! 1! USB et PIC: guide rapide pour un cadre de HID USB Comment utiliser un cadre open source USB avec les microcontrôleurs PIC Open source

  8  

EnableUSBModule (); si (UCFGbits.UTEYE = 1!) ProcessUSBTransactions (); Processio (); } Evidemment ProcessUSBTransactions () gère le protocole, à savoir ce qui vient à point final 0. Ce qui est intéressant pour l'utilisateur est de savoir comment envoyer et recevoir des données; rapports d'entrée et de sortie sont transférés à des tampons de endpoint1 (HIDRxBuffer et HIDTxBuffer, en USB RAM), et à partir de là, ils doivent être copiés à un emplacement de l'utilisateur en appelant la fonction de lecture: number_of_bytes_read = HIDRxReport (receive_buffer, HID_OUTPUT_REPORT_BYTES); Lecture de données vide le tampon d'entrée et permet à l'appareil de recevoir un nouveau rapport; jusqu'à ce point toutes les données entrantes ne sont pas acceptées. Voici la radiation correspondant: number_of_bytes_written = HIDTxReport (transmit_buffer, HID_INPUT_REPORT_BYTES); Lors de l'utilisation GET_REPORT et SET_REPORT il est nécessaire d'insérer un code d'utilisateur dans les fonctions SetOutputReport (octet reportID) et GetInputReport (octet reportID). Donc, avec les transferts d'interruption, le code d'utilisateur doit vérifier si quelque chose a été reçue; avec des transferts de commande est la manipulation de routine de protocole qui appelle la fonction de l'utilisateur chaque fois qu'un transfert est terminé. En ce qui concerne le rapport de fonction, la procédure est similaire à celle décrite ci-dessus, seulement modifier les fonctions: SetFeatureReport (octet reportID) et GetFeatureReport (octet reportID). Comment compiler Ce projet utilise le compilateur MPLAB MCC18, mais

Page 9: USB et PIC - WordPress.com · 2016-05-17 · ! 1! USB et PIC: guide rapide pour un cadre de HID USB Comment utiliser un cadre open source USB avec les microcontrôleurs PIC Open source

  9  

probablement le chemin de l'exécutable sera différent; la première fois que vous compilez MPLAB relèvera ce et vous permettra d'utiliser les bons chemins. Il est également nécessaire de changer le chemin de la bibliothèque: des options de projet, les répertoires de la section, cliquez sur suite défauts de s ou régler les chemins manuellement. Si vous voulez changer de dispositif (actuellement le 18F2550), aller à Configurer -> Sélectionner le périphérique. Il sera nécessaire de modifier les bits de configuration en conséquence, et pour spécifier un nouveau script de liaison; son exécution par défaut est ok, sauf pour les appareils avec moins de RAM, comme 18F2450 et 4450: Ici, vous devez réduire la taille de la pile à quelque chose comme 40 octets. L'oscillateur à quartz peut fonctionner à n'importe quel multiple de 4 MHz, tant que diviseur d'entrée est réglée en conséquence; maintenant il fonctionne à 12 MHz. Comment simuler MPSIM ne prend pas en charge les périphériques USB actuellement, mais de toute façon il ne serait pas utile de simuler le processus de recensement; ce qui est important est de vérifier le code qui utilise les données transférées. Il peut être fait comme suit: ajouter un point d'arrêt sur la ligne if ((deviceState <configuré) || (== 1) UCONbits.SUSPND) return; exécuter (Run, F9, ou sur le bouton aller); à partir des registres de fichiers ou la fenêtre Montre changer la valeur de deviceState à 5 (qui correspond à l'état configuré). De cette façon, vous sautez énumération; maintenant vous devez vous arrêter après la fonction HIDRxReport et modifier le nombre d'octets lus (variable number_of_bytes_read). Les données transférées doivent être écrites manuellement sur HIDrxBuffer.

Page 10: USB et PIC - WordPress.com · 2016-05-17 · ! 1! USB et PIC: guide rapide pour un cadre de HID USB Comment utiliser un cadre open source USB avec les microcontrôleurs PIC Open source

  10  

A partir de maintenant il est comme une session ordinaire de débogage. Pour simuler la transmission est suffisante pour modifier number_of_bytes_written, si elle est utilisée. Communication avec le PC le code de communication dépend du système d'exploitation; il est généralement possible d'utiliser les bibliothèques tout-en-un qui prennent soin de détection et de communication dispositif, mais je préfère ne pas dépendre de paquets externes (qui transportent leurs propres problèmes de licence) et d'utiliser le système d'exploitation directement. Fenêtres Notre exemple de C (compilé avec DevC ++ ) est un programme en ligne de commande qui envoie et reçoit un paquet de 64 octets à l'aide de diverses méthodes. Pour éviter d'utiliser le (kit de développement DDK ) nous lisons explicitement les bibliothèques système nécessaires, hid.dll et Setupapi.dll, et chargeons manuellement les fonctions nécessaires. Le programme analyse tous les périphériques HID jusqu'à ce qu'il en trouve un avec le bon vid & pid. Il existe 3 méthodes pour échanger des données avec: rapport entrée / sortie en mode interruption, en mode de commande, ou avec un rapport de fonction. Le firmware doit bien sûr appuyer la méthode que vous choisissez. Microsoft conseille d'utiliser le mode d'interruption pour les transferts continus; dans ce cas, les fonctions sont similaires à déposer I / O: Résultat = WriteFile (WRITEHANDLE, bufferU, DIMBUF, et BytesWritten, NULL); à écrire, et Résultat = ReadFile (ReadHandle, bufferI, DIMBUF, et NumberOfBytesRead, (lpOverlapped) & HIDOverlapped);

Page 11: USB et PIC - WordPress.com · 2016-05-17 · ! 1! USB et PIC: guide rapide pour un cadre de HID USB Comment utiliser un cadre open source USB avec les microcontrôleurs PIC Open source

  11  

Résultat = WaitForSingleObject (hEventObject, 10); ResetEvent (hEventObject); à lire. Ceci est une lecture asynchrone, à savoir ReadFile renvoie immédiatement et vous devez appeler WaitForSingleObject et attendre l'achèvement d'E / S. Communication en mode de contrôle (par SET_REPORT et GET_REPORT) peut être commandée avec: HidD_SetOutputReport (DeviceHandle, bufferOut, n) à écrire, et HidD_GetOutputReport (DeviceHandle, Bufferin, n) à lire. De même d'utiliser le rapport de fonction: HidD_SetFeature (DeviceHandle, bufferOut, n) à écrire, et HidD_GetFeature (DeviceHandle, Bufferin, n) à lire. Dans tous ces cas, le premier octet transféré indique l'ID de rapport (généralement 0); d'autres données suivent, si la totalité des augmentations de taille par une (ici 65 octets). Si vous demandez moins de données que spécifié dans le rapport descripteur le système signale une erreur; si vous demandez plus la réponse est complétée par des zéros. Voir le code réel pour plus de détails. HidCom restaurant: -h, --help aide -c, --control utiliser le transfert de contrôle [no] \ -d, --delay lire retard (ms) [0] -f, rapport de fonction de l'utilisation --feature [no] -i, --info info dispositif [no] -I, Octet de chaque incrément --increment 6 de transfert [no] \ -p, ID pid du produit [0x1FF] -q, réponse d'impression --quiet ne [pas] -r N fois répétées --repeat [1]

Page 12: USB et PIC - WordPress.com · 2016-05-17 · ! 1! USB et PIC: guide rapide pour un cadre de HID USB Comment utiliser un cadre open source USB avec les microcontrôleurs PIC Open source

  12  

-s, --size taille du rapport [64] -v, --vid Vendor ID [0x4D8] Exemple: HidCom -i -d -r 5 16 1 2 3 4 5 6 7 8 9 0 abcdef Linux De toutes les méthodes possibles pour communiquer avec des périphériques HID- utiliser ce qui est probablement le niveau le plus bas: l'interaction avec hiddev, le pilote Linux HID; De cette façon, il n'y a pas besoin de bibliothèques externes. Après avoir branché un périphérique du système d'exploitation HID crée un périphérique / dev / usb / hiddevX, où X est un numéro progressif. Vous devez lire les droits de communiquer avec lui: > Sudo chmod a + r / dev / usb / hiddev0 Pour activer en permanence un utilisateur faire ce qui suit (sur Ubuntu et autres distributions basées sur Debian, vérifier pour les autres): en tant que root créer un fichier /etc/udev/rules.d/99-hiddev.rules si vous souhaitez activer l'écriture d'un groupe d'utilisateurs: KERNEL == "hiddev [0-9]", sous-système == "usb", SYSFS {} == idProduct, SYSFS {} idVendor == "04d8", GROUP = "<groupe>" "de 01FF" où <groupe> est l'un des groupes d'utilisateurs (pour obtenir un type de liste "groupes"); sélectionner un groupe approprié et si votre utilisateur desn't lui appartiennent exécuter "addgroup <utilisateur> <groupe>". Ou, si vous voulez permettre à tous les utilisateurs, modifier les autorisations de lecture: KERNEL == "hiddev [0-9]", sous-système == "usb", SYSFS {} idProduct == "01FF", SYSFS {} idVendor == "04d8", MODE = "0664" redémarrer udev pour appliquer les modifications:

Page 13: USB et PIC - WordPress.com · 2016-05-17 · ! 1! USB et PIC: guide rapide pour un cadre de HID USB Comment utiliser un cadre open source USB avec les microcontrôleurs PIC Open source

  13  

> /etc/init.d/udev Rechargement Pid et vid venir du firmware exemple, changer en fonction de ce qui est dans l'appareil. Le programme communique à l'aide des appels ioctl, en passant comme paramètre des srutctures de données qui spécifient le mode de transfert. struct hiddev_report_info rep_info_i, rep_info_u; struct hiddev_usage_ref_multi ref_multi_i, ref_multi_u; Hiddev a été développé pour les appareils classiques d'entrée / sortie, de sorte que de nombreuses fonctions pour vérifier les usages simples indiquées dans le rapport descripteur; mais nous devons trouver un moyen de transférer l'ensemble du rapport en une seule fois; cela est possible avec HIDIOCSUSAGES et HIDIOCGUSAGES; données est en ref_multi_u.values et ref_multi_i.values. Transfert d'interruption: ioctl (fd, HIDIOCSUSAGES, et ref_multi_u); // Ecrire ref_multi_u.values ioctl (fd, HIDIOCSREPORT, et rep_info_u); ... ioctl (fd, HIDIOCGUSAGES, et ref_multi_i); // Lire à ref_multi_i.values ioctl (fd, HIDIOCGREPORT, et rep_info_i); transfert de contrôle: ioctl (fd, HIDIOCSUSAGES, et ref_multi_u); // Ecrire ref_multi_u.values ioctl (fd, HIDIOCSREPORT, et rep_info_u); ... ioctl (fd, HIDIOCGREPORT, et rep_info_i); ioctl (fd, HIDIOCGUSAGES, et ref_multi_i); // Lire à ref_multi_i.values En réalité, seules les lectures sont obligés de contrôler critère; Je ne pouvais pas trouver un moyen de forcer les écritures. Quoi qu'il en soit, il n'y a aucune raison de choisir les transferts de

Page 14: USB et PIC - WordPress.com · 2016-05-17 · ! 1! USB et PIC: guide rapide pour un cadre de HID USB Comment utiliser un cadre open source USB avec les microcontrôleurs PIC Open source

  14  

contrôle lorsque l'interruption est disponible; et si un appareil ne supporte pas l'interrompre est pas donné à hiddev. Transfert à l'aide du rapport de fonction (après avoir spécifié HID_REPORT_TYPE_FEATURE dans les structures de données): ioctl (fd, HIDIOCSUSAGES, et ref_multi_u); // Ecrire ref_multi_u.values ioctl (fd, HIDIOCSREPORT, et rep_info_u); ... ioctl (fd, HIDIOCGREPORT, et rep_info_i); ioctl (fd, HIDIOCGUSAGES, et ref_multi_i); // Lire à ref_multi_i.values Voir le code réel pour plus de détails. HidCom restaurant: -h, --help aide -c, --control utiliser le transfert de contrôle [no] \ -d, --delay lire retard (ms) [0] -f, rapport de fonction de l'utilisation --feature [no] -i, --info info dispositif [no] -I, Octet de chaque incrément --increment 6 de transfert [no] \ --path chemin de l'unité [/ dev / usb / hiddev0] \ -p, ID pid du produit [0x1FF] -q, réponse d'impression --quiet ne [pas] -r N fois répétées --repeat [1] -s, --size taille du rapport [64] -v, --vid Vendor ID [0x4D8]

Page 15: USB et PIC - WordPress.com · 2016-05-17 · ! 1! USB et PIC: guide rapide pour un cadre de HID USB Comment utiliser un cadre open source USB avec les microcontrôleurs PIC Open source

  15  

Exemple: #include <windows.h> #include <setupapi.h> #include <stdio.h> #include <getopt.h> #include <ddk/hidusage.h> #include <ddk/hidpi.h> int main (int argc, char **argv) { int n=65,d=0,info=0,increment=0,p=0,vid=0x4d8,pid=0x1ff,q=0,r=1,f=0,ctrl=0,c,i,j; unsigned char buf[256],bufI[256]; wchar_t string[128]; string[0]=0; for(i=0;i<256;i++) buf[i]=bufI[i]=0; for(i=0;i<128;i++) string[i]=0; opterr=0; int option_index = 0; struct option long_options[] = { {"control", no_argument, &ctrl,1}, {"c", no_argument, &ctrl,1}, {"delay", required_argument, 0, 'd'}, {"d", required_argument, 0, 'd'}, {"feature", no_argument, &f,1}, {"f", no_argument, &f,1}, {"help", no_argument, 0, 'h'}, {"i", no_argument, &info, 1}, {"info", no_argument, &info, 1},

Page 16: USB et PIC - WordPress.com · 2016-05-17 · ! 1! USB et PIC: guide rapide pour un cadre de HID USB Comment utiliser un cadre open source USB avec les microcontrôleurs PIC Open source

  16  

{"I", no_argument,&increment, 1}, {"increment",no_argument,&increment, 1}, {"pid", required_argument, 0, 'p'}, {"quiet", no_argument, &q, 1}, {"q", no_argument, &q, 1}, {"repeat", required_argument, 0, 'r'}, {"size", required_argument, 0, 's'}, {"vid", required_argument, 0, 'v'}, {0, 0, 0, 0} }; while ((c = getopt_long (argc, argv, "cd:fhiIp:qv:r:s:",long_options,&option_index)) != -1) switch (c) { case 'h': printf("hid_test [options] [data]\ \noptions:\ \n-h, --help help\ \n-c, --control use control endpoint [no]\ \n-d, --delay read delay (ms) [0]\ \n-f, --feature use feature report [no]\ \n-i, --info device info [no]\ \n-I, --increment increment byte 6 every transfer [no]\ \n-p, --pid Product ID [0x1FF]\ \n-q, --quiet print response only [no]\ \n-r, --repeat repeat N times [1]\ \n-s, --size report size [64]\ \n-v, --vid Vendor ID [0x4D8]\ \n example: HidCom -i 1 2 3 4\n"); exit(1); break; case 'c': //control endpoint ctrl=1; break; case 'd': //delay

Page 17: USB et PIC - WordPress.com · 2016-05-17 · ! 1! USB et PIC: guide rapide pour un cadre de HID USB Comment utiliser un cadre open source USB avec les microcontrôleurs PIC Open source

  17  

d = atoi(optarg); break; case 'f': //feature report f=1; break; case 'i': //info info=1; break; case 'I': //increment increment=1; break; case 'p': //pid sscanf(optarg, "%x", &pid); break; case 'q': //quiet q=1; break; case 'r': //repeat r = atoi(optarg); break; case 's': //report size n = atoi(optarg)+1; //always add report index break; case 'v': //vid sscanf(optarg, "%x", &vid); break; case '?': fprintf (stderr, "Unknown option character 0x%02x (%c)\n",optopt,optopt); return 1; default: //abort (); break; }

Page 18: USB et PIC - WordPress.com · 2016-05-17 · ! 1! USB et PIC: guide rapide pour un cadre de HID USB Comment utiliser un cadre open source USB avec les microcontrôleurs PIC Open source

  18  

for (j=1,i = optind; i < argc&&i<128; i++,j++) sscanf(argv[i], "%x", &buf[j]); PSP_DEVICE_INTERFACE_DETAIL_DATA detailData; HANDLE DeviceHandle; HANDLE hEventObject; HANDLE hDevInfo; GUID HidGuid; OVERLAPPED HIDOverlapped; ULONG Length; bool MyDeviceDetected; char MyDevicePathName[1024]; DWORD NumberOfBytesRead; HANDLE ReadHandle; ULONG Required; HANDLE WriteHandle; typedef struct _HIDD_ATTRIBUTES { ULONG Size; USHORT VendorID; USHORT ProductID; USHORT VersionNumber; } HIDD_ATTRIBUTES, *PHIDD_ATTRIBUTES; typedef void (__stdcall*GETHIDGUID) (OUT LPGUID HidGuid); typedef BOOLEAN (__stdcall*GETATTRIBUTES)(IN HANDLE HidDeviceObject,OUT PHIDD_ATTRIBUTES Attributes); typedef BOOLEAN (__stdcall*SETNUMINPUTBUFFERS)(IN HANDLE HidDeviceObject,OUT ULONG NumberBuffers); typedef BOOLEAN (__stdcall*GETNUMINPUTBUFFERS)(IN HANDLE HidDeviceObject,OUT PULONG NumberBuffers); typedef BOOLEAN (__stdcall*GETFEATURE) (IN HANDLE HidDeviceObject, OUT PVOID ReportBuffer, IN ULONG ReportBufferLength); typedef BOOLEAN (__stdcall*SETFEATURE) (IN HANDLE

Page 19: USB et PIC - WordPress.com · 2016-05-17 · ! 1! USB et PIC: guide rapide pour un cadre de HID USB Comment utiliser un cadre open source USB avec les microcontrôleurs PIC Open source

  19  

HidDeviceObject, IN PVOID ReportBuffer, IN ULONG ReportBufferLength); typedef BOOLEAN (__stdcall*GETREPORT) (IN HANDLE HidDeviceObject, OUT PVOID ReportBuffer, IN ULONG ReportBufferLength); typedef BOOLEAN (__stdcall*SETREPORT) (IN HANDLE HidDeviceObject, IN PVOID ReportBuffer, IN ULONG ReportBufferLength); typedef BOOLEAN (__stdcall*GETMANUFACTURERSTRING) (IN HANDLE HidDeviceObject, OUT PVOID ReportBuffer, IN ULONG ReportBufferLength); typedef BOOLEAN (__stdcall*GETPRODUCTSTRING) (IN HANDLE HidDeviceObject, OUT PVOID ReportBuffer, IN ULONG ReportBufferLength); typedef BOOLEAN (__stdcall*GETINDEXEDSTRING) (IN HANDLE HidDeviceObject, IN ULONG StringIndex, OUT PVOID ReportBuffer, IN ULONG ReportBufferLength); HIDD_ATTRIBUTES Attributes; SP_DEVICE_INTERFACE_DATA devInfoData; bool LastDevice = FALSE; int MemberIndex = 0; LONG Result; char UsageDescription[256]; Length=0; detailData=NULL; DeviceHandle=NULL; HMODULE hHID=0; GETHIDGUID HidD_GetHidGuid=0; GETATTRIBUTES HidD_GetAttributes=0; SETNUMINPUTBUFFERS HidD_SetNumInputBuffers=0; GETNUMINPUTBUFFERS HidD_GetNumInputBuffers=0; GETFEATURE HidD_GetFeature=0;

Page 20: USB et PIC - WordPress.com · 2016-05-17 · ! 1! USB et PIC: guide rapide pour un cadre de HID USB Comment utiliser un cadre open source USB avec les microcontrôleurs PIC Open source

  20  

SETFEATURE HidD_SetFeature=0; GETREPORT HidD_GetInputReport=0; SETREPORT HidD_SetOutputReport=0; GETMANUFACTURERSTRING HidD_GetManufacturerString=0; GETPRODUCTSTRING HidD_GetProductString=0; hHID = LoadLibrary("hid.dll"); if(!hHID){ printf("Can't find hid.dll"); return 0; } HidD_GetHidGuid=(GETHIDGUID)GetProcAddress(hHID,"HidD_GetHidGuid"); HidD_GetAttributes=(GETATTRIBUTES)GetProcAddress(hHID,"HidD_GetAttributes"); HidD_SetNumInputBuffers=(SETNUMINPUTBUFFERS)GetProcAddress(hHID,"HidD_SetNumInputBuffers"); HidD_GetNumInputBuffers=(GETNUMINPUTBUFFERS)GetProcAddress(hHID,"HidD_GetNumInputBuffers"); HidD_GetFeature=(GETFEATURE)GetProcAddress(hHID,"HidD_GetFeature"); HidD_SetFeature=(SETFEATURE)GetProcAddress(hHID,"HidD_SetFeature"); HidD_GetInputReport=(GETREPORT)GetProcAddress(hHID,"HidD_GetInputReport"); HidD_SetOutputReport=(SETREPORT)GetProcAddress(hHID,"HidD_SetOutputReport"); HidD_GetManufacturerString=(GETMANUFACTURERSTRING)GetProcAddress(hHID,"HidD_GetManufacturerString"); HidD_GetProductString=(GETPRODUCTSTRING)GetProcAddress(hHID,"HidD_GetProductString"); if(HidD_GetHidGuid==NULL\ ||HidD_GetAttributes==NULL\ ||HidD_GetFeature==NULL\ ||HidD_SetFeature==NULL\

Page 21: USB et PIC - WordPress.com · 2016-05-17 · ! 1! USB et PIC: guide rapide pour un cadre de HID USB Comment utiliser un cadre open source USB avec les microcontrôleurs PIC Open source

  21  

||HidD_GetInputReport==NULL\ ||HidD_SetOutputReport==NULL\ ||HidD_GetManufacturerString==NULL\ ||HidD_GetProductString==NULL\ ||HidD_SetNumInputBuffers==NULL\ ||HidD_GetNumInputBuffers==NULL) return -1; HMODULE hSAPI=0; hSAPI = LoadLibrary("setupapi.dll"); if(!hSAPI){ printf("Can't find setupapi.dll"); return 0; } typedef HDEVINFO (WINAPI* SETUPDIGETCLASSDEVS) (CONST GUID*,PCSTR,HWND,DWORD); typedef BOOL (WINAPI* SETUPDIENUMDEVICEINTERFACES) (HDEVINFO,PSP_DEVINFO_DATA,CONST GUID*,DWORD,PSP_DEVICE_INTERFACE_DATA); typedef BOOL (WINAPI* SETUPDIGETDEVICEINTERFACEDETAIL) (HDEVINFO,PSP_DEVICE_INTERFACE_DATA,PSP_DEVICE_INTERFACE_DETAIL_DATA_A,DWORD,PDWORD,PSP_DEVINFO_DATA); typedef BOOL (WINAPI* SETUPDIDESTROYDEVICEINFOLIST) (HDEVINFO); SETUPDIGETCLASSDEVS SetupDiGetClassDevsA=0; SETUPDIENUMDEVICEINTERFACES SetupDiEnumDeviceInterfaces=0; SETUPDIGETDEVICEINTERFACEDETAIL SetupDiGetDeviceInterfaceDetailA=0; SETUPDIDESTROYDEVICEINFOLIST SetupDiDestroyDeviceInfoList=0; SetupDiGetClassDevsA=(SETUPDIGETCLASSDEVS)

Page 22: USB et PIC - WordPress.com · 2016-05-17 · ! 1! USB et PIC: guide rapide pour un cadre de HID USB Comment utiliser un cadre open source USB avec les microcontrôleurs PIC Open source

  22  

GetProcAddress(hSAPI,"SetupDiGetClassDevsA"); SetupDiEnumDeviceInterfaces=(SETUPDIENUMDEVICEINTERFACES) GetProcAddress(hSAPI,"SetupDiEnumDeviceInterfaces"); SetupDiGetDeviceInterfaceDetailA=(SETUPDIGETDEVICEINTERFACEDETAIL) GetProcAddress(hSAPI,"SetupDiGetDeviceInterfaceDetailA"); SetupDiDestroyDeviceInfoList=(SETUPDIDESTROYDEVICEINFOLIST) GetProcAddress(hSAPI,"SetupDiDestroyDeviceInfoList"); if(SetupDiGetClassDevsA==NULL\ ||SetupDiEnumDeviceInterfaces==NULL\ ||SetupDiDestroyDeviceInfoList==NULL\ ||SetupDiGetDeviceInterfaceDetailA==NULL) return -1; /* The following code is adapted from Usbhidio_vc6 application example by Jan Axelson for more information see see http://www.lvr.com/hidpage.htm */ /* API function: HidD_GetHidGuid Get the GUID for all system HIDs. Returns: the GUID in HidGuid. */ HidD_GetHidGuid(&HidGuid); /* API function: SetupDiGetClassDevs Returns: a handle to a device information set for all installed devices. Requires: the GUID returned by GetHidGuid. */

Page 23: USB et PIC - WordPress.com · 2016-05-17 · ! 1! USB et PIC: guide rapide pour un cadre de HID USB Comment utiliser un cadre open source USB avec les microcontrôleurs PIC Open source

  23  

hDevInfo=SetupDiGetClassDevs(&HidGuid,NULL,NULL,DIGCF_PRESENT|DIGCF_INTERFACEDEVICE); devInfoData.cbSize = sizeof(devInfoData); //Step through the available devices looking for the one we want. //Quit on detecting the desired device or checking all available devices without success. MemberIndex = 0; LastDevice = FALSE; do { /* API function: SetupDiEnumDeviceInterfaces On return, MyDeviceInterfaceData contains the handle to a SP_DEVICE_INTERFACE_DATA structure for a detected device. Requires: The DeviceInfoSet returned in SetupDiGetClassDevs. The HidGuid returned in GetHidGuid. An index to specify a device. */ Result=SetupDiEnumDeviceInterfaces (hDevInfo, 0, &HidGuid, MemberIndex, &devInfoData); if (Result != 0) { //A device has been detected, so get more information about it. /* API function: SetupDiGetDeviceInterfaceDetail Returns: an SP_DEVICE_INTERFACE_DETAIL_DATA structure containing information about a device. To retrieve the information, call this function twice. The first time returns the size of the structure in Length.

Page 24: USB et PIC - WordPress.com · 2016-05-17 · ! 1! USB et PIC: guide rapide pour un cadre de HID USB Comment utiliser un cadre open source USB avec les microcontrôleurs PIC Open source

  24  

The second time returns a pointer to the data in DeviceInfoSet. Requires: A DeviceInfoSet returned by SetupDiGetClassDevs The SP_DEVICE_INTERFACE_DATA structure returned by SetupDiEnumDeviceInterfaces. The final parameter is an optional pointer to an SP_DEV_INFO_DATA structure. This application doesn't retrieve or use the structure. If retrieving the structure, set MyDeviceInfoData.cbSize = length of MyDeviceInfoData. and pass the structure's address. */ //Get the Length value. //The call will return with a "buffer too small" error which can be ignored. Result = SetupDiGetDeviceInterfaceDetail(hDevInfo, &devInfoData, NULL, 0, &Length, NULL); //Allocate memory for the hDevInfo structure, using the returned Length. detailData = (PSP_DEVICE_INTERFACE_DETAIL_DATA)malloc(Length); //Set cbSize in the detailData structure. detailData -> cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA); //Call the function again, this time passing it the returned buffer size. Result = SetupDiGetDeviceInterfaceDetail(hDevInfo, &devInfoData, detailData, Length,&Required, NULL);

Page 25: USB et PIC - WordPress.com · 2016-05-17 · ! 1! USB et PIC: guide rapide pour un cadre de HID USB Comment utiliser un cadre open source USB avec les microcontrôleurs PIC Open source

  25  

// Open a handle to the device. // To enable retrieving information about a system mouse or keyboard, // don't request Read or Write access for this handle. /* API function: CreateFile Returns: a handle that enables reading and writing to the device. Requires: The DevicePath in the detailData structure returned by SetupDiGetDeviceInterfaceDetail. */ DeviceHandle=CreateFile(detailData->DevicePath, 0, FILE_SHARE_READ|FILE_SHARE_WRITE, (LPSECURITY_ATTRIBUTES)NULL,OPEN_EXISTING, 0, NULL); /* API function: HidD_GetAttributes Requests information from the device. Requires: the handle returned by CreateFile. Returns: a HIDD_ATTRIBUTES structure containing the Vendor ID, Product ID, and Product Version Number. Use this information to decide if the detected device is the one we're looking for. */ //Set the Size to the number of bytes in the structure. Attributes.Size = sizeof(Attributes); Result = HidD_GetAttributes(DeviceHandle,&Attributes); //Is it the desired device? MyDeviceDetected = FALSE;

Page 26: USB et PIC - WordPress.com · 2016-05-17 · ! 1! USB et PIC: guide rapide pour un cadre de HID USB Comment utiliser un cadre open source USB avec les microcontrôleurs PIC Open source

  26  

char a[256]; if (Attributes.VendorID == vid) { if (Attributes.ProductID == pid) { //Both the Vendor ID and Product ID match. MyDeviceDetected = TRUE; strcpy(MyDevicePathName,detailData->DevicePath); // Get a handle for writing Output reports. WriteHandle=CreateFile(detailData->DevicePath, GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, (LPSECURITY_ATTRIBUTES)NULL,OPEN_EXISTING,0,NULL); //Get a handle to the device for the overlapped ReadFiles. ReadHandle=CreateFile(detailData->DevicePath, GENERIC_READ,FILE_SHARE_READ|FILE_SHARE_WRITE,(LPSECURITY_ATTRIBUTES)NULL, OPEN_EXISTING,FILE_FLAG_OVERLAPPED,NULL); if (hEventObject) CloseHandle(hEventObject); hEventObject = CreateEvent(NULL,TRUE,TRUE,""); //Set the members of the overlapped structure.

Page 27: USB et PIC - WordPress.com · 2016-05-17 · ! 1! USB et PIC: guide rapide pour un cadre de HID USB Comment utiliser un cadre open source USB avec les microcontrôleurs PIC Open source

  27  

HIDOverlapped.hEvent = hEventObject; HIDOverlapped.Offset = 0; HIDOverlapped.OffsetHigh = 0; Result=HidD_SetNumInputBuffers(DeviceHandle,64); } else //The Product ID doesn't match. CloseHandle(DeviceHandle); } else //The Vendor ID doesn't match. CloseHandle(DeviceHandle); //Free the memory used by the detailData structure (no longer needed). free(detailData); } else //SetupDiEnumDeviceInterfaces returned 0, so there are no more devices to check. LastDevice=TRUE; //If we haven't found the device yet, and haven't tried every available device, //try the next one. MemberIndex = MemberIndex + 1; } //do while ((LastDevice == FALSE) && (MyDeviceDetected == FALSE)); //Free the memory reserved for hDevInfo by SetupDiClassDevs. SetupDiDestroyDeviceInfoList(hDevInfo); if (MyDeviceDetected == FALSE){ printf("Can't find device\n"); return -1;

Page 28: USB et PIC - WordPress.com · 2016-05-17 · ! 1! USB et PIC: guide rapide pour un cadre de HID USB Comment utiliser un cadre open source USB avec les microcontrôleurs PIC Open source

  28  

} if(info){ printf("Device detected: vid=0x%04X pid=0x%04X\nPath: %s\n",vid,pid,MyDevicePathName); if(HidD_GetManufacturerString(DeviceHandle,string,sizeof(string))==TRUE) wprintf(L"Manufacturer string: %s\n",string); if(HidD_GetProductString(DeviceHandle,string,sizeof(string))==TRUE) wprintf(L"Product string: %s\n",string); } DWORD BytesWritten=0; for(j=0;j<r;j++){ if(!q){ printf("-> "); for(i=1;i<n;i++) printf("%02X ",(unsigned char)buf[i]); printf("\n"); } if(f){ //use feature report if(HidD_SetFeature(DeviceHandle,buf,n)==FALSE) printf("Error sending feature report\n"); Sleep(d); if(HidD_GetFeature(DeviceHandle,bufI,n)==FALSE) printf("Error receiving feature report\n"); } else if(ctrl){ //use control endpoint if(HidD_SetOutputReport(DeviceHandle,buf,n)==FALSE) printf("Error sending output report through control endpoint\n"); Sleep(d); if(HidD_GetInputReport(DeviceHandle,bufI,n)==FALSE) printf("Error receiving input report through control endpoint\n"); } else{ //use regular file IO

Page 29: USB et PIC - WordPress.com · 2016-05-17 · ! 1! USB et PIC: guide rapide pour un cadre de HID USB Comment utiliser un cadre open source USB avec les microcontrôleurs PIC Open source

  29  

if(WriteFile(WriteHandle,buf,n,&BytesWritten,NULL)==FALSE) printf("Error sending output report\n"); Sleep(d); if(ReadFile(ReadHandle,bufI,n,&NumberOfBytesRead,(LPOVERLAPPED) &HIDOverlapped)==FALSE) printf("Error receiving input report\n"); if(WaitForSingleObject(hEventObject,10)!=WAIT_OBJECT_0) printf("Timeout\n"); ResetEvent(hEventObject); } if(!q) printf("<- "); for(i=1;i<n;i++) printf("%02X ",bufI[i]); printf("\n"); if(increment) buf[6]++; } return 0; }