This commit is contained in:
Jack Humbert 2015-08-20 00:42:08 -04:00
parent 2d76b5c3d4
commit e528087ee5
10 changed files with 392 additions and 9 deletions

View File

@ -24,7 +24,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#define PRODUCT_ID 0x6060 #define PRODUCT_ID 0x6060
#define DEVICE_VER 0x0001 #define DEVICE_VER 0x0001
#define MANUFACTURER Ortholinear Keyboards #define MANUFACTURER Ortholinear Keyboards
#define PRODUCT Planck #define PRODUCT The Planck Keyboard
#define DESCRIPTION A compact ortholinear keyboard #define DESCRIPTION A compact ortholinear keyboard
/* key matrix size */ /* key matrix size */

View File

@ -48,6 +48,7 @@ typedef union {
keymap_config_t keymap_config; keymap_config_t keymap_config;
#endif #endif
/* translates key to keycode */ /* translates key to keycode */
uint16_t keymap_key_to_keycode(uint8_t layer, keypos_t key); uint16_t keymap_key_to_keycode(uint8_t layer, keypos_t key);

View File

@ -1,5 +1,6 @@
#include "extended_keymap_common.h" #include "extended_keymap_common.h"
#include "backlight.h" #include "backlight.h"
#include "lufa.h"
const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
[0] = { /* Qwerty */ [0] = { /* Qwerty */
@ -50,10 +51,18 @@ const macro_t *action_get_macro(keyrecord_t *record, uint8_t id, uint8_t opt)
switch(id) { switch(id) {
case 0: case 0:
if (record->event.pressed) { if (record->event.pressed) {
if (!&midi_device) {
register_code(KC_RSFT); register_code(KC_RSFT);
} else {
midi_send_noteon(&midi_device, 1, 64, 127);
}
backlight_step(); backlight_step();
} else { } else {
if (!&midi_device) {
unregister_code(KC_RSFT); unregister_code(KC_RSFT);
} else {
midi_send_noteoff(&midi_device, 1, 64, 127);
}
} }
break; break;
} }

View File

@ -78,6 +78,7 @@ void matrix_init(void)
} }
} }
uint8_t matrix_scan(void) uint8_t matrix_scan(void)
{ {
for (uint8_t i = 0; i < MATRIX_ROWS; i++) { for (uint8_t i = 0; i < MATRIX_ROWS; i++) {

View File

@ -19,7 +19,12 @@ endif
LUFA_SRC = $(LUFA_DIR)/lufa.c \ LUFA_SRC = $(LUFA_DIR)/lufa.c \
$(LUFA_DIR)/descriptor.c \ $(LUFA_DIR)/descriptor.c \
$(LUFA_SRC_USB) $(LUFA_SRC_USB) \
$(LUFA_DIR)/midi/midi.c \
$(LUFA_DIR)/midi/midi_device.c \
$(LUFA_DIR)/midi/bytequeue/bytequeue.c \
$(LUFA_DIR)/midi/bytequeue/interrupt_setting.c \
$(LUFA_DIR)/LUFA-git/LUFA/Drivers/USB/Class/Device/MIDIClassDevice.c
SRC += $(LUFA_SRC) SRC += $(LUFA_SRC)

View File

@ -486,6 +486,164 @@ const USB_Descriptor_Configuration_t PROGMEM ConfigurationDescriptor =
.PollingIntervalMS = 0x01 .PollingIntervalMS = 0x01
}, },
#endif #endif
.Audio_ControlInterface =
{
.Header = {.Size = sizeof(USB_Descriptor_Interface_t), .Type = DTYPE_Interface},
.InterfaceNumber = (NKRO_INTERFACE + 1),
.AlternateSetting = 0,
.TotalEndpoints = 0,
.Class = AUDIO_CSCP_AudioClass,
.SubClass = AUDIO_CSCP_ControlSubclass,
.Protocol = AUDIO_CSCP_ControlProtocol,
.InterfaceStrIndex = NO_DESCRIPTOR
},
.Audio_ControlInterface_SPC =
{
.Header = {.Size = sizeof(USB_Audio_Descriptor_Interface_AC_t), .Type = DTYPE_CSInterface},
.Subtype = AUDIO_DSUBTYPE_CSInterface_Header,
.ACSpecification = VERSION_BCD(1,1,1),
.TotalLength = sizeof(USB_Audio_Descriptor_Interface_AC_t),
.InCollection = 1,
.InterfaceNumber = (NKRO_INTERFACE + 2),
},
.Audio_StreamInterface =
{
.Header = {.Size = sizeof(USB_Descriptor_Interface_t), .Type = DTYPE_Interface},
.InterfaceNumber = (NKRO_INTERFACE + 2),
.AlternateSetting = 0,
.TotalEndpoints = 2,
.Class = AUDIO_CSCP_AudioClass,
.SubClass = AUDIO_CSCP_MIDIStreamingSubclass,
.Protocol = AUDIO_CSCP_StreamingProtocol,
.InterfaceStrIndex = NO_DESCRIPTOR
},
.Audio_StreamInterface_SPC =
{
.Header = {.Size = sizeof(USB_MIDI_Descriptor_AudioInterface_AS_t), .Type = DTYPE_CSInterface},
.Subtype = AUDIO_DSUBTYPE_CSInterface_General,
.AudioSpecification = VERSION_BCD(1,1,1),
.TotalLength = (sizeof(USB_Descriptor_Configuration_t) -
offsetof(USB_Descriptor_Configuration_t, Audio_StreamInterface_SPC))
},
.MIDI_In_Jack_Emb =
{
.Header = {.Size = sizeof(USB_MIDI_Descriptor_InputJack_t), .Type = DTYPE_CSInterface},
.Subtype = AUDIO_DSUBTYPE_CSInterface_InputTerminal,
.JackType = MIDI_JACKTYPE_Embedded,
.JackID = 0x01,
.JackStrIndex = NO_DESCRIPTOR
},
.MIDI_In_Jack_Ext =
{
.Header = {.Size = sizeof(USB_MIDI_Descriptor_InputJack_t), .Type = DTYPE_CSInterface},
.Subtype = AUDIO_DSUBTYPE_CSInterface_InputTerminal,
.JackType = MIDI_JACKTYPE_External,
.JackID = 0x02,
.JackStrIndex = NO_DESCRIPTOR
},
.MIDI_Out_Jack_Emb =
{
.Header = {.Size = sizeof(USB_MIDI_Descriptor_OutputJack_t), .Type = DTYPE_CSInterface},
.Subtype = AUDIO_DSUBTYPE_CSInterface_OutputTerminal,
.JackType = MIDI_JACKTYPE_Embedded,
.JackID = 0x03,
.NumberOfPins = 1,
.SourceJackID = {0x02},
.SourcePinID = {0x01},
.JackStrIndex = NO_DESCRIPTOR
},
.MIDI_Out_Jack_Ext =
{
.Header = {.Size = sizeof(USB_MIDI_Descriptor_OutputJack_t), .Type = DTYPE_CSInterface},
.Subtype = AUDIO_DSUBTYPE_CSInterface_OutputTerminal,
.JackType = MIDI_JACKTYPE_External,
.JackID = 0x04,
.NumberOfPins = 1,
.SourceJackID = {0x01},
.SourcePinID = {0x01},
.JackStrIndex = NO_DESCRIPTOR
},
.MIDI_In_Jack_Endpoint =
{
.Endpoint =
{
.Header = {.Size = sizeof(USB_Audio_Descriptor_StreamEndpoint_Std_t), .Type = DTYPE_Endpoint},
.EndpointAddress = (ENDPOINT_DIR_IN | MIDI_STREAM_IN_EPNUM),
.Attributes = (EP_TYPE_BULK | ENDPOINT_ATTR_NO_SYNC | ENDPOINT_USAGE_DATA),
.EndpointSize = MIDI_STREAM_EPSIZE,
.PollingIntervalMS = 0x01
},
.Refresh = 0,
.SyncEndpointNumber = 0
},
.MIDI_In_Jack_Endpoint_SPC =
{
.Header = {.Size = sizeof(USB_MIDI_Descriptor_Jack_Endpoint_t), .Type = DTYPE_CSEndpoint},
.Subtype = AUDIO_DSUBTYPE_CSEndpoint_General,
.TotalEmbeddedJacks = 0x01,
.AssociatedJackID = {0x01}
},
.MIDI_Out_Jack_Endpoint =
{
.Endpoint =
{
.Header = {.Size = sizeof(USB_Audio_Descriptor_StreamEndpoint_Std_t), .Type = DTYPE_Endpoint},
.EndpointAddress = (ENDPOINT_DIR_OUT | MIDI_STREAM_OUT_EPNUM),
.Attributes = (EP_TYPE_BULK | ENDPOINT_ATTR_NO_SYNC | ENDPOINT_USAGE_DATA),
.EndpointSize = MIDI_STREAM_EPSIZE,
.PollingIntervalMS = 0x01
},
.Refresh = 0,
.SyncEndpointNumber = 0
},
.MIDI_Out_Jack_Endpoint_SPC =
{
.Header = {.Size = sizeof(USB_MIDI_Descriptor_Jack_Endpoint_t), .Type = DTYPE_CSEndpoint},
.Subtype = AUDIO_DSUBTYPE_CSEndpoint_General,
.TotalEmbeddedJacks = 0x01,
.AssociatedJackID = {0x03}
}
}; };

View File

@ -85,6 +85,23 @@ typedef struct
USB_HID_Descriptor_HID_t NKRO_HID; USB_HID_Descriptor_HID_t NKRO_HID;
USB_Descriptor_Endpoint_t NKRO_INEndpoint; USB_Descriptor_Endpoint_t NKRO_INEndpoint;
#endif #endif
// MIDI Audio Control Interface
USB_Descriptor_Interface_t Audio_ControlInterface;
USB_Audio_Descriptor_Interface_AC_t Audio_ControlInterface_SPC;
// MIDI Audio Streaming Interface
USB_Descriptor_Interface_t Audio_StreamInterface;
USB_MIDI_Descriptor_AudioInterface_AS_t Audio_StreamInterface_SPC;
USB_MIDI_Descriptor_InputJack_t MIDI_In_Jack_Emb;
USB_MIDI_Descriptor_InputJack_t MIDI_In_Jack_Ext;
USB_MIDI_Descriptor_OutputJack_t MIDI_Out_Jack_Emb;
USB_MIDI_Descriptor_OutputJack_t MIDI_Out_Jack_Ext;
USB_Audio_Descriptor_StreamEndpoint_Std_t MIDI_In_Jack_Endpoint;
USB_MIDI_Descriptor_Jack_Endpoint_t MIDI_In_Jack_Endpoint_SPC;
USB_Audio_Descriptor_StreamEndpoint_Std_t MIDI_Out_Jack_Endpoint;
USB_MIDI_Descriptor_Jack_Endpoint_t MIDI_Out_Jack_Endpoint_SPC;
} USB_Descriptor_Configuration_t; } USB_Descriptor_Configuration_t;
@ -117,7 +134,7 @@ typedef struct
/* nubmer of interfaces */ /* nubmer of interfaces */
#define TOTAL_INTERFACES (NKRO_INTERFACE + 1) #define TOTAL_INTERFACES (NKRO_INTERFACE + 3)
// Endopoint number and size // Endopoint number and size
@ -150,12 +167,16 @@ typedef struct
# endif # endif
#endif #endif
#define MIDI_STREAM_IN_EPNUM (NKRO_IN_EPNUM + 1)
#define MIDI_STREAM_OUT_EPNUM (NKRO_IN_EPNUM + 1)
#define KEYBOARD_EPSIZE 8 #define KEYBOARD_EPSIZE 8
#define MOUSE_EPSIZE 8 #define MOUSE_EPSIZE 8
#define EXTRAKEY_EPSIZE 8 #define EXTRAKEY_EPSIZE 8
#define CONSOLE_EPSIZE 32 #define CONSOLE_EPSIZE 32
#define NKRO_EPSIZE 16 #define NKRO_EPSIZE 16
#define MIDI_STREAM_EPSIZE 64
uint16_t CALLBACK_USB_GetDescriptor(const uint16_t wValue, uint16_t CALLBACK_USB_GetDescriptor(const uint16_t wValue,

View File

@ -52,6 +52,7 @@
#include "descriptor.h" #include "descriptor.h"
#include "lufa.h" #include "lufa.h"
uint8_t keyboard_idle = 0; uint8_t keyboard_idle = 0;
uint8_t keyboard_protocol = 1; uint8_t keyboard_protocol = 1;
static uint8_t keyboard_led_stats = 0; static uint8_t keyboard_led_stats = 0;
@ -65,14 +66,51 @@ static void send_keyboard(report_keyboard_t *report);
static void send_mouse(report_mouse_t *report); static void send_mouse(report_mouse_t *report);
static void send_system(uint16_t data); static void send_system(uint16_t data);
static void send_consumer(uint16_t data); static void send_consumer(uint16_t data);
void usb_send_func(MidiDevice * device, uint16_t cnt, uint8_t byte0, uint8_t byte1, uint8_t byte2);
void usb_get_midi(MidiDevice * device);
void midi_usb_init(MidiDevice * device);
host_driver_t lufa_driver = { host_driver_t lufa_driver = {
keyboard_leds, keyboard_leds,
send_keyboard, send_keyboard,
send_mouse, send_mouse,
send_system, send_system,
send_consumer send_consumer,
usb_send_func,
usb_get_midi,
midi_usb_init
}; };
void SetupHardware(void);
USB_ClassInfo_MIDI_Device_t USB_MIDI_Interface =
{
.Config =
{
.StreamingInterfaceNumber = 1,
.DataINEndpoint =
{
.Address = (ENDPOINT_DIR_IN | MIDI_STREAM_IN_EPNUM),
.Size = MIDI_STREAM_EPSIZE,
.Banks = 1,
},
.DataOUTEndpoint =
{
.Address = (ENDPOINT_DIR_OUT | MIDI_STREAM_OUT_EPNUM),
.Size = MIDI_STREAM_EPSIZE,
.Banks = 1,
},
},
};
#define SYSEX_START_OR_CONT 0x40
#define SYSEX_ENDS_IN_1 0x50
#define SYSEX_ENDS_IN_2 0x60
#define SYSEX_ENDS_IN_3 0x70
#define SYS_COMMON_1 0x50
#define SYS_COMMON_2 0x20
#define SYS_COMMON_3 0x30
/******************************************************************************* /*******************************************************************************
* Console * Console
@ -240,8 +278,13 @@ void EVENT_USB_Device_ConfigurationChanged(void)
ConfigSuccess &= ENDPOINT_CONFIG(NKRO_IN_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_IN, ConfigSuccess &= ENDPOINT_CONFIG(NKRO_IN_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_IN,
NKRO_EPSIZE, ENDPOINT_BANK_SINGLE); NKRO_EPSIZE, ENDPOINT_BANK_SINGLE);
#endif #endif
ConfigSuccess &= MIDI_Device_ConfigureEndpoints(&USB_MIDI_Interface);
} }
/* /*
Appendix G: HID Request Support Requirements Appendix G: HID Request Support Requirements
@ -263,6 +306,8 @@ void EVENT_USB_Device_ControlRequest(void)
uint8_t* ReportData = NULL; uint8_t* ReportData = NULL;
uint8_t ReportSize = 0; uint8_t ReportSize = 0;
MIDI_Device_ProcessControlRequest(&USB_MIDI_Interface);
/* Handle HID Class specific requests */ /* Handle HID Class specific requests */
switch (USB_ControlRequest.bRequest) switch (USB_ControlRequest.bRequest)
{ {
@ -541,10 +586,109 @@ int8_t sendchar(uint8_t c)
#endif #endif
void usb_send_func(MidiDevice * device, uint16_t cnt, uint8_t byte0, uint8_t byte1, uint8_t byte2) {
MIDI_EventPacket_t event;
event.Data1 = byte0;
event.Data2 = byte1;
event.Data3 = byte2;
//if the length is undefined we assume it is a SYSEX message
if (midi_packet_length(byte0) == UNDEFINED) {
switch(cnt) {
case 3:
if (byte2 == SYSEX_END)
event.Event = MIDI_EVENT(0, SYSEX_ENDS_IN_3);
else
event.Event = MIDI_EVENT(0, SYSEX_START_OR_CONT);
break;
case 2:
if (byte1 == SYSEX_END)
event.Event = MIDI_EVENT(0, SYSEX_ENDS_IN_2);
else
event.Event = MIDI_EVENT(0, SYSEX_START_OR_CONT);
break;
case 1:
if (byte0 == SYSEX_END)
event.Event = MIDI_EVENT(0, SYSEX_ENDS_IN_1);
else
event.Event = MIDI_EVENT(0, SYSEX_START_OR_CONT);
break;
default:
return; //invalid cnt
}
} else {
//deal with 'system common' messages
//TODO are there any more?
switch(byte0 & 0xF0){
case MIDI_SONGPOSITION:
event.Event = MIDI_EVENT(0, SYS_COMMON_3);
break;
case MIDI_SONGSELECT:
case MIDI_TC_QUARTERFRAME:
event.Event = MIDI_EVENT(0, SYS_COMMON_2);
break;
default:
event.Event = MIDI_EVENT(0, byte0);
break;
}
}
MIDI_Device_SendEventPacket(&USB_MIDI_Interface, &event);
MIDI_Device_Flush(&USB_MIDI_Interface);
MIDI_Device_USBTask(&USB_MIDI_Interface);
USB_USBTask();
}
void usb_get_midi(MidiDevice * device) {
MIDI_EventPacket_t event;
while (MIDI_Device_ReceiveEventPacket(&USB_MIDI_Interface, &event)) {
midi_packet_length_t length = midi_packet_length(event.Data1);
uint8_t input[3];
input[0] = event.Data1;
input[1] = event.Data2;
input[2] = event.Data3;
if (length == UNDEFINED) {
//sysex
if (event.Event == MIDI_EVENT(0, SYSEX_START_OR_CONT) || event.Event == MIDI_EVENT(0, SYSEX_ENDS_IN_3)) {
length = 3;
} else if (event.Event == MIDI_EVENT(0, SYSEX_ENDS_IN_2)) {
length = 2;
} else if(event.Event == MIDI_EVENT(0, SYSEX_ENDS_IN_1)) {
length = 1;
} else {
//XXX what to do?
}
}
//pass the data to the device input function
if (length != UNDEFINED)
midi_device_input(device, length, input);
}
MIDI_Device_USBTask(&USB_MIDI_Interface);
USB_USBTask();
}
void midi_usb_init(MidiDevice * device){
midi_device_init(device);
midi_device_set_send_func(device, usb_send_func);
midi_device_set_pre_input_process_func(device, usb_get_midi);
SetupHardware();
sei();
}
/******************************************************************************* /*******************************************************************************
* main * main
******************************************************************************/ ******************************************************************************/
static void SetupHardware(void) void SetupHardware(void)
{ {
/* Disable watchdog if enabled by bootloader/fuses */ /* Disable watchdog if enabled by bootloader/fuses */
MCUSR &= ~(1 << WDRF); MCUSR &= ~(1 << WDRF);
@ -563,12 +707,34 @@ static void SetupHardware(void)
print_set_sendchar(sendchar); print_set_sendchar(sendchar);
} }
void fallthrough_callback(MidiDevice * device,
uint16_t cnt, uint8_t byte0, uint8_t byte1, uint8_t byte2);
void cc_callback(MidiDevice * device,
uint8_t chan, uint8_t num, uint8_t val);
void sysex_callback(MidiDevice * device,
uint16_t start, uint8_t length, uint8_t * data);
int main(void) __attribute__ ((weak)); int main(void) __attribute__ ((weak));
int main(void) int main(void)
{ {
//setup the device
midi_device_init(&midi_device);
midi_device_set_send_func(&midi_device, usb_send_func);
midi_device_set_pre_input_process_func(&midi_device, usb_get_midi);
SetupHardware(); SetupHardware();
sei(); sei();
midi_register_fallthrough_callback(&midi_device, fallthrough_callback);
midi_register_cc_callback(&midi_device, cc_callback);
midi_register_sysex_callback(&midi_device, sysex_callback);
midi_send_cc(&midi_device, 0, 1, 2);
midi_send_cc(&midi_device, 15, 1, 0);
midi_send_noteon(&midi_device, 0, 64, 127);
midi_send_noteoff(&midi_device, 0, 64, 127);
/* wait for USB startup & debug output */ /* wait for USB startup & debug output */
while (USB_DeviceState != DEVICE_STATE_Configured) { while (USB_DeviceState != DEVICE_STATE_Configured) {
#if defined(INTERRUPT_CONTROL_ENDPOINT) #if defined(INTERRUPT_CONTROL_ENDPOINT)
@ -598,8 +764,29 @@ int main(void)
keyboard_task(); keyboard_task();
midi_device_process(&midi_device);
#if !defined(INTERRUPT_CONTROL_ENDPOINT) #if !defined(INTERRUPT_CONTROL_ENDPOINT)
USB_USBTask(); USB_USBTask();
#endif #endif
} }
} }
//echo data back
void fallthrough_callback(MidiDevice * device,
uint16_t cnt, uint8_t byte0, uint8_t byte1, uint8_t byte2){
//pass the data back to the device, using the general purpose send data
//function, any bytes after cnt are ignored
}
void cc_callback(MidiDevice * device,
uint8_t chan, uint8_t num, uint8_t val) {
//sending it back on the next channel
midi_send_cc(device, (chan + 1) % 16, num, val);
}
void sysex_callback(MidiDevice * device,
uint16_t start, uint8_t length, uint8_t * data) {
for (int i = 0; i < length; i++)
midi_send_cc(device, 15, 0x7F & data[i], 0x7F & (start + i));
}

View File

@ -48,7 +48,7 @@
#include <LUFA/Version.h> #include <LUFA/Version.h>
#include <LUFA/Drivers/USB/USB.h> #include <LUFA/Drivers/USB/USB.h>
#include "host.h" #include "host.h"
#include "midi/midi.h"
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
@ -66,6 +66,7 @@ typedef struct {
uint16_t usage; uint16_t usage;
} __attribute__ ((packed)) report_extra_t; } __attribute__ ((packed)) report_extra_t;
MidiDevice midi_device;
#if LUFA_VERSION_INTEGER < 0x120730 #if LUFA_VERSION_INTEGER < 0x120730
/* old API 120219 */ /* old API 120219 */