You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

184 lines
4.7KB

  1. // Copyright 2011 Olivier Gillet.
  2. //
  3. // This program is free software: you can redistribute it and/or modify
  4. // it under the terms of the GNU General Public License as published by
  5. // the Free Software Foundation, either version 3 of the License, or
  6. // (at your option) any later version.
  7. // This program is distributed in the hope that it will be useful,
  8. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. // GNU General Public License for more details.
  11. // You should have received a copy of the GNU General Public License
  12. // along with this program. If not, see <http://www.gnu.org/licenses/>.
  13. //
  14. // -----------------------------------------------------------------------------
  15. //
  16. // Bootloader supporting MIDI SysEx update.
  17. //
  18. // Caveat: assumes the firmware flashing is always done from first to last
  19. // block, in increasing order. Random access flashing is not supported!
  20. #include "avrlibx/io/gpio.h"
  21. #include "avrlibx/io/usart.h"
  22. #include "avrlibx/system/init.h"
  23. #include "avrlibx/system/time.h"
  24. #include "avrlibx/third_party/sp_driver/sp_driver.h"
  25. #include "edges/hardware_config.h"
  26. using namespace avrlibx;
  27. using namespace edges;
  28. MidiIO midi;
  29. Leds leds;
  30. Switches switches;
  31. uint16_t page = 0;
  32. uint8_t rx_buffer[APP_SECTION_PAGE_SIZE + 1];
  33. typedef void (*MainEntryPoint)(void) __attribute__ ((noreturn));
  34. MainEntryPoint main_entry_point = (MainEntryPoint)0x0000;
  35. inline void Init() {
  36. SysInit();
  37. leds.set_direction(OUTPUT);
  38. switches.set_direction(INPUT);
  39. switches.set_mode(PORT_MODE_PULL_UP);
  40. midi.Init();
  41. }
  42. void WriteBufferToFlash() {
  43. SP_LoadFlashPage(rx_buffer);
  44. SP_EraseWriteApplicationPage(page);
  45. SP_WaitForSPM();
  46. NVM_CMD = NVM_CMD_NO_OPERATION_gc;
  47. }
  48. void FlashLedsOk() {
  49. for (uint8_t i = 0; i < 8; ++i) {
  50. leds.Write(0xf);
  51. ConstantDelay(50);
  52. leds.Write(8);
  53. ConstantDelay(50);
  54. }
  55. }
  56. void FlashLedsError() {
  57. leds.Write(0);
  58. for (uint8_t i = 0; i < 5; ++i) {
  59. ConstantDelay(100);
  60. leds.Toggle();
  61. }
  62. }
  63. static const uint8_t sysex_header[] = {
  64. 0xf0, // <SysEx>
  65. 0x00, 0x21, 0x02, // Mutable instruments manufacturer id.
  66. 0x00, 0x0a, // Product ID for "any product".
  67. };
  68. enum SysExReceptionState {
  69. MATCHING_HEADER = 0,
  70. READING_COMMAND = 1,
  71. READING_DATA = 2,
  72. };
  73. inline void MidiLoop() {
  74. uint8_t byte;
  75. uint16_t bytes_read = 0;
  76. uint16_t rx_buffer_index;
  77. uint8_t state = MATCHING_HEADER;
  78. uint8_t checksum;
  79. uint8_t sysex_commands[2];
  80. uint8_t page_byte = 0;
  81. midi.Init();
  82. page = 0;
  83. while (1) {
  84. leds.Write(8 | (4 >> ((page_byte + 3) & 0x3)));
  85. byte = midi.Read();
  86. // In case we see a realtime message in the stream, safely ignore it.
  87. if (byte > 0xf0 && byte != 0xf7) {
  88. continue;
  89. }
  90. switch (state) {
  91. case MATCHING_HEADER:
  92. if (byte == sysex_header[bytes_read]) {
  93. ++bytes_read;
  94. if (bytes_read == sizeof(sysex_header)) {
  95. bytes_read = 0;
  96. state = READING_COMMAND;
  97. }
  98. } else {
  99. bytes_read = 0;
  100. }
  101. break;
  102. case READING_COMMAND:
  103. if (byte < 0x80) {
  104. sysex_commands[bytes_read++] = byte;
  105. if (bytes_read == 2) {
  106. bytes_read = 0;
  107. rx_buffer_index = 0;
  108. checksum = 0;
  109. state = READING_DATA;
  110. }
  111. } else {
  112. state = MATCHING_HEADER;
  113. bytes_read = 0;
  114. }
  115. break;
  116. case READING_DATA:
  117. if (byte < 0x80) {
  118. if (bytes_read & 1) {
  119. rx_buffer[rx_buffer_index] |= byte & 0xf;
  120. if (rx_buffer_index < APP_SECTION_PAGE_SIZE) {
  121. checksum += rx_buffer[rx_buffer_index];
  122. }
  123. ++rx_buffer_index;
  124. } else {
  125. rx_buffer[rx_buffer_index] = (byte << 4);
  126. }
  127. ++bytes_read;
  128. } else if (byte == 0xf7) {
  129. if (sysex_commands[0] == 0x7f &&
  130. sysex_commands[1] == 0x00 &&
  131. bytes_read == 0) {
  132. // Reset.
  133. return;
  134. } else if (rx_buffer_index == APP_SECTION_PAGE_SIZE + 1 &&
  135. sysex_commands[0] == 0x7e &&
  136. sysex_commands[1] == 0x00 &&
  137. rx_buffer[rx_buffer_index - 1] == checksum) {
  138. // Block write.
  139. WriteBufferToFlash();
  140. page += APP_SECTION_PAGE_SIZE;
  141. ++page_byte;
  142. } else {
  143. FlashLedsError();
  144. }
  145. state = MATCHING_HEADER;
  146. bytes_read = 0;
  147. }
  148. break;
  149. }
  150. }
  151. }
  152. int main(void) {
  153. Init();
  154. ConstantDelay(25);
  155. if (!(switches.Read() & 1)) {
  156. FlashLedsOk();
  157. MidiLoop();
  158. FlashLedsOk();
  159. }
  160. SP_LockSPM();
  161. EIND = 0x00;
  162. main_entry_point();
  163. }