-
Notifications
You must be signed in to change notification settings - Fork 15
/
Copy pathKeyboard_and_Touchpad.ino
2118 lines (2113 loc) · 102 KB
/
Keyboard_and_Touchpad.ino
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
//
// Keyboard and Touchpad controller for Sony Viao PCG-K25 laptop.
//
// Copyright 2017 Frank Adams
/*
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// Revision History
// Rev 1.00 - Nov 5, 2017 - Original Release
// Rev 1.01 - Nov 10, 2017 - Expanded i2c request event to include 32 characters
// Rev 2.0 - Dec 24, 2017 - Added ADC read of battery and low voltage shutdown of laptop
// Rev 2.1 - Dec 27, 2017 - Added warning counter to track the times the ADC says the battery is undervoltage
// Rev 2.2 - Jan 1, 2018 - Cleanup ADC variables and divide by 8 using shift
// Rev 3.0 - Feb 14, 2018 - Remove code for Teensy to shutdown laptop at particular battery voltage.
// Add i2c command for Pi to blink the LCD.
// Return battery voltage to the Pi from the ADC over the i2c bus
// Rev 3.1 - July 7, 2018 - Added watchdog timer to touchpad routine to break out of while loops. This fixed
// the lock up problem at startup and reset.
// Rev 3.2 - Nov 30, 2018 - Added Apache License header. Replaced playground arduino ps/2 touchpad code with my code.
//
// The ps/2 code for the Touchpad is written from timing diagrams at http://www.burtonsys.com/ps2_chapweske.htm
// The USB Mouse Functions are described at https://www.pjrc.com/teensy/td_mouse.html
// The USB Keyboard Functions are described at https://www.pjrc.com/teensy/td_keyboard.html
//
// Keyboard part number is KFRMBA151B
// The print screen and num lock keys were not functional on my keyboard so they do not show up in the matrix.
// The Menu key is not included in Teensyduino so it will be used as a print screen key.
//
// The keyboard matrix: columns (inputs) across the top and rows (outputs) along the side
/*
0 1 2 3 4 5 6 7
0 CTRL-R CTRL-L
1 ARROW-L ARROW-D ARROW-U PAGE-D PAGE-U END ARROW-R
2 ENTER ] = "
3 F12 MENU / ; [ P - BCKSPACE
4 INSERT \ HOME L DELETE
5 F10 COMMA PERIOD i ZERO 9 F F11
6 F8 M B 8 U O J F9
7 F7 N G Y K 7 H 6
8 F5 V S T R 5 C F6
9 F3 X E 4 3 D F4
10 F1 Z SPACE Q 2 1 W F2
11 SHIFT-L SHIFT-R
12 ~ A TAB CAPS LCK ESC
13 ALT-R ALT-L
14 GUI
15 Fn
*/
//
#include <Wire.h> // needed for I2C
//
// Define the keyboard columns that will be inputs to the Teensy (internal pullups in Teensy)
#define Col0 PIN_E0
#define Col1 PIN_E4
#define Col2 PIN_C1
#define Col3 PIN_A0
#define Col4 PIN_C2
#define Col5 PIN_A5
#define Col6 PIN_C4
#define Col7 PIN_A6
// Define the keyboard rows that will be driven low or floated by the Teensy (acts like open drain)
#define Row0 PIN_D3
#define Row1 PIN_D4
#define Row2 PIN_D5
#define Row3 PIN_E5
#define Row4 PIN_D7
#define Row5 PIN_E1
#define Row6 PIN_C0
#define Row7 PIN_A4
#define Row8 PIN_C3
#define Row9 PIN_A1
#define Row10 PIN_C5
#define Row11 PIN_A2
#define Row12 PIN_C6
#define Row13 PIN_A7
#define Row14 PIN_C7
#define Row15 PIN_A3
//
// Define the touchpad clock and data connections to the Teensy (bi-directional signals)
#define TP_DATA PIN_B3 // The tp_data & tp_clk are driven low or floated (pull ups to 5V are in the touchpad chip).
#define TP_CLK PIN_B2 // They are also read by the Teensy as inputs.
//
// Define the volume up and down, menu, and on/off controls from the Teensy to the LCD Controller card.
// These 4 controls are initiated by holding down the Fn key and then pushing a function key as follows:
// Fn & F1 = Menu, Fn & F3 = Vol_Dn, Fn & F4 = Vol_Up, Fn & F7 = On_Off
#define Vol_Up PIN_B7 // The Teensy takes the place of the push button switches to navigate the menus of the card.
#define Vol_Dn PIN_B6 // The signals are driven low or floated by the Teensy (acts like open drain).
#define Menu PIN_B5 // The LCD Controller card has pullups on these signals to 3.3 volts.
#define On_Off PIN_B4 // DO NOT drive these to 5 volts. It may damage the LCD Controller chip.
//
#define BLINK_LED PIN_D6 // LED on Teensy board blinks at 1 second rate to show it's alive
//
#define RESET_PI PIN_B1 // Teensy outputs low pulse to reset Pi
//
#define SHUTDOWN PIN_B0 // Teensy outputs high pulse to shut down the voltage regulators
//
#define CAPS_LED PIN_E7 // Send low to turn on the Caps Lock LED
//
#define DISK_LED PIN_E6 // spare LED used for code debug
//
// Declare variables that will be used by functions
boolean slots_full = LOW; // Goes high when slots 1 thru 6 contain keys
// slot 1 thru slot 6 hold the normal key values to be sent over USB.
int slot1 = 0; //value of 0 means the slot is empty and can be used.
int slot2 = 0;
int slot3 = 0;
int slot4 = 0;
int slot5 = 0;
int slot6 = 0;
//
// Declare variables that pi controls and reads via i2c
boolean debug = LOW; // HIGH turns on the DISK_LED (used for code debug)
boolean reset_all = LOW; // HIGH resets the Pi and Teensy
boolean kill_power = LOW; // HIGH disables all 3 voltage regulators
boolean blink_display = LOW; // HIGH causes LCD display to blink off and back on
int adc_ave; // holds the A to D conversion of the battery/4 value
//
boolean touchpad_error = LOW; // sent high when touch pad routine times out
boolean touchpad_fail = LOW; // sent high if the touchpad won't initialize
//
// Function to clear the slot that contains the key name
void clear_slot(int key) {
if (slot1 == key) {
slot1 = 0;
}
else if (slot2 == key) {
slot2 = 0;
}
else if (slot3 == key) {
slot3 = 0;
}
else if (slot4 == key) {
slot4 = 0;
}
else if (slot5 == key) {
slot5 = 0;
}
else {
slot6 = 0;
}
slots_full = LOW;
}
// Function to load the key name into the first available slot
void load_slot(int key) {
if (!slot1) {
slot1 = key;
}
else if (!slot2) {
slot2 = key;
}
else if (!slot3) {
slot3 = key;
}
else if (!slot4) {
slot4 = key;
}
else if (!slot5) {
slot5 = key;
}
else {
slot6 = key;
}
if (!slot1 || !slot2 || !slot3 || !slot4 || !slot5 || !slot6) {
slots_full = LOW;
}
else {
slots_full = HIGH;
}
}
// Function to send a pin to high impedance (float)
void go_z(int pin)
{
pinMode(pin, INPUT);
digitalWrite(pin, HIGH);
}
// Function to send a pin to a logic low (0 volts)
void go_0(int pin)
{
pinMode(pin, OUTPUT);
digitalWrite(pin, LOW);
}
// Function to send a pin to a logic 1 (5 volts)
void go_1(int pin)
{
pinMode(pin, OUTPUT);
digitalWrite(pin, HIGH);
}
// Function to send the Touchpad a command
void tp_write(char send_data)
{
unsigned int timeout = 200; // breakout of loop if over this value in msec
elapsedMillis watchdog; // zero the watchdog timer clock
char odd_parity = 0; // clear parity bit count
// Enable the bus by floating the clock and data
go_z(TP_CLK); //
go_z(TP_DATA); //
delayMicroseconds(250); // wait before requesting the bus
go_0(TP_CLK); // Send the Clock line low to request to transmit data
delayMicroseconds(100); // wait for 100 microseconds per bus spec
go_0(TP_DATA); // Send the Data line low (the start bit)
delayMicroseconds(1); //
go_z(TP_CLK); // Release the Clock line so it is pulled high
delayMicroseconds(1); // give some time to let the clock line go high
while (digitalRead(TP_CLK) == HIGH) { // loop until the clock goes low
if (watchdog >= timeout) { //check for infinite loop
touchpad_error = HIGH; // set error flag
break; // break out of infinite loop
}
}
// send the 8 bits of send_data
for (int j=0; j<8; j++) {
if (send_data & 1) { //check if lsb is set
go_z(TP_DATA); // send a 1 to TP
odd_parity = odd_parity + 1; // keep running total of 1's sent
}
else {
go_0(TP_DATA); // send a 0 to TP
}
delayMicroseconds(1); // delay to let the clock settle out
while (digitalRead(TP_CLK) == LOW) { // loop until the clock goes high
if (watchdog >= timeout) { //check for infinite loop
touchpad_error = HIGH; // set error flag
break; // break out of infinite loop
}
}
delayMicroseconds(1); // delay to let the clock settle out
while (digitalRead(TP_CLK) == HIGH) { // loop until the clock goes low
if (watchdog >= timeout) { //check for infinite loop
touchpad_error = HIGH; // set error flag
break; // break out of infinite loop
}
}
send_data = send_data >> 1; // shift data right by 1 to prepare for next loop
}
// send the parity bit
if (odd_parity & 1) { //check if lsb of parity is set
go_0(TP_DATA); // already odd so send a 0 to TP
}
else {
go_z(TP_DATA); // send a 1 to TP to make parity odd
}
delayMicroseconds(1); // delay to let the clock settle out
while (digitalRead(TP_CLK) == LOW) { // loop until the clock goes high
if (watchdog >= timeout) { //check for infinite loop
touchpad_error = HIGH; // set error flag
break; // break out of infinite loop
}
}
delayMicroseconds(1); // delay to let the clock settle out
while (digitalRead(TP_CLK) == HIGH) { // loop until the clock goes low
if (watchdog >= timeout) { //check for infinite loop
touchpad_error = HIGH; // set error flag
break; // break out of infinite loop
}
}
go_z(TP_DATA); // Release the Data line so it goes high as the stop bit
delayMicroseconds(80); // testing shows delay at least 40us
while (digitalRead(TP_CLK) == HIGH) { // loop until the clock goes low
if (watchdog >= timeout) { //check for infinite loop
touchpad_error = HIGH; // set error flag
break; // break out of infinite loop
}
}
delayMicroseconds(1); // wait to let the data settle
if (digitalRead(TP_DATA)) { // Ack bit s/b low if good transfer
touchpad_error = HIGH; //bad ack bit so set the error flag
}
while ((digitalRead(TP_CLK) == LOW) || (digitalRead(TP_DATA) == LOW)) { // loop if clock or data are low
if (watchdog >= timeout) { //check for infinite loop
touchpad_error = HIGH; // set error flag
break; // break out of infinite loop
}
}
// Inhibit the bus so the tp only talks when we're listening
go_0(TP_CLK);
}
//
// Function to get a byte of data from the touchpad
//
char tp_read(void)
{
unsigned int timeout = 200; // breakout of loop if over this value in msec
elapsedMillis watchdog; // zero the watchdog timer clock
char rcv_data = 0; // initialize to zero
char mask = 1; // shift a 1 across the 8 bits to select where to load the data
char rcv_parity = 0; // count the ones received
go_z(TP_CLK); // release the clock
go_z(TP_DATA); // release the data
delayMicroseconds(5); // delay to let clock go high
while (digitalRead(TP_CLK) == HIGH) { // loop until the clock goes low
if (watchdog >= timeout) { //check for infinite loop
touchpad_error = HIGH; // set error flag
break; // break out of infinite loop
}
}
if (digitalRead(TP_DATA)) { // Start bit s/b low from tp
touchpad_error = HIGH; // No start bit so set the error flag
}
delayMicroseconds(1); // delay to let the clock settle out
while (digitalRead(TP_CLK) == LOW) { // loop until the clock goes high
if (watchdog >= timeout) { //check for infinite loop
touchpad_error = HIGH; // set error flag
break; // break out of infinite loop
}
}
for (int k=0; k<8; k++) {
delayMicroseconds(1); // delay to let the clock settle out
while (digitalRead(TP_CLK) == HIGH) { // loop until the clock goes low
if (watchdog >= timeout) { //check for infinite loop
touchpad_error = HIGH; // set error flag
break; // break out of infinite loop
}
}
if (digitalRead(TP_DATA)) { // check if data is high
rcv_data = rcv_data | mask; // set the appropriate bit in the rcv data
rcv_parity++; // increment the parity bit counter
}
mask = mask << 1;
delayMicroseconds(1); // delay to let the clock settle out
while (digitalRead(TP_CLK) == LOW) { // loop until the clock goes high
if (watchdog >= timeout) { //check for infinite loop
touchpad_error = HIGH; // set error flag
break; // break out of infinite loop
}
}
}
// receive parity
delayMicroseconds(1); // delay to let the clock settle out
while (digitalRead(TP_CLK) == HIGH) { // loop until the clock goes low
if (watchdog >= timeout) { //check for infinite loop
touchpad_error = HIGH; // set error flag
break; // break out of infinite loop
}
}
if (digitalRead(TP_DATA)) { // check if received parity is high
rcv_parity++; // increment the parity bit counter
}
rcv_parity = rcv_parity & 1; // mask off all bits except the lsb
if (rcv_parity == 0) { // check for bad (even) parity
touchpad_error = HIGH; //bad parity so set the error flag
}
delayMicroseconds(1); // delay to let the clock settle out
while (digitalRead(TP_CLK) == LOW) { // loop until the clock goes high
if (watchdog >= timeout) { //check for infinite loop
touchpad_error = HIGH; // set error flag
break; // break out of infinite loop
}
}
// stop bit
delayMicroseconds(1); // delay to let the clock settle out
while (digitalRead(TP_CLK) == HIGH) { // loop until the clock goes low
if (watchdog >= timeout) { //check for infinite loop
touchpad_error = HIGH; // set error flag
break; // break out of infinite loop
}
}
if (digitalRead(TP_DATA) == LOW) { // check if stop bit is bad (low)
touchpad_error = HIGH; //bad stop bit so set the error flag
}
delayMicroseconds(1); // delay to let the clock settle out
while (digitalRead(TP_CLK) == LOW) { // loop until the clock goes high
if (watchdog >= timeout) { //check for infinite loop
touchpad_error = HIGH; // set error flag
break; // break out of infinite loop
}
}
// Inhibit the bus so the tp only talks when we're listening
go_0(TP_CLK);
return rcv_data; // pass the received data back
}
// Function to initialize the Touchpad
void touchpad_init()
{
touchpad_error = LOW; // start with no error
go_z(TP_CLK); // float the clock and data to touchpad
go_z(TP_DATA);
// Sending reset command to touchpad
tp_write(0xff);
if (tp_read() != 0xfa) { // verify correct ack byte
touchpad_error = HIGH;
}
delayMicroseconds(100); // give the tp time to run its self diagnostic
// verify proper response from tp
if (tp_read() != 0xaa) { // verify basic assurance test passed
touchpad_error = HIGH;
}
if (tp_read() != 0x00) { // verify correct device id
touchpad_error = HIGH;
}
// increase resolution from 4 counts/mm to 8 counts/mm
tp_write(0xe8); // Sending resolution command
if (tp_read() != 0xfa) { // verify correct ack byte
touchpad_error = HIGH;
}
tp_write(0x03); // value of 03 = 8 counts/mm resolution (default is 4 counts/mm)
if (tp_read() != 0xfa) { // verify correct ack byte
touchpad_error = HIGH;
}
// Sending remote mode code so the touchpad will send data only when polled
tp_write(0xf0); // remote mode
if (tp_read() != 0xfa) { // verify correct ack byte
touchpad_error = HIGH;
}
if (touchpad_error == HIGH) { // check for any errors from tp
delayMicroseconds(300); // wait before trying to initialize tp one last time
tp_write(0xff); // send tp reset code
tp_read(); // read but don't look at response from tp
tp_read(); // read but don't look at response from tp
tp_read(); // read but don't look at response from tp
tp_write(0xe8); // Send resolution command
tp_read(); // read but don't look at response from tp
tp_write(0x03); // value of 03 gives 8 counts/mm resolution
tp_read(); // read but don't look at response from tp
tp_write(0xf0); // remote mode
tp_read(); // read but don't look at response from tp
delayMicroseconds(100);
}
}
// Function to send the 4 keyboard modifier keys over usb
void send_modifiers(int mod_shift, int mod_ctrl, int mod_alt, int mod_gui) {
Keyboard.set_modifier(mod_shift | mod_ctrl | mod_alt | mod_gui);
Keyboard.send_now();
}
// Function to send the keyboard normal keys in the 6 slots over usb
void send_normals(int slot1, int slot2, int slot3, int slot4, int slot5, int slot6) {
Keyboard.set_key1(slot1);
Keyboard.set_key2(slot2);
Keyboard.set_key3(slot3);
Keyboard.set_key4(slot4);
Keyboard.set_key5(slot5);
Keyboard.set_key6(slot6);
Keyboard.send_now();
}
// Function to initialize the keyboard
void keyboard_init()
{
pinMode(Col0, INPUT_PULLUP); // Configure the 8 keyboard columns with pullups
pinMode(Col1, INPUT_PULLUP);
pinMode(Col2, INPUT_PULLUP);
pinMode(Col3, INPUT_PULLUP);
pinMode(Col4, INPUT_PULLUP);
pinMode(Col5, INPUT_PULLUP);
pinMode(Col6, INPUT_PULLUP);
pinMode(Col7, INPUT_PULLUP);
//
go_z(Row0); // Send all 16 rows to high impedance (the off state)
go_z(Row1);
go_z(Row2);
go_z(Row3);
go_z(Row4);
go_z(Row5);
go_z(Row6);
go_z(Row7);
go_z(Row8);
go_z(Row9);
go_z(Row10);
go_z(Row11);
go_z(Row12);
go_z(Row13);
go_z(Row14);
go_z(Row15);
//
send_modifiers(0, 0, 0, 0); // tell the pi all mod keys are released
send_normals(0, 0, 0, 0, 0, 0); // tell the pi all normal keys are released
}
// Function to initialize the lcd control interface
void lcd_control_init()
{
go_z(Vol_Dn); // send all lcd controls to hi z
go_z(Vol_Up);
go_z(Menu);
go_z(On_Off);
}
// Function to initialize the reset and shutdown signals and turn off the disk led
void reset_shutdown_init()
{
go_z(RESET_PI); // put reset signal in inactive state
go_0(SHUTDOWN); // put shutdown signal in inactive state
go_1(DISK_LED); // turn off disk led
}
// Function to pulse the Menu key on the lcd control card
void pulse_menu()
{
go_0(Menu); //Pulse Menu key low
delay(200);
go_z(Menu);
delay(800);
}
// Function to pulse the Vol Up key on the lcd control card
void pulse_vol_up()
{
go_0(Vol_Up); //Pulse Vol_Up key low
delay(200);
go_z(Vol_Up);
delay(800);
}
// Function to pulse the Vol_Dn key on the lcd control card
void pulse_vol_dn()
{
go_0(Vol_Dn); //Pulse Vol_Dn key low
delay(200);
go_z(Vol_Dn);
delay(800);
}
// Function to receive commands over i2c
// Commands are: shutdown = 0x5a, reset = 0xb7, debug led on = 0x10, debug led off = 0x11, blink lcd = e2
void receiveEvent(int numBytes) {
byte read_value;
int i;
for (i=0; i < numBytes; i++) {
read_value = Wire.read();
if (read_value == 0x5a) {
kill_power = HIGH; // Send variable "true" for shutdown on next keyboard polling cycle
}
if (read_value == 0xb7) {
reset_all = HIGH; // Send variable "true" for reset on next keyboard polling cycle
}
if (read_value == 0x10) {
debug = HIGH; // Send variable "true" for led turn on at the next keyboard polling cycle
}
if (read_value == 0x11) {
debug = LOW; // Send variable "false" for led turn off at the next keyboard polling cycle
}
if (read_value == 0xe2) {
blink_display = HIGH; // Send variable "true" for lcd to blink off and back on at the next keyboard polling cycle
}
}
}
// Function to send Battery voltage from ADC, Teensy code version number, date and author to Pi.
// Formula for the ADC 10 bit code is below. All values read 22 bits lower than expected so there is a negative offset from something.
// ADC 10 bit Result = [(Battery_voltage/4)/(5v/1023bits)] - 22 bits
void requestEvent() {
if (adc_ave >= 0x345) {
Wire.write("Battery = 16.8v V3.2 7/7/18 MFA");
}
else if (adc_ave >= 0x340) {
Wire.write("Battery = 16.7v V3.2 7/7/18 MFA");
}
else if (adc_ave >= 0x33b) {
Wire.write("Battery = 16.6v V3.2 7/7/18 MFA");
}
else if (adc_ave >= 0x335) {
Wire.write("Battery = 16.5v V3.2 7/7/18 MFA");
}
else if (adc_ave >= 0x330) {
Wire.write("Battery = 16.4v V3.2 7/7/18 MFA");
}
else if (adc_ave >= 0x32b) {
Wire.write("Battery = 16.3v V3.2 7/7/18 MFA");
}
else if (adc_ave >= 0x326) {
Wire.write("Battery = 16.2v V3.2 7/7/18 MFA");
}
else if (adc_ave >= 0x321) {
Wire.write("Battery = 16.1v V3.2 7/7/18 MFA");
}
else if (adc_ave >= 0x31c) {
Wire.write("Battery = 16.0v V3.2 7/7/18 MFA");
}
else if (adc_ave >= 0x317) {
Wire.write("Battery = 15.9v V3.2 7/7/18 MFA");
}
else if (adc_ave >= 0x312) {
Wire.write("Battery = 15.8v V3.2 7/7/18 MFA");
}
else if (adc_ave >= 0x30d) {
Wire.write("Battery = 15.7v V3.2 7/7/18 MFA");
}
else if (adc_ave >= 0x307) {
Wire.write("Battery = 15.6v V3.2 7/7/18 MFA");
}
else if (adc_ave >= 0x302) {
Wire.write("Battery = 15.5v V3.2 7/7/18 MFA");
}
else if (adc_ave >= 0x2fd) {
Wire.write("Battery = 15.4v V3.2 7/7/18 MFA");
}
else if (adc_ave >= 0x2f8) {
Wire.write("Battery = 15.3v V3.2 7/7/18 MFA");
}
else if (adc_ave >= 0x2f3) {
Wire.write("Battery = 15.2v V3.2 7/7/18 MFA");
}
else if (adc_ave >= 0x2ee) {
Wire.write("Battery = 15.1v V3.2 7/7/18 MFA");
}
else if (adc_ave >= 0x2e9) {
Wire.write("Battery = 15.0v V3.2 7/7/18 MFA");
}
else if (adc_ave >= 0x2e4) {
Wire.write("Battery = 14.9v V3.2 7/7/18 MFA");
}
else if (adc_ave >= 0x2df) {
Wire.write("Battery = 14.8v V3.2 7/7/18 MFA");
}
else if (adc_ave >= 0x2d9) {
Wire.write("Battery = 14.7v V3.2 7/7/18 MFA");
}
else if (adc_ave >= 0x2d4) {
Wire.write("Battery = 14.6v V3.2 7/7/18 MFA");
}
else if (adc_ave >= 0x2cf) {
Wire.write("Battery = 14.5v V3.2 7/7/18 MFA");
}
else if (adc_ave >= 0x2ca) {
Wire.write("Battery = 14.4v V3.2 7/7/18 MFA");
}
else if (adc_ave >= 0x2c5) {
Wire.write("Battery = 14.3v V3.2 7/7/18 MFA");
}
else if (adc_ave >= 0x2c0) {
Wire.write("Battery = 14.2v V3.2 7/7/18 MFA");
}
else if (adc_ave >= 0x2bb) {
Wire.write("Battery = 14.1v V3.2 7/7/18 MFA");
}
else if (adc_ave >= 0x2b6) {
Wire.write("Battery = 14.0v V3.2 7/7/18 MFA");
}
else {
Wire.write("Battery < 14.0v V3.2 7/7/18 MFA");
}
}
// Setup the keyboard and touchpad. Float the lcd controls & pi reset. Drive the shutdown inactive.
void setup() {
analogReference(EXTERNAL); // Configure ADC to use external 5 volt reference
reset_shutdown_init(); // initialize reset and shutdown signals
lcd_control_init(); // initialize lcd control signals
keyboard_init(); // initialize keyboard
touchpad_init(); // initialize touchpad
if (touchpad_error) { // check for error
touchpad_init(); // try one more time to initialize the touchpad
if (touchpad_error) {
touchpad_fail = HIGH; // touchpad failed to initialize
}
}
Wire.begin(8); // join i2c bus with address #8
Wire.onReceive(receiveEvent); // register event to receive command from Pi
Wire.onRequest(requestEvent); // register event to send info back to Pi
}
// Declare and Initialize Keyboard Variables
boolean old_key_1 = HIGH; // old_key_ ... holds the state of every normal keyboard switch
boolean old_key_2 = HIGH; // as it was on the previous scan.
boolean old_key_3 = HIGH; // Initialize all of the old_key_ ... variables to High (the off state).
boolean old_key_4 = HIGH;
boolean old_key_5 = HIGH;
boolean old_key_6 = HIGH;
boolean old_key_7 = HIGH;
boolean old_key_8 = HIGH;
boolean old_key_9 = HIGH;
boolean old_key_0 = HIGH;
boolean old_key_A = HIGH;
boolean old_key_B = HIGH;
boolean old_key_C = HIGH;
boolean old_key_D = HIGH;
boolean old_key_E = HIGH;
boolean old_key_F = HIGH;
boolean old_key_G = HIGH;
boolean old_key_H = HIGH;
boolean old_key_I = HIGH;
boolean old_key_J = HIGH;
boolean old_key_K = HIGH;
boolean old_key_L = HIGH;
boolean old_key_M = HIGH;
boolean old_key_N = HIGH;
boolean old_key_O = HIGH;
boolean old_key_P = HIGH;
boolean old_key_Q = HIGH;
boolean old_key_R = HIGH;
boolean old_key_S = HIGH;
boolean old_key_T = HIGH;
boolean old_key_U = HIGH;
boolean old_key_V = HIGH;
boolean old_key_W = HIGH;
boolean old_key_X = HIGH;
boolean old_key_Y = HIGH;
boolean old_key_Z = HIGH;
boolean old_key_LEFT = HIGH;
boolean old_key_RIGHT = HIGH;
boolean old_key_UP = HIGH;
boolean old_key_DOWN = HIGH;
boolean old_key_TILDE = HIGH;
boolean old_key_MINUS = HIGH;
boolean old_key_EQUAL = HIGH;
boolean old_key_BACKSPACE = HIGH;
boolean old_key_BACKSLASH = HIGH;
boolean old_key_RIGHT_BRACE = HIGH;
boolean old_key_LEFT_BRACE = HIGH;
boolean old_key_ENTER = HIGH;
boolean old_key_QUOTE = HIGH;
boolean old_key_SEMICOLON = HIGH;
boolean old_key_SLASH = HIGH;
boolean old_key_PERIOD = HIGH;
boolean old_key_COMMA = HIGH;
boolean old_key_SPACE = HIGH;
boolean old_key_CAPS_LOCK = HIGH;
boolean old_key_TAB = HIGH;
boolean old_key_ESC = HIGH;
boolean old_key_PAGE_UP = HIGH;
boolean old_key_PAGE_DOWN = HIGH;
boolean old_key_END = HIGH;
boolean old_key_HOME = HIGH;
boolean old_key_INSERT = HIGH;
boolean old_key_DELETE = HIGH;
boolean old_key_PRINTSCREEN = HIGH;
boolean old_key_F1 = HIGH;
boolean old_key_F2 = HIGH;
boolean old_key_F3 = HIGH;
boolean old_key_F4 = HIGH;
boolean old_key_F5 = HIGH;
boolean old_key_F6 = HIGH;
boolean old_key_F7 = HIGH;
boolean old_key_F8 = HIGH;
boolean old_key_F9 = HIGH;
boolean old_key_F10 = HIGH;
boolean old_key_F11 = HIGH;
boolean old_key_F12 = HIGH;
boolean old_key_MENU = HIGH; // the Menu key is not used in Teensyduino so it becomes the printscreen key
//
boolean old_key_SHIFT = HIGH; // old_key_ ... holds the state of every modifier keyboard switch
boolean old_key_CTRL = HIGH; // Initialize all of the old_key_ ... variables to High (the off state).
boolean old_key_ALT = HIGH;
boolean old_key_GUI = HIGH;
//
boolean Fn_pressed = HIGH; // Active low, Saves the state of the Fn key
//
boolean touchpad_enabled = HIGH; // Active high, controls whether the touchpad is used or not
boolean button_change = LOW; // Active high, shows when a touchpad left or right button has changed since last polling cycle
//
int mod_shift = 0; // These 4 variables are sent over USB as modifier keys.
int mod_ctrl = 0; // Either set to 0 or MODIFIER_ ... SHIFT, CTRL, ALT, GUI
int mod_alt = 0;
int mod_gui = 0;
// Declare and Initialize Touchpad variables
char mstat; // touchpad status reg = Y overflow, X overflow, Y sign bit, X sign bit, Always 1, Middle Btn, Right Btn, Left Btn
char mx; // touchpad x movement = 8 data bits. The sign bit is in the status register to
// make a 9 bit 2's complement value. Left to right on the touchpad gives a positive value.
char my; // touchpad y movement = 8 bits plus sign. Touchpad movement bottom to top gives a positive value.
boolean over_flow; // set if x or y movement values are bad due to overflow
boolean left_button = 0; // on/off variable for left button = bit 0 of mstat
boolean right_button = 0; // on/off variable for right button = bit 1 of mstat
boolean old_left_button = 0; // on/off variable for left button status from the previous polling cycle
boolean old_right_button = 0; // on/off variable for right button status from the previous polling cycle
//
int blink_count = 0; // loop counter
boolean blinky = LOW; // Blink LED state
//
extern volatile uint8_t keyboard_leds; // 8 bits sent from Pi to Teensy that give keyboard LED status. Caps lock is bit D1.
//
// Main Loop scans the keyboard switches and then polls the touchpad
//
void loop() {
//
// -------Scan keyboard matrix Rows 0 thru 15 & Columns 0 thru 7-------
//
// ------------------------------------------------------Row 15-----------------------------
go_0(Row15); // Activate Row (send it low), then read the column
//
delayMicroseconds(10); // give time to let the signals settle out
//
// ****************Fn Key***************************
// Fn key is checked first so the Fn_pressed variable can be used later when the function keys are scanned
if (!digitalRead(Col0)) { // Check if Fn key is pressed
Fn_pressed = LOW; // Fn pressed
}
else {
Fn_pressed = HIGH; // Fn not pressed
}
go_z(Row15); // send row back to off state
//
// ------------------------------------------------------Row 0-----------------------------
go_0(Row0); // Activate Row (send it low), then read the columns
//
delayMicroseconds(10); // give time to let the signals settle out
//
// ****************CTRL Key L and R***************************
// Check if left or right control key is pressed and wasn't pressed last time
if ((!digitalRead(Col2) || (!digitalRead(Col6))) && (old_key_CTRL)) {
mod_ctrl = MODIFIERKEY_CTRL;
old_key_CTRL = LOW;
send_modifiers(mod_shift, mod_ctrl, mod_alt, mod_gui); // use function to send 4 modifiers over usb
}
// Check if left and right control keys are released and was pressed last time
else if (digitalRead(Col2) && digitalRead(Col6) && (!old_key_CTRL)) {
mod_ctrl = 0;
old_key_CTRL = HIGH;
send_modifiers(mod_shift, mod_ctrl, mod_alt, mod_gui); // use function to send 4 modifiers over usb
}
go_z(Row0); // send row back to off state
// ------------------------------------------------------Row 11-----------------------------
go_0(Row11); // Activate Row (send it low), then read the columns
//
delayMicroseconds(10); // give time to let the signals settle out
//
// ****************SHIFT Key L and R***************************
// Check if left or right shift key is pressed and wasn't pressed last time
if ((!digitalRead(Col5) || (!digitalRead(Col7))) && (old_key_SHIFT)) {
mod_shift = MODIFIERKEY_SHIFT;
old_key_SHIFT = LOW;
send_modifiers(mod_shift, mod_ctrl, mod_alt, mod_gui); // use function to send 4 modifiers over usb
}
// Check if left and right shift keys are released and was pressed last time
else if (digitalRead(Col5) && digitalRead(Col7) && (!old_key_SHIFT)) {
mod_shift = 0;
old_key_SHIFT = HIGH;
send_modifiers(mod_shift, mod_ctrl, mod_alt, mod_gui); // use function to send 4 modifiers over usb
}
//
go_z(Row11); // send row back to off state
// ------------------------------------------------------Row 13-----------------------------
go_0(Row13); // Activate Row (send it low), then read the columns
//
delayMicroseconds(10); // give time to let the signals settle out
//
// ****************ALT Key L and R***************************
// Check if left or right alt key is pressed and wasn't pressed last time
if ((!digitalRead(Col1) || (!digitalRead(Col3))) && (old_key_ALT)) {
mod_alt = MODIFIERKEY_ALT;
old_key_ALT = LOW;
send_modifiers(mod_shift, mod_ctrl, mod_alt, mod_gui); // use function to send 4 modifiers over usb
}
// Check if left and right alt keys are released and was pressed last time
else if (digitalRead(Col1) && digitalRead(Col3) && (!old_key_ALT)) {
mod_alt = 0;
old_key_ALT = HIGH;
send_modifiers(mod_shift, mod_ctrl, mod_alt, mod_gui); // use function to send 4 modifiers over usb
}
//
go_z(Row13); // send row back to off state
// ------------------------------------------------------Row 14-----------------------------
go_0(Row14); // Activate Row (send it low), then read the columns
//
delayMicroseconds(10); // give time to let the signals settle out
//
// ****************GUI Key***************************
// Check if gui key is pressed and wasn't pressed last time
if (!digitalRead(Col4) && (old_key_GUI)) {
mod_gui = MODIFIERKEY_GUI;
old_key_GUI = LOW;
send_modifiers(mod_shift, mod_ctrl, mod_alt, mod_gui); // use function to send 4 modifiers over usb
}
// Check if gui key is released and was pressed last time
else if (digitalRead(Col4) && (!old_key_GUI)) {
mod_gui = 0;
old_key_GUI = HIGH;
send_modifiers(mod_shift, mod_ctrl, mod_alt, mod_gui); // use function to send 4 modifiers over usb
}
go_z(Row14); // send row back to off state
// --------------------------------------------------Row 1---------------------------------
go_0(Row1); // Activate Row (send it low), then read the columns
//
delayMicroseconds(10); // give the row time to go low and settle out
// *****************Left Arrow Key***************************
// Check if key is pressed and wasn't pressed last time and a usb slot is empty
if (!digitalRead(Col1) && old_key_LEFT && (!slots_full)) {
load_slot(KEY_LEFT); //update first available slot with key name
old_key_LEFT = LOW; //remember key is now pressed
send_normals(slot1, slot2, slot3, slot4, slot5, slot6); // use function to send 6 slots over usb
}
// Check if key is released and was pressed last time
else if (digitalRead(Col1) && !old_key_LEFT) {
clear_slot(KEY_LEFT); // clear slot that contains key name
old_key_LEFT = HIGH; // remember key is now released
send_normals(slot1, slot2, slot3, slot4, slot5, slot6); // use function to send 6 slots over usb
}
// *****************Down Arrow Key***************************
// Check if key is pressed and wasn't pressed last time and a usb slot is empty
if (!digitalRead(Col2) && old_key_DOWN && (!slots_full)) {
load_slot(KEY_DOWN); //update first available slot with key name
old_key_DOWN = LOW; //remember key is now pressed
send_normals(slot1, slot2, slot3, slot4, slot5, slot6); // use function to send 6 slots over usb
}
// Check if key is released and was pressed last time
else if (digitalRead(Col2) && !old_key_DOWN) {
clear_slot(KEY_DOWN); // clear slot that contains key name
old_key_DOWN = HIGH; // remember key is now released
send_normals(slot1, slot2, slot3, slot4, slot5, slot6); // use function to send 6 slots over usb
}
// *****************Up Arrow Key***************************
// Check if key is pressed and wasn't pressed last time and a usb slot is empty
if (!digitalRead(Col3) && old_key_UP && (!slots_full)) {
load_slot(KEY_UP); //update first available slot with key name
old_key_UP = LOW; //remember key is now pressed
send_normals(slot1, slot2, slot3, slot4, slot5, slot6); // use function to send 6 slots over usb
}
// Check if key is released and was pressed last time
else if (digitalRead(Col3) && !old_key_UP) {
clear_slot(KEY_UP); // clear slot that contains key name
old_key_UP = HIGH; // remember key is now released
send_normals(slot1, slot2, slot3, slot4, slot5, slot6); // use function to send 6 slots over usb
}
// *****************Page Down Key***************************
// Check if key is pressed and wasn't pressed last time and a usb slot is empty
if (!digitalRead(Col4) && old_key_PAGE_DOWN && (!slots_full)) {
load_slot(KEY_PAGE_DOWN); //update first available slot with key name
old_key_PAGE_DOWN = LOW; //remember key is now pressed
send_normals(slot1, slot2, slot3, slot4, slot5, slot6); // use function to send 6 slots over usb
}
// Check if key is released and was pressed last time
else if (digitalRead(Col4) && !old_key_PAGE_DOWN) {
clear_slot(KEY_PAGE_DOWN); // clear slot that contains key name
old_key_PAGE_DOWN = HIGH; // remember key is now released
send_normals(slot1, slot2, slot3, slot4, slot5, slot6); // use function to send 6 slots over usb
}
// *****************Page Up Key***************************
// Check if key is pressed and wasn't pressed last time and a usb slot is empty
if (!digitalRead(Col5) && old_key_PAGE_UP && (!slots_full)) {
load_slot(KEY_PAGE_UP); //update first available slot with key name
old_key_PAGE_UP = LOW; //remember key is now pressed
send_normals(slot1, slot2, slot3, slot4, slot5, slot6); // use function to send 6 slots over usb
}
// Check if key is released and was pressed last time
else if (digitalRead(Col5) && !old_key_PAGE_UP) {
clear_slot(KEY_PAGE_UP); // clear slot that contains key name
old_key_PAGE_UP = HIGH; // remember key is now released
send_normals(slot1, slot2, slot3, slot4, slot5, slot6); // use function to send 6 slots over usb
}
// *****************End Key***************************
// Check if key is pressed and wasn't pressed last time and a usb slot is empty
if (!digitalRead(Col6) && old_key_END && (!slots_full)) {
load_slot(KEY_END); //update first available slot with key name
old_key_END = LOW; //remember key is now pressed
send_normals(slot1, slot2, slot3, slot4, slot5, slot6); // use function to send 6 slots over usb
}
// Check if key is released and was pressed last time
else if (digitalRead(Col6) && !old_key_END) {
clear_slot(KEY_END); // clear slot that contains key name
old_key_END = HIGH; // remember key is now released
send_normals(slot1, slot2, slot3, slot4, slot5, slot6); // use function to send 6 slots over usb
}
// *****************Right Arrow Key***************************
// Check if key is pressed and wasn't pressed last time and a usb slot is empty
if (!digitalRead(Col7) && old_key_RIGHT && (!slots_full)) {
load_slot(KEY_RIGHT); //update first available slot with key name
old_key_RIGHT = LOW; //remember key is now pressed
send_normals(slot1, slot2, slot3, slot4, slot5, slot6); // use function to send 6 slots over usb
}
// Check if key is released and was pressed last time
else if (digitalRead(Col7) && !old_key_RIGHT) {
clear_slot(KEY_RIGHT); // clear slot that contains key name
old_key_RIGHT = HIGH; // remember key is now released
send_normals(slot1, slot2, slot3, slot4, slot5, slot6); // use function to send 6 slots over usb
}
go_z(Row1); // send row back to off state
// ------------------------------------------------------Row 2-----------------------------
go_0(Row2); // Activate Row (send it low), then read the columns
//
delayMicroseconds(10); // give time to let the signals settle out
//
// *****************Enter Key***************************
// Check if key is pressed and wasn't pressed last time and a usb slot is empty
if (!digitalRead(Col1) && old_key_ENTER && (!slots_full)) {
load_slot(KEY_ENTER); //update first available slot with key name
old_key_ENTER = LOW; //remember key is now pressed
send_normals(slot1, slot2, slot3, slot4, slot5, slot6); // use function to send 6 slots over usb
}
// Check if key is released and was pressed last time
else if (digitalRead(Col1) && !old_key_ENTER) {
clear_slot(KEY_ENTER); // clear slot that contains key name
old_key_ENTER = HIGH; // remember key is now released
send_normals(slot1, slot2, slot3, slot4, slot5, slot6); // use function to send 6 slots over usb
}
// *****************Right Brace Key***************************
// Check if key is pressed and wasn't pressed last time and a usb slot is empty
if (!digitalRead(Col3) && old_key_RIGHT_BRACE && (!slots_full)) {
load_slot(KEY_RIGHT_BRACE); //update first available slot with key name
old_key_RIGHT_BRACE = LOW; //remember key is now pressed
send_normals(slot1, slot2, slot3, slot4, slot5, slot6); // use function to send 6 slots over usb
}
// Check if key is released and was pressed last time
else if (digitalRead(Col3) && !old_key_RIGHT_BRACE) {
clear_slot(KEY_RIGHT_BRACE); // clear slot that contains key name
old_key_RIGHT_BRACE = HIGH; // remember key is now released
send_normals(slot1, slot2, slot3, slot4, slot5, slot6); // use function to send 6 slots over usb
}
// *****************Equal Key***************************
// Check if key is pressed and wasn't pressed last time and a usb slot is empty
if (!digitalRead(Col5) && old_key_EQUAL && (!slots_full)) {
load_slot(KEY_EQUAL); //update first available slot with key name
old_key_EQUAL = LOW; //remember key is now pressed
send_normals(slot1, slot2, slot3, slot4, slot5, slot6); // use function to send 6 slots over usb
}
// Check if key is released and was pressed last time
else if (digitalRead(Col5) && !old_key_EQUAL) {
clear_slot(KEY_EQUAL); // clear slot that contains key name
old_key_EQUAL = HIGH; // remember key is now released
send_normals(slot1, slot2, slot3, slot4, slot5, slot6); // use function to send 6 slots over usb
}