diff options
| author | tmk <nobody@nowhere> | 2013-03-16 17:30:18 +0900 | 
|---|---|---|
| committer | tmk <nobody@nowhere> | 2013-03-16 17:30:18 +0900 | 
| commit | e4589f808eba875d7bf74fb470d5d1ce9ed41123 (patch) | |
| tree | f68e720804c1c82109c1de19dc3cc7d9eb2cabf0 | |
| parent | b78c654693014c60ced089648c29f46939d23437 (diff) | |
| parent | f0c5f1b910ecf9536e5b95cc4ca9a43b0f4b2c36 (diff) | |
| download | firmware-e4589f808eba875d7bf74fb470d5d1ce9ed41123.tar.gz firmware-e4589f808eba875d7bf74fb470d5d1ce9ed41123.tar.bz2 firmware-e4589f808eba875d7bf74fb470d5d1ce9ed41123.zip | |
Merge branch 'remote_wakeup'
| -rw-r--r-- | common.mk | 6 | ||||
| -rw-r--r-- | common/sleep_led.c | 84 | ||||
| -rw-r--r-- | common/sleep_led.h | 10 | ||||
| -rw-r--r-- | keyboard/gh60/Makefile.lufa | 1 | ||||
| -rw-r--r-- | protocol/lufa/lufa.c | 128 | 
5 files changed, 225 insertions, 4 deletions
| @@ -47,5 +47,11 @@ ifdef $(or MOUSEKEY_ENABLE, PS2_MOUSE_ENABLE)      OPT_DEFS += -DMOUSE_ENABLE  endif +ifdef SLEEP_LED_ENABLE +    SRC += $(COMMON_DIR)/sleep_led.c +    OPT_DEFS += -DSLEEP_LED_ENABLE +endif + +  # Search Path  VPATH += $(TOP_DIR)/common diff --git a/common/sleep_led.c b/common/sleep_led.c new file mode 100644 index 000000000..edf68c352 --- /dev/null +++ b/common/sleep_led.c @@ -0,0 +1,84 @@ +#include <stdint.h> +#include <avr/io.h> +#include <avr/interrupt.h> +#include <avr/pgmspace.h> +#include "led.h" +#include "sleep_led.h" + +/* Software PWM + *  ______           ______           __ + * |  ON  |___OFF___|  ON  |___OFF___|   .... + * |<-------------->|<-------------->|<- .... + *     PWM period       PWM period + * + * 256              interrupts/period[resolution] + * 64               periods/second[frequency] + * 256*64           interrupts/second + * F_CPU/(256*64)   clocks/interrupt + */ +#define SLEEP_LED_TIMER_TOP F_CPU/(256*64) + +void sleep_led_init(void) +{ +    /* Timer1 setup */ +    /* CTC mode */ +    TCCR1B |= _BV(WGM12); +    /* Clock selelct: clk/1 */ +    TCCR1B |= _BV(CS10); +    /* Set TOP value */ +    uint8_t sreg = SREG; +    cli(); +    OCR1AH = (SLEEP_LED_TIMER_TOP>>8)&0xff; +    OCR1AL = SLEEP_LED_TIMER_TOP&0xff; +    SREG = sreg; +} + +void sleep_led_enable(void) +{ +    /* Enable Compare Match Interrupt */ +    TIMSK1 |= _BV(OCIE1A); +} + +void sleep_led_disable(void) +{ +    /* Disable Compare Match Interrupt */ +    TIMSK1 &= ~_BV(OCIE1A); +} + + +/* Breathing Sleep LED brighness(PWM On period) table + * (32[steps] * 8[duration]) / 64[PWM periods/s] = 4 second breath cycle + */ +static const uint8_t breathing_table[32] PROGMEM = { +    0, 0, 0, 2, 9, 21, 37, 56, 78, 127, 151, 175, 197, 216, 232, 244, +    254, 244, 216, 197, 175, 151, 127, 78, 56, 37, 21, 9, 2, 0, 0, 0 +}; + +ISR(TIMER1_COMPA_vect) +{ +    /* Software PWM +     * timer:1111 1111 1111 1111 +     *       \----/\-/ \-------/+---  count(0-255) +     *         |    +---------------  duration of step(8) +     *         +--------------------  index of step table(0-31) +     */ +    static union { +        uint16_t row; +        struct { +            uint8_t count:8; +            uint8_t duration:3; +            uint8_t index:5; +        } pwm; +    } timer = { .row = 0 }; + +    timer.row++; +     +    // LED on +    if (timer.pwm.count == 0) { +        led_set(1<<USB_LED_CAPS_LOCK); +    } +    // LED off +    if (timer.pwm.count == pgm_read_byte(&breathing_table[timer.pwm.index])) { +        led_set(0); +    } +} diff --git a/common/sleep_led.h b/common/sleep_led.h new file mode 100644 index 000000000..aebdbeaa5 --- /dev/null +++ b/common/sleep_led.h @@ -0,0 +1,10 @@ +#ifndef SLEEP_LED_H +#define SLEEP_LED_H + +#define NO_SUSPEND_POWER_DOWN + +void sleep_led_init(void); +void sleep_led_enable(void); +void sleep_led_disable(void); + +#endif diff --git a/keyboard/gh60/Makefile.lufa b/keyboard/gh60/Makefile.lufa index a5ff609a7..8042ff3f4 100644 --- a/keyboard/gh60/Makefile.lufa +++ b/keyboard/gh60/Makefile.lufa @@ -103,6 +103,7 @@ BOOTMAGIC_ENABLE = yes	# Virtual DIP switch configuration(+1000)  MOUSEKEY_ENABLE = yes	# Mouse keys(+4700)  EXTRAKEY_ENABLE = yes	# Audio control and System control(+450)  CONSOLE_ENABLE = yes	# Console for debug(+400) +SLEEP_LED_ENABLE = yes  # Breathing sleep LED during USB suspend  #NKRO_ENABLE = yes	# USB Nkey Rollover - not yet supported in LUFA  #PS2_MOUSE_ENABLE = yes	# PS/2 mouse(TrackPoint) support diff --git a/protocol/lufa/lufa.c b/protocol/lufa/lufa.c index 98c3a68ff..127dece54 100644 --- a/protocol/lufa/lufa.c +++ b/protocol/lufa/lufa.c @@ -36,12 +36,20 @@    this software.  */ +#include <avr/sleep.h> +#include <avr/wdt.h>  #include "report.h"  #include "host.h"  #include "host_driver.h"  #include "keyboard.h" +#include "action.h" +#include "matrix.h" +#include "led.h"  #include "sendchar.h"  #include "debug.h" +#ifdef SLEEP_LED_ENABLE +#include "sleep_led.h" +#endif  #include "descriptor.h"  #include "lufa.h" @@ -133,16 +141,45 @@ static void Console_Task(void)  /*******************************************************************************   * USB Events   ******************************************************************************/ -/** Event handler for the USB_Connect event. */ +/* + * Event Order of Plug in: + * 0) EVENT_USB_Device_Connect + * 1) EVENT_USB_Device_Suspend + * 2) EVENT_USB_Device_Reset + * 3) EVENT_USB_Device_Wake +*/  void EVENT_USB_Device_Connect(void)  { +    led_set(0x1f);  // all on  } -/** Event handler for the USB_Disconnect event. */  void EVENT_USB_Device_Disconnect(void)  {  } +void EVENT_USB_Device_Reset(void) +{ +} + +void EVENT_USB_Device_Suspend() +{ +#ifdef SLEEP_LED_ENABLE +    sleep_led_enable(); +#endif +} + +void EVENT_USB_Device_WakeUp() +{ +    // initialize +    matrix_init(); +    clear_keyboard(); + +#ifdef SLEEP_LED_ENABLE +    sleep_led_disable(); +#endif +    led_set(host_keyboard_leds()); +} +  void EVENT_USB_Device_StartOfFrame(void)  {      Console_Task(); @@ -466,17 +503,83 @@ static void SetupHardware(void)      USB_Device_EnableSOFEvents();  } + +static bool wakeup_condition(void) +{ +    matrix_scan(); +    for (uint8_t r = 0; r < MATRIX_ROWS; r++) { +        if (matrix_get_row(r)) return true; +    } +    return false; +} + +#define wdt_intr_enable(value)   \ +__asm__ __volatile__ (  \ +    "in __tmp_reg__,__SREG__" "\n\t"    \ +    "cli" "\n\t"    \ +    "wdr" "\n\t"    \ +    "sts %0,%1" "\n\t"  \ +    "out __SREG__,__tmp_reg__" "\n\t"   \ +    "sts %0,%2" "\n\t" \ +    : /* no outputs */  \ +    : "M" (_SFR_MEM_ADDR(_WD_CONTROL_REG)), \ +    "r" (_BV(_WD_CHANGE_BIT) | _BV(WDE)), \ +    "r" ((uint8_t) ((value & 0x08 ? _WD_PS3_MASK : 0x00) | \ +        _BV(WDIE) | (value & 0x07)) ) \ +    : "r0"  \ +) +  int main(void)  __attribute__ ((weak));  int main(void)  {      SetupHardware();      keyboard_init();      host_set_driver(&lufa_driver); +#ifdef SLEEP_LED_ENABLE +    sleep_led_init(); +#endif      sei(); -    // TODO: can't print here -    debug("LUFA init\n");      while (1) { +        // while suspend +        while (USB_DeviceState == DEVICE_STATE_Suspended) { +#ifndef NO_SUSPEND_POWER_DOWN +            // Enable watchdog to wake from MCU sleep +            cli(); +            wdt_reset(); + +            // Watchdog Interrupt and System Reset Mode +            //wdt_enable(WDTO_1S); +            //WDTCSR |= _BV(WDIE); +             +            // Watchdog Interrupt Mode +            wdt_intr_enable(WDTO_120MS); +             +            // TODO: more power saving +            // See PicoPower application note +            // - I/O port input with pullup +            // - prescale clock +            // - BOD disable +            // - Power Reduction Register PRR +            // sleep in power down mode +            set_sleep_mode(SLEEP_MODE_PWR_DOWN); +            sleep_enable(); +            sei(); +            sleep_cpu(); +            sleep_disable(); + +            // Disable watchdog after sleep +            wdt_disable(); +#endif + +            // Send request of USB Wakeup from Suspend to host +            if (USB_Device_RemoteWakeupEnabled) { +                if (wakeup_condition()) { +                    USB_Device_SendRemoteWakeup(); +                } +            } +        } +          keyboard_task();  #if !defined(INTERRUPT_CONTROL_ENDPOINT) @@ -484,3 +587,20 @@ int main(void)  #endif      }  } + +#ifndef NO_SUSPEND_POWER_DOWN +/* watchdog timeout */ +ISR(WDT_vect) +{ +    /* wakeup from MCU sleep mode */ +/* +    // blink LED +    static uint8_t led_state = 0; +    static uint8_t led_count = 0; +    led_count++; +    if ((led_count & 0x07) == 0) { +        led_set((led_state ^= (1<<USB_LED_CAPS_LOCK))); +    } +*/ +} +#endif | 
