static void pnx0106_leds_event (led_event_t ledevt) { if (ledevt == led_idle_end) LED_TURN_ON(GPIO_LED_ACTIVITY); else if (ledevt == led_idle_start) LED_TURN_OFF(GPIO_LED_ACTIVITY); else if (ledevt == led_timer) gpio_toggle_output (GPIO_LED_HEARTBEAT); }
main(void) { // {{{ uchar sensor_probe_counter = 0; uchar timer_overflow = 0; #if ENABLE_IDLE_RATE int idle_counter = 0; #endif cli(); hardware_init(); #if ENABLE_KEYBOARD init_keyboard_emulation(); init_ui_system(); #endif #if ENABLE_MOUSE init_mouse_emulation(); #endif TWI_Master_Initialise(); usbInit(); init_int_eeprom(); init_button_state(); wdt_reset(); sei(); // Sensor initialization must be done with interrupts enabled! // It uses I2C (TWI) to configure the sensor. sensor_init_configuration(); LED_TURN_ON(GREEN_LED); for (;;) { // main event loop wdt_reset(); usbPoll(); if (TIFR & (1<<TOV0)) { timer_overflow = 1; // Resetting the Timer0 // Setting this bit to one will clear it. TIFR = 1<<TOV0; } else { timer_overflow = 0; } update_button_state(timer_overflow); // Red LED lights up if there is any kind of error in I2C communication if ( TWI_statusReg.lastTransOK ) { LED_TURN_OFF(RED_LED); } else { LED_TURN_ON(RED_LED); } // Handling the state change of the main switch if (ON_KEY_UP(BUTTON_SWITCH)) { // Upon releasing the switch, stop the continuous reading. sensor_stop_continuous_reading(); #if ENABLE_KEYBOARD // And also reset the menu system. init_ui_system(); #endif } else if (ON_KEY_DOWN(BUTTON_SWITCH)) { // Upon pressing the switch, start the continuous reading for // mouse emulation code. sensor_start_continuous_reading(); } // Continuous reading of sensor data if (sensor.continuous_reading) { // {{{ // Timer is set to 1.365ms if (timer_overflow) { // The sensor is configured for 75Hz measurements. // I'm using this timer to read the values twice that rate. // 5 * 1.365ms = 6.827ms ~= 146Hz if (sensor_probe_counter > 0){ // Waiting... sensor_probe_counter--; } } if (sensor_probe_counter == 0) { // Time for reading new data! uchar return_code; return_code = sensor_read_data_registers(); if (return_code == SENSOR_FUNC_DONE || return_code == SENSOR_FUNC_ERROR) { // Restart the counter+timer sensor_probe_counter = 5; } } } // }}} #if ENABLE_IDLE_RATE // Timer is set to 1.365ms if (timer_overflow) { // {{{ // Implementing the idle rate... if (idle_rate != 0) { if (idle_counter > 0){ idle_counter--; } else { // idle_counter counts how many Timer0 overflows are // required before sending another report. // The exact formula is: // idle_counter = (idle_rate * 4)/1.365; // But it's better to avoid floating point math. // 4/1.365 = 2.93, so let's just multiply it by 3. idle_counter = idle_rate * 3; //keyDidChange = 1; LED_TOGGLE(YELLOW_LED); // TODO: Actually implement idle rate... Should re-send // the current status. } } } // }}} #endif // MAIN code. Code that emulates the mouse or implements the menu // system. if (button.state & BUTTON_SWITCH) { // Code for when the switch is held down // Should read data and do things #if ENABLE_MOUSE // nothing here #endif } else { // Code for when the switch is "off" // Basically, this is the menu system (implemented as keyboard) #if ENABLE_KEYBOARD ui_main_code(); #endif } // Sending USB Interrupt-in report if(usbInterruptIsReady()) { if (0) { // This useless "if" is here to make all the following // conditionals an "else if", and thus making it a lot // easier to add/remove them using preprocessor directives. } #if ENABLE_KEYBOARD else if(string_output_pointer != NULL){ // Automatically send keyboard report if there is something // in the buffer send_next_char(); usbSetInterrupt((void*) &keyboard_report, sizeof(keyboard_report)); } #endif #if ENABLE_MOUSE else if (button.state & BUTTON_SWITCH) { if (mouse_prepare_next_report()) { usbSetInterrupt((void*) &mouse_report, sizeof(mouse_report)); } } #endif } } } // }}}
static void hardware_init(void) { // {{{ // Configuring Watchdog to about 2 seconds // See pages 43 and 44 from ATmega8 datasheet // See also http://www.nongnu.org/avr-libc/user-manual/group__avr__watchdog.html wdt_enable(WDTO_2S); PORTB = 0xff; // activate all pull-ups DDRB = 0; // all pins input PORTC = 0xff; // activate all pull-ups DDRC = 0; // all pins input // From usbdrv.h: //#define USBMASK ((1<<USB_CFG_DPLUS_BIT) | (1<<USB_CFG_DMINUS_BIT)) // activate pull-ups, except on USB lines and LED pins PORTD = 0xFF ^ (USBMASK | ALL_LEDS); // LED pins as output, the other pins as input DDRD = 0 | ALL_LEDS; // Doing a USB reset // This is done here because the device might have been reset // by the watchdog or some condition other than power-up. // // A reset is done by holding both D+ and D- low (setting the // pins as output with value zero) for longer than 10ms. // // See page 145 of usb_20.pdf // See also http://www.beyondlogic.org/usbnutshell/usb2.shtml DDRD |= USBMASK; // Setting as output PORTD &= ~USBMASK; // Setting as zero _delay_ms(15); // Holding this state for at least 10ms DDRD &= ~USBMASK; // Setting as input //PORTD &= ~USBMASK; // Pull-ups are already disabled // End of USB reset // Disabling Timer0 Interrupt // It's disabled by default, anyway, so this shouldn't be needed TIMSK &= ~(TOIE0); // Configuring Timer0 (with main clock at 12MHz) // 0 = No clock (timer stopped) // 1 = Prescaler = 1 => 0.0213333ms // 2 = Prescaler = 8 => 0.1706666ms // 3 = Prescaler = 64 => 1.3653333ms // 4 = Prescaler = 256 => 5.4613333ms // 5 = Prescaler = 1024 => 21.8453333ms // 6 = External clock source on T0 pin (falling edge) // 7 = External clock source on T0 pin (rising edge) // See page 72 from ATmega8 datasheet. // Also thanks to http://frank.circleofcurrent.com/cache/avrtimercalc.htm TCCR0 = 3; // I'm using Timer0 as a 1.365ms ticker. Every time it overflows, the TOV0 // flag in TIFR is set. // I'm not using serial-line debugging //odDebugInit(); LED_TURN_ON(YELLOW_LED); } // }}}