diff --git a/firmware/Makefile b/firmware/Makefile
index 76a64f8..70f1760 100644
--- a/firmware/Makefile
+++ b/firmware/Makefile
@@ -70,3 +70,4 @@ $(eval $(call BOARD_MCU_template,midi-router-x4-flat,atxmega32a4u))
$(eval $(call BOARD_MCU_template,midi-router-x4,atxmega128a4u))
$(eval $(call BOARD_MCU_template,midi-router-x4-flat,atxmega128a4u))
$(eval $(call BOARD_MCU_template,midi-router-x7,atxmega128a1u))
+$(eval $(call BOARD_MCU_template,midi-router-x7-rack,atxmega128a1u))
diff --git a/firmware/midi-router-x7-rack/conf_usb.h b/firmware/midi-router-x7-rack/conf_usb.h
new file mode 100644
index 0000000..880a69d
--- /dev/null
+++ b/firmware/midi-router-x7-rack/conf_usb.h
@@ -0,0 +1,237 @@
+/**
+ * \file
+ *
+ * \brief USB configuration file
+ *
+ * Copyright (c) 2011-2018 Microchip Technology Inc. and its subsidiaries.
+ *
+ * \asf_license_start
+ *
+ * \page License
+ *
+ * Subject to your compliance with these terms, you may use Microchip
+ * software and any derivatives exclusively with Microchip products.
+ * It is your responsibility to comply with third party license terms applicable
+ * to your use of third party software (including open source software) that
+ * may accompany Microchip software.
+ *
+ * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES,
+ * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE,
+ * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY,
+ * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE
+ * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL
+ * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE
+ * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE
+ * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT
+ * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY
+ * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY,
+ * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE.
+ *
+ * \asf_license_stop
+ *
+ */
+/*
+ * Support and FAQ: visit Microchip Support
+ */
+
+#ifndef _CONF_USB_H_
+#define _CONF_USB_H_
+
+#include "compiler.h"
+
+/**
+ * USB Device Configuration
+ * @{
+ */
+
+/* See https://raw.githubusercontent.com/arduino/ArduinoISP/master/usbdrv/USB-IDs-for-free.txt */
+
+//! Device definition (mandatory)
+#define USB_DEVICE_VENDOR_ID 0x16c0
+#define USB_DEVICE_PRODUCT_ID 0x05e4
+#define USB_DEVICE_MAJOR_VERSION 1
+#define USB_DEVICE_MINOR_VERSION 0
+#define USB_DEVICE_POWER 100 // Consumption on Vbus line (mA)
+#define USB_DEVICE_ATTR (USB_CONFIG_ATTR_BUS_POWERED)
+// (USB_CONFIG_ATTR_SELF_POWERED)
+// (USB_CONFIG_ATTR_REMOTE_WAKEUP|USB_CONFIG_ATTR_SELF_POWERED)
+// (USB_CONFIG_ATTR_REMOTE_WAKEUP|USB_CONFIG_ATTR_BUS_POWERED)
+
+//! USB Device string definitions (Optional)
+#define USB_DEVICE_MANUFACTURE_NAME "MVR-Electronic.ru"
+#define USB_DEVICE_PRODUCT_NAME "MIDI Router x7"
+#define USB_DEVICE_GET_SERIAL_NAME_POINTER main_serial_name()
+#define USB_DEVICE_GET_SERIAL_NAME_LENGTH 16 /* 2 * sizeof(struct nvm_device_serial) */
+
+/**
+ * USB Device Callbacks definitions (Optional)
+ * @{
+ */
+#define UDC_VBUS_EVENT(b_vbus_high)
+#define UDC_SOF_EVENT() main_sof_action()
+#define UDC_SUSPEND_EVENT() main_suspend_action()
+#define UDC_RESUME_EVENT() main_resume_action()
+//! Mandatory when USB_DEVICE_ATTR authorizes remote wakeup feature
+// #define UDC_REMOTEWAKEUP_ENABLE() user_callback_remotewakeup_enable()
+// extern void user_callback_remotewakeup_enable(void);
+// #define UDC_REMOTEWAKEUP_DISABLE() user_callback_remotewakeup_disable()
+// extern void user_callback_remotewakeup_disable(void);
+//! When a extra string descriptor must be supported
+//! other than manufacturer, product and serial string
+//# d efine UDC_GET_EXTRA_STRING() main_extra_string()
+//@}
+
+/**
+ * USB Device low level configuration
+ * When only one interface is used, these configurations are defined by the class module.
+ * For composite device, these configuration must be defined here
+ * @{
+ */
+//! Control endpoint size
+#define USB_DEVICE_EP_CTRL_SIZE 64
+
+//! Four interfaces for this device (CDC COM + CDC DATA + AUDIO CONTROL + MIDI STREAMING)
+#define USB_DEVICE_NB_INTERFACE 4
+
+//! 5 endpoints used by CDC and MIDI interfaces
+// (1 | USB_EP_DIR_IN) // CDC Notify endpoint
+// (2 | USB_EP_DIR_IN) // CDC TX
+// (3 | USB_EP_DIR_OUT) // CDC RX
+// (4 | USB_EP_DIR_OUT) // MIDI OUT
+// (5 | USB_EP_DIR_IN) // MIDI IN
+#define USB_DEVICE_MAX_EP 5
+//@}
+
+//@}
+
+
+/**
+ * USB Interface Configuration
+ * @{
+ */
+/**
+ * Configuration of CDC interface
+ * @{
+ */
+
+//! Define USB communication port
+#define UDI_CDC_PORT_NB 1
+
+//! Interface callback definition
+#define UDI_CDC_ENABLE_EXT(port) main_cdc_enable(port)
+#define UDI_CDC_DISABLE_EXT(port) main_cdc_disable(port)
+#define UDI_CDC_RX_NOTIFY(port) main_cdc_rx_notify(port)
+#define UDI_CDC_TX_EMPTY_NOTIFY(port)
+#define UDI_CDC_SET_CODING_EXT(port,cfg) main_cdc_config(port,cfg)
+#define UDI_CDC_SET_DTR_EXT(port,set) main_cdc_set_dtr(port,set)
+#define UDI_CDC_SET_RTS_EXT(port,set)
+
+//! Define it when the transfer CDC Device to Host is a low rate (<512000 bauds)
+//! to reduce CDC buffers size
+//#define UDI_CDC_LOW_RATE
+
+//! Default configuration of communication port
+#define UDI_CDC_DEFAULT_RATE 115200
+#define UDI_CDC_DEFAULT_STOPBITS CDC_STOP_BITS_1
+#define UDI_CDC_DEFAULT_PARITY CDC_PAR_NONE
+#define UDI_CDC_DEFAULT_DATABITS 8
+
+//! Enable id string of interface to add an extra USB string
+//#define UDI_CDC_IAD_STRING_ID 4
+
+/**
+ * USB CDC low level configuration
+ * In standalone these configurations are defined by the CDC module.
+ * For composite device, these configuration must be defined here
+ * @{
+ */
+//! Endpoint numbers definition
+#define UDI_CDC_COMM_EP_0 (1 | USB_EP_DIR_IN) // Notify endpoint
+#define UDI_CDC_DATA_EP_IN_0 (2 | USB_EP_DIR_IN) // TX
+#define UDI_CDC_DATA_EP_OUT_0 (3 | USB_EP_DIR_OUT)// RX
+
+//! Interface numbers
+#define UDI_CDC_COMM_IFACE_NUMBER_0 0
+#define UDI_CDC_DATA_IFACE_NUMBER_0 1
+//@}
+//@}
+
+
+/**
+ * Configuration of MIDI interface
+ * @{
+ */
+
+/**
+ * USB MIDI low level configuration
+ * In standalone these configurations are defined by the MIDI module.
+ * For composite device, these configuration must be defined here
+ * @{
+ */
+//! Endpoint numbers definition
+#define UDI_MIDI_EP_OUT (4 | USB_EP_DIR_OUT)
+#define UDI_MIDI_EP_IN (5 | USB_EP_DIR_IN)
+
+//! Interface number
+#define UDI_AUDIO_IFACE_NUMBER 2
+#define UDI_MIDI_IFACE_NUMBER 3
+//@}
+//@}
+
+//@}
+
+/**
+ * Description of Composite Device
+ * @{
+ */
+//! USB Interfaces descriptor structure
+#define UDI_COMPOSITE_DESC_T \
+ usb_iad_desc_t udi_cdc_iad; \
+ udi_cdc_comm_desc_t udi_cdc_comm; \
+ udi_cdc_data_desc_t udi_cdc_data; \
+ usb_iad_desc_t udi_midi_iad; \
+ udi_audio_ctrl_desc_t udi_audio_ctrl; \
+ udi_midi_desc7_t udi_midi
+
+//! USB Interfaces descriptor value for Full Speed
+#define UDI_COMPOSITE_DESC_FS \
+ .udi_cdc_iad = UDI_CDC_IAD_DESC_0, \
+ .udi_cdc_comm = UDI_CDC_COMM_DESC_0, \
+ .udi_cdc_data = UDI_CDC_DATA_DESC_0_FS, \
+ .udi_midi_iad = UDI_MIDI_IAD_DESC, \
+ .udi_audio_ctrl = UDI_AUDIO_CTRL_DESC, \
+ .udi_midi = UDI_MIDI_DESC7
+
+//! USB Interfaces descriptor value for High Speed
+#define UDI_COMPOSITE_DESC_HS \
+ .udi_cdc_iad = UDI_CDC_IAD_DESC_0, \
+ .udi_cdc_comm = UDI_CDC_COMM_DESC_0, \
+ .udi_cdc_data = UDI_CDC_DATA_DESC_0_HS, \
+ .udi_midi_iad = UDI_MIDI_IAD_DESC, \
+ .udi_audio_ctrl = UDI_AUDIO_CTRL_DESC, \
+ .udi_midi = UDI_MIDI_DESC7
+
+//! USB Interface APIs
+#define UDI_COMPOSITE_API \
+ &udi_api_cdc_comm, \
+ &udi_api_cdc_data, \
+ &udi_api_audio_ctrl, \
+ &udi_api_midi
+
+// &udi_api_msc
+//@}
+
+#define MIDI_PORTS 7
+
+/**
+ * USB Device Driver Configuration
+ * @{
+ */
+//@}
+
+//! The includes of classes and other headers must be done at the end of this file to avoid compile error
+#include "udi_cdc.h"
+#include "udi_midi.h"
+#include "main.h"
+
+#endif // _CONF_USB_H_
diff --git a/firmware/midi-router-x7-rack/led.h b/firmware/midi-router-x7-rack/led.h
new file mode 100644
index 0000000..d36e737
--- /dev/null
+++ b/firmware/midi-router-x7-rack/led.h
@@ -0,0 +1,33 @@
+#pragma once
+
+#include
+
+using led_pwr = artl::digital_out;
+
+using led_txusb = artl::digital_out;
+using led_rxusb = artl::digital_out;
+
+using led_rx0 = artl::digital_out;
+using led_rx1 = artl::digital_out;
+using led_rx2 = artl::digital_out;
+using led_rx3 = artl::digital_out;
+using led_rx4 = artl::digital_out;
+using led_rx5 = artl::digital_out;
+using led_rx6 = artl::digital_out;
+
+using led_tx0 = artl::digital_out;
+using led_tx1 = artl::digital_out;
+using led_tx2 = artl::digital_out;
+using led_tx3 = artl::digital_out;
+using led_tx4 = artl::digital_out;
+using led_tx5 = artl::digital_out;
+using led_tx6 = artl::digital_out;
+
+using led_mode0 = artl::digital_out;
+using led_mode1 = artl::digital_out;
+using led_mode2 = artl::digital_out;
+using led_mode3 = artl::digital_out;
+using led_mode4 = artl::digital_out;
+using led_mode_btn = artl::digital_out;
+
+using oen = artl::digital_out;
diff --git a/firmware/midi-router-x7-rack/midi.cpp b/firmware/midi-router-x7-rack/midi.cpp
new file mode 100644
index 0000000..1052598
--- /dev/null
+++ b/firmware/midi-router-x7-rack/midi.cpp
@@ -0,0 +1,199 @@
+
+#include
+#include
+#include
+
+namespace {
+
+using uart_c0 = uart_t, tx_midi_traits<6> >;
+template<> uart_c0::tx_ring_t uart_c0::tx_ring = {};
+template<> uint8_t uart_c0::want_write = 0;
+
+using uart_c1 = uart_t, tx_midi_traits<5> >;
+template<> uart_c1::tx_ring_t uart_c1::tx_ring = {};
+template<> uint8_t uart_c1::want_write = 0;
+
+using uart_d0 = uart_t, tx_midi_traits<4> >;
+template<> uart_d0::tx_ring_t uart_d0::tx_ring = {};
+template<> uint8_t uart_d0::want_write = 0;
+
+using uart_e0 = uart_t, tx_midi_traits<3> >;
+template<> uart_e0::tx_ring_t uart_e0::tx_ring = {};
+template<> uint8_t uart_e0::want_write = 0;
+
+using uart_e1 = uart_t, tx_midi_traits<2> >;
+template<> uart_e1::tx_ring_t uart_e1::tx_ring = {};
+template<> uint8_t uart_e1::want_write = 0;
+
+using uart_f0 = uart_t, tx_midi_traits<1> >;
+template<> uart_f0::tx_ring_t uart_f0::tx_ring = {};
+template<> uint8_t uart_f0::want_write = 0;
+
+using uart_f1 = uart_t, tx_midi_traits<0> >;
+template<> uart_f1::tx_ring_t uart_f1::tx_ring = {};
+template<> uint8_t uart_f1::want_write = 0;
+
+}
+
+namespace midi {
+
+void init() {
+ PORTC.INT0MASK = 0;
+ PORTC.INTCTRL = 0;
+
+ uart_c0::setup();
+ uart_c1::setup();
+ uart_d0::setup();
+ uart_e0::setup();
+ uart_e1::setup();
+ uart_f0::setup();
+ uart_f1::setup();
+
+ uart_c0::rxc_int_hi();
+ uart_c1::rxc_int_hi();
+ uart_d0::rxc_int_hi();
+ uart_e0::rxc_int_hi();
+ uart_e1::rxc_int_hi();
+ uart_f0::rxc_int_hi();
+ uart_f1::rxc_int_hi();
+}
+
+void splitter() {
+ uart_c0::disable();
+ uart_c1::disable();
+ uart_d0::disable();
+ uart_e0::disable();
+ uart_e1::disable();
+ uart_f0::disable();
+ uart_f1::disable();
+
+ uart_c0::port_traits::setup_pins();
+ uart_c1::port_traits::setup_pins();
+ uart_d0::port_traits::setup_pins();
+ uart_e0::port_traits::setup_pins();
+ uart_e1::port_traits::setup_pins();
+ uart_f0::port_traits::setup_pins();
+ uart_f1::port_traits::setup_pins();
+
+ PORTC.INT0MASK = (1 << 2);
+ PORTC.INTCTRL = PORT_INT0LVL_HI_gc;
+}
+
+uint8_t send(uint8_t port, const uint8_t *buf, uint8_t size) {
+ switch (port) {
+ case 6: return uart_c0::write_buf(buf, size);
+ case 5: return uart_c1::write_buf(buf, size);
+ case 4: return uart_d0::write_buf(buf, size);
+ case 3: return uart_e0::write_buf(buf, size);
+ case 2: return uart_e1::write_buf(buf, size);
+ case 1: return uart_f0::write_buf(buf, size);
+ case 0: return uart_f1::write_buf(buf, size);
+ }
+
+ return 0;
+}
+
+}
+
+ISR(USARTC0_RXC_vect)
+{
+ uart_c0::on_rxc_int();
+}
+
+ISR(USARTC0_DRE_vect)
+{
+ uart_c0::on_dre_int();
+}
+
+
+ISR(USARTC1_RXC_vect)
+{
+ uart_c1::on_rxc_int();
+}
+
+ISR(USARTC1_DRE_vect)
+{
+ uart_c1::on_dre_int();
+}
+
+
+ISR(USARTD0_RXC_vect)
+{
+ uart_d0::on_rxc_int();
+}
+
+ISR(USARTD0_DRE_vect)
+{
+ uart_d0::on_dre_int();
+}
+
+ISR(PORTC_INT0_vect)
+{
+ crit_sec cs;
+
+ bool v = uart_c0::rx::read();
+
+ if (v) {
+ uart_c0::tx::high();
+ uart_c1::tx::high();
+ uart_d0::tx::high();
+ uart_e0::tx::high();
+ uart_e1::tx::high();
+ uart_f0::tx::high();
+ uart_f1::tx::high();
+ } else {
+ uart_c0::tx::low();
+ uart_c1::tx::low();
+ uart_d0::tx::low();
+ uart_e0::tx::low();
+ uart_e1::tx::low();
+ uart_f0::tx::low();
+ uart_f1::tx::low();
+
+ midi::rx_ready = 1;
+ }
+}
+
+
+ISR(USARTE0_RXC_vect)
+{
+ uart_e0::on_rxc_int();
+}
+
+ISR(USARTE0_DRE_vect)
+{
+ uart_e0::on_dre_int();
+}
+
+
+ISR(USARTE1_RXC_vect)
+{
+ uart_e1::on_rxc_int();
+}
+
+ISR(USARTE1_DRE_vect)
+{
+ uart_e1::on_dre_int();
+}
+
+
+ISR(USARTF0_RXC_vect)
+{
+ uart_f0::on_rxc_int();
+}
+
+ISR(USARTF0_DRE_vect)
+{
+ uart_f0::on_dre_int();
+}
+
+
+ISR(USARTF1_RXC_vect)
+{
+ uart_f1::on_rxc_int();
+}
+
+ISR(USARTF1_DRE_vect)
+{
+ uart_f1::on_dre_int();
+}
diff --git a/firmware/midi-router-x7-rack/ui.cpp b/firmware/midi-router-x7-rack/ui.cpp
new file mode 100644
index 0000000..5a2034d
--- /dev/null
+++ b/firmware/midi-router-x7-rack/ui.cpp
@@ -0,0 +1,274 @@
+/**
+ * \file
+ *
+ * \brief User Interface
+ *
+ * Copyright (c) 2011-2018 Microchip Technology Inc. and its subsidiaries.
+ *
+ * \asf_license_start
+ *
+ * \page License
+ *
+ * Subject to your compliance with these terms, you may use Microchip
+ * software and any derivatives exclusively with Microchip products.
+ * It is your responsibility to comply with third party license terms applicable
+ * to your use of third party software (including open source software) that
+ * may accompany Microchip software.
+ *
+ * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES,
+ * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE,
+ * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY,
+ * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE
+ * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL
+ * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE
+ * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE
+ * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT
+ * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY
+ * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY,
+ * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE.
+ *
+ * \asf_license_stop
+ *
+ */
+/*
+ * Support and FAQ: visit Microchip Support
+ */
+
+#include
+
+#include "led.h"
+#include
+#include
+#include
+#include
+
+namespace {
+
+using btn_in = artl::digital_in;
+
+artl::button<> btn;
+
+bool led_test = false;
+
+}
+
+namespace ui {
+
+void init(void)
+{
+ led_pwr::setup();
+ led_txusb::setup();
+ led_rxusb::setup();
+ led_rx0::setup();
+ led_rx1::setup();
+ led_rx2::setup();
+ led_rx3::setup();
+ led_rx4::setup();
+ led_rx5::setup();
+ led_rx6::setup();
+ led_tx0::setup();
+ led_tx1::setup();
+ led_tx2::setup();
+ led_tx3::setup();
+ led_tx4::setup();
+ led_tx5::setup();
+ led_tx6::setup();
+
+ oen::setup();
+
+ btn_in::setup();
+
+ TCD2.INTCTRLA |= TC2_HUNFINTLVL_MED_gc; // enable HIGH underflow interrupt, pri level 2 (see 15.10.5 in AU manual)
+}
+
+void powerdown(void)
+{
+ TCD2.INTCTRLA &= ~TC2_HUNFINTLVL_MED_gc; // disable HIGH underflow interrupt, pri level 2 (see 15.10.5 in AU manual)
+
+ led_pwr::low();
+ led_txusb::low();
+ led_rxusb::low();
+
+ led_rx0::low();
+ led_rx1::low();
+ led_rx2::low();
+ led_rx3::low();
+ led_rx4::low();
+ led_rx5::low();
+ led_rx6::low();
+
+ led_tx0::low();
+ led_tx1::low();
+ led_tx2::low();
+ led_tx3::low();
+ led_tx4::low();
+ led_tx5::low();
+ led_tx6::low();
+}
+
+void wakeup(void)
+{
+ TCD2.INTCTRLA |= TC2_HUNFINTLVL_MED_gc; // enable HIGH underflow interrupt, pri level 2 (see 15.10.5 in AU manual)
+}
+
+bool btn_update(unsigned long t) {
+ return btn.update(!btn_in::read(), t);
+}
+
+bool btn_down() {
+ return btn.down();
+}
+
+void usb_midi_disable() {
+ usb_midi_enabled = false;
+
+ rx_blink_state[USB_LED_ID].stop();
+ led_rxusb::high();
+
+ tx_blink_state[USB_LED_ID].stop();
+ led_txusb::high();
+}
+
+void led_test_enable() {
+ if (led_test) return;
+
+ led_test = true;
+
+ led_pwr::high();
+ led_txusb::high();
+ led_rxusb::high();
+
+ led_rx0::high();
+ led_rx1::high();
+ led_rx2::high();
+ led_rx3::high();
+ led_rx4::high();
+ led_rx5::high();
+ led_rx6::high();
+
+ led_tx0::high();
+ led_tx1::high();
+ led_tx2::high();
+ led_tx3::high();
+ led_tx4::high();
+ led_tx5::high();
+ led_tx6::high();
+}
+
+void led_test_disable() {
+ if (!led_test) return;
+
+ led_test = false;
+
+ if (!btn.down()) {
+ pulse_state.force_write();
+ } else {
+ rst_blink_state.force_write();
+ }
+
+ rx_blink_state[0].force_write();
+ rx_blink_state[1].force_write();
+ rx_blink_state[2].force_write();
+ rx_blink_state[3].force_write();
+ rx_blink_state[4].force_write();
+ rx_blink_state[5].force_write();
+ rx_blink_state[6].force_write();
+
+ tx_blink_state[0].force_write();
+ tx_blink_state[1].force_write();
+ tx_blink_state[2].force_write();
+ tx_blink_state[3].force_write();
+ tx_blink_state[4].force_write();
+ tx_blink_state[5].force_write();
+ tx_blink_state[6].force_write();
+
+ if (usb_midi_enabled) {
+ rx_blink_state[USB_LED_ID].force_write();
+ tx_blink_state[USB_LED_ID].force_write();
+ } else {
+ led_rxusb::high();
+ led_txusb::high();
+ }
+}
+
+void startup_animation() {
+ const unsigned long frame_delay = 150;
+ unsigned long t = millis();
+
+ artl::timer<> next_frame;
+ next_frame.schedule(t + frame_delay);
+ uint8_t frame_no = 0;
+
+ while (true) {
+ sleepmgr_enter_sleep();
+
+ if (!tc_flag) continue;
+
+ tc_flag = 0;
+
+ t = millis();
+
+ if (!next_frame.update(t)) continue;
+
+ ++frame_no;
+
+ switch (frame_no) {
+ case 1: rx_blink(7); tx_blink(7); break;
+ case 2: rx_blink(0); tx_blink(6); break;
+ case 3: rx_blink(1); tx_blink(5); break;
+ case 4: rx_blink(2); tx_blink(4); break;
+ case 5: rx_blink(3); tx_blink(3); break;
+ case 6: rx_blink(4); tx_blink(2); break;
+ case 7: rx_blink(5); tx_blink(1); break;
+ case 8: rx_blink(6); tx_blink(0); break;
+ case 9: /* blank frame */; break;
+ }
+
+ if (frame_no < 9) {
+ next_frame.schedule(t + frame_delay);
+ } else {
+ break;
+ }
+ }
+
+ if (!usb_midi_enabled) { usb_midi_disable(); }
+}
+
+}
+
+using namespace ui;
+
+ISR(TCD2_HUNF_vect)
+{
+ if (led_test) {
+ if (btn.down()) {
+ rst_blink_state.write();
+ }
+
+ return;
+ }
+
+ if (!btn.down()) {
+ pulse_state.write();
+ } else {
+ rst_blink_state.write();
+ }
+
+ rx_blink_state[0].write();
+ rx_blink_state[1].write();
+ rx_blink_state[2].write();
+ rx_blink_state[3].write();
+ rx_blink_state[4].write();
+ rx_blink_state[5].write();
+ rx_blink_state[6].write();
+ rx_blink_state[7].write();
+
+ tx_blink_state[0].write();
+ tx_blink_state[1].write();
+ tx_blink_state[2].write();
+ tx_blink_state[3].write();
+ tx_blink_state[4].write();
+ tx_blink_state[5].write();
+ tx_blink_state[6].write();
+ tx_blink_state[7].write();
+}