--- /dev/null
+#!/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())
*/
#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
*/
};
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 {
Led_Compose = 4,
Led_Kana = 5,
Led_Power = 6,
+ Led_Shift = 7,
Led_Glacial = 65500,
Led_Slow = 48000,
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,
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()
{
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;
}
}
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;
#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
}
/* 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) {
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))
}
#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(;;) {