Пример #1
0
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);
}  // }}}