Information
Credits: Thiago Naves, Led Lab, PUC-Rio
Status: Stable
Runs on: All platforms
Description
This is a module to allow eLua programs to use a regular PC keyboard connected to any 4 GPIO pins of any eLua-capable platform.
Instructions
(coming soon ...)
Installing
Please refer to http://wiki.eluaproject.net/Tutorials/cmodules for installation instructions
Code
The code for this project is maintained in this Google Code subversion repository. Please refer to the eLua discussion list for any questions regarding it's use and techniques. We reproduce here below the module code and a Lua example for ilustration purposes.
C module code
1 /****************************************************************************/
2 /* pc_keyboard is a ps/2 keyboard driver for eLua ( www.eluaproject.net ) */
3 /* */
4 /* v0.2, June 2010, by Thiago Naves, LED Lab, PUC-Rio */
5 /* */
6 /****************************************************************************/
7
8 /* Functions */
9
10 /*
11 - keyboard.init( Clock, Data, Clock PullDown, Data PullDown )
12 - keyboard.setflags( Start, Stop, Parity )
13 - keyboard.receive()
14 - keyboard.send( Data )
15 - keyboard.setleds( Num Lock, Caps Lock, Scroll Lock )
16 - keyboard.disablekeyevents( Key code, Break, Typematic repeat )
17 - keyboard.configkeys( Break, Typematic repeat )
18 - keyboard.setrepeatrateanddelay( rate, delay )
19 - keyboard.setscancodeset( Code set )
20 - keyboard.enable()
21 - keyboard.disable()
22 - keyboard.reset()
23 - keyboard.default()
24 - keyboard.resend()
25 - keyboard.echo()
26 */
27
28 #include "lua.h"
29 #include "lualib.h"
30 #include "lauxlib.h"
31 #include "platform.h"
32 #include "auxmods.h"
33 #include "lrotable.h"
34 #include "platform_conf.h"
35 #include <string.h>
36
37 #define MIN_OPT_LEVEL 2
38 #include "lrodefs.h"
39
40 #define DIR_OUT 0
41 #define DIR_IN 1
42
43 #define IGNORE 1
44 #define USE 0
45
46 #define ERROR 0
47
48 #define ACK 0xFA
49 #define SETLEDS 0xED
50 #define ECHO 0xEE
51 #define SET_TYPEMATIC_RD 0xF3
52 #define SET_SCAN_CODE_SET 0xF0
53 #define ENABLE 0xF4
54 #define DISABLE 0xF5
55 #define DEFAULT 0xF6
56 #define RESET 0xFF
57 #define RESEND 0xFE
58
59 typedef struct sPin
60 {
61 pio_type pin, port;
62 } tPin;
63
64 /* Pin Configuration */
65 tPin P_CLK, P_DATA, P_CLK_PD, P_DATA_PD;
66
67 /* Start, Stop and Parity bits ignore configuration */
68 char igStart = USE;
69 char igStop = USE;
70 char igParity = USE;
71
72 /* Returns the absolut value of a number */
73 static unsigned int abs( int i )
74 {
75 if ( i < 0 )
76 return -i;
77 else
78 return i;
79 }
80
81 /* Converts a pin number got from the Lua stack to the tPin format */
82 static tPin convertPin( int p )
83 {
84 tPin result;
85 result.port = PLATFORM_IO_GET_PORT( p );
86 result.pin = ( 1 << PLATFORM_IO_GET_PIN( p ) );
87
88 return result;
89 }
90
91 /* Just to make the code easier to read
92 * Sets a pin value ( 1 / 0 )
93 */
94 static void setPinVal( tPin p, char val )
95 {
96 if ( val )
97 platform_pio_op( p.port, p.pin, PLATFORM_IO_PIN_SET );
98 else
99 platform_pio_op( p.port, p.pin, PLATFORM_IO_PIN_CLEAR );
100 }
101
102 /* Just to make the code easier to read
103 * Sets a pin direction ( DIR_IN / DIR_OU )
104 */
105 static void setPinDir( tPin p, char dir )
106 {
107 if ( dir == DIR_IN )
108 platform_pio_op( p.port, p.pin, PLATFORM_IO_PIN_DIR_INPUT );
109 else
110 platform_pio_op( p.port, p.pin, PLATFORM_IO_PIN_DIR_OUTPUT );
111 }
112
113 /* Just to make the code easier to read
114 * Returns the current pin value
115 */
116 static int getPinVal( tPin p )
117 {
118 return platform_pio_op( p.port, p.pin, PLATFORM_IO_PIN_GET );
119 }
120
121 /* Generates a Parity bit for a given char ( to send data ) */
122 static char genCRC( unsigned char data )
123 {
124 int i, count;
125
126 count = 0;
127
128 /* Count the 1s */
129 for ( i=0; i<8; i++ )
130 {
131 if ( ( data & 1 ) == 1 )
132 count ++;
133
134 data = data >> 1;
135 }
136
137 /* The parity bit is set if there is an even number of 1s */
138 return ( ( count & 1 ) != 1 );
139 }
140
141 /* Checks the Parity bit for a given package */
142 static char checkCRC( unsigned int data )
143 {
144 /* Checks the parity bit ( odd parity ) */
145 unsigned int tmp;
146 int i, count;
147
148 count = 0;
149 tmp = data;
150
151 /* Extract data bits */
152 data = data >> 1;
153 data = data & 255;
154
155 /* Count the 1s */
156 for ( i=0; i<8; i++ )
157 {
158 if ( ( data & 1 ) == 1 )
159 count ++;
160
161 data = data >> 1;
162 }
163
164 /* The parity bit is set if there is an even number of 1s */
165 return ( ( count & 1 ) != ( tmp & 512 ) );
166 }
167
168 /* Set IGNORE flags for Start, Stop and/or Parity bits
169 * This is due to buggy keyboards
170 * Lua: keyboard.setflags( Start, Stop, Parity )
171 */
172 static int keyboard_setflags( lua_State *L )
173 {
174 /* Start, Stop, Parity */
175 /* Set ignore bits flags */
176 igStart = luaL_checkinteger( L, 1 );
177 igStop = luaL_checkinteger( L, 2 );
178 igParity = luaL_checkinteger( L, 3 );
179
180 return 0;
181 }
182
183 /* Initializes pin directions and default values
184 * Lua: keyboard.init( Clock, Data, Clock PullDown, Data PullDown )
185 */
186 static int keyboard_init( lua_State *L )
187 {
188 P_CLK = convertPin( luaL_checkinteger( L, 1 ) );
189 P_DATA = convertPin( luaL_checkinteger( L, 2 ) );
190 P_CLK_PD = convertPin( luaL_checkinteger( L, 3 ) );
191 P_DATA_PD = convertPin( luaL_checkinteger( L, 4 ) );
192
193 setPinDir( P_CLK_PD, DIR_OUT );
194 setPinDir( P_DATA_PD, DIR_OUT );
195 setPinDir( P_DATA, DIR_IN );
196 setPinDir( P_CLK, DIR_IN );
197
198 setPinVal( P_DATA_PD, 1 );
199 setPinVal( P_CLK_PD, 1 );
200
201 return 0;
202 }
203
204 /* Receives a char from the keyboard */
205 static char keyboard_getchar( )
206 {
207 unsigned int data = 0;
208
209 int i;
210 for ( i=1; i<12; i++ )
211 {
212 while ( getPinVal( P_CLK ) != 1 ) /* Wait for next clock */
213 {}
214
215 if ( i < 11 )
216 while ( getPinVal( P_CLK ) ) /* Wait for clock to go low */
217 {}
218
219 data = data >> 1;
220
221 if ( getPinVal( P_DATA ) == 1 )
222 data = data | ( 1 << 10 );
223 }
224
225 /* Check start bit */
226 if ( ( ( data & 1 ) == 1 ) && ( igStart == USE ) )
227 return ERROR;
228
229 /* Check stop bit */
230 if ( ( ( data & 1024 ) == 0 ) && ( igStop == USE ) )
231 return ERROR;
232
233 /* Check CRC bit */
234 if ( ( checkCRC( data ) == 0 ) && ( igParity == USE ) )
235 return ERROR;
236
237 /* Remove Start, Stop and CRC bits */
238 data = data >> 1;
239 data = data & 255;
240
241 return data;
242 }
243
244 /* Wrapper ( bind ) for keyboard_getchar function
245 * Lua: keyboard.receive()
246 */
247 static int keyboard_receive( lua_State *L )
248 {
249 lua_pushinteger( L, keyboard_getchar () );
250 return 1;
251 }
252
253 /* Sends data to the keyboard */
254 static void keyboard_write( char data )
255 {
256 char bit; /* Counter */
257 char par = genCRC( data ); /* Parity Bit */
258
259
260 /* Disable communication & Request Send */
261 setPinVal( P_CLK_PD, 0 );
262 platform_timer_delay( 1, 120 ); /* 120 microseconds */
263 setPinVal( P_DATA_PD, 0 );
264 setPinVal( P_CLK_PD, 1 );
265
266 /* Wait for clock and send data */
267 for ( bit=1; bit<= 11; bit++ )
268 {
269 while ( getPinVal( P_CLK ) == 1 )
270 {}
271
272 if ( bit == 9 ) /* Parity Bit */
273 setPinVal( P_DATA_PD, par );
274 else
275 if ( bit == 10 ) /* Stop Bit */
276 setPinVal( P_DATA_PD, 1 );
277 else
278 if ( bit != 11 ) /* Data Bit */
279 setPinVal( P_DATA_PD, data & ( 1 << ( bit -1 ) ) );
280
281 /* bit == 11 -> ACK bit, just ignore it */
282
283 while ( getPinVal( P_CLK ) == 0 )
284 {}
285 }
286 }
287
288 /* Bind to keyboard_write function
289 * Sends a byte to the Keyboard
290 * Lua: keyboard.send( Data byte )
291 */
292 static int keyboard_send( lua_State *L )
293 {
294 int i;
295 i = luaL_checkinteger( L, 1 );
296 keyboard_write( i );
297 return 0;
298 }
299
300 /* Sets the Num Lock, Caps Lock and Scroll Lock Leds state
301 * Lua: keyboard.setleds( Num Lock, Caps Lock, Scroll Lock )
302 */
303 static int keyboard_setleds( lua_State *L )
304 {
305 int i = 0;
306 i = i | ( luaL_checkinteger( L, 1 ) << 1 ); /* Num Lock */
307 i = i | ( luaL_checkinteger( L, 2 ) << 2 ); /* Caps Lock */
308 i = i | ( luaL_checkinteger( L, 3 ) ); /* Scroll Lock */
309
310 keyboard_write( SETLEDS );
311 keyboard_write( i );
312
313 return 0;
314 }
315
316 /* Configure wich key events the keyboard will send for a given key
317 * Params: Key code, Break, Typematic repeat
318 * If param == USE then enable that message
319 * If param == IGNORE then ignore that message
320 * Lua: keyboard.disablekeyevents( Key, Break, Typematic )
321 */
322 static int keyboard_disablekeyevents( lua_State *L )
323 {
324 #define makeOnly 0xFD
325 #define makeBreak 0xFC
326 #define makeType 0xFB
327 int bk, tp, i;
328 char ret;
329 const char * buf;
330 size_t len;
331
332 /* Get params */
333 luaL_checktype( L, 1, LUA_TSTRING );
334 buf = lua_tolstring( L, 1, &len );
335 bk = luaL_checkinteger( L, 2 );
336 tp = luaL_checkinteger( L, 3 );
337
338 /* Send operation code */
339 if ( ( bk == IGNORE ) && ( tp == IGNORE ) )
340 {
341 keyboard_write( makeOnly );
342 }
343
344 if ( ( bk == IGNORE ) && ( tp == USE ) )
345 {
346 keyboard_write( makeType );
347 }
348
349 if ( ( tp == IGNORE ) && ( bk == USE ) )
350 {
351 keyboard_write( makeBreak );
352 }
353
354 /* Wait for ACK */
355 ret = keyboard_getchar();
356
357 if ( ret != ACK )
358 {
359 printf( "Error: No ACK ! " );
360 return 0;
361 }
362
363 /* send key ( make ) code */
364 for ( i=0; i<len; i++ )
365 {
366 /* Send key code */
367 keyboard_write( buf[i] );
368
369 /* Wait for ACK */
370 ret = keyboard_getchar();
371
372 if ( ret != ACK )
373 {
374 printf( "Error: No ACK ! " );
375 return 0;
376 }
377 }
378
379 /* Send echo ( ends key list ) */
380 keyboard_write( ECHO );
381
382 return 0;
383 }
384
385 /* Configure wich key events the keyboard will send for all keys
386 * If param == USE then enable that message
387 * If param == IGNORE then ignore that message
388 * Params: Break, Typematic repeat
389 * Lua: keyboard.configkeys( Break, Typematic )
390 */
391 static int keyboard_configkeys( lua_State *L )
392 {
393 #define amakeOnly 0xF9
394 #define amakeBreak 0xF8
395 #define amakeType 0xF7
396 #define amakeBreakType 0xFA
397 int bk, tp;
398 char ret;
399
400 /* Get params */
401 bk = luaL_checkinteger( L, 1 );
402 tp = luaL_checkinteger( L, 2 );
403
404 /* Enable all */
405 keyboard_write( amakeBreakType );
406
407 /* Wait for ACK */
408 ret = keyboard_getchar();
409
410 if ( ret != ACK )
411 {
412 printf( "Error: No ACK ! " );
413 return 0;
414 }
415
416 /* Disable something ( or not ) */
417
418 if ( ( bk == IGNORE ) && ( tp == IGNORE ) )
419 {
420 keyboard_write( amakeOnly );
421 }
422
423 if ( ( bk == IGNORE ) && ( tp == USE ) )
424 {
425 keyboard_write( amakeType );
426 }
427
428 if ( ( tp == IGNORE ) && ( bk == USE ) )
429 {
430 keyboard_write( amakeBreak );
431 }
432
433 /* Send echo ( ends key list ) */
434 keyboard_write( ECHO );
435
436 /* Wait for Echo reply */
437 keyboard_getchar();
438
439 return 0;
440 }
441
442 /* Defines the typematic delay and character repeat rate
443 *
444 * Typematic delay is the delay before repeating a character
445 * when a key is hold down.
446 *
447 * Repeat rate tells how many characters per second will be
448 * sent after that delay
449 *
450 * Lua: keyboard.setrepeatrateanddelay( rate, delay )
451 */
452 static int keyboard_setRepeatRateAndDelay( lua_State *L )
453 {
454 int rates[32] = { 300, 267, 240, 218, 207, 185, 171, 160, 150, 133, 120,
455 109, 100, 92, 86, 80, 75, 67, 60, 55, 50, 46, 43, 40,
456 37, 33, 30, 27, 25, 23, 21, 20 };
457
458 int delays[4] = { 250, 500, 750, 1000 };
459
460 unsigned int rate, delay; /* Parameters sent by user */
461 unsigned int i, rDiff, rateId; /* Used to find the rate closest to the param */
462 unsigned int dDiff, delayId; /* Used to find the delay closest to the param */
463 unsigned int cmd; /* Control byte to send to the keyboard */
464
465 rate = luaL_checkinteger( L, 1 );
466 delay = luaL_checkinteger( L, 2 );
467
468 /* Find the rate closest to the one passed */
469 rDiff = abs( rate - rates[0] );
470 dDiff = abs( delay - delays[0] );
471 rateId = 0;
472 delayId = 0;
473
474 for ( i=1; i<32; i++ )
475 {
476 if ( abs( rate - rates[i] ) < rDiff )
477 {
478 rDiff = abs( rate - rates[i] );
479 rateId = i;
480 }
481
482 if ( abs( rate - rates[i] ) > rDiff )
483 break;
484 }
485
486 /* Find the delay closest to the one passed */
487 for ( i=1; i<4; i++ )
488 {
489 if ( abs( delay - delays[i] ) < dDiff )
490 {
491 dDiff = abs( delay - delays[i] );
492 delayId = i;
493 }
494
495 if ( abs( delay - delays[i] ) > dDiff )
496 break;
497 }
498
499 cmd = rateId;
500 cmd = cmd | delayId << 5;
501
502 keyboard_write( 0xF3 );
503 keyboard_write( cmd );
504
505 lua_pushinteger( L, rates[ rateId ] );
506 lua_pushinteger( L, delays[ delayId ] );
507
508 return 2;
509 }
510
511 /* Sets the used Key Scan Code Set ( 1, 2 or 3 )
512 *
513 * Lua: keyboard.setscancodeset( set )
514 */
515 static int keyboard_setScanCodeSet( lua_State *L )
516 {
517 int i = luaL_checkinteger( L, 1 );
518
519 if ( ( i > 3 ) || ( i < 1 ) )
520 return 0;
521
522 /* Send Command Code */
523 keyboard_write( SET_SCAN_CODE_SET );
524
525 /* Wait for ACK */
526 if ( keyboard_getchar() != ACK )
527 return 0;
528
529 /* Send Scan Set Code */
530 keyboard_write( i );
531
532 return 0;
533 }
534
535 /* Enables keyboard's key scanning after a disable command
536 *
537 * Lua: keyboard.enable()
538 */
539 static int keyboard_enable( lua_State *L )
540 {
541 keyboard_write( ENABLE );
542 return 0;
543 }
544
545 /* Disable keyboard's key scanning ( keyboard stops looking for
546 * pressed keys.
547 *
548 * Note: keyboard will return to the default configuration
549 * ( see keyboard.default() command ).
550 *
551 * Lua: keyboard.disable()
552 */
553 static int keyboard_disable( lua_State *L )
554 {
555 keyboard_write( DISABLE );
556 return 0;
557 }
558
559 /* Retuns keyboard to it's default state:
560 * Typematic delay = 500ms
561 * Typematic rate = 10.9 c.p.s
562 * Keyboard sends key Make, Break and Typematic messages
563 * Key Scan Code Set = 2
564 *
565 * Lua: keyboard.default()
566 */
567 static int keyboard_default( lua_State *L )
568 {
569 keyboard_write( DEFAULT );
570 return 0;
571 }
572
573 /* Resets the keyboard
574 *
575 * Lua: keyboard.reset()
576 */
577 static int keyboard_reset( lua_State *L )
578 {
579 keyboard_write( RESET );
580
581 /* Wait for ACK */
582 keyboard_getchar();
583
584 return 0;
585 }
586
587 /* Keyboards resends last byte, except if it was "resend".
588 * In this case it sends the last non-resend byte.
589 *
590 * Lua: keyboard.resend()
591 */
592 static int keyboard_resend( lua_State *L )
593 {
594 /* Send command code */
595 keyboard_write( RESEND );
596
597 /* Returns the response */
598 lua_pushinteger( L, keyboard_getchar() );
599 return 1;
600 }
601
602 /* Keyboard responds with echo ( keyboard.ECHO - 0xEE )
603 *
604 * Lua: keyboard.echo()
605 */
606 static int keyboard_echo( lua_State *L )
607 {
608 /* Sends echo */
609 keyboard_write( ECHO );
610
611 /* Returns the response */
612 lua_pushinteger( L, keyboard_getchar() );
613
614 return 1;
615 }
616
617 const LUA_REG_TYPE keyboard_map[] = {
618 { LSTRKEY( "init" ), LFUNCVAL( keyboard_init ) },
619 { LSTRKEY( "receive" ), LFUNCVAL( keyboard_receive ) },
620 { LSTRKEY( "setflags" ), LFUNCVAL( keyboard_setflags ) },
621 { LSTRKEY( "send" ), LFUNCVAL( keyboard_send ) },
622 { LSTRKEY( "setleds" ), LFUNCVAL( keyboard_setleds ) },
623 { LSTRKEY( "configkeys" ), LFUNCVAL( keyboard_configkeys ) },
624 { LSTRKEY( "disablekeyevents" ), LFUNCVAL( keyboard_disablekeyevents ) },
625 { LSTRKEY( "setrepeatrateanddelay" ), LFUNCVAL( keyboard_setRepeatRateAndDelay) },
626 { LSTRKEY( "setscancodeset" ), LFUNCVAL( keyboard_setScanCodeSet ) },
627 { LSTRKEY( "reset" ), LFUNCVAL( keyboard_reset ) },
628 { LSTRKEY( "enable" ), LFUNCVAL( keyboard_enable ) },
629 { LSTRKEY( "disable" ), LFUNCVAL( keyboard_disable ) },
630 { LSTRKEY( "default" ), LFUNCVAL( keyboard_default ) },
631 { LSTRKEY( "resend" ), LFUNCVAL( keyboard_resend ) },
632 { LSTRKEY( "echo" ), LFUNCVAL( keyboard_echo ) },
633 { LSTRKEY( "ECHO" ), LNUMVAL( ECHO ) },
634 { LSTRKEY( "IGNORE" ), LNUMVAL( IGNORE ) },
635 { LSTRKEY( "USE" ), LNUMVAL( USE ) },
636 { LSTRKEY( "ERROR" ), LNUMVAL( ERROR ) },
637 { LSTRKEY( "ACK" ), LNUMVAL( ACK) },
638 { LNILKEY, LNILVAL }
639 };
640
641 LUALIB_API int luaopen_keyboard ( lua_State *L )
642 {
643 LREGISTER( L, "keyboard", keyboard_map );
644 };
645
Lua using example
1 -----------------------------------------------------------------------------
2 -- This file exemplifies the use of keyboard lib running on a MBED --
3 -- This example implements keyboard_read() function that prints --
4 -- received keys on screen. --
5 -- Note: Only letters a ~ z, space, shift and enter keys are --
6 -- implemented. Any other key will break the ( endless ) loop. --
7
8 local chars = {}
9
10 chars[ 0x1C ] = "a"
11 chars[ 0x32 ] = "b"
12 chars[ 0x21 ] = "c"
13 chars[ 0x23 ] = "d"
14 chars[ 0x24 ] = "e"
15 chars[ 0x2B ] = "f"
16 chars[ 0x34 ] = "g"
17 chars[ 0x33 ] = "h"
18 chars[ 0x43 ] = "i"
19 chars[ 0x3B ] = "j"
20 chars[ 0x42 ] = "k"
21 chars[ 0x4B ] = "l"
22 chars[ 0x3A ] = "m"
23 chars[ 0x31 ] = "n"
24 chars[ 0x44 ] = "o"
25 chars[ 0x4D ] = "p"
26 chars[ 0x15 ] = "q"
27 chars[ 0x2D ] = "r"
28 chars[ 0x1B ] = "s"
29 chars[ 0x2C ] = "t"
30 chars[ 0x3C ] = "u"
31 chars[ 0x2A ] = "v"
32 chars[ 0x1D ] = "w"
33 chars[ 0x22 ] = "x"
34 chars[ 0x35 ] = "y"
35 chars[ 0x1A ] = "z"
36 chars[ 0x29 ] = " "
37 -- chars[ 0x5A ] = "\n"
38
39 function keyboard_read()
40 local c
41 local shift = false
42
43 while true do
44 c = keyboard.receive()
45
46 -- check if it's the Shift key
47 if ( c == 0x12 ) or ( c == 0x59 ) then -- Shift press
48 shift = true
49 else -- Shift release ( or other key press / release )
50 if c == 0xF0 then
51 c = keyboard.receive()
52 if ( c == 0x12 ) or ( c == 0x59 ) then
53 shift = false
54 end
55 else -- Other keys
56 -- If it's a keyup message, ignore ( 2 bytes )
57 if c == 0xF0 then
58 keyboard.receive()
59 else -- Else, print the Char
60 if c == 0x5A then
61 print( "" )
62 else
63 if chars[ c] == nil then
64 print( "" )
65 return
66 else
67 if shift then
68 term.print( string.upper( chars[ c ] ) )
69 else
70 term.print( chars[ c ] )
71 end;
72 end
73 end
74 end
75 end
76 end
77 end
78 end
79
80 -- Initialize the IOs
81 keyboard.init( mbed.pio.P18, mbed.pio.P10, mbed.pio.P19, mbed.pio.P11 )
82
83 -- Pins:
84 -- Clock: Pin 18
85 -- Data: Pin 10
86 -- Clock Pull Down: Pin 19
87 -- Data Pull Down: Pin 11
88
89 -- Ignore stop bit ( buggy keyboard... )
90 -- keyboard.setflags( 0, 1, 0 )
91 keyboard.setflags( keyboard.USE, keyboard.IGNORE, keyboard.USE );
92
