【USB开发 】用pcDuino的otg做鼠标键盘-Arduino中文社区 - Powered by Discuz! Archiver

土豆变薯条 发表于 2013-12-4 14:24

【USB开发 】用pcDuino的otg做鼠标键盘

有人说现代社会,计算机锁住了人类的双手,为什么呢?因为基本上一个人一天上班8小时手是不断的在键盘鼠标上面工作的。我们能不能让电脑更智 能一些,例如电脑放弃人类的双手 ,更智能的工作,这里pcDuino跟你提过一个建议。让兼容arduino的各种传感器去采集信号,让pcDuino帮你实现鼠标键盘的各种工作。
      

       一,修改内核
                                                                                           vim vim linux-sunxi/drivers/usb/gadget/hid.c #在里面添加几个结构体和几行代码
               static LIST_HEAD(hidg_func_list);
               /* hid descriptor for a keyboard */
               static struct hidg_func_descriptor pcduino_keyboard_date = {
                   .subclass       = 0, /* No subclass */
                   .protocol       = 1, /* Keyboard */
                   .report_length      = 8,
                   .report_desc_length = 63,
                   .report_desc      = {
                     0×05, 0×01, /* USAGE_PAGE (Generic Desktop)         */
                     0×09, 0×06, /* USAGE (Keyboard)                     */
                     0xa1, 0×01, /* COLLECTION (Application)               */
                     0×05, 0×07, /*   USAGE_PAGE (Keyboard)                */
                     0×19, 0xe0, /*   USAGE_MINIMUM (Keyboard LeftControl) */
                     0×29, 0xe7, /*   USAGE_MAXIMUM (Keyboard Right GUI)   */
                     0×15, 0×00, /*   LOGICAL_MINIMUM (0)                  */
                     0×25, 0×01, /*   LOGICAL_MAXIMUM (1)                  */
                     0×75, 0×01, /*   REPORT_SIZE (1)                      */
                     0×95, 0×08, /*   REPORT_COUNT (8)                     */
                     0×81, 0×02, /*   INPUT (Data,Var,Abs)               */
                     0×95, 0×01, /*   REPORT_COUNT (1)                     */
                     0×75, 0×08, /*   REPORT_SIZE (8)                      */
                     0×81, 0×03, /*   INPUT (Cnst,Var,Abs)               */
                     0×95, 0×05, /*   REPORT_COUNT (5)                     */
                     0×75, 0×01, /*   REPORT_SIZE (1)                      */
                     0×05, 0×08, /*   USAGE_PAGE (LEDs)                  */
                     0×19, 0×01, /*   USAGE_MINIMUM (Num Lock)             */
                     0×29, 0×05, /*   USAGE_MAXIMUM (Kana)               */
                     0×91, 0×02, /*   OUTPUT (Data,Var,Abs)                */
                     0×95, 0×01, /*   REPORT_COUNT (1)                     */
                     0×75, 0×03, /*   REPORT_SIZE (3)                      */
                     0×91, 0×03, /*   OUTPUT (Cnst,Var,Abs)                */
                     0×95, 0×06, /*   REPORT_COUNT (6)                     */
                     0×75, 0×08, /*   REPORT_SIZE (8)                      */
                     0×15, 0×00, /*   LOGICAL_MINIMUM (0)                  */
                     0×25, 0×65, /*   LOGICAL_MAXIMUM (101)                */
                     0×05, 0×07, /*   USAGE_PAGE (Keyboard)                */
                     0×19, 0×00, /*   USAGE_MINIMUM (Reserved)             */
                     0×29, 0×65, /*   USAGE_MAXIMUM (Keyboard Application) */
                     0×81, 0×00, /*   INPUT (Data,Ary,Abs)               */
                     0xc0      /* END_COLLECTION                         */
                   }
               };
               static struct platform_device pcduino_hid_keyboard = {
                   .name         = “hidg”,
                   .id         = 0,
                   .num_resources      = 0,
                   .resource       = 0,
                   .dev.platform_data= &pcduino_keyboard_date,
               };
               /* hid descriptor for a mouse */
               static struct hidg_func_descriptor pcduino_mouse_data = {
                .subclass = 0, //No SubClass
                .protocol = 2, //Mouse
                .report_length = 4,
                .report_desc_length = 52,
                .report_desc = {
                0×05, 0×01,//Usage Page(Generic Desktop Controls)
                0×09, 0×02,//Usage (Mouse)
                0xa1, 0×01,//Collction (Application)
                0×09, 0×01,//Usage (pointer)
                0xa1, 0×00,//Collction (Physical)
                0×05, 0×09,//Usage Page (Button)
                0×19, 0×01,//Usage Minimum(1)
                0×29, 0×05,//Usage Maximum(5)
                0×15, 0×00,//Logical Minimum(1)
                0×25, 0×01,//Logical Maximum(1)
                0×95, 0×05,//Report Count(5)
                0×75, 0×01,//Report Size(1)
                0×81, 0×02,//Input(Data,Variable,Absolute,BitField)
                0×95, 0×01,//Report Count(1)
                0×75, 0×03,//Report Size(3)
                0×81, 0×01,//Input(Constant,Array,Absolute,BitField)
                0×05, 0×01,//Usage Page(Generic Desktop Controls)
                0×09, 0×30,//Usage(x)
                0×09, 0×31,//Usage(y)
                0×09, 0×38,//Usage(Wheel)
                0×15, 0×81,//Logical Minimum(-127)
                0×25, 0x7F,//Logical Maximum(127)
                0×75, 0×08,//Report Size(8)
                0×95, 0×03,//Report Count(3)
                0×81, 0×06,//Input(Data,Variable,Relative,BitField)
                0xc0,//End Collection
                0xc0//End Collection
                }
               };
            
               static struct platform_device pcduino_hid_mouse = {
                .name = “hidg”,
                .id = 1,
                .num_resources = 0,
                .resource = 0,
                .dev.platform_data = &pcduino_mouse_data,
               };
               static int __init hidg_init(void)
               {
                   int status;
            
                   status = platform_device_register(&pcduino_hid_keyboard);
                   if (status < 0) {
                     printk(“hid keyboardreg failed\n”);
                     platform_device_unregister(&pcduino_hid_keyboard);
                     return status;
                   }
                   status = platform_device_register(&pcduino_hid_mouse);
                   if (status < 0) {
                     printk(“hid mouse regfailed\n”);
                     platform_device_unregister(&pcduino_hid_mouse);
                     return status;
                   }
            
            
                   status = platform_driver_probe(&hidg_plat_driver,
                               hidg_plat_driver_probe);
                   if (status < 0)
                     return status;
            
                   status = usb_composite_probe(&hidg_driver, hid_bind);
                   if (status < 0)
                     platform_driver_unregister(&hidg_plat_driver);
            
                   return status;
               }
               module_init(hidg_init);
            
               static void __exit hidg_cleanup(void)
               {
                   platform_driver_unregister(&hidg_plat_driver);
                   platform_device_unregister(&pcduino_hid_keyboard);
                   platform_device_unregister(&pcduino_hid_mouse);
                   usb_composite_unregister(&hidg_driver);
               }
               结构体是需要添加的,后面两个函数里面要加上结构注册。这里说明一下,根据usb协议,每一个设备都要有描述符,两个结构体就是hid 鼠标键盘的描述符。下面配置内核。
                              Device Drivers—>
                         [*] USB support—>
                                   <M>   USB Gadget Support—>
                                                    <M>   SoftWinner SUN4I USB Peripheral Controller                              
                                   < >   Dummy HCD (DEVELOPMENT)                        
                                         USB Gadget Drivers                              
                                   < >   Gadget Zero (DEVELOPMENT)                     
                                   < >   Audio Gadget (EXPERIMENTAL)                     
                                   <M>   Ethernet Gadget (with CDC Ethernet support)   
                                   [*]       RNDIS support                                 
                                   [ ]       Ethernet Emulation Model (EEM) support      
                                   < >   Network Control Model (NCM) support            
                                   < >   Gadget Filesystem (EXPERIMENTAL)               
                                   < >   Function Filesystem (EXPERIMENTAL)            
                                   < >   File-backed Storage Gadget (DEPRECATED)         
                                   < >   Mass Storage Gadget                           
                                   <M>   Serial Gadget (with CDC ACM and CDC OBEX support)
                                   <M>   MIDI Gadget (EXPERIMENTAL)                     
                                   <M>   Printer Gadget                                 
                                   < >   CDC Composite Device (Ethernet and ACM)         
                                   < >   CDC Composite Device (ACM and mass storage)      
                                   < >   Multifunction Composite Gadget (EXPERIMENTAL)   
                                   <M>   HID Gadget                                    
                                   < >   EHCI Debug Device Gadget                        
                                   < >   USB Webcam Gadget
            
            
            
         
         
         
      
      
      
      二,加载内核                               关于怎么使用编译生成的内核,已经写过好多文章了。这里大致提一下。
                  sudo mount/dev/nanda/mnt
         tar xvf pcduino_a10_hwpack_20131129.tar.xz
         cpkernel/*/mnt-f
         cprootfs/lib/modules/3.4.29+/lib/modules/
         vim /etc/modules #添加下面内容
         sw_usb_udc
         g_hid
         
      
      
      
       三,测试驱动
                               这里测试用到的是linux-sunxi/Documentation/usb里面的测试程序。
                   1 /* hid_gadget_test */
         2
         3 #include <pthread.h>
         4 #include <string.h>
         5 #include <stdio.h>
         6 #include <ctype.h>
         7 #include <fcntl.h>
         8 #include <errno.h>
         9 #include <stdio.h>
          10 #include <stdlib.h>
          11 #include <unistd.h>
          12
          13 #define BUF_LEN 512
          14
          15 struct options {
          16   const char    *opt;
          17   unsigned char val;
          18 };
          19
          20 static struct options kmod[] = {
          21   {.opt = “–left-ctrl”,      .val = 0×01},
          22   {.opt = “–right-ctrl”,   .val = 0×10},
          23   {.opt = “–left-shift”,   .val = 0×02},
          24   {.opt = “–right-shift”,    .val = 0×20},
          25   {.opt = “–left-alt”,       .val = 0×04},
          26   {.opt = “–right-alt”,      .val = 0×40},
          27   {.opt = “–left-meta”,      .val = 0×08},
          28   {.opt = “–right-meta”,   .val = 0×80},
          29   {.opt = NULL}
          30 };
          31
          32 static struct options kval[] = {
          33   {.opt = “–return”, .val = 0×28},
          34   {.opt = “–esc”,    .val = 0×29},
          35   {.opt = “–bckspc”, .val = 0x2a},
          36   {.opt = “–tab”,    .val = 0x2b},
          37   {.opt = “–spacebar”,   .val = 0x2c},
          38   {.opt = “–caps-lock”,.val = 0×39},
          39   {.opt = “–f1″,   .val = 0x3a},
          40   {.opt = “–f2″,   .val = 0x3b},
          41   {.opt = “–f3″,   .val = 0x3c},
          42   {.opt = “–f4″,   .val = 0x3d},
          43   {.opt = “–f5″,   .val = 0x3e},
          44   {.opt = “–f6″,   .val = 0x3f},
          45   {.opt = “–f7″,   .val = 0×40},
          46   {.opt = “–f8″,   .val = 0×41},
          47   {.opt = “–f9″,   .val = 0×42},
          48   {.opt = “–f10″,    .val = 0×43},
          49   {.opt = “–f11″,    .val = 0×44},
          50   {.opt = “–f12″,    .val = 0×45},
          51   {.opt = “–insert”, .val = 0×49},
          52   {.opt = “–home”,   .val = 0x4a},
          53   {.opt = “–pageup”, .val = 0x4b},
          54   {.opt = “–del”,    .val = 0x4c},
          55   {.opt = “–end”,    .val = 0x4d},
          56   {.opt = “–pagedown”,   .val = 0x4e},
          57   {.opt = “–right”,.val = 0x4f},
          58   {.opt = “–left”,   .val = 0×50},
          59   {.opt = “–down”,   .val = 0×51},
          60   {.opt = “–kp-enter”,   .val = 0×58},
          61   {.opt = “–up”,   .val = 0×52},
          62   {.opt = “–num-lock”,   .val = 0×53},
          63   {.opt = NULL}
          64 };
          65
          66 int keyboard_fill_report(char report, char buf, int *hold)
          67 {
          68   char *tok = strtok(buf, ” “);
          69   int key = 0;
          70   int i = 0;
          71
          72   for (; tok != NULL; tok = strtok(NULL, ” “)) {
          73
          74         if (strcmp(tok, “–quit”) == 0)
          75             return -1;
          76
          77         if (strcmp(tok, “–hold”) == 0) {
          78             *hold = 1;
          79             continue;
          80         }
          81
          82         if (key < 6) {
          83             for (i = 0; kval.opt != NULL; i++)
          84               if (strcmp(tok, kval.opt) == 0) {
          85                     report = kval.val;
          86                     break;
          87               }
          88             if (kval.opt != NULL)
          89               continue;
          90         }
          91
          92         if (key < 6)
          93             if (islower(tok)) {
          94               report = (tok – (‘a’ – 0×04));
          95               continue;
          96             }
          97
          98         for (i = 0; kmod.opt != NULL; i++)
          99             if (strcmp(tok, kmod.opt) == 0) {
         100               report = report | kmod.val;
         101               break;
         102             }
         103         if (kmod.opt != NULL)
         104             continue;
         105
         106         if (key < 6)
         107             fprintf(stderr, “unknown option: %s\n”, tok);
         108   }
         109   return 8;
         110 }
         111
         112 static struct options mmod[] = {
         113   {.opt = “–b1″, .val = 0×01},
         114   {.opt = “–b2″, .val = 0×02},
         115   {.opt = “–b3″, .val = 0×04},
         116   {.opt = NULL}
         117 };
         118
         119 int mouse_fill_report(char report, char buf, int *hold)
         120 {
         121   char *tok = strtok(buf, ” “);
         122   int mvt = 0;
         123   int i = 0;
         124   for (; tok != NULL; tok = strtok(NULL, ” “)) {
         125
         126         if (strcmp(tok, “–quit”) == 0)
         127             return -1;
         128
         129         if (strcmp(tok, “–hold”) == 0) {
         130             *hold = 1;
         131             continue;
         132         }
         133
         134         for (i = 0; mmod.opt != NULL; i++)
         135             if (strcmp(tok, mmod.opt) == 0) {
         136               report = report | mmod.val;
         137               break;
         138             }
         139         if (mmod.opt != NULL)
         140             continue;
         141
         142         if (!(tok == ‘-’ && tok == ‘-’) && mvt < 2) {
         143             errno = 0;
         144             report = (char)strtol(tok, NULL, 0);
         145             if (errno != 0) {
         146               fprintf(stderr, “Bad value:’%s’\n”, tok);
         147               report = 0;
         148             }
         149             continue;
         150         }
         151
         152         fprintf(stderr, “unknown option: %s\n”, tok);
         153   }
         154   return 3;
         155 }
         156
         157 static struct options jmod[] = {
         158   {.opt = “–b1″,   .val = 0×10},
         159   {.opt = “–b2″,   .val = 0×20},
         160   {.opt = “–b3″,   .val = 0×40},
         161   {.opt = “–b4″,   .val = 0×80},
         162   {.opt = “–hat1″,   .val = 0×00},
         163   {.opt = “–hat2″,   .val = 0×01},
         164   {.opt = “–hat3″,   .val = 0×02},
         165   {.opt = “–hat4″,   .val = 0×03},
         166   {.opt = “–hatneutral”, .val = 0×04},
         167   {.opt = NULL}
         168 };
         169
         170 int joystick_fill_report(char report, char buf, int *hold)
         171 {
         172   char *tok = strtok(buf, ” “);
         173   int mvt = 0;
         174   int i = 0;
         175
         176   *hold = 1;
         177
         178   /* set default hat position: neutral */
         179   report = 0×04;
         180
         181   for (; tok != NULL; tok = strtok(NULL, ” “)) {
         182
         183         if (strcmp(tok, “–quit”) == 0)
         184             return -1;
         185
         186         for (i = 0; jmod.opt != NULL; i++)
         187             if (strcmp(tok, jmod.opt) == 0) {
         188               report = (report & 0xF0) | jmod.val;
         189               break;
         190             }
         191         if (jmod.opt != NULL)
         192             continue;
         193
         194         if (!(tok == ‘-’ && tok == ‘-’) && mvt < 3) {
         195             errno = 0;
         196             report = (char)strtol(tok, NULL, 0);
         197             if (errno != 0) {
         198               fprintf(stderr, “Bad value:’%s’\n”, tok);
         199               report = 0;
         200             }
         201             continue;
         202         }
         203
         204         fprintf(stderr, “unknown option: %s\n”, tok);
         205   }
         206   return 4;
         207 }
         208
         209 void print_options(char c)
         210 {
         211   int i = 0;
         212
         213   if (c == ‘k’) {
         214         printf(“    keyboard options:\n”
         215                “      –hold\n”);
         216         for (i = 0; kmod.opt != NULL; i++)
         217             printf(“\t\t%s\n”, kmod.opt);
         218         printf(“\nkeyboard values:\n”
         219                “       or\n”);
         220         for (i = 0; kval.opt != NULL; i++)
         221             printf(“\t\t%-8s%s”, kval.opt, i % 2 ? “\n” : “”);
         222         printf(“\n”);
         223   } else if (c == ‘m’) {
         224         printf(“    mouse options:\n”
         225                “      –hold\n”);
         226         for (i = 0; mmod.opt != NULL; i++)
         227             printf(“\t\t%s\n”, mmod.opt);
         228         printf(“\nmouse values:\n”
         229                ”      Two signed numbers\n”
         230                “–quit to close\n”);
         231   } else {
         232         printf(“    joystick options:\n”);
         233         for (i = 0; jmod.opt != NULL; i++)
         234             printf(“\t\t%s\n”, jmod.opt);
         235         printf(“\njoystick values:\n”
         236                “      three signed numbers\n”
         237                “–quit to close\n”);
         238   }
         239 }
         240
         241 int main(int argc, const char *argv[])
         242 {
         243   const char *filename = NULL;
         244   int fd = 0;
         245   char buf;
         246   int cmd_len;
         247   char report;
         248   int to_send = 8;
         249   int hold = 0;
         250   fd_set rfds;
         251   int retval, i;
         252
         253   if (argc < 3) {
         254         fprintf(stderr, “Usage: %s devname mouse|keyboard|joystick\n”,
         255             argv);
         256         return 1;
         257   }
         258
         259   if (argv != ‘k’ && argv != ‘m’ && argv != ‘j’)
         260       return 2;
         261
         262   filename = argv;
         263
         264   if ((fd = open(filename, O_RDWR, 0666)) == -1) {
         265         perror(filename);
         266         return 3;
         267   }
         268
         269   print_options(argv);
         270
         271   while (42) {
         272
         273         FD_ZERO(&rfds);
         274         FD_SET(STDIN_FILENO, &rfds);
         275         FD_SET(fd, &rfds);
         276
         277         retval = select(fd + 1, &rfds, NULL, NULL, NULL);
         278         if (retval == -1 && errno == EINTR)
         279             continue;
         280         if (retval < 0) {
         281             perror(“select()”);
         282             return 4;
         283         }
         284
         285         if (FD_ISSET(fd, &rfds)) {
         286             cmd_len = read(fd, buf, BUF_LEN – 1);
         287             printf(“recv report:”);
         288             for (i = 0; i < cmd_len; i++)
         289               printf(” %02x”, buf);
         290             printf(“\n”);
         291         }
         292
         293         if (FD_ISSET(STDIN_FILENO, &rfds)) {
         294             memset(report, 0×0, sizeof(report));
         295             cmd_len = read(STDIN_FILENO, buf, BUF_LEN – 1);
         296
         297             if (cmd_len == 0)
         298               break;
         299
         300             buf = ‘\0′;
         301             hold = 0;
         302
         303             memset(report, 0×0, sizeof(report));
         304             if (argv == ‘k’)
         305               to_send = keyboard_fill_report(report, buf, &hold);
         306             else if (argv == ‘m’)
         307               to_send = mouse_fill_report(report, buf, &hold);
         308             else
         309               to_send = joystick_fill_report(report, buf, &hold);
         310
         311             if (to_send == -1)
         312               break;
         313
         314             if (write(fd, report, to_send) != to_send) {
         315               perror(filename);
         316               return 5;
         317             }
         318             if (!hold) {
         319               memset(report, 0×0, sizeof(report));
         320               if (write(fd, report, to_send) != to_send) {
         321                     perror(filename);
         322                     return 6;
         323               }
         324             }
         325         }
         326   }
         327
         328   close(fd);
         329   return 0;
         330 }
         编译:gccgadget_hid.c
         运行:
         root@ubuntu:/home/ubuntu# ./a.out /dev/hidg0k   # 键盘
         keyboard options:
         –hold
         –left-ctrl
         –right-ctrl
         –left-shift
         –right-shift
         –left-alt
         –right-alt
         –left-meta
         –right-meta
         keyboard values:
          or
         –return             –esc
         –bckspc             –tab
         –spacebar               –caps-lock
         –f1                –f2
         –f3                –f4
         –f5                –f6
         –f7                –f8
         –f9                –f10
         –f11               –f12
         –insert            –home
         –pageup         –del
         –end            –pagedown
         –right               –left
         –down            –kp-enter
         –up               –num-lock
         根据提示输入: abcdef
         你电脑上可以看到已经有显示了。
         root@ubuntu:/home/ubuntu# ./a.out /dev/hidg1 m#鼠标
         mouse options:
         –hold
         –b1
         –b2
         –b3
         mouse values:
         Two signed numbers
         –quit to close
         说明一下
         –b11010
         执行这个的时候,相当于鼠标左键。
         –b21
         执行这个的时候,相等于鼠标右键
         –b3-10100
         这个相当于移动鼠标。
         
      
      
      
      四,用joystick做鼠标                               这里代码太多了,今天写了一天,我就不贴,你可以到
          https://github.com/Pillar1989/arduino
          我git上面下载,直接运行output/test/usb
          joystick接的是pcDuino的A4和A5,由于里面有个delay(500)。所有移动的时候桌面有些卡顿。具体的演示,就看你自己的了。
      
      
      
      五,补充USB协议                               下面是自己整理的鼠标键盘的通信格式,如果你有兴趣可以研究一下。
          鼠标发送给PC的数据每次4个字节
          BYTE1 BYTE2 BYTE3 BYTE4
          定义分别是:
          BYTE1 –
          |–bit7:   1   表示   Y   坐标的变化量超出-256   ~   255的范围,0表示没有溢出
          |–bit6:   1   表示   X   坐标的变化量超出-256   ~   255的范围,0表示没有溢出
          |–bit5:   Y   坐标变化的符号位,1表示负数,即鼠标向下移动
          |–bit4:   X   坐标变化的符号位,1表示负数,即鼠标向左移动
          |–bit3:   恒为1
          |–bit2:   1表示中键按下
          |–bit1:   1表示右键按下
          |–bit0:   1表示左键按下
          BYTE2 — X坐标变化量,与byte的bit4组成9位符号数,负数表示向左移,正数表右移。用补码表示变化量
          BYTE3 — Y坐标变化量,与byte的bit5组成9位符号数,负数表示向下移,正数表上移。用补码表示变化量
          BYTE4 — 滚轮变化。
          由于手上没有USB鼠标,对BYTE1的4-7位没有测试,对于BYTE2 BYTE3做个测试,BYTE1的4-7全为0的时候,BYTE2 BYTE3的正负表示鼠标移动方向
          键盘发送给PC的数据每次8个字节
          BYTE1 BYTE2 BYTE3 BYTE4 BYTE5 BYTE6 BYTE7 BYTE8
          定义分别是:
          BYTE1 –
          |–bit0:   Left Control是否按下,按下为1
          |–bit1:   Left Shift是否按下,按下为1
          |–bit2:   Left Alt    是否按下,按下为1
          |–bit3:   Left GUI    是否按下,按下为1
          |–bit4:   Right Control是否按下,按下为1
          |–bit5:   Right Shift 是否按下,按下为1
          |–bit6:   Right Alt   是否按下,按下为1
          |–bit7:   Right GUI   是否按下,按下为1
          BYTE2 — 暂不清楚,有的地方说是保留位
          BYTE3–BYTE8 — 这六个为普通按键
          键盘经过测试。
          例如:键盘发送一帧数据   02 00 0×04 0×05 00 00 00 00
          表示同时按下了Left Shift + ‘a’+‘b’三个键
          附件里面是usb协议中文版,喜欢折腾的可以看看。USB1.1协议中文版
      
      
      
      帖子出自:http://cnlearn.linksprite.com/?p=1531   
页: [1]
查看完整版本: 【USB开发 】用pcDuino的otg做鼠标键盘