|
- // Copyright 2011 Olivier Gillet.
- //
- // This program is free software: you can redistribute it and/or modify
- // it under the terms of the GNU General Public License as published by
- // the Free Software Foundation, either version 3 of the License, or
- // (at your option) any later version.
- // This program is distributed in the hope that it will be useful,
- // but WITHOUT ANY WARRANTY; without even the implied warranty of
- // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- // GNU General Public License for more details.
- // You should have received a copy of the GNU General Public License
- // along with this program. If not, see <http://www.gnu.org/licenses/>.
- //
- // -----------------------------------------------------------------------------
- //
- // Bootloader supporting MIDI SysEx update.
- //
- // Caveat: assumes the firmware flashing is always done from first to last
- // block, in increasing order. Random access flashing is not supported!
-
- #include "avrlibx/io/gpio.h"
- #include "avrlibx/io/usart.h"
- #include "avrlibx/system/init.h"
- #include "avrlibx/system/time.h"
-
- #include "avrlibx/third_party/sp_driver/sp_driver.h"
-
- #include "edges/hardware_config.h"
-
- using namespace avrlibx;
- using namespace edges;
-
- MidiIO midi;
- Leds leds;
- Switches switches;
-
- uint16_t page = 0;
- uint8_t rx_buffer[APP_SECTION_PAGE_SIZE + 1];
-
- typedef void (*MainEntryPoint)(void) __attribute__ ((noreturn));
- MainEntryPoint main_entry_point = (MainEntryPoint)0x0000;
-
- inline void Init() {
- SysInit();
- leds.set_direction(OUTPUT);
- switches.set_direction(INPUT);
- switches.set_mode(PORT_MODE_PULL_UP);
- midi.Init();
- }
-
- void WriteBufferToFlash() {
- SP_LoadFlashPage(rx_buffer);
- SP_EraseWriteApplicationPage(page);
- SP_WaitForSPM();
-
- NVM_CMD = NVM_CMD_NO_OPERATION_gc;
- }
-
- void FlashLedsOk() {
- for (uint8_t i = 0; i < 8; ++i) {
- leds.Write(0xf);
- ConstantDelay(50);
- leds.Write(8);
- ConstantDelay(50);
- }
- }
-
- void FlashLedsError() {
- leds.Write(0);
- for (uint8_t i = 0; i < 5; ++i) {
- ConstantDelay(100);
- leds.Toggle();
- }
- }
-
- static const uint8_t sysex_header[] = {
- 0xf0, // <SysEx>
- 0x00, 0x21, 0x02, // Mutable instruments manufacturer id.
- 0x00, 0x0a, // Product ID for "any product".
- };
-
- enum SysExReceptionState {
- MATCHING_HEADER = 0,
- READING_COMMAND = 1,
- READING_DATA = 2,
- };
-
- inline void MidiLoop() {
- uint8_t byte;
- uint16_t bytes_read = 0;
- uint16_t rx_buffer_index;
- uint8_t state = MATCHING_HEADER;
- uint8_t checksum;
- uint8_t sysex_commands[2];
- uint8_t page_byte = 0;
-
- midi.Init();
- page = 0;
-
- while (1) {
- leds.Write(8 | (4 >> ((page_byte + 3) & 0x3)));
- byte = midi.Read();
- // In case we see a realtime message in the stream, safely ignore it.
- if (byte > 0xf0 && byte != 0xf7) {
- continue;
- }
- switch (state) {
- case MATCHING_HEADER:
- if (byte == sysex_header[bytes_read]) {
- ++bytes_read;
- if (bytes_read == sizeof(sysex_header)) {
- bytes_read = 0;
- state = READING_COMMAND;
- }
- } else {
- bytes_read = 0;
- }
- break;
-
- case READING_COMMAND:
- if (byte < 0x80) {
- sysex_commands[bytes_read++] = byte;
- if (bytes_read == 2) {
- bytes_read = 0;
- rx_buffer_index = 0;
- checksum = 0;
- state = READING_DATA;
- }
- } else {
- state = MATCHING_HEADER;
- bytes_read = 0;
- }
- break;
-
- case READING_DATA:
- if (byte < 0x80) {
- if (bytes_read & 1) {
- rx_buffer[rx_buffer_index] |= byte & 0xf;
- if (rx_buffer_index < APP_SECTION_PAGE_SIZE) {
- checksum += rx_buffer[rx_buffer_index];
- }
- ++rx_buffer_index;
- } else {
- rx_buffer[rx_buffer_index] = (byte << 4);
- }
- ++bytes_read;
- } else if (byte == 0xf7) {
- if (sysex_commands[0] == 0x7f &&
- sysex_commands[1] == 0x00 &&
- bytes_read == 0) {
- // Reset.
- return;
- } else if (rx_buffer_index == APP_SECTION_PAGE_SIZE + 1 &&
- sysex_commands[0] == 0x7e &&
- sysex_commands[1] == 0x00 &&
- rx_buffer[rx_buffer_index - 1] == checksum) {
- // Block write.
- WriteBufferToFlash();
- page += APP_SECTION_PAGE_SIZE;
- ++page_byte;
- } else {
- FlashLedsError();
- }
- state = MATCHING_HEADER;
- bytes_read = 0;
- }
- break;
- }
- }
- }
-
- int main(void) {
- Init();
- ConstantDelay(25);
- if (!(switches.Read() & 1)) {
- FlashLedsOk();
- MidiLoop();
- FlashLedsOk();
- }
- SP_LockSPM();
- EIND = 0x00;
- main_entry_point();
- }
|