View difference between Paste ID: FakrPpSx and sVpzLwg9
SHOW: | | - or go back to the newest paste.
1
/* A component to convert 7i73 bytecodes to bit pins */
2
#include "rtapi.h"
3
#include "rtapi_app.h"
4
#include "hal.h"
5
#include <linux/input.h>
6
#include <linux/uinput.h>
7
8
#ifndef SIM // KERNEL (RTAPI) MODE
9
10
#define keyb_dev_t struct input_dev *
11
#define CREATE_KB_DEV       input_allocate_device()
12
#define UNLOAD_KB_DEV(kb)   input_unregister_device(kb)  
13
#define REGISTER_KB(kb)     input_register_device(kb)
14
#define NAME_KB(kb, n)      kb->name = n;
15
#define SETEVENT(kb)        set_bit(EV_KEY, kb->evbit);
16
#define SETKEY(kb, ev_code) set_bit(ev_code, kb->keybit);
17
#define KEYUP(kb, ev_code)  input_report_key(kb, ev_code, 0); \
18
                            input_sync(kb);
19
#define KEYDOWN(kb, ev_code)input_report_key(kb, ev_code, 1); \
20
                            input_sync(kb);
21
22
#else // SIM OR USERLAND MODE
23
24
#include <stdio.h>
25
#include <fcntl.h>
26
#include <unistd.h>
27
#define keyb_dev_t int
28
#define CREATE_KB_DEV       open("/dev/uinput", O_WRONLY | O_NONBLOCK)
29
#define UNLOAD_KB_DEV(kb)   ioctl(kb, UI_DEV_DESTROY) 
30
#define REGISTER_KB(kb)     ioctl(kb, UI_DEV_CREATE)
31
//the "if" suppresses a compiler warning. There may be a better way
32
#define NAME_KB(kb, n)      snprintf(uidev.name, UINPUT_MAX_NAME_SIZE, "%s", n); \
33
                            uidev.id.bustype = BUS_VIRTUAL; \
34
                            if(write(kb, &uidev, sizeof(uidev)))
35
#define SETEVENT(kb)        ioctl(kb, UI_SET_EVBIT, EV_KEY); \
36
                            ioctl(kb, UI_SET_EVBIT, EV_SYN)
37
#define SETKEY(kb, ev_code) ioctl(kb, UI_SET_KEYBIT, ev_code)
38
#define KEYUP(kb, ev_code)  ev.type = EV_KEY; ev.code = ev_code; ev.value = 0; \
39
                            if(write(kb, &ev, sizeof(ev))); \
40
                            ev.type = EV_SYN; ev.code = 0; ev.value = 0;     \
41
                            if(write(kb, &ev, sizeof(ev)))
42
#define KEYDOWN(kb, ev_code)ev.type = EV_KEY; ev.code = ev_code; ev.value = 1; \
43
                            if(write(kb, &ev, sizeof(ev))); \
44
                            ev.type = EV_SYN; ev.code = 0; ev.value = 0;     \
45
                            if(write(kb, &ev, sizeof(ev)))
46
#endif
47
48
#define MAX_CHAN 8
49
#define MAX_ROLLOVER 8
50
51
/* module information */
52
MODULE_AUTHOR("Andy Pugh");
53
MODULE_DESCRIPTION("Hal-to-text component for Mesa 7i73 and similar");
54
MODULE_LICENSE("GPL");
55
56
typedef struct {
57
    struct {
58
        hal_bit_t **key;
59
        hal_bit_t **rows;
60
        hal_bit_t **cols;
61
        hal_u32_t *keycode;
62
    } hal;
63
    struct {
64
        hal_u32_t *code;
65
        hal_u32_t rollover;
66
        hal_bit_t invert;
67
    } param;
68
    hal_u32_t ncols;
69
    hal_u32_t nrows;
70
    hal_u32_t *now;
71
    hal_u32_t *then;
72
    hal_u32_t keys[MAX_ROLLOVER];
73
    hal_bit_t invert;
74
    char name[HAL_NAME_LEN + 1];
75
    keyb_dev_t key_dev;
76
    hal_u32_t index;
77
    int keydown;
78
    int keyup;
79
    int rowshift;
80
    int row;
81
    int num_keys;
82
    int lastkey;
83
    hal_bit_t scan;
84
    hal_bit_t keystroke;
85
}kb_inst_t;
86
87
typedef struct {
88
    kb_inst_t *insts;
89
    int num_insts;
90
}kb_t;
91
92
static int comp_id;
93
static kb_t *kb;
94
struct input_event ev;
95
struct uinput_user_dev uidev;
96
97
char *config[MAX_CHAN];
98
RTAPI_MP_ARRAY_STRING(config, MAX_CHAN, "screen formatting scancodes")
99
char *names[MAX_CHAN];
100
RTAPI_MP_ARRAY_STRING(names, MAX_CHAN, "component names")
101
102
void keyup(kb_inst_t *inst){
103
    int r, c;
104
    int keycode = *inst->hal.keycode & ~(inst->keydown | inst->keyup);
105
106
    r = keycode >> inst->rowshift;
107
    c = keycode & ~(0xFFFFFFFF << inst->rowshift);
108
    
109
    if  (r < 0 
110
         || c < 0
111
         || r >= inst->nrows 
112
         || c >= inst->ncols
113
         || inst->hal.key[r * inst->ncols + c] == NULL){
114
        return;
115
    }
116
    
117
    if (inst->num_keys > 0) inst->num_keys--;
118
    
119
    *inst->hal.key[r * inst->ncols + c] = 0;
120
   
121
    if(inst->keystroke){
122
        if (inst->param.code[r * inst->ncols + c]){
123
            KEYUP(inst->key_dev, inst->param.code[r * inst->ncols + c]);
124
        }
125
    }
126
127
}
128
void keydown(kb_inst_t *inst){
129
    int r, c;
130
    int keycode = *inst->hal.keycode & ~(inst->keydown | inst->keyup);
131
    
132
    r = keycode >> inst->rowshift;
133
    c = keycode & ~(0xFFFFFFFF << inst->rowshift);
134
    
135
    if  (r < 0 
136
         || c < 0
137
         || r >= inst->nrows 
138
         || c >= inst->ncols
139
         || inst->hal.key[r * inst->ncols + c] == NULL){
140
        return;
141
    }
142
    
143
    if (inst->num_keys >= inst->param.rollover) return;
144
    inst->num_keys++;
145
    
146
    *inst->hal.key[r * inst->ncols + c] = 1;
147
    
148
    if (inst->keystroke){
149
        if (inst->param.code[r * inst->ncols + c]){
150
            KEYDOWN(inst->key_dev, inst->param.code[r * inst->ncols + c]);
151
        }
152
    }
153
}
154
155
    void loop(void *arg, long period){
156
    int c;
157
    hal_u32_t scan = 0;
158
    kb_inst_t *inst = arg;
159
    
160
    if (inst->param.rollover > MAX_ROLLOVER) inst->param.rollover = MAX_ROLLOVER;
161
    
162
    if (inst->scan){ //scanning request
163
        for (c = 0; c < inst->ncols; c++){
164
            scan += ((*inst->hal.cols[c] != inst->param.invert) << c);
165
        }
166
        if (scan == inst->now[inst->row] && scan != inst->then[inst->row]){
167
            // debounced and changed
168
            for (c = 0; c < inst->ncols; c++){
169
                int mask = 1 << c;
170
                if ((inst->then[inst->row] & mask) && !(scan & mask)){ //keyup
171
                    *inst->hal.keycode = inst->keyup 
172
                    + (inst->row << inst->rowshift) 
173
                    + c;
174
                    keyup(inst);
175
                }
176
                else if (!(inst->then[inst->row] & mask) && (scan & mask)){//keydown
177
                    *inst->hal.keycode = inst->keydown 
178
                    + (inst->row << inst->rowshift) 
179
                    + c;
180
                    
181
                    keydown(inst);
182
                }
183
            }
184
        }
185
        
186
        inst->then[inst->row] = inst->now[inst->row];
187
        inst->now[inst->row] = scan;
188
        
189
        *inst->hal.rows[inst->row] = inst->param.invert;
190
        inst->row++;
191
        if (inst->row >= inst->nrows) inst->row = 0;
192
        *inst->hal.rows[inst->row] = !inst->param.invert;
193
    }
194
    else
195
    {
196
        if (*inst->hal.keycode == inst->lastkey) return;
197
        //lastkey is just to trap a 7i73 bug: keyup 0,0 == allup. 
198
        if (*inst->hal.keycode & inst->keydown){
199
            keydown(inst);
200
        }
201
        else
202
        {
203
            keyup(inst);
204
        }
205
        inst->lastkey = *inst->hal.keycode;
206
    }
207
}
208
209
210
int rtapi_app_main(void){
211
    int i, j, n;
212
    int retval;
213
    comp_id = hal_init("matrix_kb");
214
    if (comp_id < 0) {
215
        rtapi_print_msg(RTAPI_MSG_ERR, "matrix_kb: ERROR: hal_init() failed\n");
216
        return -1;
217
    }
218
    
219
    // allocate shared memory for data
220
    kb = hal_malloc(sizeof(kb_t));
221
    if (kb == 0) {
222
        rtapi_print_msg(RTAPI_MSG_ERR,
223
                        "matrix_kb component: Out of Memory\n");
224
        hal_exit(comp_id);
225
        return -1;
226
    }
227
    
228
    // Count the instances.
229
    for (kb->num_insts = 0; config[kb->num_insts];kb->num_insts++);
230
    // Count the names.
231
    for (n = 0; names[n];n++);
232
    
233
    if (n && n != kb->num_insts){
234
        rtapi_print_msg(RTAPI_MSG_ERR, "matrix_kb: Number of sizes and number"
235
                        " of names must match\n");
236
        hal_exit(comp_id);
237
        return -1;
238
    }
239
    
240
    kb->insts = hal_malloc(kb->num_insts * sizeof(kb_inst_t));
241
    
242
    for (i = 0; i < kb->num_insts; i++){
243
        int a = 0;
244
        int c, r;
245
        kb_inst_t *inst = &kb->insts[i];
246
247
        inst->index = i;
248
        inst->nrows = 0;
249
        inst->ncols = 0;
250
        inst->scan = 0;
251
        inst->keystroke = 0;
252
        inst->hal.keycode = 0;
253
        inst->lastkey = 0;
254
        inst->param.invert = 1;
255
        
256
        for(j = 0; config[i][j] !=0; j++){
257
            int n = (config[i][j] | 0x20); //lower case
258
            if (n == 'x'){
259
                inst->nrows = a;
260
                a = 0;
261
            }
262
            else if (n >= '0' && n <= '9'){
263
                a = (a * 10) + (n - '0');
264
            }
265
            else if (n == 's'){
266
                inst->scan = 1;
267
            }
268
            else if (n == 'k'){
269
                inst->keystroke = 1;
270
            }
271
        }
272
        inst->ncols = a;
273
        
274
        if (inst->ncols == 0 || inst->nrows == 0){
275
            rtapi_print_msg(RTAPI_MSG_ERR,
276
                            "matrix_kb: Invalid size format. should be NxN\n");
277
            hal_exit(comp_id);
278
            return -1;
279
        }
280
        
281
        if (inst->ncols > 32){
282
            rtapi_print_msg(RTAPI_MSG_ERR,
283
                            "matrix_kb: maximum number of columns is 32. Sorry\n");
284
            hal_exit(comp_id);
285
            return -1;
286
        }
287
        
288
        for (inst->rowshift = 1; inst->ncols > (1 << inst->rowshift); inst->rowshift++);
289
        for (inst->keydown = 0x40, inst->keyup = 0x80
290
             ; (inst->nrows << inst->rowshift) > inst->keydown
291
             ; inst->keydown <<= 1, inst->keyup <<= 1);
292
        
293
        inst->hal.key = (hal_bit_t **)hal_malloc(inst->nrows * inst->ncols * sizeof(hal_bit_t*));
294
        inst->param.code = hal_malloc(inst->nrows * inst->ncols * sizeof(inst->param.code));
295
        inst->now = hal_malloc(inst->nrows * sizeof(hal_u32_t));
296
        inst->then = hal_malloc(inst->nrows * sizeof(hal_u32_t));
297
        inst->row = 0;
298
        inst->param.rollover = 2;
299
        
300
        
301
        if (names[i]){
302
            rtapi_snprintf(inst->name, sizeof(inst->name), "%s", names[i]);
303
        }
304
        else
305
        {
306
            rtapi_snprintf(inst->name, sizeof(inst->name), "matrix_kb.%i", i);
307
        }
308
        
309
        for (c = 0; c < inst->ncols; c++){
310
            for (r = 0; r < inst->nrows; r++){  
311
                retval = hal_pin_bit_newf(HAL_OUT,
312
                                          &(inst->hal.key[r * inst->ncols + c]), 
313
                                          comp_id,
314
                                          "%s.key.r%xc%x", 
315
                                          inst->name, r, c);
316
                if (retval != 0) {
317
                    rtapi_print_msg(RTAPI_MSG_ERR,
318
                                    "matrix_kb: Failed to create output pin\n");
319
                    hal_exit(comp_id);
320
                    return -1;
321
                }
322
323
                if (inst->keystroke){
324
                    retval = hal_param_u32_newf(HAL_RW,
325
                                                &inst->param.code[r * inst->ncols + c], 
326
                                                comp_id,
327
                                                "%s.code.r%xc%x", 
328
                                                inst->name, r, c);
329
                    if (retval != 0) {
330
                        rtapi_print_msg(RTAPI_MSG_ERR,
331
                                        "matrix_kb: Failed to create output pin\n");
332
                        hal_exit(comp_id);
333
                        return -1;
334
                    }
335
                }
336
            }
337
        }
338
        
339
        if (inst->scan){ //internally generated scanning
340
            inst->hal.rows = (hal_bit_t **)hal_malloc(inst->nrows * sizeof(hal_bit_t*));
341
            inst->hal.cols = (hal_bit_t **)hal_malloc(inst->ncols * sizeof(hal_bit_t*));
342
            
343
            for (r = 0; r < inst->nrows; r++){
344
                retval = hal_pin_bit_newf(HAL_OUT,
345
                                          &(inst->hal.rows[r]), comp_id,
346
                                          "%s.row-%02i-out",inst->name, r);
347
                if (retval != 0) {
348
                    rtapi_print_msg(RTAPI_MSG_ERR,
349
                                    "matrix_kb: Failed to create output row pin\n");
350
                    hal_exit(comp_id);
351
                    return -1;
352
                }
353
            }
354
            for (c = 0; c < inst->ncols; c++){
355
                retval = hal_pin_bit_newf(HAL_IN,
356
                                          &(inst->hal.cols[c]), comp_id,
357
                                          "%s.col-%02i-in",inst->name, c);
358
                if (retval != 0) {
359
                    rtapi_print_msg(RTAPI_MSG_ERR,
360
                                    "matrix_kb: Failed to create input col pin\n");
361
                    hal_exit(comp_id);
362
                    return -1;
363
                }
364
            }
365
                
366
            retval = hal_pin_u32_newf(HAL_OUT,
367
                                      &(inst->hal.keycode), comp_id,
368
                                      "%s.keycode",inst->name);
369
            if (retval != 0) {
370
                rtapi_print_msg(RTAPI_MSG_ERR,
371
                                "matrix_kb: Failed to create output pin\n");
372
                hal_exit(comp_id);
373
                return -1;
374
            }
375
            
376
            retval = hal_param_bit_newf(HAL_RW,
377
                                      &(inst->param.invert), comp_id,
378
                                      "%s.negative-logic",inst->name);
379
            if (retval != 0) {
380
                rtapi_print_msg(RTAPI_MSG_ERR,
381
                                "matrix_kb: Failed to create output pin\n");
382
                hal_exit(comp_id);
383
                return -1;
384
            }
385
            
386
            
387
            retval = hal_param_u32_newf(HAL_RW,
388
                                      &(inst->param.rollover), comp_id,
389
                                      "%s.key_rollover",inst->name);
390
            if (retval != 0) {
391
                rtapi_print_msg(RTAPI_MSG_ERR,
392
                                "matrix_kb: Failed to create rollover param\n");
393
                hal_exit(comp_id);
394
                return -1;
395
            }
396
            
397
        }
398
        else // scanning by 7i73 or similar
399
        {
400
            retval = hal_pin_u32_newf(HAL_IN,
401
                                      &(inst->hal.keycode), comp_id,
402
                                      "%s.keycode",inst->name);
403
            if (retval != 0) {
404
                rtapi_print_msg(RTAPI_MSG_ERR,
405
                                "matrix_kb: Failed to create input pin\n");
406
                hal_exit(comp_id);
407
                return -1;
408
            }
409
        }
410
        
411
        retval = hal_export_funct(inst->name, loop, inst, 1, 0, comp_id); //needs fp?
412
        if (retval < 0) {
413
            rtapi_print_msg(RTAPI_MSG_ERR, "matrix_kb: ERROR: function export failed\n");
414
            return -1;
415
        }
416
        
417
        if (inst->keystroke){ // keyboard output needed
418
            inst->key_dev = CREATE_KB_DEV;
419
            if (inst->key_dev <= 0) {
420
                rtapi_print_msg(RTAPI_MSG_ERR,"matrix_kb: failed to create dev\n");
421
                return -1;
422
            }
423
            
424
            SETEVENT(inst->key_dev);
425
            for(j = 0; j < 226 ; j++){ 
426
                SETKEY(inst->key_dev, j);
427
            }
428
            
429
            NAME_KB(inst->key_dev, inst->name);
430
            retval = REGISTER_KB(inst->key_dev);
431
            
432
            if (retval < 0) {
433
                rtapi_print_msg(RTAPI_MSG_ERR, "matrix_kb: Failed to register device %i\n", retval);
434
                return -1;
435
            }
436
        }
437
    }
438
    hal_ready(comp_id);
439
    
440
    return 0;
441
}
442
443
void rtapi_app_exit(void)
444
{
445
    hal_exit(comp_id);
446
    {
447
        int i;
448
        for (i = 0; i < kb->num_insts ; i++){
449
            if (kb->insts[i].keystroke) UNLOAD_KB_DEV(kb->insts[i].key_dev);
450
        }
451
    }
452
}