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(); +}