/* hid_keybd.c
*
* This uses a ATtiny45
+ * (4K flash, 256 bytes RAM, 256 bytes EEPROM)
* +----------+
* reset -| RST VCC|- 5V
* Key_A -| PB3 PB2|- D+ / SCK
#include "descriptor.c"
-/* one byte reserved for oscillator calibration and 6 bytes for serial number */
-#define CONFIG_TOP ((uint8_t *)1+6)
-#define CONFIG_LEN 128
+/*
+ * Specify the LED pin (used for heartbeat and CapsLock indication).
+ */
+#define LED_PIN PB1
char EEMEM ee_serial[USB_CFG_SERIAL_NUMBER_LEN] = { USB_CFG_SERIAL_NUMBER };
uint8_t EEMEM ee_calibration = 0xff;
Led_Kana = 5,
Led_Power = 6,
- Led_Slow = 64000,
+ Led_Glacial = 65500,
+ Led_Slow = 48000,
Led_Fast = 32000,
Led_Quick = 16000,
};
0, Led_Slow, 0, 0, 0xff, 0, 0xff, {0, 0, {0, 0, 0, 0, 0, 0}}
};
+static void
+setLEDspeed()
+{
+ if (Global.LED_state & Led_CapsLock) {
+ Global.led_limit = Led_Fast;
+ } else {
+ Global.led_limit = Led_Slow;
+ }
+}
+
/* called when the PC sets the LED state, we can set
- * set the caps lock led indicator
+ * set the caps lock led indicator (flash faster for capslock)
*/
uchar
usbFunctionWrite(uchar *data, uchar len)
{
- if (data[0] == Global.LED_state)
- return 1;
- else
+ if (data[0] != Global.LED_state) {
Global.LED_state = data[0];
-
- if (Global.LED_state & Led_CapsLock)
- //PORTB |= 1<< PB0;
- Global.led_limit = Led_Fast;
- else
- //PORTB &= ~(1 << PB0);
- Global.led_limit = Led_Slow;
- return 0;
+ setLEDspeed();
+ }
+ return 1; /* tell driver nothing else to write */
}
usbMsgLen_t
appInit(void)
{
/* Disable ADC and the Analog comparator as they are not used. */
- ADCSRA &= ~(_BV(ADEN));
- ACSR &= ~(_BV(ACD));
+ ACSR |= _BV(ACD); /* disable the analog comparator */
+ ADCSRA &= ~_BV(ADEN); /* disable ADC */
+ PRR &= ~_BV(PRADC); /* power down the ADC */
- /* see PCMSK for pin change interrupts
- * As PCINT interrupts can wake from sleep, we should use these and
- * be asleep or low power most of the time? USB interrupt wake?
+ /*
+ * LED_PIN is output and set high
+ * PB5 is input with pullup enabled (reset button)
+ * PB3 and PB4 are input with pullup enabled (our keyboard buttons)
+ * PB0 and PB2 are the USB comms pins and are set to output for 10ms
+ * to cause a USB reset, then set to input.
*/
-
- /* Set PB3 and 4 as input (0 to DDRB bit)
- * Set PB0 and 2 as output (1 to DDRB bit) for USB comms
- * Enable pullup on PB5 (reset) and drive PB1 high (LED output pin)
- */
- PORTB = _BV(PB1) | _BV(PB3) | _BV(PB5);
- DDRB = _BV(PB0) | _BV(PB2); /* usb pins output (reset) */
+ PORTB = _BV(LED_PIN) | _BV(PB3) | _BV(PB4) | _BV(PB5);
+ DDRB = _BV(LED_PIN) |_BV(DDB0) |_BV(DDB2);
_delay_ms(10);
- DDRB = _BV(PB1); /* undo usb reset and set led to output */
+ DDRB &= ~(_BV(DDB0) | _BV(DDB2));
+}
- TCCR0B |= (1 << CS01); /* timer 0 at clk/8 will generate randomness */
+static void
+handleKeyPress(uint8_t modifier, uint8_t keycode)
+{
+ 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;
+ Global.key_down_counter = 0;
+ }
+ }
}
static void
++Global.led_counter;
if (Global.led_counter > Global.led_limit) {
- PORTB ^= _BV(PB1); /* toggle led */
+ PORTB ^= _BV(LED_PIN); /* toggle led */
Global.led_counter = 0;
}
/* key pressed (pin driven low) */
- if (!(pin_state & (1 << PB3))) {
- Global.led_limit = Led_Quick;
- if (Global.state == State_Default) {
- if (Global.key_down_counter == 255) {
- Global.state = State_KeyReady;
- Global.keyboard_report.modifier = 0;
- Global.keyboard_report.keycode[0] = Key_A;
- Global.key_down_counter = 0;
- } else {
- ++Global.key_down_counter;
- }
- }
+ if (!(pin_state & _BV(PB3))) {
+ handleKeyPress(0, Key_A);
}
- if (!(pin_state & (1 << PB4))) {
- Global.led_limit = Led_Quick;
- if (Global.state == State_Default) {
- if (Global.key_down_counter == 255) {
- Global.state = State_KeyReady;
- Global.keyboard_report.modifier = 0;
- Global.keyboard_report.keycode[0] = Key_Execute;
- Global.key_down_counter = 0;
- } else {
- ++Global.key_down_counter;
- }
- }
+ if (!(pin_state & _BV(PB4))) {
+ handleKeyPress(0, Key_CapsLock);
}
- if (pin_state & ((1<<PB3)|(1<<PB4)) && Global.state == State_Default) {
- Global.led_limit = (Global.LED_state & Led_CapsLock)
- ? Led_Fast : Led_Slow;
+ /* 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) {
#endif
}
+/* load serial number from eeprom into RAM. The library is
+ * configured to return the string descriptor from this
+ * RAM buffer.
+ */
+
static void
load_serial_eeprom()
{
- uchar serial[USB_CFG_SERIAL_NUMBER_LEN + 2];
+ uchar serial[USB_CFG_SERIAL_NUMBER_LEN];
serial[0] = 0xff;
eeprom_read_block(&serial, &ee_serial, USB_CFG_SERIAL_NUMBER_LEN);
if (serial[0] != 0xff) {
usbDeviceDisconnect(); /* enforce re-enumeration */
_delay_ms(400);
usbDeviceConnect();
- PORTB &= ~(_BV(PB1)); /* toggle the LED */
sei();
for(;;) {
wdt_reset(); /* reset the watchdog timer */