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.

265 lines
6.9KB

  1. // Copyright 2013 Olivier Gillet.
  2. //
  3. // Author: Olivier Gillet (ol.gillet@gmail.com)
  4. //
  5. // Permission is hereby granted, free of charge, to any person obtaining a copy
  6. // of this software and associated documentation files (the "Software"), to deal
  7. // in the Software without restriction, including without limitation the rights
  8. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  9. // copies of the Software, and to permit persons to whom the Software is
  10. // furnished to do so, subject to the following conditions:
  11. //
  12. // The above copyright notice and this permission notice shall be included in
  13. // all copies or substantial portions of the Software.
  14. //
  15. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  16. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  17. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  18. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  19. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  20. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  21. // THE SOFTWARE.
  22. //
  23. // See http://creativecommons.org/licenses/MIT/ for more information.
  24. #include <stm32f10x_conf.h>
  25. #include <string.h>
  26. #include "stmlib/system/bootloader_utils.h"
  27. #include "stmlib/system/flash_programming.h"
  28. #include "stmlib/system/system_clock.h"
  29. #include "stmlib/utils/ring_buffer.h"
  30. #include "yarns/drivers/display.h"
  31. #include "yarns/drivers/encoder.h"
  32. #include "yarns/drivers/midi_io.h"
  33. #include "yarns/drivers/system.h"
  34. using namespace yarns;
  35. using namespace stmlib;
  36. System sys;
  37. Display display;
  38. Encoder encoder;
  39. MidiIO midi_io;
  40. RingBuffer<uint8_t, 128> midi_in_buffer;
  41. extern "C" {
  42. void HardFault_Handler(void) { while (1); }
  43. void MemManage_Handler(void) { while (1); }
  44. void BusFault_Handler(void) { while (1); }
  45. void UsageFault_Handler(void) { while (1); }
  46. void NMI_Handler(void) { }
  47. void SVC_Handler(void) { }
  48. void DebugMon_Handler(void) { }
  49. void PendSV_Handler(void) { }
  50. }
  51. extern "C" {
  52. void SysTick_Handler() {
  53. static uint8_t counter;
  54. if ((++counter & 7) == 0) {
  55. system_clock.Tick(); // Tick global ms counter.
  56. uint32_t ms_clock = system_clock.milliseconds();
  57. if ((ms_clock & 0x3f) == 0 && display.mutable_buffer()[0] >= '\x98') {
  58. display.mutable_buffer()[0] = '\x98' + ((ms_clock >> 6) & 7);
  59. }
  60. display.RefreshSlow();
  61. encoder.Debounce();
  62. }
  63. display.RefreshFast();
  64. // Try to read some MIDI input.
  65. if (midi_io.readable()) {
  66. midi_in_buffer.Overwrite(midi_io.ImmediateRead());
  67. }
  68. }
  69. }
  70. void PrintByte(uint8_t byte) {
  71. char str[] = "00";
  72. str[0] += byte / 10;
  73. str[1] += byte % 10;
  74. display.Print(str);
  75. }
  76. static uint32_t current_address;
  77. void ProgramPage(const uint8_t* data, size_t size) {
  78. FLASH_Unlock();
  79. FLASH_ErasePage(current_address);
  80. const uint32_t* words = static_cast<const uint32_t*>(
  81. static_cast<const void*>(data));
  82. for (size_t written = 0; written < size; written += 4) {
  83. FLASH_ProgramWord(current_address, *words++);
  84. current_address += 4;
  85. }
  86. }
  87. enum SysExReceptionState {
  88. MATCHING_HEADER = 0,
  89. READING_COMMAND = 1,
  90. READING_DATA = 2,
  91. };
  92. enum SysExReturnCode {
  93. SYSEX_RESULT_ERROR = 0,
  94. SYSEX_RESULT_OK = 1,
  95. SYSEX_RESULT_PAGE_WRITTEN = 2,
  96. SYSEX_RESULT_DONE = 3
  97. };
  98. static const uint8_t sysex_header[] = {
  99. 0xf0, // <SysEx>
  100. 0x00, 0x21, 0x02, // Mutable instruments manufacturer id.
  101. 0x00, 0x0b, // Product ID for Yarns.
  102. };
  103. static uint32_t bytes_read = 0;
  104. static uint16_t rx_buffer_index = 0;
  105. static SysExReceptionState state = MATCHING_HEADER;
  106. static uint8_t checksum;
  107. static uint8_t sysex_commands[2];
  108. static uint8_t page_index = 0;
  109. static uint8_t rx_buffer[PAGE_SIZE + 1];
  110. static uint8_t total_bytes = 0;
  111. const uint32_t kStartAddress = 0x08001000;
  112. void PrepareReception() {
  113. bytes_read = 0;
  114. rx_buffer_index = 0;
  115. state = MATCHING_HEADER;
  116. page_index = 0;
  117. current_address = kStartAddress;
  118. midi_in_buffer.Init();
  119. display.Print("\x98 ");
  120. }
  121. SysExReturnCode ProcessSysExByte(uint8_t byte) {
  122. if (byte > 0xf0 && byte != 0xf7) {
  123. return SYSEX_RESULT_OK;
  124. }
  125. ++total_bytes;
  126. switch (state) {
  127. case MATCHING_HEADER:
  128. if (byte == sysex_header[bytes_read]) {
  129. ++bytes_read;
  130. if (bytes_read == sizeof(sysex_header)) {
  131. bytes_read = 0;
  132. state = READING_COMMAND;
  133. }
  134. } else {
  135. bytes_read = 0;
  136. return SYSEX_RESULT_ERROR;
  137. }
  138. break;
  139. case READING_COMMAND:
  140. if (byte < 0x80) {
  141. sysex_commands[bytes_read++] = byte;
  142. if (bytes_read == 2) {
  143. bytes_read = 0;
  144. rx_buffer_index = 0;
  145. checksum = 0;
  146. state = READING_DATA;
  147. }
  148. } else {
  149. state = MATCHING_HEADER;
  150. bytes_read = 0;
  151. return SYSEX_RESULT_ERROR;
  152. }
  153. break;
  154. case READING_DATA:
  155. if (byte < 0x80) {
  156. if (bytes_read & 1) {
  157. rx_buffer[rx_buffer_index] |= byte & 0xf;
  158. if (rx_buffer_index < PAGE_SIZE) {
  159. checksum += rx_buffer[rx_buffer_index];
  160. }
  161. ++rx_buffer_index;
  162. } else {
  163. rx_buffer[rx_buffer_index] = (byte << 4);
  164. }
  165. ++bytes_read;
  166. } else if (byte == 0xf7) {
  167. if (sysex_commands[0] == 0x7f &&
  168. sysex_commands[1] == 0x00 &&
  169. bytes_read == 0) {
  170. return SYSEX_RESULT_DONE;
  171. } else if (rx_buffer_index == PAGE_SIZE + 1 &&
  172. sysex_commands[0] == 0x7e &&
  173. sysex_commands[1] == 0x00 &&
  174. rx_buffer[rx_buffer_index - 1] == checksum) {
  175. // Block write.
  176. ProgramPage(rx_buffer, PAGE_SIZE);
  177. ++page_index;
  178. }
  179. state = MATCHING_HEADER;
  180. bytes_read = 0;
  181. return SYSEX_RESULT_PAGE_WRITTEN;
  182. }
  183. break;
  184. }
  185. return SYSEX_RESULT_OK;
  186. }
  187. void Init() {
  188. SystemInit();
  189. RCC_APB2PeriphClockCmd(
  190. RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOC |
  191. RCC_APB2Periph_TIM1 | RCC_APB2Periph_USART1, ENABLE);
  192. system_clock.Init();
  193. encoder.Init();
  194. display.Init();
  195. midi_io.Init();
  196. SysTick_Config(F_CPU / 8000);
  197. }
  198. int main(void) {
  199. Init();
  200. PrepareReception();
  201. bool exit_updater = !encoder.pressed_immediate();
  202. while (!exit_updater) {
  203. while (midi_in_buffer.readable() && !exit_updater) {
  204. SysExReturnCode result = ProcessSysExByte(midi_in_buffer.ImmediateRead());
  205. switch (result) {
  206. case SYSEX_RESULT_DONE:
  207. {
  208. display.Print("OK");
  209. system_clock.Delay(1000);
  210. exit_updater = true;
  211. }
  212. break;
  213. case SYSEX_RESULT_PAGE_WRITTEN:
  214. {
  215. PrintByte(page_index);
  216. }
  217. break;
  218. case SYSEX_RESULT_OK:
  219. break;
  220. case SYSEX_RESULT_ERROR:
  221. display.Print("Er");
  222. system_clock.Delay(1000);
  223. PrepareReception();
  224. break;
  225. }
  226. }
  227. }
  228. Uninitialize();
  229. JumpTo(kStartAddress);
  230. while (1) { }
  231. }