leona 发表于 2013-12-20 10:18:32

用pcDuino的otg做鼠标键盘

                                                                                                有人说现代社会,计算机锁住了人类的双手,为什么呢?因为基本上一个人一天上班8小时手是不断的在键盘鼠标上面工作的。我们能不能让电脑更智能一些,例如电脑放弃人类的双手 ,更智能的工作,这里pcDuino跟你提过一个建议。让兼容arduino的各种传感器去采集信号,让pcDuino帮你实现鼠标键盘的各种工作。
http://cnlearn.linksprite.com/wp-content/uploads/2013/10/QQ%E5%9B%BE%E7%89%8720131022100317.jpg
               
       
               
       

第一步: 修改内核:

                                                                                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协议中文版
               
       
                       





               
       
                       
                                                                                                                   


页: [1]
查看完整版本: 用pcDuino的otg做鼠标键盘