From c7b136e0b1d6936561fed2c8a0e7fabc29e28b8b Mon Sep 17 00:00:00 2001 From: Pat Thoyts Date: Sat, 9 Nov 2013 15:08:11 +0000 Subject: [PATCH] Support entering either keycode or passphrase per button. All the configuration data is now held in eeprom and for each button either a multi-character alphanumeric phrase or a single keycode can be configured. Added a python script to configure the eeprom image (either taken from the device or generated by the compiler). Signed-off-by: Pat Thoyts --- Makefile | 8 ++- config_eeprom.py | 76 ++++++++++++++++++++++ main.c | 160 +++++++++++++++++++++++++++++++++++++++-------- 3 files changed, 215 insertions(+), 29 deletions(-) create mode 100755 config_eeprom.py diff --git a/Makefile b/Makefile index 06df256..747aa4f 100644 --- a/Makefile +++ b/Makefile @@ -91,12 +91,14 @@ main.hex: main.bin # do the checksize script as our last action to allow successful compilation # on Windows with WinAVR where the Unix commands will fail. -serial: main.bin +eeprom: main.eep.hex +main.eep.hex: main.bin @avr-objcopy -j .eeprom --set-section-flags=.eeprom="alloc,load" \ --change-section-lma .eeprom=0 -O ihex main.bin main.eep.hex - @python setserial.py main.eep.hex + @echo call configure_eeprom.py to set eeprom values + #@python setserial.py main.eep.hex -flash_serial: +flash_eeprom: $(AVRDUDE) -U eeprom:w:main.eep.hex:i disasm: main.bin diff --git a/config_eeprom.py b/config_eeprom.py new file mode 100755 index 0000000..4311a83 --- /dev/null +++ b/config_eeprom.py @@ -0,0 +1,76 @@ +#!/usr/bin/python + +import sys,os +import argparse +from intelhex import IntelHex + +def main(argv = None): + """ Configure the eeprom image for the hid keyboard device + --serialnum 8 --phraseA 'something' -keycodeB 4 + + 0: calibration byte + 1: calibration write count + 3: 6 byte serial number + 9: init delay value (ms/8) + 10: key A code + 11: phrase len for A + 12: key B code + 13: phrase len for B + 14..: phrase data + """ + + if (argv is None): + argv = sys.argv + + parser = argparse.ArgumentParser(description= + r'configure keyboard device eeprom data') + parser.add_argument('filename', type=file, + help='eeprom data file in intel hex format') + parser.add_argument('--serial', type=int, help='set device serial number') + parser.add_argument('--phraseA', help='set phrase emitted by key A') + parser.add_argument('--keycodeA', type=int, help='set keycode for key A') + parser.add_argument('--phraseB', help='set phrase emitted by key B') + parser.add_argument('--keycodeB', type=int, help='set keycode for key B') + parser.add_argument('--init_delay', type=int, + help='set initialization delay in milliseconds') + parser.add_argument('--debug', action='store_true', + help='dump modified hex to stdout for review') + args = parser.parse_args(argv[1:]) + + lenA = 0 if args.phraseA is None else len(args.phraseA) + lenB = 0 if args.phraseB is None else len(args.phraseB) + if 14 + lenA + lenB > 255: + print("error: over 256 bytes of eeprom data") + return 1 + + data = IntelHex(args.filename) + + if args.serial is not None: + data.puts(3, 'K%05d' % args.serial) + if args.init_delay is not None: + data[9] = delay / 8 + + if args.phraseA is not None: + data[11] = len(args.phraseA) + data.puts(14, args.phraseA) + else: + if args.keycodeA is not None: + data[10] = args.keycodeA + + if args.phraseB is not None: + data[13] = len(args.phraseB) + data.puts(14 + lenA, args.phraseB) + else: + if args.keycodeB is not None: + data[12] = args.keycodeB + + if args.debug: + data.dump() + else: + with open(argv[1], 'w') as f: + data.write_hex_file(f) + + return 0 + +if __name__=='__main__': + sys.exit(main()) diff --git a/main.c b/main.c index 5d19854..0ac5ea8 100644 --- a/main.c +++ b/main.c @@ -35,9 +35,6 @@ */ #define LED_PIN PB1 -char EEMEM ee_serial[USB_CFG_SERIAL_NUMBER_LEN] = { USB_CFG_SERIAL_NUMBER }; -uint8_t EEMEM ee_calibration = 0xff; - /* Declare space in RAM for the default serial number. This should * be overwrittern from eeprom before USB gets initialized */ @@ -48,9 +45,14 @@ int usbDescriptorStringSerialNumber[USB_CFG_SERIAL_NUMBER_LEN + 2] = { }; enum { - Modifier_NumLock = 1, - Modifier_CapsLock = 2, - Modifier_ScrollLock = 4, + Modifier_LeftControl = (1<<0), + Modifier_LeftShift = (1<<1), + Modifier_LeftAlt = (1<<2), + Modifier_LeftGUI = (1<<3), /* Windows/Compose/Apple/Meta */ + Modifier_RightControl = (1<<4), + Modifier_RightShift = (1<<5), + Modifier_RightAlt = (1<<6), + Modifier_RightGUI = (1<<7), }; enum { @@ -61,6 +63,7 @@ enum { Led_Compose = 4, Led_Kana = 5, Led_Power = 6, + Led_Shift = 7, Led_Glacial = 65500, Led_Slow = 48000, @@ -71,6 +74,11 @@ enum { enum { Key_A = 4, Key_B = 5, + Key_X = 27, + Key_Y = 28, + Key_Z = 29, + Key_1 = 30, + Key_Return = 40, Key_CapsLock = 57, Key_NumLock = 83, Key_Execute = 116, @@ -99,12 +107,30 @@ typedef struct Global_t { uchar LED_state; uchar idle_rate; uint8_t calibrationValue; + uchar code_A; + uchar phraselen_A; + uchar code_B; + uchar phraselen_B; + uchar current_index; /* index of char to send or 0xff for not sending */ + uchar current_pin; keyboard_report_t keyboard_report; } Global_t; static Global_t Global = { - 0, Led_Slow, 0, 0, 0xff, 0, 0xff, {0, 0, {0, 0, 0, 0, 0, 0}} + 0, Led_Slow, 0, 0, 0xff, 0, 0xff, + Key_A, 0, Key_B, 0, 0xff, 0, + {0, 0, {0, 0, 0, 0, 0, 0}} }; +EEMEM uchar ee_phrases; /* start of phrase storage */ +EEMEM uint8_t ee_phraselenB = 0; /* length of stored phrase B*/ +EEMEM uchar ee_code_B = Key_Y; /* key value for button B */ +EEMEM uint8_t ee_phraselenA = 0; /* length of stored phrase A */ +EEMEM uchar ee_code_A = Key_X; /* key value for button A */ +EEMEM uint8_t ee_init_delay = 50; /* delay on init (ms/8) */ +EEMEM char ee_serial[USB_CFG_SERIAL_NUMBER_LEN] = { USB_CFG_SERIAL_NUMBER }; +EEMEM uint16_t ee_cal_write_count = 0; /* record number of calibration writes */ +EEMEM uint8_t ee_calibration = 0xff; + static void setLEDspeed() { @@ -174,17 +200,65 @@ appInit(void) DDRB &= ~(_BV(DDB0) | _BV(DDB2)); } +/* convert an ascii char into a keyboar report - only does alphanum */ static void -handleKeyPress(uint8_t modifier, uint8_t keycode) +set_report(uchar c, keyboard_report_t *report) +{ + report->modifier = 0; + if (c >= '0' && c <= '9') { + report->keycode[0] = (c == '0') ? 39 : 30 + (c - '1'); + } else if (c >= 'a' && c <= 'z') { + report->keycode[0] = 4 + (c - 'a'); + } else if (c >= 'A' && c <= 'Z') { + report->modifier = Modifier_LeftShift; + report->keycode[0] = 4 + (c - 'a'); + } else { + report->keycode[0] = 85; /* KP_* */ + } +} + +static void +queueNextChar() +{ + const uint8_t *p = (const uint8_t *)&ee_phrases; + uchar len = (Global.current_pin == PB3) ? Global.phraselen_A : Global.phraselen_B; + if (Global.current_index == len) { + Global.current_index = 0xff; + } else { + uchar c; + if (Global.current_pin == PB4) + p += Global.phraselen_A; + c = eeprom_read_byte(p + Global.current_index); + if (c == 0xff) { + Global.keyboard_report.modifier = 0; + Global.keyboard_report.keycode[0] = 85; + } else { + set_report(c, &Global.keyboard_report); + } + ++Global.current_index; + Global.state = State_KeyReady; + } +} + +static void +handleKeyPress(uint8_t pin) { if (Global.state == State_Default) { Global.led_limit = Led_Quick; ++Global.key_down_counter; if (Global.key_down_counter > 8000) { - Global.state = State_KeyReady; - Global.keyboard_report.modifier = modifier; - Global.keyboard_report.keycode[0] = keycode; + uchar len = (pin == PB3) ? Global.phraselen_A : Global.phraselen_B; + if (len == 0) { + uchar code = (pin == PB3) ? Global.code_A : Global.code_B; + Global.keyboard_report.modifier = 0; + Global.keyboard_report.keycode[0] = code; + Global.state = State_KeyReady; + } else { + Global.current_index = 0; + Global.current_pin = pin; + queueNextChar(); + } Global.key_down_counter = 0; } } @@ -201,23 +275,28 @@ appPoll(void) Global.led_counter = 0; } - /* key pressed (pin driven low) */ - if (!(pin_state & _BV(PB3))) { - handleKeyPress(0, Key_A); - } - if (!(pin_state & _BV(PB4))) { - handleKeyPress(0, Key_CapsLock); - } - /* when a key is released, reset the LED flash speed */ - if (pin_state & (_BV(PB3)|_BV(PB4)) && Global.state == State_Default) { - setLEDspeed(); + if (Global.state == State_Default && Global.current_index != 0xff) { + queueNextChar(); + } else { + /* key pressed (pin driven low) */ + if (!(pin_state & _BV(PB3))) { + handleKeyPress(PB3); + } + if (!(pin_state & _BV(PB4))) { + handleKeyPress(PB4); + } + /* when a key is released, reset the LED flash speed */ + if (pin_state & (_BV(PB3)|_BV(PB4)) && Global.state == State_Default) { + setLEDspeed(); + } } + /* called after every poll of the interrupt endpoint */ if (usbInterruptIsReady() && Global.LED_state != 0xff) { if (Global.state != State_Default) { switch (Global.state) { case State_KeyReady: - Global.state = State_Pending; + Global.state = State_KeyRelease; break; case State_Pending: Global.state = State_KeyRelease; @@ -242,8 +321,12 @@ on_usb_reset(void) #if F_CPU==16500000 /* store the calibrated value in EEPROM only if changed */ if (Global.calibrationValue != OSCCAL) { + uint16_t count = 0; eeprom_write_byte(&ee_calibration, OSCCAL); Global.calibrationValue = OSCCAL; + count = eeprom_read_word(&ee_cal_write_count); + ++count; + eeprom_write_word(&ee_cal_write_count, count); } #endif } @@ -251,12 +334,14 @@ on_usb_reset(void) /* load serial number from eeprom into RAM. The library is * configured to return the string descriptor from this * RAM buffer. + * + * Also loads the configured keycodes. */ static void -load_serial_eeprom() +load_eeprom_data() { - uchar serial[USB_CFG_SERIAL_NUMBER_LEN]; + uchar c, serial[USB_CFG_SERIAL_NUMBER_LEN]; serial[0] = 0xff; eeprom_read_block(&serial, &ee_serial, USB_CFG_SERIAL_NUMBER_LEN); if (serial[0] != 0xff) { @@ -265,6 +350,22 @@ load_serial_eeprom() usbDescriptorStringSerialNumber[1 + n] = (int)(serial[n]); } } + + c = eeprom_read_byte(&ee_code_A); + if (c != 0xff) + Global.code_A = c; + + c = eeprom_read_byte(&ee_phraselenA); + if (c != 0xff) + Global.phraselen_A = c; + + c = eeprom_read_byte(&ee_code_B); + if (c != 0xff) + Global.code_B = c; + + c = eeprom_read_byte(&ee_phraselenB); + if (c != 0xff) + Global.phraselen_B = c; } int __attribute__((noreturn)) @@ -278,13 +379,20 @@ main(void) } #endif - load_serial_eeprom(); /* load the serial number from eeprom[1..7] */ + load_eeprom_data(); /* load the serial number from eeprom[1..7] */ wdt_enable(WDTO_1S); /* setup a 1 second watchdog */ odDebugInit(); appInit(); /* app specific initialization */ usbInit(); /* usb library initialization */ usbDeviceDisconnect(); /* enforce re-enumeration */ - _delay_ms(400); + { + uint16_t n, delay = (uint16_t)eeprom_read_byte(&ee_init_delay); + if (delay == 0x00ff || delay < 5) delay = 50; + for (n = 0; n < delay; ++n) { + wdt_reset(); + _delay_ms(8); + } + } usbDeviceConnect(); sei(); for(;;) { -- 2.23.0