/* Copyright 2019 Basic I/O Instruments(Scott Wei) <scot.wei@gmail.com> This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <avr/pgmspace.h> #include <util/delay.h> #include "report.h" #include "host.h" #include "host_driver.h" #include "keyboard.h" #include "action.h" #include "led.h" #include "sendchar.h" #include "debug.h" #include "print.h" #ifdef SLEEP_LED_ENABLE #include "sleep_led.h" #endif #include "suspend.h" #include "usb_descriptor.h" #include "lufa.h" #include "quantum.h" #include <util/atomic.h> #include "outputselect.h" #ifdef NKRO_ENABLE #include "keycode_config.h" extern keymap_config_t keymap_config; #endif #ifdef AUDIO_ENABLE #include <audio.h> #endif #ifdef BLUETOOTH_ENABLE #ifdef MODULE_ADAFRUIT_BLE #include "adafruit_ble.h" #else #include "bluetooth.h" #endif #endif #ifdef VIRTSER_ENABLE #include "virtser.h" #endif #if (defined(RGB_MIDI) | defined(RGBLIGHT_ANIMATIONS)) & defined(RGBLIGHT_ENABLE) #include "rgblight.h" #endif #ifdef MIDI_ENABLE #include "qmk_midi.h" #endif #ifdef RAW_ENABLE #include "raw_hid.h" #endif #include "ble.h" #include "usart.h" #include <avr/power.h> #include <avr/sleep.h> bool force_usb = false; //Reserved for FORCE USB Mode function. bool force_ble = false; //Reserved for FORCE USB Mode function. bool usb_connected = false; bool ble_enabled = false; uint32_t kb_idle_timer = 0; bool usb_state_sent = false; uint8_t USB_DeviceLastState = 0; #ifdef RAW_ENABLE /** \brief Raw HID Task * * FIXME: Needs doc */ static void raw_hid_task(void) { // Create a temporary buffer to hold the read in data from the host uint8_t data[RAW_EPSIZE]; bool data_read = false; // Device must be connected and configured for the task to run if (USB_DeviceState != DEVICE_STATE_Configured) return; Endpoint_SelectEndpoint(RAW_OUT_EPNUM); // Check to see if a packet has been sent from the host if (Endpoint_IsOUTReceived()) { // Check to see if the packet contains data if (Endpoint_IsReadWriteAllowed()) { /* Read data */ Endpoint_Read_Stream_LE(data, sizeof(data), NULL); data_read = true; } // Finalize the stream transfer to receive the last packet Endpoint_ClearOUT(); if (data_read) { raw_hid_receive(data, sizeof(data)); } } } #endif static void setup_mcu(void) { /* Disable watchdog if enabled by bootloader/fuses */ MCUSR &= ~(1 << WDRF); wdt_disable(); CLKPR = (1 << CLKPCE); CLKPR = (0 << CLKPS3) | (0 << CLKPS2) | (0 << CLKPS1) | (0 << CLKPS0); } static void setup_usb(void) { // Leonardo needs. Without this USB device is not recognized. USB_Disable(); USB_Init(); // for Console_Task USB_Device_EnableSOFEvents(); print_set_sendchar(sendchar); } void power_saving(void) { power_adc_disable(); power_usart0_disable(); power_spi_disable(); power_twi_disable(); USBCON |= (1 << FRZCLK); // Freeze the USB Clock PLLCSR &= ~(1 << PLLE); // Disable the USB Clock (PPL) USBCON &= ~(1 << USBE); } void power_recover(void) { USBCON |= (1 << USBE); PLLCSR |= (1 << PLLE); // Resume the USB Clock (PPL) USBCON &= ~(1 << FRZCLK); // Resume the USB Clock power_adc_enable(); power_usart0_enable(); power_spi_enable(); power_twi_enable(); } void ble_task_init(void) { kb_idle_timer = timer_read32(); //Mark current time, reserved for further usage; } void ble_task(void) { if (USB_DeviceLastState != USB_DeviceState) { usb_state_sent = false; #ifdef BLE_DEBUG send_str(PSTR("USB State Changed\r\n")); if (USB_DeviceState == DEVICE_STATE_Unattached) { send_str(PSTR("USB State Unattached\r\n")); } #endif if (USB_DeviceState == DEVICE_STATE_Powered) { #ifdef BLE_DEBUG send_str(PSTR("USB State Powered\r\n")); #endif power_recover(); host_set_driver(&null_driver); } #ifdef BLE_DEBUG if ((USB_DeviceState == DEVICE_STATE_Default)) { send_str(PSTR("USB State Default\r\n")); } if ((USB_DeviceState == DEVICE_STATE_Addressed)) { send_str(PSTR("USB State Addressed\r\n")); } if (USB_DeviceState == DEVICE_STATE_Configured) { send_str(PSTR("USB State Configured\r\n")); } if (USB_DeviceState > DEVICE_STATE_Unattached) { } else { // } #endif } else { #ifdef BLE_DEBUG if (!usb_state_sent) { if (USB_DeviceState == DEVICE_STATE_Unattached) { send_str(PSTR("USB State Stopped at Unattached\r\n")); } if (USB_DeviceState == DEVICE_STATE_Powered) { send_str(PSTR("USB State Stopped at Powered\r\n")); } if ((USB_DeviceState == DEVICE_STATE_Default)) { send_str(PSTR("USB State Stopped at Default\r\n")); } if ((USB_DeviceState == DEVICE_STATE_Addressed)) { send_str(PSTR("USB State Stopped at Addressed\r\n")); } if (USB_DeviceState == DEVICE_STATE_Configured) { send_str(PSTR("USB State Stopped at Configured\r\n")); } } #endif if (USB_DeviceState == DEVICE_STATE_Unattached) { if (host_get_driver() && host_get_driver() != &bluefruit_driver) { #ifdef BLE_DEBUG send_str(PSTR("USB State stopped at Unattached\r\n")); #endif ble_task_init(); force_usb = 0; usb_connected = 0; //Reinit USB to prepare for next connection. USB_Init(); USB_Detach(); USB_Attach(); #ifdef BLE_DEBUG send_str(PSTR("Loading &bluefruit_driver\r\n")); #endif host_set_driver(&bluefruit_driver); clear_keyboard(); power_saving(); } else { //Do nothing if USB is unattached and the driver is &bluefruit_driver } } if (USB_DeviceState == DEVICE_STATE_Configured) { if (host_get_driver() && host_get_driver() != &lufa_driver) { #ifdef BLE_DEBUG send_str(PSTR("USB State stopped at Configured\r\n")); #endif power_recover(); usb_connected = 1; ble_enabled = 0; #ifdef BLE_DEBUG send_str(PSTR("Loading &lufa_driver\r\n")); #endif host_set_driver(&lufa_driver); clear_keyboard(); } else { //Do nothing if the driver is &lufa_driver } } usb_state_sent = true; } USB_DeviceLastState = USB_DeviceState; } // Use a custom main() function because the task logic is different from the common one. int main(void) { #ifdef MIDI_ENABLE setup_midi(); #endif setup_mcu(); keyboard_setup(); setup_usb(); sei(); #if defined(MODULE_ADAFRUIT_EZKEY) || defined(MODULE_RN42) serial_init(); #endif /* wait for USB startup to get ready for debug output */ uint8_t timeout = 255; // timeout when USB is not available(Bluetooth) while (timeout-- && USB_DeviceState != DEVICE_STATE_Configured) { wait_ms(4); #if defined(INTERRUPT_CONTROL_ENDPOINT) ; #else USB_USBTask(); #endif } print("\nUSB init\n"); keyboard_init(); host_set_driver(&lufa_driver); backlight_disable(); //host_set_driver(&lufa_driver); print("Keyboard initialized.\n"); //Init Hardware UART usart_init(); #ifdef BLE_DEBUG send_str(PSTR("Keyboard has been setup up\r\n")); if (usb_connected) { send_str(PSTR("usb_connected=1\r\n")); } else { send_str(PSTR("usb_connected=0\r\n")); } #endif #ifdef SLEEP_LED_ENABLE sleep_led_init(); #endif #ifdef VIRTSER_ENABLE virtser_init(); #endif while (1) { ble_task(); keyboard_task(); #ifdef RAW_ENABLE raw_hid_task(); #endif #if defined(RGBLIGHT_ANIMATIONS) && defined(RGBLIGHT_ENABLE) rgblight_task(); #endif #if !defined(INTERRUPT_CONTROL_ENDPOINT) USB_USBTask(); #endif } }