mirror of
https://github.com/mon/PocketVoltex.git
synced 2026-10-08 06:38:29 +03:00
Rename firmware folder
This commit is contained in:
@@ -0,0 +1,47 @@
|
||||
#include <Config.h>
|
||||
|
||||
#include <avr/eeprom.h>
|
||||
#include <avr/pgmspace.h>
|
||||
|
||||
#define MAGIC_NUMBER 42
|
||||
|
||||
static sdvx_config_t defaults PROGMEM = {
|
||||
.switches = {
|
||||
HID_KEYBOARD_SC_Z,
|
||||
HID_KEYBOARD_SC_X,
|
||||
HID_KEYBOARD_SC_DOT_AND_GREATER_THAN_SIGN,
|
||||
HID_KEYBOARD_SC_SLASH_AND_QUESTION_MARK,
|
||||
HID_KEYBOARD_SC_C,
|
||||
HID_KEYBOARD_SC_M,
|
||||
HID_KEYBOARD_SC_ENTER},
|
||||
.ledsOn = true,
|
||||
.debounce = 30,
|
||||
.macroClick = HID_KEYBOARD_SC_KEYPAD_PLUS,
|
||||
.macroPin = {HID_KEYBOARD_SC_KEYPAD_0_AND_INSERT,
|
||||
HID_KEYBOARD_SC_KEYPAD_0_AND_INSERT,
|
||||
HID_KEYBOARD_SC_KEYPAD_0_AND_INSERT,
|
||||
HID_KEYBOARD_SC_KEYPAD_0_AND_INSERT}
|
||||
};
|
||||
|
||||
uint8_t firstRun EEMEM; // init to 255
|
||||
sdvx_config_t eeConfig EEMEM;
|
||||
|
||||
sdvx_config_t sdvxConfig;
|
||||
|
||||
void InitConfig(void) {
|
||||
if (eeprom_read_byte(&firstRun) != MAGIC_NUMBER) { // store defaults
|
||||
memcpy_P(&sdvxConfig, &defaults, sizeof(sdvx_config_t));
|
||||
eeprom_write_block(&sdvxConfig, &eeConfig, sizeof(sdvx_config_t));
|
||||
eeprom_write_byte(&firstRun, MAGIC_NUMBER); // defaults set
|
||||
}
|
||||
eeprom_read_block(&sdvxConfig, &eeConfig, sizeof(sdvx_config_t));
|
||||
sdvxConfig.version = FIRMWARE_VERSION;
|
||||
}
|
||||
|
||||
void SetConfig(sdvx_config_t* config) {
|
||||
memcpy(&sdvxConfig, config, sizeof(sdvx_config_t));
|
||||
// Version is set in firmware, not software
|
||||
sdvxConfig.version = FIRMWARE_VERSION;
|
||||
|
||||
eeprom_write_block(&sdvxConfig, &eeConfig, sizeof(sdvx_config_t));
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
#ifndef _CONFIG_H
|
||||
#define _CONFIG_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <LUFA/Drivers/USB/USB.h>
|
||||
|
||||
// 7 gameplay switches + macro combo switch
|
||||
#define SWITCH_COUNT 8
|
||||
#define MAGIC_RESET_NUMBER 42
|
||||
#define FIRMWARE_VERSION 1
|
||||
|
||||
typedef struct {
|
||||
// used to reboot into programming mode
|
||||
uint8_t reboot;
|
||||
uint8_t version;
|
||||
// SWITCH ORDER: A-D, FXL-R, START
|
||||
uint8_t switches[SWITCH_COUNT];
|
||||
bool ledsOn;
|
||||
uint8_t debounce;
|
||||
// When tapping or long-pressing the macro key
|
||||
uint8_t macroClick;
|
||||
uint8_t macroPin[4];
|
||||
} sdvx_config_t;
|
||||
|
||||
// + 1 for some reason
|
||||
// TODO: what is the reason
|
||||
#define CONFIG_BYTES sizeof(sdvx_config_t)
|
||||
|
||||
extern sdvx_config_t sdvxConfig;
|
||||
|
||||
extern void InitConfig(void);
|
||||
extern void SetConfig(sdvx_config_t* config);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
LUFA Library
|
||||
Copyright (C) Dean Camera, 2014.
|
||||
|
||||
dean [at] fourwalledcubicle [dot] com
|
||||
www.lufa-lib.org
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright 2014 Dean Camera (dean [at] fourwalledcubicle [dot] com)
|
||||
|
||||
Permission to use, copy, modify, distribute, and sell this
|
||||
software and its documentation for any purpose is hereby granted
|
||||
without fee, provided that the above copyright notice appear in
|
||||
all copies and that both that the copyright notice and this
|
||||
permission notice and warranty disclaimer appear in supporting
|
||||
documentation, and that the name of the author not be used in
|
||||
advertising or publicity pertaining to distribution of the
|
||||
software without specific, written prior permission.
|
||||
|
||||
The author disclaims all warranties with regard to this
|
||||
software, including all implied warranties of merchantability
|
||||
and fitness. In no event shall the author be liable for any
|
||||
special, indirect or consequential damages or any damages
|
||||
whatsoever resulting from loss of use, data or profits, whether
|
||||
in an action of contract, negligence or other tortious action,
|
||||
arising out of or in connection with the use or performance of
|
||||
this software.
|
||||
*/
|
||||
|
||||
/** \file
|
||||
* \brief LUFA Library Configuration Header File
|
||||
*
|
||||
* This header file is used to configure LUFA's compile time options,
|
||||
* as an alternative to the compile time constants supplied through
|
||||
* a makefile.
|
||||
*
|
||||
* For information on what each token does, refer to the LUFA
|
||||
* manual section "Summary of Compile Tokens".
|
||||
*/
|
||||
|
||||
#ifndef _LUFA_CONFIG_H_
|
||||
#define _LUFA_CONFIG_H_
|
||||
/* Non-USB Related Configuration Tokens: */
|
||||
// #define DISABLE_TERMINAL_CODES
|
||||
|
||||
/* USB Class Driver Related Tokens: */
|
||||
// #define HID_HOST_BOOT_PROTOCOL_ONLY
|
||||
// #define HID_STATETABLE_STACK_DEPTH {Insert Value Here}
|
||||
// #define HID_USAGE_STACK_DEPTH {Insert Value Here}
|
||||
// #define HID_MAX_COLLECTIONS {Insert Value Here}
|
||||
// #define HID_MAX_REPORTITEMS {Insert Value Here}
|
||||
// #define HID_MAX_REPORT_IDS {Insert Value Here}
|
||||
// #define NO_CLASS_DRIVER_AUTOFLUSH
|
||||
|
||||
/* General USB Driver Related Tokens: */
|
||||
// #define ORDERED_EP_CONFIG
|
||||
#define USE_STATIC_OPTIONS (USB_DEVICE_OPT_FULLSPEED | USB_OPT_REG_ENABLED | USB_OPT_AUTO_PLL)
|
||||
#define USB_DEVICE_ONLY
|
||||
// #define USB_HOST_ONLY
|
||||
// #define USB_STREAM_TIMEOUT_MS {Insert Value Here}
|
||||
// #define NO_LIMITED_CONTROLLER_CONNECT
|
||||
// #define NO_SOF_EVENTS
|
||||
|
||||
/* USB Device Mode Driver Related Tokens: */
|
||||
// #define USE_RAM_DESCRIPTORS
|
||||
#define USE_FLASH_DESCRIPTORS
|
||||
// #define USE_EEPROM_DESCRIPTORS
|
||||
// #define NO_INTERNAL_SERIAL
|
||||
#define FIXED_CONTROL_ENDPOINT_SIZE 8
|
||||
// #define DEVICE_STATE_AS_GPIOR {Insert Value Here}
|
||||
#define FIXED_NUM_CONFIGURATIONS 1
|
||||
// #define CONTROL_ONLY_DEVICE
|
||||
// #define INTERRUPT_CONTROL_ENDPOINT
|
||||
// #define NO_DEVICE_REMOTE_WAKEUP
|
||||
// #define NO_DEVICE_SELF_POWER
|
||||
|
||||
/* USB Host Mode Driver Related Tokens: */
|
||||
// #define HOST_STATE_AS_GPIOR {Insert Value Here}
|
||||
// #define USB_HOST_TIMEOUT_MS {Insert Value Here}
|
||||
// #define HOST_DEVICE_SETTLE_DELAY_MS {Insert Value Here}
|
||||
// #define NO_AUTO_VBUS_MANAGEMENT
|
||||
// #define INVERTED_VBUS_ENABLE_LINE
|
||||
#endif
|
||||
@@ -0,0 +1,150 @@
|
||||
"""
|
||||
LUFA Library
|
||||
Copyright (C) Dean Camera, 2014.
|
||||
|
||||
dean [at] fourwalledcubicle [dot] com
|
||||
www.lufa-lib.org
|
||||
"""
|
||||
|
||||
"""
|
||||
Front-end programmer for the LUFA HID class bootloader.
|
||||
|
||||
Usage:
|
||||
python hid_bootloader_loader.py <Device> <Input>.hex
|
||||
|
||||
Example:
|
||||
python hid_bootloader_loader.py at90usb1287 Mouse.hex
|
||||
|
||||
Requires the pywinusb (https://pypi.python.org/pypi/pywinusb/) and
|
||||
IntelHex (http://bialix.com/intelhex/) libraries.
|
||||
"""
|
||||
|
||||
import sys
|
||||
from pywinusb import hid
|
||||
from intelhex import IntelHex
|
||||
import time
|
||||
|
||||
|
||||
# Device information table
|
||||
device_info_map = dict()
|
||||
device_info_map['at90usb1287'] = {'page_size': 256, 'flash_kb': 128}
|
||||
device_info_map['at90usb1286'] = {'page_size': 256, 'flash_kb': 128}
|
||||
device_info_map['at90usb647'] = {'page_size': 256, 'flash_kb': 64}
|
||||
device_info_map['at90usb646'] = {'page_size': 256, 'flash_kb': 64}
|
||||
device_info_map['atmega32u4'] = {'page_size': 128, 'flash_kb': 32}
|
||||
device_info_map['atmega32u2'] = {'page_size': 128, 'flash_kb': 32}
|
||||
device_info_map['atmega16u4'] = {'page_size': 128, 'flash_kb': 16}
|
||||
device_info_map['atmega16u2'] = {'page_size': 128, 'flash_kb': 16}
|
||||
device_info_map['at90usb162'] = {'page_size': 128, 'flash_kb': 16}
|
||||
device_info_map['atmega8u2'] = {'page_size': 128, 'flash_kb': 8}
|
||||
device_info_map['at90usb82'] = {'page_size': 128, 'flash_kb': 8}
|
||||
|
||||
|
||||
def get_hid_device_handle():
|
||||
hid_device_filter = hid.HidDeviceFilter(vendor_id=0x03EB,
|
||||
product_id=0x2067)
|
||||
|
||||
valid_hid_devices = hid_device_filter.get_devices()
|
||||
|
||||
if len(valid_hid_devices) is 0:
|
||||
return None
|
||||
else:
|
||||
return valid_hid_devices[0]
|
||||
|
||||
def bootloader_boot():
|
||||
hid_device_filter = hid.HidDeviceFilter(vendor_id=0x16D0,
|
||||
product_id=0x0A6D,
|
||||
product_name="Pocket Voltex Config")
|
||||
|
||||
valid_hid_devices = hid_device_filter.get_devices()
|
||||
|
||||
if len(valid_hid_devices) is 0:
|
||||
return False
|
||||
else:
|
||||
try:
|
||||
hid_device = valid_hid_devices[0]
|
||||
hid_device.open()
|
||||
# switch count + static stuff + report id
|
||||
output_report_data = [0] * (8 + 9 + 1)
|
||||
# report ID is 0 at byte 0
|
||||
output_report_data[1] = 42;
|
||||
|
||||
hid_device.send_output_report(output_report_data)
|
||||
finally:
|
||||
hid_device.close()
|
||||
return True
|
||||
|
||||
def send_page_data(hid_device, address, data):
|
||||
# Bootloader page data should be the HID Report ID (always zero) followed
|
||||
# by the starting address to program, then one device's flash page worth
|
||||
# of data
|
||||
output_report_data = [0]
|
||||
output_report_data.extend([address & 0xFF, address >> 8])
|
||||
output_report_data.extend(data)
|
||||
|
||||
hid_device.send_output_report(output_report_data)
|
||||
|
||||
|
||||
def program_device(hex_data, device_info):
|
||||
hid_device = get_hid_device_handle()
|
||||
|
||||
if hid_device is None:
|
||||
if not bootloader_boot():
|
||||
print("No valid HID device found.")
|
||||
sys.exit(1)
|
||||
print("Rebooted to bootloader")
|
||||
time.sleep(6)
|
||||
hid_device = get_hid_device_handle()
|
||||
if hid_device is None:
|
||||
print("No valid HID device found.")
|
||||
sys.exit(1)
|
||||
|
||||
try:
|
||||
hid_device.open()
|
||||
print("Connected to bootloader.")
|
||||
|
||||
# Program in all data from the loaded HEX file, in a number of device
|
||||
# page sized chunks
|
||||
for addr in range(0, hex_data.maxaddr(), device_info['page_size']):
|
||||
# Compute the address range of the current page in the device
|
||||
current_page_range = range(addr, addr+device_info['page_size'])
|
||||
|
||||
# Extract the data from the hex file at the specified start page
|
||||
# address and convert it to a regular list of bytes
|
||||
page_data = [hex_data[i] for i in current_page_range]
|
||||
|
||||
print("Writing address 0x%04X-0x%04X" % (current_page_range[0], current_page_range[-1]))
|
||||
|
||||
# Devices with more than 64KB of flash should shift down the page
|
||||
# address so that it is 16-bit (page size is guaranteed to be
|
||||
# >= 256 bytes so no non-zero address bits are discarded)
|
||||
if device_info['flash_kb'] < 64:
|
||||
send_page_data(hid_device, addr, page_data)
|
||||
else:
|
||||
send_page_data(hid_device, addr >> 8, page_data)
|
||||
|
||||
# Once programming is complete, start the application via a dummy page
|
||||
# program to the page address 0xFFFF
|
||||
print("Programming complete, starting application.")
|
||||
send_page_data(hid_device, 0xFFFF, [0] * device_info['page_size'])
|
||||
|
||||
finally:
|
||||
hid_device.close()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
# Load the specified HEX file
|
||||
try:
|
||||
hex_data = IntelHex(sys.argv[2])
|
||||
except:
|
||||
print("Could not open the specified HEX file.")
|
||||
sys.exit(1)
|
||||
|
||||
# Retrieve the device information entry for the specified device
|
||||
try:
|
||||
device_info = device_info_map[sys.argv[1]]
|
||||
except:
|
||||
print("Unknown device name specified.")
|
||||
sys.exit(1)
|
||||
|
||||
program_device(hex_data, device_info)
|
||||
@@ -0,0 +1,489 @@
|
||||
#include "Descriptors.h"
|
||||
|
||||
#define WEBUSB_ID 0x01
|
||||
#define MS_OS_ID 0x02
|
||||
|
||||
const USB_Descriptor_HIDReport_Datatype_t PROGMEM GenericReport[] =
|
||||
{
|
||||
HID_RI_USAGE_PAGE(16, 0xFFDC), /* Vendor Page 0xDC */
|
||||
HID_RI_USAGE(8, 0xFB), /* Vendor Usage 0xFB */
|
||||
HID_RI_COLLECTION(8, 0x01), /* Vendor Usage 1 */
|
||||
// Global Items
|
||||
HID_RI_LOGICAL_MINIMUM(8, 0x00),
|
||||
HID_RI_LOGICAL_MAXIMUM(8, 0xFF),
|
||||
HID_RI_REPORT_SIZE(8, 8),
|
||||
HID_RI_REPORT_COUNT(8, CONFIG_BYTES),
|
||||
|
||||
// Write config
|
||||
HID_RI_USAGE(8, 0x02), /* Vendor Usage 2 */
|
||||
HID_RI_OUTPUT(8, HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_ABSOLUTE | HID_IOF_NON_VOLATILE),
|
||||
|
||||
// Read config
|
||||
HID_RI_USAGE(8, 0x02), /* Vendor Usage 2 */
|
||||
HID_RI_INPUT(8, HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_ABSOLUTE | HID_IOF_NON_VOLATILE),
|
||||
HID_RI_END_COLLECTION(0),
|
||||
};
|
||||
|
||||
const USB_Descriptor_HIDReport_Datatype_t PROGMEM LEDReport[] =
|
||||
{
|
||||
HID_RI_USAGE_PAGE(8, 0x01), /* Generic Desktop */
|
||||
HID_RI_USAGE(8, 0x00), /* Undefined */
|
||||
HID_RI_COLLECTION(8, 0x01), /* Application */
|
||||
// Globals
|
||||
HID_RI_REPORT_COUNT(8, LED_TOTAL_COUNT),
|
||||
HID_RI_REPORT_SIZE(8, 8),
|
||||
HID_RI_LOGICAL_MINIMUM(8, 0),
|
||||
HID_RI_LOGICAL_MAXIMUM(8, BRIGHTNESS_LEVELS-1),
|
||||
HID_RI_USAGE_PAGE(8, 0x0A), // Ordinals
|
||||
|
||||
// Locals
|
||||
0x79, STRING_ID_LED_INDIV, //HID_RI_STRING_MINIMUM(8, STRING_ID_LED_INDIV),
|
||||
0x89, STRING_ID_LED_INDIV + LED_TOTAL_COUNT, //HID_RI_STRING_MAXIMUM(8, STRING_ID_LED_INDIV + LED_COUNT),
|
||||
HID_RI_USAGE_MINIMUM(8, 1), // LED 1
|
||||
HID_RI_USAGE_MAXIMUM(8, LED_TOTAL_COUNT), // LED 8 + buttons
|
||||
HID_RI_OUTPUT(8, HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_ABSOLUTE | HID_IOF_NON_VOLATILE),
|
||||
|
||||
// at least 1 INPUT is also needed to be recognised by Bemanitools
|
||||
HID_RI_USAGE_MINIMUM(8, 1),
|
||||
HID_RI_USAGE_MAXIMUM(8, 1),
|
||||
HID_RI_INPUT(8, HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_ABSOLUTE | HID_IOF_NON_VOLATILE),
|
||||
//0x79, STRING_ID_LED_INDIV, //HID_RI_STRING_MINIMUM(8, STRING_ID_LED_INDIV),
|
||||
//0x89, STRING_ID_LED_INDIV + LED_TOTAL_COUNT, //HID_RI_STRING_MAXIMUM(8, STRING_ID_LED_INDIV + LED_COUNT),
|
||||
//HID_RI_USAGE_MINIMUM(8, 1), // LED 1
|
||||
//HID_RI_USAGE_MAXIMUM(8, LED_TOTAL_COUNT), // LED 8 + buttons
|
||||
//HID_RI_INPUT(8, HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_ABSOLUTE | HID_IOF_NON_VOLATILE),
|
||||
HID_RI_END_COLLECTION(0),
|
||||
};
|
||||
|
||||
const USB_Descriptor_HIDReport_Datatype_t PROGMEM KeyboardReport[] =
|
||||
{
|
||||
// Use the HID class driver's standard Keyboard report
|
||||
HID_DESCRIPTOR_KEYBOARD(SWITCH_COUNT)
|
||||
};
|
||||
|
||||
const USB_Descriptor_HIDReport_Datatype_t PROGMEM MouseReport[] =
|
||||
{
|
||||
/* Use the HID class driver's standard Mouse report.
|
||||
* Min/max X/Y -128 to 127
|
||||
* NOTE: need at least 1 button or report does not work
|
||||
* Relative coordinates
|
||||
*/
|
||||
HID_DESCRIPTOR_MOUSE(-128, 127, -128, 127, 1, false)
|
||||
};
|
||||
|
||||
const USB_Descriptor_Device_t PROGMEM DeviceDescriptor =
|
||||
{
|
||||
.Header = {.Size = sizeof(USB_Descriptor_Device_t), .Type = DTYPE_Device},
|
||||
|
||||
.USBSpecification = VERSION_BCD(2,1,0),
|
||||
.Class = USB_CSCP_NoDeviceClass,
|
||||
.SubClass = USB_CSCP_NoDeviceSubclass,
|
||||
.Protocol = USB_CSCP_NoDeviceProtocol,
|
||||
|
||||
.Endpoint0Size = FIXED_CONTROL_ENDPOINT_SIZE,
|
||||
// mon.im VID/PID pair, unique!
|
||||
.VendorID = 0x16D0,
|
||||
.ProductID = 0x0A6D,
|
||||
.ReleaseNumber = VERSION_BCD(0,0,1),
|
||||
|
||||
.ManufacturerStrIndex = STRING_ID_Manufacturer,
|
||||
.ProductStrIndex = STRING_ID_Product,
|
||||
.SerialNumStrIndex = STRING_ID_Product,
|
||||
|
||||
.NumberOfConfigurations = FIXED_NUM_CONFIGURATIONS
|
||||
};
|
||||
|
||||
const uint8_t PROGMEM MS_OS_Descriptor[] =
|
||||
{
|
||||
MS_OS_DESCRIPTOR_SET(
|
||||
MS_OS_CONFIG_SUBSET_HEADER(0x00, // Config 0
|
||||
MS_OS_FUNCTION_SUBSET_HEADER(INTERFACE_ID_Generic, // Interface ID
|
||||
MS_OS_COMPAT_ID_WINUSB
|
||||
)
|
||||
)
|
||||
)
|
||||
};
|
||||
|
||||
const uint8_t PROGMEM WebUSBAllowedOrigins[] = {
|
||||
WEBUSB_ALLOWED_ORIGINS_HEADER(1, // 1 config header present
|
||||
WEBUSB_CONFIG_SUBSET_HEADER(0x00, 1, // Config 0, 1 function header
|
||||
// Config interface accessible from the web, two valid URLs
|
||||
WEBUSB_FUNCTION_SUBSET_HEADER(INTERFACE_ID_Generic, URL_ID_Config, URL_ID_Localhost)
|
||||
)
|
||||
)
|
||||
};
|
||||
|
||||
const uint8_t PROGMEM BOSDescriptor[] =
|
||||
{
|
||||
BOS_DESCRIPTOR(2, // 2 capability descriptors in use
|
||||
WEBUSB_CAPABILITY_DESCRIPTOR(WEBUSB_ID, URL_ID_Config), // Vendor request ID, URL ID
|
||||
// Required to force WinUSB driver for driverless WebUSB compatibility
|
||||
MS_OS_20_CAPABILITY_DESCRIPTOR(MS_OS_ID, sizeof(MS_OS_Descriptor)) // Vendor request ID, Descriptor set length
|
||||
)
|
||||
};
|
||||
|
||||
const USB_Descriptor_Configuration_t PROGMEM ConfigurationDescriptor =
|
||||
{
|
||||
.Config =
|
||||
{
|
||||
.Header = {.Size = sizeof(USB_Descriptor_Configuration_Header_t), .Type = DTYPE_Configuration},
|
||||
|
||||
.TotalConfigurationSize = sizeof(USB_Descriptor_Configuration_t),
|
||||
.TotalInterfaces = 4,
|
||||
|
||||
.ConfigurationNumber = 1,
|
||||
.ConfigurationStrIndex = STRING_ID_Product,
|
||||
|
||||
.ConfigAttributes = USB_CONFIG_ATTR_RESERVED,
|
||||
|
||||
.MaxPowerConsumption = USB_CONFIG_POWER_MA(500)
|
||||
},
|
||||
|
||||
.HID1_Interface =
|
||||
{
|
||||
.Header = {.Size = sizeof(USB_Descriptor_Interface_t), .Type = DTYPE_Interface},
|
||||
|
||||
.InterfaceNumber = INTERFACE_ID_Keyboard,
|
||||
.AlternateSetting = 0x00,
|
||||
|
||||
.TotalEndpoints = 1,
|
||||
|
||||
.Class = HID_CSCP_HIDClass,
|
||||
.SubClass = HID_CSCP_NonBootSubclass,
|
||||
.Protocol = HID_CSCP_NonBootProtocol,
|
||||
|
||||
.InterfaceStrIndex = NO_DESCRIPTOR
|
||||
},
|
||||
|
||||
.HID1_KeyboardHID =
|
||||
{
|
||||
.Header = {.Size = sizeof(USB_HID_Descriptor_HID_t), .Type = HID_DTYPE_HID},
|
||||
|
||||
.HIDSpec = VERSION_BCD(1,1,1),
|
||||
.CountryCode = 0x00,
|
||||
.TotalReportDescriptors = 1,
|
||||
.HIDReportType = HID_DTYPE_Report,
|
||||
.HIDReportLength = sizeof(KeyboardReport)
|
||||
},
|
||||
|
||||
.HID1_ReportINEndpoint =
|
||||
{
|
||||
.Header = {.Size = sizeof(USB_Descriptor_Endpoint_t), .Type = DTYPE_Endpoint},
|
||||
|
||||
.EndpointAddress = KEYBOARD_EPADDR,
|
||||
.Attributes = (EP_TYPE_INTERRUPT | ENDPOINT_ATTR_NO_SYNC | ENDPOINT_USAGE_DATA),
|
||||
.EndpointSize = KEYBOARD_EPSIZE,
|
||||
.PollingIntervalMS = 0x01
|
||||
},
|
||||
|
||||
.HID2_MouseInterface =
|
||||
{
|
||||
.Header = {.Size = sizeof(USB_Descriptor_Interface_t), .Type = DTYPE_Interface},
|
||||
|
||||
.InterfaceNumber = INTERFACE_ID_Mouse,
|
||||
.AlternateSetting = 0x00,
|
||||
|
||||
.TotalEndpoints = 1,
|
||||
|
||||
.Class = HID_CSCP_HIDClass,
|
||||
.SubClass = HID_CSCP_BootSubclass,
|
||||
.Protocol = HID_CSCP_MouseBootProtocol,
|
||||
|
||||
.InterfaceStrIndex = STRING_ID_KNOB
|
||||
},
|
||||
|
||||
.HID2_MouseHID =
|
||||
{
|
||||
.Header = {.Size = sizeof(USB_HID_Descriptor_HID_t), .Type = HID_DTYPE_HID},
|
||||
|
||||
.HIDSpec = VERSION_BCD(1,1,1),
|
||||
.CountryCode = 0x00,
|
||||
.TotalReportDescriptors = 1,
|
||||
.HIDReportType = HID_DTYPE_Report,
|
||||
.HIDReportLength = sizeof(MouseReport)
|
||||
},
|
||||
|
||||
.HID2_ReportINEndpoint =
|
||||
{
|
||||
.Header = {.Size = sizeof(USB_Descriptor_Endpoint_t), .Type = DTYPE_Endpoint},
|
||||
|
||||
.EndpointAddress = MOUSE_IN_EPADDR,
|
||||
.Attributes = (EP_TYPE_INTERRUPT | ENDPOINT_ATTR_NO_SYNC | ENDPOINT_USAGE_DATA),
|
||||
.EndpointSize = MOUSE_EPSIZE,
|
||||
.PollingIntervalMS = 0x01
|
||||
},
|
||||
|
||||
.HID3_Interface =
|
||||
{
|
||||
.Header = {.Size = sizeof(USB_Descriptor_Interface_t), .Type = DTYPE_Interface},
|
||||
|
||||
.InterfaceNumber = INTERFACE_ID_Generic,
|
||||
.AlternateSetting = 0x00,
|
||||
|
||||
.TotalEndpoints = 1,
|
||||
|
||||
.Class = HID_CSCP_HIDClass,
|
||||
.SubClass = HID_CSCP_NonBootSubclass,
|
||||
.Protocol = HID_CSCP_NonBootProtocol,
|
||||
|
||||
.InterfaceStrIndex = STRING_ID_Config
|
||||
},
|
||||
|
||||
.HID3_VendorHID =
|
||||
{
|
||||
.Header = {.Size = sizeof(USB_HID_Descriptor_HID_t), .Type = HID_DTYPE_HID},
|
||||
|
||||
.HIDSpec = VERSION_BCD(1,1,1),
|
||||
.CountryCode = 0x00,
|
||||
.TotalReportDescriptors = 1,
|
||||
.HIDReportType = HID_DTYPE_Report,
|
||||
.HIDReportLength = sizeof(GenericReport)
|
||||
},
|
||||
|
||||
.HID3_ReportINEndpoint =
|
||||
{
|
||||
.Header = {.Size = sizeof(USB_Descriptor_Endpoint_t), .Type = DTYPE_Endpoint},
|
||||
|
||||
.EndpointAddress = GENERIC_EPADDR,
|
||||
.Attributes = (EP_TYPE_INTERRUPT | ENDPOINT_ATTR_NO_SYNC | ENDPOINT_USAGE_DATA),
|
||||
.EndpointSize = GENERIC_EPSIZE,
|
||||
.PollingIntervalMS = 255
|
||||
},
|
||||
|
||||
.HID4_Interface =
|
||||
{
|
||||
.Header = {.Size = sizeof(USB_Descriptor_Interface_t), .Type = DTYPE_Interface},
|
||||
|
||||
.InterfaceNumber = INTERFACE_ID_LED,
|
||||
.AlternateSetting = 0x00,
|
||||
|
||||
.TotalEndpoints = 1,
|
||||
|
||||
.Class = HID_CSCP_HIDClass,
|
||||
.SubClass = HID_CSCP_NonBootSubclass,
|
||||
.Protocol = HID_CSCP_NonBootProtocol,
|
||||
|
||||
.InterfaceStrIndex = STRING_ID_LED
|
||||
},
|
||||
|
||||
.HID4_LEDHID =
|
||||
{
|
||||
.Header = {.Size = sizeof(USB_HID_Descriptor_HID_t), .Type = HID_DTYPE_HID},
|
||||
|
||||
.HIDSpec = VERSION_BCD(1,1,1),
|
||||
.CountryCode = 0x00,
|
||||
.TotalReportDescriptors = 1,
|
||||
.HIDReportType = HID_DTYPE_Report,
|
||||
.HIDReportLength = sizeof(LEDReport)
|
||||
},
|
||||
|
||||
.HID4_ReportINEndpoint =
|
||||
{
|
||||
.Header = {.Size = sizeof(USB_Descriptor_Endpoint_t), .Type = DTYPE_Endpoint},
|
||||
|
||||
.EndpointAddress = LED_EPADDR,
|
||||
.Attributes = (EP_TYPE_INTERRUPT | ENDPOINT_ATTR_NO_SYNC | ENDPOINT_USAGE_DATA),
|
||||
.EndpointSize = LED_EPSIZE,
|
||||
.PollingIntervalMS = 255
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
const USB_Descriptor_URL_t PROGMEM ConfigURL = URL_STRING_DESCRIPTOR(URL_HTTPS, "mon.im/sdvx/config");
|
||||
const USB_Descriptor_URL_t PROGMEM LocalhostURL = URL_STRING_DESCRIPTOR(URL_HTTP, "localhost");
|
||||
|
||||
const USB_Descriptor_String_t PROGMEM LanguageString = USB_STRING_DESCRIPTOR_ARRAY(LANGUAGE_ID_ENG);
|
||||
const USB_Descriptor_String_t PROGMEM ManufacturerString = USB_STRING_DESCRIPTOR(L"mon.im");
|
||||
const USB_Descriptor_String_t PROGMEM ProductString = USB_STRING_DESCRIPTOR(L"Pocket Voltex");
|
||||
const USB_Descriptor_String_t PROGMEM ConfigString = USB_STRING_DESCRIPTOR(L"Pocket Voltex Config");
|
||||
const USB_Descriptor_String_t PROGMEM LEDString = USB_STRING_DESCRIPTOR(L"Pocket Voltex LEDs");
|
||||
const USB_Descriptor_String_t PROGMEM KnobString = USB_STRING_DESCRIPTOR(L"Pocket Voltex Knobs");
|
||||
// There may be a better way to do this
|
||||
const USB_Descriptor_String_t PROGMEM LEDString_indiv[] = {
|
||||
USB_STRING_DESCRIPTOR(L"L1-B"),
|
||||
USB_STRING_DESCRIPTOR(L"L1-G"),
|
||||
USB_STRING_DESCRIPTOR(L"L1-R"),
|
||||
USB_STRING_DESCRIPTOR(L"L2-B"),
|
||||
USB_STRING_DESCRIPTOR(L"L2-G"),
|
||||
USB_STRING_DESCRIPTOR(L"L2-R"),
|
||||
USB_STRING_DESCRIPTOR(L"L3-B"),
|
||||
USB_STRING_DESCRIPTOR(L"L3-G"),
|
||||
USB_STRING_DESCRIPTOR(L"L3-R"),
|
||||
USB_STRING_DESCRIPTOR(L"L4-B"),
|
||||
USB_STRING_DESCRIPTOR(L"L4-G"),
|
||||
USB_STRING_DESCRIPTOR(L"L4-R"),
|
||||
USB_STRING_DESCRIPTOR(L"L5-B"),
|
||||
USB_STRING_DESCRIPTOR(L"L5-G"),
|
||||
USB_STRING_DESCRIPTOR(L"L5-R"),
|
||||
USB_STRING_DESCRIPTOR(L"L6-B"),
|
||||
USB_STRING_DESCRIPTOR(L"L6-G"),
|
||||
USB_STRING_DESCRIPTOR(L"L6-R"),
|
||||
USB_STRING_DESCRIPTOR(L"L7-B"),
|
||||
USB_STRING_DESCRIPTOR(L"L7-G"),
|
||||
USB_STRING_DESCRIPTOR(L"L7-R"),
|
||||
USB_STRING_DESCRIPTOR(L"L8-B"),
|
||||
USB_STRING_DESCRIPTOR(L"L8-G"),
|
||||
USB_STRING_DESCRIPTOR(L"L8-R"),
|
||||
USB_STRING_DESCRIPTOR(L"BT-A"),
|
||||
USB_STRING_DESCRIPTOR(L"BT-B"),
|
||||
USB_STRING_DESCRIPTOR(L"BT-C"),
|
||||
USB_STRING_DESCRIPTOR(L"BT-D"),
|
||||
USB_STRING_DESCRIPTOR(L"FX-L"),
|
||||
USB_STRING_DESCRIPTOR(L"FX-R"),
|
||||
};
|
||||
|
||||
void USB_Process_BOS(void) {
|
||||
const void* Address = NULL;
|
||||
uint16_t Size = 0;
|
||||
|
||||
if(!(Endpoint_IsSETUPReceived()) ||
|
||||
USB_ControlRequest.bmRequestType != (REQDIR_DEVICETOHOST | REQTYPE_VENDOR | REQREC_DEVICE)) {
|
||||
return;
|
||||
}
|
||||
switch(USB_ControlRequest.bRequest) {
|
||||
case WEBUSB_ID:
|
||||
switch(USB_ControlRequest.wIndex) {
|
||||
case WEBUSB_REQUEST_GET_ALLOWED_ORIGINS:
|
||||
Address = &WebUSBAllowedOrigins;
|
||||
Size = sizeof(WebUSBAllowedOrigins);
|
||||
break;
|
||||
case WEBUSB_REQUEST_GET_URL:
|
||||
switch(USB_ControlRequest.wValue) {
|
||||
case URL_ID_Localhost:
|
||||
Address = &LocalhostURL;
|
||||
Size = pgm_read_byte(&LocalhostURL.Header.Size);
|
||||
break;
|
||||
case URL_ID_Config:
|
||||
Address = &ConfigURL;
|
||||
Size = pgm_read_byte(&ConfigURL.Header.Size);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case MS_OS_ID:
|
||||
if(USB_ControlRequest.wIndex == MS_OS_20_DESCRIPTOR_INDEX) {
|
||||
Address = &MS_OS_Descriptor;
|
||||
Size = sizeof(MS_OS_Descriptor);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
if(Address != NULL) {
|
||||
Endpoint_SelectEndpoint(ENDPOINT_CONTROLEP);
|
||||
|
||||
Endpoint_ClearSETUP();
|
||||
|
||||
Endpoint_Write_Control_PStream_LE(Address, Size);
|
||||
Endpoint_ClearOUT();
|
||||
}
|
||||
}
|
||||
|
||||
/** This function is called by the library when in device mode, and must be overridden (see library "USB Descriptors"
|
||||
* documentation) by the application code so that the address and size of a requested descriptor can be given
|
||||
* to the USB library. When the device receives a Get Descriptor request on the control endpoint, this function
|
||||
* is called so that the descriptor details can be passed back and the appropriate descriptor sent back to the
|
||||
* USB host.
|
||||
*/
|
||||
uint16_t CALLBACK_USB_GetDescriptor(const uint16_t wValue,
|
||||
const uint16_t wIndex,
|
||||
const void** const DescriptorAddress)
|
||||
{
|
||||
const uint8_t DescriptorType = (wValue >> 8);
|
||||
const uint8_t DescriptorNumber = (wValue & 0xFF);
|
||||
|
||||
const void* Address = NULL;
|
||||
uint16_t Size = NO_DESCRIPTOR;
|
||||
|
||||
switch (DescriptorType)
|
||||
{
|
||||
case DTYPE_Device:
|
||||
Address = &DeviceDescriptor;
|
||||
Size = sizeof(USB_Descriptor_Device_t);
|
||||
break;
|
||||
case DTYPE_Configuration:
|
||||
Address = &ConfigurationDescriptor;
|
||||
Size = sizeof(USB_Descriptor_Configuration_t);
|
||||
break;
|
||||
case DTYPE_BOS:
|
||||
Address = &BOSDescriptor;
|
||||
Size = sizeof(BOSDescriptor);
|
||||
break;
|
||||
case DTYPE_String:
|
||||
switch (DescriptorNumber)
|
||||
{
|
||||
case STRING_ID_Language:
|
||||
Address = &LanguageString;
|
||||
Size = pgm_read_byte(&LanguageString.Header.Size);
|
||||
break;
|
||||
case STRING_ID_Manufacturer:
|
||||
Address = &ManufacturerString;
|
||||
Size = pgm_read_byte(&ManufacturerString.Header.Size);
|
||||
break;
|
||||
case STRING_ID_Product:
|
||||
Address = &ProductString;
|
||||
Size = pgm_read_byte(&ProductString.Header.Size);
|
||||
break;
|
||||
case STRING_ID_Config:
|
||||
Address = &ConfigString;
|
||||
Size = pgm_read_byte(&ConfigString.Header.Size);
|
||||
break;
|
||||
case STRING_ID_LED:
|
||||
Address = &LEDString;
|
||||
Size = pgm_read_byte(&LEDString.Header.Size);
|
||||
break;
|
||||
case STRING_ID_KNOB:
|
||||
Address = &KnobString;
|
||||
Size = pgm_read_byte(&KnobString.Header.Size);
|
||||
break;
|
||||
default:
|
||||
if(DescriptorNumber >= STRING_ID_LED_INDIV) {
|
||||
Address = &(LEDString_indiv[STRING_ID_LED_INDIV - DescriptorNumber]);
|
||||
Size = pgm_read_byte(&LEDString_indiv[STRING_ID_LED_INDIV - DescriptorNumber].Header.Size);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case HID_DTYPE_HID:
|
||||
Size = sizeof(USB_HID_Descriptor_HID_t);
|
||||
switch (wIndex) {
|
||||
case INTERFACE_ID_Keyboard:
|
||||
Address = &ConfigurationDescriptor.HID1_KeyboardHID;
|
||||
break;
|
||||
case INTERFACE_ID_Mouse:
|
||||
Address = &ConfigurationDescriptor.HID2_MouseHID;
|
||||
break;
|
||||
case INTERFACE_ID_Generic:
|
||||
Address = &ConfigurationDescriptor.HID3_VendorHID;
|
||||
break;
|
||||
case INTERFACE_ID_LED:
|
||||
Address = &ConfigurationDescriptor.HID4_LEDHID;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case HID_DTYPE_Report:
|
||||
switch (wIndex) {
|
||||
case INTERFACE_ID_Keyboard:
|
||||
Address = &KeyboardReport;
|
||||
Size = sizeof(KeyboardReport);
|
||||
break;
|
||||
case INTERFACE_ID_Mouse:
|
||||
Address = &MouseReport;
|
||||
Size = sizeof(MouseReport);
|
||||
break;
|
||||
case INTERFACE_ID_Generic:
|
||||
Address = &GenericReport;
|
||||
Size = sizeof(GenericReport);
|
||||
break;
|
||||
case INTERFACE_ID_LED:
|
||||
Address = &LEDReport;
|
||||
Size = sizeof(LEDReport);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
*DescriptorAddress = Address;
|
||||
return Size;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,129 @@
|
||||
/*
|
||||
LUFA Library
|
||||
Copyright (C) Dean Camera, 2014.
|
||||
|
||||
dean [at] fourwalledcubicle [dot] com
|
||||
www.lufa-lib.org
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright 2014 Dean Camera (dean [at] fourwalledcubicle [dot] com)
|
||||
|
||||
Permission to use, copy, modify, distribute, and sell this
|
||||
software and its documentation for any purpose is hereby granted
|
||||
without fee, provided that the above copyright notice appear in
|
||||
all copies and that both that the copyright notice and this
|
||||
permission notice and warranty disclaimer appear in supporting
|
||||
documentation, and that the name of the author not be used in
|
||||
advertising or publicity pertaining to distribution of the
|
||||
software without specific, written prior permission.
|
||||
|
||||
The author disclaims all warranties with regard to this
|
||||
software, including all implied warranties of merchantability
|
||||
and fitness. In no event shall the author be liable for any
|
||||
special, indirect or consequential damages or any damages
|
||||
whatsoever resulting from loss of use, data or profits, whether
|
||||
in an action of contract, negligence or other tortious action,
|
||||
arising out of or in connection with the use or performance of
|
||||
this software.
|
||||
*/
|
||||
|
||||
/** \file
|
||||
*
|
||||
* Header file for Descriptors.c.
|
||||
*/
|
||||
|
||||
#ifndef _DESCRIPTORS_H_
|
||||
#define _DESCRIPTORS_H_
|
||||
|
||||
/* Includes: */
|
||||
#include <avr/pgmspace.h>
|
||||
|
||||
#include <LUFA/Drivers/USB/USB.h>
|
||||
|
||||
#include "Config.h"
|
||||
#include "LED.h"
|
||||
|
||||
/* Type Defines: */
|
||||
/** Type define for the device configuration descriptor structure. This must be defined in the
|
||||
* application code, as the configuration descriptor contains several sub-descriptors which
|
||||
* vary between devices, and which describe the device's usage to the host.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
USB_Descriptor_Configuration_Header_t Config;
|
||||
|
||||
// Keyboard HID Interface
|
||||
USB_Descriptor_Interface_t HID1_Interface;
|
||||
USB_HID_Descriptor_HID_t HID1_KeyboardHID;
|
||||
USB_Descriptor_Endpoint_t HID1_ReportINEndpoint;
|
||||
|
||||
// Mouse HID Interface
|
||||
USB_Descriptor_Interface_t HID2_MouseInterface;
|
||||
USB_HID_Descriptor_HID_t HID2_MouseHID;
|
||||
USB_Descriptor_Endpoint_t HID2_ReportINEndpoint;
|
||||
|
||||
// Generic HID Interface for configuration
|
||||
USB_Descriptor_Interface_t HID3_Interface;
|
||||
USB_HID_Descriptor_HID_t HID3_VendorHID;
|
||||
USB_Descriptor_Endpoint_t HID3_ReportINEndpoint;
|
||||
|
||||
// LED HID Interface for pretty lights
|
||||
USB_Descriptor_Interface_t HID4_Interface;
|
||||
USB_HID_Descriptor_HID_t HID4_LEDHID;
|
||||
USB_Descriptor_Endpoint_t HID4_ReportINEndpoint;
|
||||
} USB_Descriptor_Configuration_t;
|
||||
|
||||
/** Enum for the device interface descriptor IDs within the device.
|
||||
*/
|
||||
enum InterfaceDescriptors_t
|
||||
{
|
||||
INTERFACE_ID_Keyboard = 0, /**< Keyboard interface descriptor ID */
|
||||
INTERFACE_ID_Mouse = 1, /**< Mouse interface descriptor ID */
|
||||
INTERFACE_ID_Generic = 2, /**< Generic interface descriptor ID */
|
||||
INTERFACE_ID_LED = 3 /**< LED interface descriptor ID */
|
||||
};
|
||||
|
||||
/** Enum for the device string descriptor IDs within the device. Each string descriptor should
|
||||
*/
|
||||
enum StringDescriptors_t
|
||||
{
|
||||
STRING_ID_Language = 0, /**< Supported Languages string descriptor ID (must be zero) */
|
||||
STRING_ID_Manufacturer = 1, /**< Manufacturer string ID */
|
||||
STRING_ID_Product = 2, /**< Product string ID */
|
||||
STRING_ID_Config = 3, /**< Config string ID */
|
||||
STRING_ID_KNOB = 4,
|
||||
STRING_ID_LED = 5, /**< LED string ID */
|
||||
STRING_ID_LED_INDIV = 6,
|
||||
};
|
||||
|
||||
enum URLDescriptors_t
|
||||
{
|
||||
URL_ID_Localhost = 1,
|
||||
URL_ID_Config = 2,
|
||||
};
|
||||
|
||||
/* Macros: */
|
||||
#define KEYBOARD_EPADDR (ENDPOINT_DIR_IN | 1)
|
||||
|
||||
#define MOUSE_IN_EPADDR (ENDPOINT_DIR_IN | 2)
|
||||
|
||||
#define GENERIC_EPADDR (ENDPOINT_DIR_IN | 3)
|
||||
|
||||
#define LED_EPADDR (ENDPOINT_DIR_IN | 4)
|
||||
|
||||
#define KEYBOARD_EPSIZE SWITCH_COUNT + 2
|
||||
#define MOUSE_EPSIZE 8
|
||||
#define GENERIC_EPSIZE CONFIG_BYTES
|
||||
#define LED_EPSIZE LED_TOTAL_COUNT
|
||||
|
||||
/* Function Prototypes: */
|
||||
uint16_t CALLBACK_USB_GetDescriptor(const uint16_t wValue,
|
||||
const uint16_t wIndex,
|
||||
const void** const DescriptorAddress)
|
||||
ATTR_WARN_UNUSED_RESULT ATTR_NON_NULL_PTR_ARG(3);
|
||||
|
||||
void USB_Process_BOS(void);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
#include "Encoder.h"
|
||||
|
||||
// SDVX Controller - PD0-3
|
||||
#define ENCODER_COUNT 2
|
||||
|
||||
#define ENCODER_PORT PORTD
|
||||
#define ENCODER_PIN PIND
|
||||
#define ENCODER_DDR DDRD
|
||||
|
||||
#define GET_ENCODER_0() (ENCODER_PIN & 0b11)
|
||||
#define GET_ENCODER_1() ((ENCODER_PIN >> 2) & 0b11)
|
||||
|
||||
typedef struct {
|
||||
int8_t position;
|
||||
uint8_t state;
|
||||
} encoder_t;
|
||||
|
||||
static volatile encoder_t encoders[ENCODER_COUNT] = {};
|
||||
|
||||
void encoder_init(void) {
|
||||
// inputs
|
||||
ENCODER_DDR &= ~0x0F;
|
||||
// pullups
|
||||
ENCODER_PORT |= 0x0F;
|
||||
|
||||
encoders[0].state = GET_ENCODER_0();
|
||||
encoders[1].state = GET_ENCODER_1();
|
||||
|
||||
// Edge interrupts on all INT pins
|
||||
EICRA = _BV(ISC30) | _BV(ISC20) | _BV(ISC10) | _BV(ISC00);
|
||||
// Enable the interrupts
|
||||
EIMSK = _BV(INT3) | _BV(INT2) | _BV(INT1) | _BV(INT0);
|
||||
// Clear interrupt flags
|
||||
EIFR = _BV(INTF3) | _BV(INTF2) | _BV(INTF1) | _BV(INTF0);
|
||||
}
|
||||
|
||||
int8_t encoder_get(uint8_t num) {
|
||||
return encoders[num].position;
|
||||
}
|
||||
|
||||
void encoder_set(uint8_t num, int8_t val) {
|
||||
encoders[num].position = val;
|
||||
}
|
||||
|
||||
// Adapted from the wonderful Encoder.h by PJRC
|
||||
void update(uint8_t num, uint8_t newState) {
|
||||
int8_t position = encoders[num].position;
|
||||
uint8_t state = encoders[num].state | (newState << 2);
|
||||
encoders[num].state = newState;
|
||||
switch (state) {
|
||||
case 1: case 7: case 8: case 14:
|
||||
if(position < 127)
|
||||
encoders[num].position++;
|
||||
return;
|
||||
case 2: case 4: case 11: case 13:
|
||||
if(position > -128)
|
||||
encoders[num].position--;
|
||||
return;
|
||||
case 3: case 12:
|
||||
if(position < 125)
|
||||
encoders[num].position += 2;
|
||||
return;
|
||||
case 6: case 9:
|
||||
if(position > -126)
|
||||
encoders[num].position -= 2;
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
ISR(INT0_vect) { update(0, GET_ENCODER_0()); }
|
||||
ISR(INT1_vect) { update(0, GET_ENCODER_0()); }
|
||||
ISR(INT2_vect) { update(1, GET_ENCODER_1()); }
|
||||
ISR(INT3_vect) { update(1, GET_ENCODER_1()); }
|
||||
@@ -0,0 +1,12 @@
|
||||
#ifndef Encoder_h_
|
||||
#define Encoder_h_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <avr/io.h>
|
||||
#include <avr/interrupt.h>
|
||||
|
||||
void encoder_init(void);
|
||||
int8_t encoder_get(uint8_t num);
|
||||
void encoder_set(uint8_t num, int8_t val);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,29 @@
|
||||
BRIGHTNESS_LEVELS = 64
|
||||
STAGES = 3
|
||||
LEDS = 8
|
||||
RING = [0,2,4,6,7,5,3,1]
|
||||
|
||||
TOTAL = STAGES * BRIGHTNESS_LEVELS
|
||||
INTERVAL = TOTAL / LEDS
|
||||
|
||||
RISE = range(0,BRIGHTNESS_LEVELS)
|
||||
FALL = range(BRIGHTNESS_LEVELS-1,-1,-1)
|
||||
OFF = [0]*BRIGHTNESS_LEVELS
|
||||
|
||||
R = FALL + OFF + RISE
|
||||
Rdir = [0, 0, 1]
|
||||
G = RISE + FALL + OFF
|
||||
Gdir = [1, 0, 0]
|
||||
B = OFF + RISE + FALL
|
||||
Bdir = [0, 1, 0]
|
||||
|
||||
print "// Generated by FollowerGen.py"
|
||||
print "static const uint8_t followStart[][4] = {"
|
||||
for i in range(LEDS):
|
||||
# map to the different order in the board
|
||||
actualIndex = RING.index(i)
|
||||
offset = INTERVAL * actualIndex
|
||||
dirOffset = offset / BRIGHTNESS_LEVELS
|
||||
dir = Rdir[dirOffset] | Gdir[dirOffset] << 1 | Bdir[dirOffset] << 2
|
||||
print "\t{%d, %d, %d, %s}," % (R[offset], G[offset], B[offset],'{:#05b}'.format(dir))
|
||||
print "};"
|
||||
@@ -0,0 +1,141 @@
|
||||
#include "LED.h"
|
||||
|
||||
#define GND_COUNT 4
|
||||
// RGB * 2
|
||||
#define LED_PINS 6
|
||||
|
||||
// LED gnd 0-3 are on PC7-4
|
||||
#define GND_PORT PORTC
|
||||
#define GND_DDR DDRC
|
||||
#define GND_MASK 0xF0
|
||||
#define GND_OFFSET 4 // in bits
|
||||
|
||||
// LED power BGR BGR PB2-7
|
||||
#define LED_PORT PORTB
|
||||
#define LED_DDR DDRB
|
||||
#define LED_MASK (0b111111 << 2)
|
||||
|
||||
#define UPDATE_HZ 100
|
||||
// prescaler is the div8
|
||||
#define TIMER_COMPARE ((F_CPU / 8 / UPDATE_HZ / GND_COUNT / BRIGHTNESS_LEVELS)-1)
|
||||
#if TIMER_COMPARE > 255
|
||||
#error timer compare too large for timer register
|
||||
#endif
|
||||
|
||||
#define R 2
|
||||
#define G 1
|
||||
#define B 0
|
||||
|
||||
void led_init() {
|
||||
// all GNDs low level for high impedence or gnd
|
||||
GND_PORT &= ~GND_MASK;
|
||||
// all GNDs input
|
||||
GND_DDR &= ~GND_MASK;
|
||||
|
||||
// all LEDs off
|
||||
LED_PORT &= ~LED_MASK;
|
||||
// all LEDs output
|
||||
LED_DDR |= LED_MASK;
|
||||
|
||||
memset((uint8_t*)leds, 0, LED_PHYSICAL_COUNT);
|
||||
|
||||
// 64 light levels * 60Hz update * 4 different GND pins = 15360Hz
|
||||
// 520 clock cycles for our interrupt handler
|
||||
// CTC mode
|
||||
TCCR0A = _BV(WGM01);
|
||||
// clk/8 prescaler
|
||||
TCCR0B = _BV(CS01);
|
||||
OCR0A = TIMER_COMPARE;
|
||||
// Enable interrupt on OCR0A
|
||||
TIMSK0 = _BV(OCIE0A);
|
||||
// Clear interrupt
|
||||
TIFR0 = _BV(OCF0A);
|
||||
}
|
||||
|
||||
void led_set(uint8_t num, uint8_t r, uint8_t g, uint8_t b) {
|
||||
uint8_t offset = num * 3;
|
||||
leds[offset+R] = r;
|
||||
leds[offset+G] = g;
|
||||
leds[offset+B] = b;
|
||||
}
|
||||
|
||||
void led_set_max(uint8_t num, uint8_t r, uint8_t g, uint8_t b) {
|
||||
uint8_t offset = num * 3;
|
||||
if(r > leds[offset+R])
|
||||
leds[offset+R] = r;
|
||||
if(g > leds[offset+G])
|
||||
leds[offset+G] = g;
|
||||
if(b > leds[offset+B])
|
||||
leds[offset+B] = b;
|
||||
}
|
||||
|
||||
void led_set_all(uint8_t r, uint8_t g, uint8_t b) {
|
||||
for(uint8_t i = 0; i < LED_COUNT; i++) {
|
||||
led_set(i, r, g, b);
|
||||
}
|
||||
}
|
||||
|
||||
void led_set_indiv(uint8_t num, uint8_t val) {
|
||||
leds[num] = val;
|
||||
}
|
||||
|
||||
/* Straight voodoo magic, consult the Inline Assembler Cookbook
|
||||
Equivalent to:
|
||||
if(*led++ > brightness)
|
||||
out |= _BV(outPin)
|
||||
*/
|
||||
#define LED_PIN_SET(led, outPin) \
|
||||
__asm__ volatile( \
|
||||
"ld __tmp_reg__, %a["#led"]+ \n\t\
|
||||
cp %[bright], __tmp_reg__ \n\t\
|
||||
brcc skip%= \n\t\
|
||||
ori %[out], (1 << "#outPin") \n\t\
|
||||
skip%=:" \
|
||||
: [out] "=r" (out), "=z" (led) /* outputs */ \
|
||||
: "r" (out), [led] "z" (led), [bright] "r" (brightness) /* inputs */ )
|
||||
|
||||
// This function once took about 279 clock cycles.
|
||||
// Optimised GND accesses got it to 157
|
||||
// Optimised variables to static, got it to 100
|
||||
// Made LED setter assembly, got it to 90
|
||||
ISR(TIMER0_COMPA_vect) {
|
||||
/* Why are these static here instead of at the top of file?
|
||||
The compiler won't optimise 2 consecutive operations to use a register,
|
||||
and instead will perform a costly lds-sts every time. Making them
|
||||
static here will cache them in a local register.
|
||||
*/
|
||||
// Because we roll over on each loop and want to start at 0 this starts at max
|
||||
static uint8_t currentGnd = GND_COUNT - 1;
|
||||
// This saves us doing a costly dynamic _BV()
|
||||
static uint8_t currentGndMask = 0;
|
||||
static uint8_t brightness = BRIGHTNESS_LEVELS - 1;
|
||||
static volatile uint8_t* offset = &leds[0];
|
||||
|
||||
uint8_t out = 0;
|
||||
|
||||
currentGnd++;
|
||||
currentGndMask >>= 1;
|
||||
if(currentGnd >= GND_COUNT) {
|
||||
currentGnd = 0;
|
||||
// Because we work backwards start at the high end and shift down
|
||||
currentGndMask = _BV(7);
|
||||
offset = &leds[0];
|
||||
++brightness;
|
||||
brightness %= BRIGHTNESS_LEVELS;
|
||||
}
|
||||
|
||||
// Faster than loops
|
||||
// NOTE: ASM MACRO INCREMENTS OFFSET
|
||||
LED_PIN_SET(offset, 2);
|
||||
LED_PIN_SET(offset, 3);
|
||||
LED_PIN_SET(offset, 4);
|
||||
LED_PIN_SET(offset, 5);
|
||||
LED_PIN_SET(offset, 6);
|
||||
LED_PIN_SET(offset, 7);
|
||||
|
||||
// Turn off before switch
|
||||
LED_PORT &= ~LED_MASK;
|
||||
// Enable new ground
|
||||
GND_DDR = (GND_DDR & ~GND_MASK) | currentGndMask;
|
||||
LED_PORT |= out;
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
#ifndef LED_h_
|
||||
#define LED_h_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <avr/io.h>
|
||||
#include <avr/interrupt.h>
|
||||
#include <avr/pgmspace.h>
|
||||
#include <string.h>
|
||||
|
||||
#define LED_COUNT 8
|
||||
#define LED_PHYSICAL_COUNT (LED_COUNT*3)
|
||||
// BT + FX
|
||||
#define LED_VIRTUAL_COUNT 6
|
||||
#define LED_TOTAL_COUNT (LED_PHYSICAL_COUNT + LED_VIRTUAL_COUNT)
|
||||
#define BRIGHTNESS_LEVELS 64
|
||||
|
||||
// Arranged left to right, top to bottom
|
||||
// LED order is BGR...BGR
|
||||
volatile uint8_t leds[LED_PHYSICAL_COUNT];
|
||||
|
||||
// Maps BT/FX keys to their associated LED
|
||||
// Order is BT-1-4, FX-L, FX-R
|
||||
static const uint8_t ledMap[] = {2, 0, 1, 3, 6, 7};
|
||||
|
||||
// map LEDs to run in a circle
|
||||
static const uint8_t ledCircleMap[] = {0, 2, 4, 6, 7, 5, 3, 1};
|
||||
|
||||
void led_init(void);
|
||||
void led_set(uint8_t num, uint8_t r, uint8_t g, uint8_t b);
|
||||
void led_set_max(uint8_t num, uint8_t r, uint8_t g, uint8_t b);
|
||||
void led_set_all(uint8_t r, uint8_t g, uint8_t b);
|
||||
void led_set_indiv(uint8_t num, uint8_t val);
|
||||
|
||||
PROGMEM const static uint8_t ledLogCurve[] = {
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 1, 1, 1, 1, 2, 2,
|
||||
3, 3, 4, 5, 6, 7, 8, 9,
|
||||
11, 13, 15, 17, 20, 23, 25, 28,
|
||||
31, 34, 37, 40, 43, 45, 48, 50,
|
||||
52, 53, 55, 56, 57, 58, 59, 60,
|
||||
60, 61, 61, 61, 62, 62, 62, 62,
|
||||
63, 63, 63, 63, 63, 63, 63, 63, 63};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,177 @@
|
||||
#include "LEDPatterns.h"
|
||||
#include <avr/pgmspace.h>
|
||||
|
||||
static enum LEDMode animMode = NONE;
|
||||
static uint8_t frameCounter = 0;
|
||||
|
||||
// various things for the different modes
|
||||
static int8_t flash;
|
||||
static int8_t flashDirection;
|
||||
|
||||
typedef struct {
|
||||
uint8_t value[3];
|
||||
uint8_t direction;
|
||||
} RGBFader;
|
||||
|
||||
static RGBFader followers[LED_COUNT];
|
||||
|
||||
typedef struct {
|
||||
const uint8_t rgb[3];
|
||||
uint8_t leds[2];
|
||||
uint8_t levels[2];
|
||||
} KnobLights;
|
||||
|
||||
static KnobLights knobs[2] = {
|
||||
// Aqua, top left LEDs
|
||||
{{0,1,1}, {0,1}, {BRIGHTNESS_LEVELS-1, 0}},
|
||||
// Pink, top right LEDs
|
||||
{{1,0,1}, {6,7}, {0, BRIGHTNESS_LEVELS-1}}
|
||||
};
|
||||
|
||||
// TODO DEBUG DELETE
|
||||
uint8_t debugG = 0, debugB = 0;
|
||||
|
||||
// Called every 1ms
|
||||
void led_frame(void) {
|
||||
if(++frameCounter < LED_MS_PER_FRAME) {
|
||||
return;
|
||||
}
|
||||
|
||||
frameCounter = 0;
|
||||
|
||||
switch(animMode) {
|
||||
case INIT_FLASH:
|
||||
if(flashDirection) {
|
||||
flash+=3;
|
||||
if(flash >= BRIGHTNESS_LEVELS - 1) {
|
||||
flash = BRIGHTNESS_LEVELS - 1;
|
||||
flashDirection = 0;
|
||||
}
|
||||
} else {
|
||||
flash-=3;
|
||||
if(flash <= 0) {
|
||||
led_anim_follower();
|
||||
flash = 0;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t bright = pgm_read_byte(&ledLogCurve[flash]);
|
||||
led_set_all(bright, bright/2, 0);
|
||||
break;
|
||||
case FOLLOWER:
|
||||
for(uint8_t led = 0; led < LED_COUNT; led++) {
|
||||
uint8_t followDir;
|
||||
RGBFader* follow;
|
||||
|
||||
follow = followers + led;
|
||||
followDir = follow->direction;
|
||||
for(uint8_t i = 0; i < 3; i++) {
|
||||
if(followDir & 1) {
|
||||
if(follow->value[i]++ >= BRIGHTNESS_LEVELS - 1) {
|
||||
follow->value[i] = BRIGHTNESS_LEVELS - 1;
|
||||
follow->direction <<= 1;
|
||||
if(follow->direction == 0b1000) {
|
||||
follow->direction = 0b001;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if(follow->value[i] > 0) {
|
||||
follow->value[i]--;
|
||||
}
|
||||
}
|
||||
followDir >>= 1;
|
||||
}
|
||||
led_set(led, follow->value[0], follow->value[1], follow->value[2]);
|
||||
}
|
||||
break;
|
||||
case BREATHE:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
//led_set_all(64,debugG,debugB);
|
||||
// Knob lights, what shall I do with you?
|
||||
/*for(uint8_t i = 0; i < 2; i++) {
|
||||
for(uint8_t led = 0; led < 2; led++) {
|
||||
uint8_t r = knobs[i].levels[led] * knobs[i].rgb[0];
|
||||
uint8_t g = knobs[i].levels[led] * knobs[i].rgb[1];
|
||||
uint8_t b = knobs[i].levels[led] * knobs[i].rgb[2];
|
||||
led_set_max(ledCircleMap[knobs[i].leds[led]], r, g, b);
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
void led_knob_indiv(KnobLights* knob, int8_t value) {
|
||||
/* This is annoying and repetitive but don't think there's a nicer way */
|
||||
if(value > 0) {
|
||||
knob->levels[0] += value;
|
||||
if(value > knob->levels[1]) {
|
||||
// Not properly doing rollover since the knob doesn't spin that fast
|
||||
knob->levels[1] = 0;
|
||||
} else {
|
||||
knob->levels[1] -= value;
|
||||
}
|
||||
|
||||
if(knob->levels[0] > BRIGHTNESS_LEVELS) {
|
||||
knob->levels[0] = 0;
|
||||
knob->levels[1] = BRIGHTNESS_LEVELS - 1;
|
||||
knob->leds[1] = knob->leds[0];
|
||||
if(knob->leds[0] > 0) {
|
||||
knob->leds[0]--;
|
||||
} else {
|
||||
knob->leds[0] = LED_COUNT - 1;
|
||||
}
|
||||
}
|
||||
} else if(value < 0) {
|
||||
if(-value > knob->levels[0]) {
|
||||
knob->levels[0] = 0;
|
||||
} else {
|
||||
knob->levels[0] += value;
|
||||
}
|
||||
knob->levels[1] -= value;
|
||||
|
||||
if(knob->levels[1] > BRIGHTNESS_LEVELS) {
|
||||
knob->levels[0] = BRIGHTNESS_LEVELS - 1;
|
||||
knob->levels[1] = 0;
|
||||
knob->leds[0] = knob->leds[1];
|
||||
knob->leds[1]++;
|
||||
knob->leds[1] %= LED_COUNT;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void led_knobs_update(int8_t left, int8_t right) {
|
||||
//led_knob_indiv(&knobs[0], left*2);
|
||||
//led_knob_indiv(&knobs[1], right*2);
|
||||
debugG += left;
|
||||
debugB += right;
|
||||
}
|
||||
|
||||
void led_anim_flash(void) {
|
||||
animMode = INIT_FLASH;
|
||||
// starting at 2 stops us getting a frame of red
|
||||
flash = 2;
|
||||
flashDirection = 1;
|
||||
}
|
||||
|
||||
void led_anim_follower(void) {
|
||||
// Generated by FollowerGen.py
|
||||
static uint8_t PROGMEM followStart[][4] = {
|
||||
{63, 0, 0, 0b010},
|
||||
{40, 0, 23, 0b001},
|
||||
{39, 24, 0, 0b010},
|
||||
{16, 0, 47, 0b001},
|
||||
{15, 48, 0, 0b010},
|
||||
{0, 7, 56, 0b100},
|
||||
{0, 55, 8, 0b100},
|
||||
{0, 31, 32, 0b100},
|
||||
};
|
||||
animMode = FOLLOWER;
|
||||
|
||||
for(uint8_t i = 0; i < LED_COUNT; i++) {
|
||||
for(uint8_t j = 0; j < 3; j++) {
|
||||
followers[i].value[j] = pgm_read_byte(&followStart[i][j]);
|
||||
}
|
||||
followers[i].direction = pgm_read_byte(&followStart[i][3]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
#ifndef _LED_PATTERNS_H
|
||||
#define _LED_PATTERNS_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include "LED.h"
|
||||
|
||||
#define LED_FRAMERATE 30
|
||||
#define LED_MS_PER_FRAME (1000 / LED_FRAMERATE)
|
||||
|
||||
enum LEDMode {
|
||||
NONE = 0,
|
||||
INIT_FLASH,
|
||||
FOLLOWER,
|
||||
BREATHE,
|
||||
};
|
||||
|
||||
void led_frame(void);
|
||||
void led_anim_flash(void);
|
||||
void led_anim_follower(void);
|
||||
void led_knobs_update(int8_t left, int8_t right);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,69 @@
|
||||
#include <Macro.h>
|
||||
|
||||
// in ms
|
||||
#define KEY_DELAY 30
|
||||
#define LONGPRESS_DELAY 500
|
||||
|
||||
static uint8_t countdown = 0;
|
||||
static uint16_t longpress = 0;
|
||||
static uint8_t *data;
|
||||
static uint8_t dataLen = 0;
|
||||
static uint8_t position = 0;
|
||||
static uint8_t liftoff = 0;
|
||||
|
||||
uint8_t macro_make_report(uint8_t* key) {
|
||||
if(countdown) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(liftoff) {
|
||||
liftoff = 0;
|
||||
countdown = KEY_DELAY;
|
||||
*key = 0;
|
||||
return 1;
|
||||
} else {
|
||||
if(position >= dataLen) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
*key = data[position];
|
||||
countdown = KEY_DELAY;
|
||||
|
||||
position++;
|
||||
liftoff = 1;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
void macro_fire_click(void) {
|
||||
data = &sdvxConfig.macroClick;
|
||||
dataLen = 1;
|
||||
position = 0;
|
||||
}
|
||||
|
||||
void macro_fire_pin(void) {
|
||||
data = sdvxConfig.macroPin;
|
||||
dataLen = 4;
|
||||
position = 0;
|
||||
}
|
||||
|
||||
void macro_on_frame(switch_t* macro) {
|
||||
if(countdown) {
|
||||
countdown--;
|
||||
}
|
||||
|
||||
// Rising edge
|
||||
if(macro->state && !macro->lastReport) {
|
||||
longpress = 0;
|
||||
// held high and not triggered longpress yet
|
||||
} else if(macro->state && macro->lastReport && longpress < LONGPRESS_DELAY) {
|
||||
longpress++;
|
||||
if(longpress >= LONGPRESS_DELAY) {
|
||||
macro_fire_pin();
|
||||
}
|
||||
// falling edge before longpress time
|
||||
} else if(!macro->state && macro->lastReport && longpress < LONGPRESS_DELAY) {
|
||||
macro_fire_click();
|
||||
}
|
||||
macro->lastReport = macro->state;
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
#ifndef MACRO_H_
|
||||
#define MACRO_H_
|
||||
|
||||
#include "Config.h"
|
||||
#include "asciihid.h"
|
||||
#include "PocketVoltex.h"
|
||||
|
||||
extern sdvx_config_t sdvxConfig;
|
||||
|
||||
uint8_t macro_make_report(uint8_t* key);
|
||||
void macro_on_frame(switch_t* macro);
|
||||
void macro_fire_click(void);
|
||||
void macro_fire_pin(void);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,391 @@
|
||||
#include "PocketVoltex.h"
|
||||
#include "Config.h"
|
||||
#include "Encoder.h"
|
||||
#include "LED.h"
|
||||
#include "LEDPatterns.h"
|
||||
#include "Macro.h"
|
||||
|
||||
#define READ_SWITCH(x) (!(*pins[switches[x].switchPort] & _BV(switches[x].switchPin)))
|
||||
#define MAGIC_BOOT_KEY 0xDEADBE7A
|
||||
// offset * word size
|
||||
#define BOOTLOADER_START_ADDRESS (0x1c00 * 2)
|
||||
|
||||
// How long to wait before moving to internal lighting
|
||||
#define HID_LED_TIMEOUT 5000
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint8_t Modifier; // Keyboard modifier byte indicating pressed modifier keys (\c HID_KEYBOARD_MODIFER_* masks)
|
||||
uint8_t Reserved; // Reserved for OEM use, always set to 0.
|
||||
uint8_t KeyCode[SWITCH_COUNT]; // Length determined by the number of keys that can be reported
|
||||
} Keyboard_Report_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint8_t mainLights[LED_PHYSICAL_COUNT];
|
||||
uint8_t btFx[6];
|
||||
} LED_Report_t;
|
||||
|
||||
/** Buffer to hold the previously generated Keyboard HID report, for comparison purposes inside the HID class driver. */
|
||||
static uint8_t PrevKeyboardHIDReportBuffer[sizeof(Keyboard_Report_t)];
|
||||
static uint8_t PrevMouseHIDReportBuffer[sizeof(USB_MouseReport_Data_t)];
|
||||
static uint8_t PrevGenericHIDReportBuffer[sizeof(sdvx_config_t)];
|
||||
static uint8_t PrevLEDHIDReportBuffer[sizeof(LED_Report_t)];
|
||||
|
||||
/** LUFA HID Class driver interface configuration and state information. This structure is
|
||||
* passed to all HID Class driver functions, so that multiple instances of the same class
|
||||
* within a device can be differentiated from one another.
|
||||
*/
|
||||
USB_ClassInfo_HID_Device_t Keyboard_HID_Interface =
|
||||
{
|
||||
.Config =
|
||||
{
|
||||
.InterfaceNumber = INTERFACE_ID_Keyboard,
|
||||
.ReportINEndpoint =
|
||||
{
|
||||
.Address = KEYBOARD_EPADDR,
|
||||
.Size = KEYBOARD_EPSIZE,
|
||||
.Banks = 1,
|
||||
},
|
||||
.PrevReportINBuffer = PrevKeyboardHIDReportBuffer,
|
||||
.PrevReportINBufferSize = sizeof(PrevKeyboardHIDReportBuffer),
|
||||
},
|
||||
};
|
||||
|
||||
/** LUFA HID Class driver interface configuration and state information. This structure is
|
||||
* passed to all HID Class driver functions, so that multiple instances of the same class
|
||||
* within a device can be differentiated from one another. This is for the mouse HID
|
||||
* interface within the device.
|
||||
*/
|
||||
USB_ClassInfo_HID_Device_t Mouse_HID_Interface =
|
||||
{
|
||||
.Config =
|
||||
{
|
||||
.InterfaceNumber = INTERFACE_ID_Mouse,
|
||||
.ReportINEndpoint =
|
||||
{
|
||||
.Address = MOUSE_IN_EPADDR,
|
||||
.Size = MOUSE_EPSIZE,
|
||||
.Banks = 1,
|
||||
},
|
||||
.PrevReportINBuffer = PrevMouseHIDReportBuffer,
|
||||
.PrevReportINBufferSize = sizeof(PrevMouseHIDReportBuffer),
|
||||
},
|
||||
};
|
||||
|
||||
USB_ClassInfo_HID_Device_t Generic_HID_Interface =
|
||||
{
|
||||
.Config =
|
||||
{
|
||||
.InterfaceNumber = INTERFACE_ID_Generic,
|
||||
.ReportINEndpoint =
|
||||
{
|
||||
.Address = GENERIC_EPADDR,
|
||||
.Size = GENERIC_EPSIZE,
|
||||
.Banks = 1,
|
||||
},
|
||||
.PrevReportINBuffer = PrevGenericHIDReportBuffer,
|
||||
.PrevReportINBufferSize = sizeof(PrevGenericHIDReportBuffer),
|
||||
},
|
||||
};
|
||||
|
||||
USB_ClassInfo_HID_Device_t LED_HID_Interface =
|
||||
{
|
||||
.Config =
|
||||
{
|
||||
.InterfaceNumber = INTERFACE_ID_LED,
|
||||
.ReportINEndpoint =
|
||||
{
|
||||
.Address = LED_EPADDR,
|
||||
.Size = LED_EPSIZE,
|
||||
.Banks = 1,
|
||||
},
|
||||
.PrevReportINBuffer = PrevLEDHIDReportBuffer,
|
||||
.PrevReportINBufferSize = sizeof(PrevLEDHIDReportBuffer),
|
||||
},
|
||||
};
|
||||
|
||||
static volatile uint8_t *ports[] = {&PORTB, &PORTC, &PORTD};
|
||||
static volatile uint8_t *pins[] = {&PINB, &PINC, &PIND};
|
||||
static volatile uint8_t *ddrs[] = {&DDRB, &DDRC, &DDRD};
|
||||
|
||||
static switch_t switches[SWITCH_COUNT] = {
|
||||
{B, 1}, // A
|
||||
{D, 7}, // B
|
||||
{D, 5}, // C
|
||||
{D, 4}, // D
|
||||
{B, 0}, // FX L
|
||||
{D, 6}, // FX R
|
||||
{C, 2}, // START
|
||||
{C, 1} // Macro key
|
||||
};
|
||||
static uint8_t switchesChanged = 1;
|
||||
|
||||
// Set to max already so we have our init flash
|
||||
static uint16_t hidTimeout = HID_LED_TIMEOUT;
|
||||
|
||||
uint32_t Boot_Key ATTR_NO_INIT;
|
||||
|
||||
void Bootloader_Jump_Check(void) ATTR_INIT_SECTION(3);
|
||||
void Bootloader_Jump_Check(void)
|
||||
{
|
||||
// If the reset source was the bootloader and the key is correct, clear it and jump to the bootloader
|
||||
if ((MCUSR & (1 << WDRF)) && (Boot_Key == MAGIC_BOOT_KEY))
|
||||
{
|
||||
Boot_Key = 0;
|
||||
((void (*)(void))BOOTLOADER_START_ADDRESS)();
|
||||
}
|
||||
}
|
||||
|
||||
void RebootToBootloader(void) {
|
||||
// With this uncommented, reboot fails. Odd.
|
||||
//USB_Disable();
|
||||
cli();
|
||||
|
||||
// Back to the bootloader
|
||||
Boot_Key = MAGIC_BOOT_KEY;
|
||||
wdt_enable(WDTO_250MS);
|
||||
while(1);
|
||||
}
|
||||
|
||||
void update_switches(void) {
|
||||
uint8_t i, newState;
|
||||
|
||||
for(i = 0; i < SWITCH_COUNT; i++) {
|
||||
newState = READ_SWITCH(i);
|
||||
if(!switches[i].debounce && newState != switches[i].lastReport) {
|
||||
switches[i].state = newState;
|
||||
switches[i].debounce = sdvxConfig.debounce;
|
||||
switchesChanged = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
GlobalInterruptDisable();
|
||||
|
||||
InitConfig();
|
||||
|
||||
SetupHardware();
|
||||
|
||||
GlobalInterruptEnable();
|
||||
|
||||
// Blink to show we're not in bootloader
|
||||
led_anim_flash();
|
||||
|
||||
for (;;)
|
||||
{
|
||||
HID_Device_USBTask(&Keyboard_HID_Interface);
|
||||
HID_Device_USBTask(&Mouse_HID_Interface);
|
||||
HID_Device_USBTask(&Generic_HID_Interface);
|
||||
HID_Device_USBTask(&LED_HID_Interface);
|
||||
USB_USBTask();
|
||||
}
|
||||
}
|
||||
|
||||
/** Configures the board hardware and chip peripherals */
|
||||
void SetupHardware()
|
||||
{
|
||||
uint8_t i;
|
||||
|
||||
/* Disable watchdog if enabled by bootloader/fuses */
|
||||
MCUSR &= ~(1 << WDRF);
|
||||
wdt_disable();
|
||||
|
||||
for(i = 0; i < SWITCH_COUNT; i++) {
|
||||
switches[i].state = 0;
|
||||
switches[i].lastReport = 0;
|
||||
switches[i].debounce = 0;
|
||||
// setup switches to be inputs
|
||||
*ddrs[switches[i].switchPort] &= ~_BV(switches[i].switchPin);
|
||||
// with internal pullups
|
||||
*ports[switches[i].switchPort] |= _BV(switches[i].switchPin);
|
||||
}
|
||||
// RESET has its own pullup
|
||||
*ports[switches[SWITCH_COUNT-1].switchPort] &= ~_BV(switches[SWITCH_COUNT-1].switchPin);
|
||||
|
||||
// RESET held while plugging in
|
||||
if(READ_SWITCH(SWITCH_COUNT-1)) {
|
||||
RebootToBootloader();
|
||||
}
|
||||
|
||||
/* Hardware Initialization */
|
||||
encoder_init();
|
||||
led_init();
|
||||
|
||||
USB_Init();
|
||||
}
|
||||
|
||||
/** HID class driver callback function for the creation of HID reports to the host.
|
||||
*
|
||||
* \param[in] HIDInterfaceInfo Pointer to the HID class interface configuration structure being referenced
|
||||
* \param[in,out] ReportID Report ID requested by the host if non-zero, otherwise callback should set to the generated report ID
|
||||
* \param[in] ReportType Type of the report to create, either HID_REPORT_ITEM_In or HID_REPORT_ITEM_Feature
|
||||
* \param[out] ReportData Pointer to a buffer where the created report should be stored
|
||||
* \param[out] ReportSize Number of bytes written in the report (or zero if no report is to be sent)
|
||||
*
|
||||
* \return Boolean \c true to force the sending of the report, \c false to let the library determine if it needs to be sent
|
||||
*/
|
||||
bool CALLBACK_HID_Device_CreateHIDReport(USB_ClassInfo_HID_Device_t* const HIDInterfaceInfo,
|
||||
uint8_t* const ReportID,
|
||||
const uint8_t ReportType,
|
||||
void* ReportData,
|
||||
uint16_t* const ReportSize)
|
||||
{
|
||||
if(ReportType != HID_REPORT_ITEM_In) {
|
||||
*ReportSize = 0;
|
||||
return false;
|
||||
}
|
||||
if (HIDInterfaceInfo == &Keyboard_HID_Interface) {
|
||||
Keyboard_Report_t* KeyboardReport = (Keyboard_Report_t*)ReportData;
|
||||
|
||||
// Only the first 4 bytes are read by bemanitools, so let's use the first
|
||||
uint8_t macroUpdated = macro_make_report(&KeyboardReport->KeyCode[0]);
|
||||
update_switches();
|
||||
|
||||
if(!switchesChanged && !macroUpdated) {
|
||||
*ReportSize = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
// NOTE: using SWITCH_COUNT-1 so we don't write the report for the macro pin
|
||||
for(uint8_t i = 0; i < SWITCH_COUNT-1; i++) {
|
||||
// i+1 to take care of the shift from above
|
||||
KeyboardReport->KeyCode[i+1] = switches[i].state ? sdvxConfig.switches[i] : 0;
|
||||
switches[i].lastReport = switches[i].state;
|
||||
// Update blinkenlights
|
||||
if(switches[i].state) {
|
||||
if(sdvxConfig.ledsOn) {
|
||||
// TODO
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*ReportSize = sizeof(Keyboard_Report_t);
|
||||
|
||||
switchesChanged = 0;
|
||||
return true;
|
||||
} else if(HIDInterfaceInfo == &Mouse_HID_Interface) {
|
||||
USB_MouseReport_Data_t* MouseReport = (USB_MouseReport_Data_t*)ReportData;
|
||||
|
||||
MouseReport->X = encoder_get(0);
|
||||
MouseReport->Y = encoder_get(1);
|
||||
|
||||
led_knobs_update(MouseReport->X, MouseReport->Y);
|
||||
|
||||
encoder_set(0, 0);
|
||||
encoder_set(1, 0);
|
||||
|
||||
*ReportSize = sizeof(USB_MouseReport_Data_t);
|
||||
return true;
|
||||
} else if(HIDInterfaceInfo == &Generic_HID_Interface) {
|
||||
uint8_t* ConfigReport = (uint8_t*)ReportData;
|
||||
memcpy(ConfigReport, &sdvxConfig, sizeof(sdvx_config_t));
|
||||
*ReportSize = CONFIG_BYTES;
|
||||
return true;
|
||||
}
|
||||
*ReportSize = 0;
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
/** HID class driver callback function for the processing of HID reports from the host.
|
||||
*
|
||||
* \param[in] HIDInterfaceInfo Pointer to the HID class interface configuration structure being referenced
|
||||
* \param[in] ReportID Report ID of the received report from the host
|
||||
* \param[in] ReportType The type of report that the host has sent, either HID_REPORT_ITEM_Out or HID_REPORT_ITEM_Feature
|
||||
* \param[in] ReportData Pointer to a buffer where the received report has been stored
|
||||
* \param[in] ReportSize Size in bytes of the received HID report
|
||||
*/
|
||||
void CALLBACK_HID_Device_ProcessHIDReport(USB_ClassInfo_HID_Device_t* const HIDInterfaceInfo,
|
||||
const uint8_t ReportID,
|
||||
const uint8_t ReportType,
|
||||
const void* ReportData,
|
||||
const uint16_t ReportSize) {
|
||||
if(HIDInterfaceInfo == &Generic_HID_Interface && ReportType == HID_REPORT_ITEM_Out) {
|
||||
sdvx_config_t* ConfigReport = (sdvx_config_t*)ReportData;
|
||||
// So we can upgrade firmware without having to hit the button
|
||||
if(ConfigReport->reboot == MAGIC_RESET_NUMBER) {
|
||||
RebootToBootloader();
|
||||
}
|
||||
SetConfig(ConfigReport);
|
||||
} else if(HIDInterfaceInfo == &LED_HID_Interface && ReportType == HID_REPORT_ITEM_Out) {
|
||||
// reset our timeout
|
||||
hidTimeout = 0;
|
||||
|
||||
LED_Report_t* LEDReport = (LED_Report_t*)ReportData;
|
||||
memcpy((uint8_t*)leds, LEDReport->mainLights, LED_PHYSICAL_COUNT);
|
||||
|
||||
// Keep normal lights but override when we get flashes on BT or FX
|
||||
// BT LEDs flash pure white
|
||||
for(uint8_t i = 0; i < 4; i++) {
|
||||
if(LEDReport->btFx[i]) {
|
||||
led_set(ledMap[i], BRIGHTNESS_LEVELS, BRIGHTNESS_LEVELS, BRIGHTNESS_LEVELS);
|
||||
}
|
||||
}
|
||||
// FX LEDs flash orange
|
||||
for(uint8_t i = 4; i < 6; i++) {
|
||||
if(LEDReport->btFx[i]) {
|
||||
led_set(ledMap[i], BRIGHTNESS_LEVELS, BRIGHTNESS_LEVELS/4, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** Event handler for the library USB Connection event. */
|
||||
void EVENT_USB_Device_Connect(void)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/** Event handler for the library USB Disconnection event. */
|
||||
void EVENT_USB_Device_Disconnect(void)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/** Event handler for the library USB Configuration Changed event. */
|
||||
void EVENT_USB_Device_ConfigurationChanged(void)
|
||||
{
|
||||
HID_Device_ConfigureEndpoints(&Keyboard_HID_Interface);
|
||||
HID_Device_ConfigureEndpoints(&Mouse_HID_Interface);
|
||||
HID_Device_ConfigureEndpoints(&Generic_HID_Interface);
|
||||
HID_Device_ConfigureEndpoints(&LED_HID_Interface);
|
||||
|
||||
USB_Device_EnableSOFEvents();
|
||||
}
|
||||
|
||||
/** Event handler for the library USB Control Request reception event. */
|
||||
void EVENT_USB_Device_ControlRequest(void)
|
||||
{
|
||||
USB_Process_BOS();
|
||||
HID_Device_ProcessControlRequest(&Keyboard_HID_Interface);
|
||||
HID_Device_ProcessControlRequest(&Mouse_HID_Interface);
|
||||
HID_Device_ProcessControlRequest(&Generic_HID_Interface);
|
||||
HID_Device_ProcessControlRequest(&LED_HID_Interface);
|
||||
}
|
||||
|
||||
/** Event handler for the USB device Start Of Frame event. */
|
||||
void EVENT_USB_Device_StartOfFrame(void)
|
||||
{
|
||||
HID_Device_MillisecondElapsed(&Keyboard_HID_Interface);
|
||||
HID_Device_MillisecondElapsed(&Mouse_HID_Interface);
|
||||
HID_Device_MillisecondElapsed(&Generic_HID_Interface);
|
||||
HID_Device_MillisecondElapsed(&LED_HID_Interface);
|
||||
|
||||
if(hidTimeout > HID_LED_TIMEOUT) {
|
||||
led_frame();
|
||||
} else {
|
||||
hidTimeout++;
|
||||
}
|
||||
|
||||
macro_on_frame(&switches[SWITCH_COUNT-1]);
|
||||
|
||||
for(int i = 0; i < SWITCH_COUNT; i++) {
|
||||
if(switches[i].debounce) {
|
||||
switches[i].debounce--;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
LUFA Library
|
||||
Copyright (C) Dean Camera, 2014.
|
||||
|
||||
dean [at] fourwalledcubicle [dot] com
|
||||
www.lufa-lib.org
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright 2014 Dean Camera (dean [at] fourwalledcubicle [dot] com)
|
||||
|
||||
Permission to use, copy, modify, distribute, and sell this
|
||||
software and its documentation for any purpose is hereby granted
|
||||
without fee, provided that the above copyright notice appear in
|
||||
all copies and that both that the copyright notice and this
|
||||
permission notice and warranty disclaimer appear in supporting
|
||||
documentation, and that the name of the author not be used in
|
||||
advertising or publicity pertaining to distribution of the
|
||||
software without specific, written prior permission.
|
||||
|
||||
The author disclaims all warranties with regard to this
|
||||
software, including all implied warranties of merchantability
|
||||
and fitness. In no event shall the author be liable for any
|
||||
special, indirect or consequential damages or any damages
|
||||
whatsoever resulting from loss of use, data or profits, whether
|
||||
in an action of contract, negligence or other tortious action,
|
||||
arising out of or in connection with the use or performance of
|
||||
this software.
|
||||
*/
|
||||
|
||||
/** \file
|
||||
*
|
||||
* Header file for Keyboard.c.
|
||||
*/
|
||||
|
||||
#ifndef _KEYBOARD_H_
|
||||
#define _KEYBOARD_H_
|
||||
|
||||
/* Includes: */
|
||||
#include <avr/io.h>
|
||||
#include <avr/wdt.h>
|
||||
#include <avr/power.h>
|
||||
#include <avr/interrupt.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "Descriptors.h"
|
||||
|
||||
#include <LUFA/Drivers/USB/USB.h>
|
||||
#include <LUFA/Platform/Platform.h>
|
||||
|
||||
// NOTE: atemga16u2 does not have a PORTA
|
||||
typedef enum {
|
||||
B = 0,
|
||||
C,
|
||||
D
|
||||
} port_t;
|
||||
|
||||
typedef struct {
|
||||
port_t switchPort;
|
||||
uint8_t switchPin;
|
||||
uint8_t state;
|
||||
uint8_t lastReport;
|
||||
uint8_t debounce;
|
||||
} switch_t;
|
||||
|
||||
/* Function Prototypes: */
|
||||
void SetupHardware(void);
|
||||
|
||||
void EVENT_USB_Device_Connect(void);
|
||||
void EVENT_USB_Device_Disconnect(void);
|
||||
void EVENT_USB_Device_ConfigurationChanged(void);
|
||||
void EVENT_USB_Device_ControlRequest(void);
|
||||
void EVENT_USB_Device_StartOfFrame(void);
|
||||
|
||||
bool CALLBACK_HID_Device_CreateHIDReport(USB_ClassInfo_HID_Device_t* const HIDInterfaceInfo,
|
||||
uint8_t* const ReportID,
|
||||
const uint8_t ReportType,
|
||||
void* ReportData,
|
||||
uint16_t* const ReportSize);
|
||||
void CALLBACK_HID_Device_ProcessHIDReport(USB_ClassInfo_HID_Device_t* const HIDInterfaceInfo,
|
||||
const uint8_t ReportID,
|
||||
const uint8_t ReportType,
|
||||
const void* ReportData,
|
||||
const uint16_t ReportSize);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
#include "asciihid.h"
|
||||
|
||||
/****************************************************************************
|
||||
*
|
||||
* ASCII->HID LOOKUP TABLE
|
||||
*
|
||||
* Taken from the HID Table definition at
|
||||
* http://www.usb.org/developers/devclass_docs/Hut1_11.pdf
|
||||
*
|
||||
* This array maps the ASCII value of a type-able character to its
|
||||
* corresponding HID value.
|
||||
*
|
||||
* Example:
|
||||
* 'a' = ASCII value 97 = HID value 0x04
|
||||
* HIDTable['a'] = HIDTable[97] = 0x04
|
||||
*
|
||||
* NOTE:
|
||||
* "Shift Modified" HID values are the same as the non Shift-Modified values
|
||||
* for any given character, e.g. the HID value for '2' is equal to the
|
||||
* HID value for '@'. The Shift-Modified value is sent by setting the
|
||||
* modifier value (buf[0]) to the corresponding modifier value in the
|
||||
* modifier table.
|
||||
*
|
||||
****************************************************************************/
|
||||
const uint8_t PROGMEM HIDTable[] = {
|
||||
0x00, // 0
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2A, 0x00, 0x28, // 10
|
||||
0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 20
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, // 30
|
||||
0x00, 0x2c, 0x1e, 0x34, 0x20, 0x21, 0x22, 0x24, 0x34, 0x26, // 40
|
||||
0x27, 0x25, 0x2e, 0x36, 0x2d, 0x37, 0x38, 0x27, 0x1e, 0x1f, // 50
|
||||
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x33, 0x33, 0x36, // 60
|
||||
0x2e, 0x37, 0x38, 0x1f, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, // 70
|
||||
0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, // 80
|
||||
0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, // 90
|
||||
0x2f, 0x31, 0x30, 0x23, 0x2d, 0x35, 0x04, 0x05, 0x06, 0x07, // 100
|
||||
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, // 110
|
||||
0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, // 120
|
||||
0x1c, 0x1d, 0x2f, 0x31, 0x30, 0x35, 127 // 127
|
||||
};
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
*
|
||||
* ASCII->MODIFIER LOOKUP TABLE
|
||||
*
|
||||
* Looks up whether or not the HID report should use the SHIFT modifier.
|
||||
*
|
||||
* Example:
|
||||
* The character '2' and the character '@' have different ASCII values but
|
||||
* the same HID value. This table uses the ASCII value to determine if
|
||||
* we should hold shift while sending the key. e.g.:
|
||||
*
|
||||
* HIDTable['2'] = 0x1f and modifierTable['2'] = 0
|
||||
* HIDTable['@'] = 0x1f and modifierTable['@'] = SHIFT
|
||||
*
|
||||
* There's probaly a better way to do this, but it's functional.
|
||||
*
|
||||
****************************************************************************/
|
||||
const uint8_t PROGMEM modifierTable[] = {
|
||||
0x00, // 0
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 10
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 20
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 30
|
||||
0x00, 0x00, SHIFT, SHIFT, SHIFT, SHIFT, SHIFT, SHIFT, SHIFT, SHIFT, // 40
|
||||
SHIFT, 0x00, SHIFT, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 50
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, SHIFT, 0x00, SHIFT, // 60
|
||||
0x00, SHIFT, SHIFT, SHIFT, SHIFT, SHIFT, SHIFT, SHIFT, SHIFT, SHIFT, // 70
|
||||
SHIFT, SHIFT, SHIFT, SHIFT, SHIFT, SHIFT, SHIFT, SHIFT, SHIFT, SHIFT, // 80
|
||||
SHIFT, SHIFT, SHIFT, SHIFT, SHIFT, SHIFT, SHIFT, SHIFT, SHIFT, SHIFT, // 90
|
||||
0x00, 0x00, 0x00, SHIFT, SHIFT, 0x00, 0x00, 0x00, 0x00, 0x00, // 100
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 110
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 120
|
||||
0x00, 0x00, SHIFT, SHIFT, SHIFT, SHIFT, 0x00 // 127
|
||||
};
|
||||
|
||||
const uint8_t PROGMEM numpadTable[] = {
|
||||
0x62, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 0x60, 0x61 // 0-9 on the numpad
|
||||
};
|
||||
@@ -0,0 +1,78 @@
|
||||
// https://github.com/SFE-Chris/UNO-HIDKeyboard-Library/blob/master/HIDKeyboard.h
|
||||
#ifndef ASCIIHID_H_
|
||||
#define ASCIIHID_H_
|
||||
|
||||
#include <avr/pgmspace.h>
|
||||
|
||||
// HID Values of Function Keys
|
||||
#define F1 0x3a
|
||||
#define F2 0x3b
|
||||
#define F3 0x3c
|
||||
#define F4 0x3d
|
||||
#define F5 0x3e
|
||||
#define F6 0x3f
|
||||
#define F7 0x40
|
||||
#define F8 0x41
|
||||
#define F9 0x42
|
||||
#define F10 0x43
|
||||
#define F11 0x44
|
||||
#define F12 0x45
|
||||
|
||||
// HID Values of Special Keys
|
||||
#define ENTER 0x28
|
||||
#define ESCAPE 0x29
|
||||
#define BACKSPACE 0x2a
|
||||
#define TAB 0x2b
|
||||
#define SPACEBAR 0x2c
|
||||
#define CAPSLOCK 0x39
|
||||
#define PRINTSCREEN 0x46
|
||||
#define SCROLLLOCK 0x47
|
||||
#define PAUSE 0x48
|
||||
#define INSERT 0x49
|
||||
#define HOME 0x4a
|
||||
#define PAGEUP 0x4b
|
||||
#define DELETE 0x4c
|
||||
#define END 0x4d
|
||||
#define PAGEDOWN 0x4e
|
||||
#define RIGHTARROW 0x4f
|
||||
#define LEFTARROW 0x50
|
||||
#define DOWNARROW 0x51
|
||||
#define UPARROW 0x52
|
||||
|
||||
// HID Values of Keypad Keys
|
||||
#define NUMLOCK 0x53
|
||||
#define KEYPADSLASH 0x54
|
||||
#define KEYPADSTAR 0x55
|
||||
#define KEYPADMINUS 0x56
|
||||
#define KEYPADPLUS 0x57
|
||||
#define KEYPADENTER 0x58
|
||||
#define KEYPAD1 0x59
|
||||
#define KEYPAD2 0x5a
|
||||
#define KEYPAD3 0x5b
|
||||
#define KEYPAD4 0x5c
|
||||
#define KEYPAD5 0x5d
|
||||
#define KEYPAD6 0x5e
|
||||
#define KEYPAD7 0x5f
|
||||
#define KEYPAD8 0x60
|
||||
#define KEYPAD9 0x61
|
||||
#define KEYPAD0 0x62
|
||||
#define KEYPADPERIOD 0x63
|
||||
|
||||
// HID Values of System Keys
|
||||
#define KEYBOARDAPPLICATION 0x65
|
||||
#define KEYBOARDPOWER 0x66
|
||||
#define VOLUMEMUTE 0x7f
|
||||
#define VOLUMEUP 0x80
|
||||
#define VOLUMEDOWN 0x81
|
||||
|
||||
// Common-use modifiers
|
||||
#define CTRL 0x01
|
||||
#define SHIFT 0x02
|
||||
#define ALT 0x04
|
||||
#define GUI 0x08
|
||||
|
||||
extern PROGMEM const uint8_t HIDTable[];
|
||||
extern PROGMEM const uint8_t modifierTable[];
|
||||
extern PROGMEM const uint8_t numpadTable[];
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,68 @@
|
||||
#
|
||||
# LUFA Library
|
||||
# Copyright (C) Dean Camera, 2014.
|
||||
#
|
||||
# dean [at] fourwalledcubicle [dot] com
|
||||
# www.lufa-lib.org
|
||||
#
|
||||
# --------------------------------------
|
||||
# LUFA Project Makefile.
|
||||
# --------------------------------------
|
||||
|
||||
# Run "make help" for target help.
|
||||
|
||||
MCU = atmega16u2
|
||||
ARCH = AVR8
|
||||
BOARD = USER
|
||||
F_CPU = 16000000
|
||||
F_USB = $(F_CPU)
|
||||
OPTIMIZATION = s
|
||||
TARGET = PocketVoltex
|
||||
SRC = $(TARGET).c asciihid.c Descriptors.c Config.c Encoder.c LED.c LEDPatterns.c Macro.c $(LUFA_SRC_USB) $(LUFA_SRC_USBCLASS)
|
||||
LUFA_PATH = ../LUFA
|
||||
CC_FLAGS = -DUSE_LUFA_CONFIG_HEADER -IConfig/
|
||||
LD_FLAGS =
|
||||
|
||||
AVRDUDE = avrdude -B 8 -c usbasp -p $(MCU)
|
||||
|
||||
|
||||
# Default target
|
||||
all:
|
||||
|
||||
# Include LUFA build script makefiles
|
||||
include $(LUFA_PATH)/Build/lufa_core.mk
|
||||
include $(LUFA_PATH)/Build/lufa_sources.mk
|
||||
include $(LUFA_PATH)/Build/lufa_build.mk
|
||||
include $(LUFA_PATH)/Build/lufa_cppcheck.mk
|
||||
include $(LUFA_PATH)/Build/lufa_doxygen.mk
|
||||
include $(LUFA_PATH)/Build/lufa_dfu.mk
|
||||
include $(LUFA_PATH)/Build/lufa_hid.mk
|
||||
include $(LUFA_PATH)/Build/lufa_avrdude.mk
|
||||
include $(LUFA_PATH)/Build/lufa_atprogram.mk
|
||||
|
||||
debug: CC_FLAGS += -DDEBUG
|
||||
debug: clean flash
|
||||
|
||||
init: erase wfuse flashboot flash
|
||||
|
||||
initboot: erase wfuse flashboot
|
||||
|
||||
erase:
|
||||
$(AVRDUDE) -e
|
||||
|
||||
rfuse:
|
||||
$(AVRDUDE) -U hfuse:r:-:h -U lfuse:r:-:h -U efuse:r:-:h
|
||||
|
||||
wfuse:
|
||||
$(AVRDUDE) -U lfuse:w:0xde:m -U hfuse:w:0x9b:m -U efuse:w:0xf6:m
|
||||
|
||||
# To make this hex, compile HID Bootloader in LUFA
|
||||
# FLASH_SIZE_KB := 16
|
||||
# BOOT_SECTION_SIZE_KB := 2
|
||||
# MCU = atmega16u2
|
||||
# ARCH = AVR8
|
||||
flashboot:
|
||||
$(AVRDUDE) -U flash:w:DFU/BootloaderHID.hex:i
|
||||
|
||||
flash: all
|
||||
python DFU/hid_bootloader_loader.py atmega16u2 PocketVoltex.hex
|
||||
Reference in New Issue
Block a user