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.

251 lines
6.4KB

  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 <avr/boot.h>
  21. #include <avr/pgmspace.h>
  22. #include <avr/delay.h>
  23. #include "avrlib/gpio.h"
  24. #include "avrlib/serial.h"
  25. #include "avrlib/watchdog_timer.h"
  26. #include "avr_audio_bootloader/crc32.h"
  27. #include "avr_audio_bootloader/fsk/decoder.h"
  28. #include "grids/hardware_config.h"
  29. using namespace avrlib;
  30. using namespace grids;
  31. using namespace avr_audio_bootloader;
  32. MidiInput midi;
  33. Inputs inputs;
  34. Leds leds;
  35. Decoder decoder;
  36. uint16_t page = 0;
  37. uint8_t rx_buffer[SPM_PAGESIZE + 4];
  38. void (*main_entry_point)(void) = 0x0000;
  39. inline void Init() {
  40. cli();
  41. leds.set_mode(DIGITAL_OUTPUT);
  42. inputs.set_mode(DIGITAL_INPUT);
  43. inputs.EnablePullUpResistors();
  44. }
  45. void WriteBufferToFlash() {
  46. uint16_t i;
  47. const uint8_t* p = rx_buffer;
  48. eeprom_busy_wait();
  49. boot_page_erase(page);
  50. boot_spm_busy_wait();
  51. for (i = 0; i < SPM_PAGESIZE; i += 2) {
  52. uint16_t w = *p++;
  53. w |= (*p++) << 8;
  54. boot_page_fill(page + i, w);
  55. }
  56. boot_page_write(page);
  57. boot_spm_busy_wait();
  58. boot_rww_enable();
  59. }
  60. void FlashLedsOk() {
  61. for (uint8_t i = 0; i < 8; ++i) {
  62. _delay_ms(50);
  63. leds.Write(0xf);
  64. _delay_ms(50);
  65. leds.Write(LED_CLOCK);
  66. }
  67. }
  68. void FlashLedsError() {
  69. for (uint8_t i = 0; i < 5; ++i) {
  70. _delay_ms(120);
  71. leds.Write(0xf);
  72. _delay_ms(120);
  73. leds.Write(0x0);
  74. }
  75. }
  76. // MIDI loader -----------------------------------------------------------------
  77. static const uint8_t sysex_header[] = {
  78. 0xf0, // <SysEx>
  79. 0x00, 0x21, 0x02, // Mutable instruments manufacturer id.
  80. 0x00, 0x09, // Product ID for Grids.
  81. };
  82. enum SysExReceptionState {
  83. MATCHING_HEADER = 0,
  84. READING_COMMAND = 1,
  85. READING_DATA = 2,
  86. };
  87. inline void LoaderLoop() {
  88. uint8_t byte;
  89. uint16_t bytes_read = 0;
  90. uint16_t rx_buffer_index;
  91. uint8_t state = MATCHING_HEADER;
  92. uint8_t checksum;
  93. uint8_t sysex_commands[2];
  94. uint8_t status = 0;
  95. uint8_t page_byte = 0;
  96. midi.Init();
  97. decoder.Init();
  98. decoder.Sync();
  99. decoder.set_packet_destination(rx_buffer);
  100. page = 0;
  101. TCCR2A = 0;
  102. TCCR2B = 2;
  103. while (1) {
  104. leds.Write(LED_CLOCK | (LED_BD >> ((page_byte + 3) & 0x3)));
  105. // Sample the clock input at 20kHz and feed to the FSK decoder.
  106. if (TCNT2 >= (F_CPU / 8 / 40000 - 1)) {
  107. TCNT2 = 0;
  108. switch (decoder.PushSample(inputs.Read() & INPUT_CLOCK)) {
  109. case DECODER_STATE_ERROR_SYNC:
  110. FlashLedsError();
  111. decoder.Sync();
  112. break;
  113. case DECODER_STATE_END_OF_TRANSMISSION:
  114. return;
  115. break;
  116. case DECODER_STATE_PACKET_RECEIVED:
  117. {
  118. uint32_t crc = crc32(0, rx_buffer, SPM_PAGESIZE);
  119. uint32_t expected_crc = \
  120. (static_cast<uint32_t>(rx_buffer[SPM_PAGESIZE + 0]) << 24) | \
  121. (static_cast<uint32_t>(rx_buffer[SPM_PAGESIZE + 1]) << 16) | \
  122. (static_cast<uint32_t>(rx_buffer[SPM_PAGESIZE + 2]) << 8) | \
  123. (static_cast<uint32_t>(rx_buffer[SPM_PAGESIZE + 3]) << 0);
  124. if (crc == expected_crc) {
  125. WriteBufferToFlash();
  126. page += SPM_PAGESIZE;
  127. ++page_byte;
  128. } else {
  129. FlashLedsError();
  130. }
  131. }
  132. decoder.Sync();
  133. break;
  134. default:
  135. break;
  136. }
  137. }
  138. // Poll the MIDI input.
  139. if (midi.readable()) {
  140. byte = midi.ImmediateRead();
  141. if (byte > 0xf0 && byte != 0xf7) {
  142. continue;
  143. }
  144. switch (state) {
  145. case MATCHING_HEADER:
  146. if (byte == sysex_header[bytes_read]) {
  147. ++bytes_read;
  148. if (bytes_read == sizeof(sysex_header)) {
  149. bytes_read = 0;
  150. state = READING_COMMAND;
  151. }
  152. } else {
  153. bytes_read = 0;
  154. }
  155. break;
  156. case READING_COMMAND:
  157. if (byte < 0x80) {
  158. sysex_commands[bytes_read++] = byte;
  159. if (bytes_read == 2) {
  160. bytes_read = 0;
  161. rx_buffer_index = 0;
  162. checksum = 0;
  163. state = READING_DATA;
  164. }
  165. } else {
  166. state = MATCHING_HEADER;
  167. status = 0;
  168. bytes_read = 0;
  169. }
  170. break;
  171. case READING_DATA:
  172. if (byte < 0x80) {
  173. if (bytes_read & 1) {
  174. rx_buffer[rx_buffer_index] |= byte & 0xf;
  175. if (rx_buffer_index < SPM_PAGESIZE) {
  176. checksum += rx_buffer[rx_buffer_index];
  177. }
  178. ++rx_buffer_index;
  179. } else {
  180. rx_buffer[rx_buffer_index] = (byte << 4);
  181. }
  182. ++bytes_read;
  183. } else if (byte == 0xf7) {
  184. if (sysex_commands[0] == 0x7f &&
  185. sysex_commands[1] == 0x00 &&
  186. bytes_read == 0) {
  187. // Reset.
  188. return;
  189. } else if (rx_buffer_index == SPM_PAGESIZE + 1 &&
  190. sysex_commands[0] == 0x7e &&
  191. sysex_commands[1] == 0x00 &&
  192. rx_buffer[rx_buffer_index - 1] == checksum) {
  193. // Block write.
  194. WriteBufferToFlash();
  195. page += SPM_PAGESIZE;
  196. ++page_byte;
  197. } else {
  198. FlashLedsError();
  199. }
  200. state = MATCHING_HEADER;
  201. bytes_read = 0;
  202. }
  203. break;
  204. }
  205. }
  206. }
  207. }
  208. int main(void) {
  209. ResetWatchdog();
  210. Init();
  211. _delay_ms(40);
  212. if (!(inputs.Read() & INPUT_SW_RESET)) {
  213. FlashLedsOk();
  214. LoaderLoop();
  215. FlashLedsOk();
  216. FlashLedsOk();
  217. }
  218. main_entry_point();
  219. }