Fixed return code for usbFunctionWrite to indicate no more data.
authorPat Thoyts <patthoyts@users.sourceforge.net>
Wed, 6 Nov 2013 22:20:21 +0000 (22:20 +0000)
committerPat Thoyts <patthoyts@users.sourceforge.net>
Sat, 9 Nov 2013 15:10:33 +0000 (15:10 +0000)
On some hubs the device was being polled rapidly which slowed down the
heartbeat led indicating too much processing was going on. It turns out
we failed to respond correctly when the LED status was set and the host
permanently attempted to get a response from the device.

Also reworked the initialization code and tidied up and added more
comments.

Signed-off-by: Pat Thoyts <patthoyts@users.sourceforge.net>
main.c

diff --git a/main.c b/main.c
index 21ee415f632e21af624bbff326ff307492a33cef..5d19854b56add4f7b2d61fe053d7b92279671130 100644 (file)
--- a/main.c
+++ b/main.c
@@ -1,6 +1,7 @@
 /* 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;
@@ -60,7 +62,8 @@ enum {
     Led_Kana = 5,
     Led_Power = 6,
 
-    Led_Slow = 64000,
+    Led_Glacial = 65500,
+    Led_Slow = 48000,
     Led_Fast = 32000,
     Led_Quick = 16000,
 };
@@ -102,24 +105,27 @@ static Global_t Global = {
     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
@@ -151,24 +157,37 @@ static void
 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
@@ -178,40 +197,20 @@ appPoll(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) {
@@ -249,10 +248,15 @@ on_usb_reset(void)
 #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) {
@@ -282,7 +286,6 @@ main(void)
     usbDeviceDisconnect(); /* enforce re-enumeration */
     _delay_ms(400);
     usbDeviceConnect();
-    PORTB &= ~(_BV(PB1));  /* toggle the LED */
     sei();
     for(;;) {
         wdt_reset();       /* reset the watchdog timer */