1 // Copyright 2014 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
25 #include <stm32f10x_conf.h>
26 #include <string.h>
27
28 #include "stmlib/utils/dsp.h"
29 #include "stmlib/utils/ring_buffer.h"
30 #include "stmlib/system/bootloader_utils.h"
31 #include "stmlib/system/flash_programming.h"
32 #include "stmlib/system/system_clock.h"
33
34 #include "stm_audio_bootloader/qpsk/packet_decoder.h"
35 #include "stm_audio_bootloader/qpsk/demodulator.h"
36
37 #include "streams/drivers/adc.h"
38 #include "streams/drivers/switches.h"
39 #include "streams/drivers/leds.h"
40 #include "streams/drivers/system.h"
41
42 using namespace streams;
43 using namespace stmlib;
44 using namespace stm_audio_bootloader;
45
46 const double kSampleRate = 48000.0;
47 const double kModulationRate = 6000.0;
48 const double kBitRate = 12000.0;
49
50 const uint32_t kStartAddress = 0x08004000;
51
52 Adc adc;
53 System sys;
54 Leds leds;
55 Switches switches;
56 PacketDecoder decoder;
57 Demodulator demodulator;
58
59
60 const int16_t wav_db[] = {
61 -32768, -32768, -24576, -19783,
62 -16384, -13746, -11591, -9770,
63 -8192, -6799, -5554, -4428,
64 -3399, -2453, -1578, -762,
65 0, 716, 1392, 2031,
66 2637, 3213, 3763, 4289,
67 4792, 5274, 5738, 6184,
68 6613, 7028, 7429, 7816,
69 8192, 8555, 8908, 9251,
70 9584, 9907, 10223, 10530,
71 10829, 11121, 11405, 11683,
72 11955, 12221, 12481, 12735,
73 12984, 13227, 13466, 13700,
74 13930, 14155, 14376, 14592,
75 14805, 15015, 15220, 15422,
76 15621, 15816, 16008, 16197,
77 16384, 16567, 16747, 16925,
78 17100, 17273, 17443, 17610,
79 17776, 17939, 18099, 18258,
80 18415, 18569, 18722, 18872,
81 19021, 19168, 19313, 19456,
82 19597, 19737, 19875, 20012,
83 20147, 20281, 20413, 20543,
84 20673, 20800, 20927, 21052,
85 21176, 21298, 21419, 21539,
86 21658, 21776, 21892, 22007,
87 22122, 22235, 22347, 22458,
88 22568, 22676, 22784, 22891,
89 22997, 23102, 23207, 23310,
90 23412, 23514, 23614, 23714,
91 23813, 23911, 24008, 24105,
92 24200, 24295, 24389, 24483,
93 24576, 24667, 24759, 24849,
94 24939, 25028, 25117, 25205,
95 25292, 25379, 25465, 25550,
96 25635, 25719, 25802, 25885,
97 25968, 26049, 26131, 26211,
98 26291, 26371, 26450, 26529,
99 26607, 26684, 26761, 26838,
100 26914, 26989, 27064, 27139,
101 27213, 27286, 27360, 27432,
102 27505, 27576, 27648, 27719,
103 27789, 27860, 27929, 27999,
104 28067, 28136, 28204, 28272,
105 28339, 28406, 28473, 28539,
106 28605, 28670, 28735, 28800,
107 28865, 28929, 28992, 29056,
108 29119, 29181, 29244, 29306,
109 29368, 29429, 29490, 29551,
110 29611, 29671, 29731, 29791,
111 29850, 29909, 29968, 30026,
112 30084, 30142, 30199, 30257,
113 30314, 30370, 30427, 30483,
114 30539, 30594, 30650, 30705,
115 30760, 30814, 30868, 30923,
116 30976, 31030, 31083, 31136,
117 31189, 31242, 31294, 31347,
118 31399, 31450, 31502, 31553,
119 31604, 31655, 31706, 31756,
120 31806, 31856, 31906, 31955,
121 32005, 32054, 32103, 32152,
122 32200, 32248, 32297, 32345,
123 32392, 32440, 32487, 32534,
124 32581, 32628, 32675, 32721,
125 32721,
126 };
127
128 extern "C" {
129
HardFault_Handler(void)130 void HardFault_Handler(void) { while (1); }
MemManage_Handler(void)131 void MemManage_Handler(void) { while (1); }
BusFault_Handler(void)132 void BusFault_Handler(void) { while (1); }
UsageFault_Handler(void)133 void UsageFault_Handler(void) { while (1); }
NMI_Handler(void)134 void NMI_Handler(void) { }
SVC_Handler(void)135 void SVC_Handler(void) { }
DebugMon_Handler(void)136 void DebugMon_Handler(void) { }
PendSV_Handler(void)137 void PendSV_Handler(void) { }
138
139 }
140
141 extern "C" {
142
143 enum UiState {
144 UI_STATE_WAITING,
145 UI_STATE_RECEIVING,
146 UI_STATE_ERROR,
147 UI_STATE_PACKET_OK
148 };
149
150 volatile bool switch_released = false;
151 volatile UiState ui_state;
152 int32_t peak = 0;
153 int32_t gain = 0;
154
UpdateLeds()155 inline void UpdateLeds() {
156 leds.Clear();
157
158 // Show vu-meter on right side.
159 int32_t rectified_sample = adc.cv(0) - 32768;
160 rectified_sample = rectified_sample * gain >> 4;
161 if (rectified_sample < 0) {
162 rectified_sample = -rectified_sample;
163 }
164 if (rectified_sample > peak) {
165 peak = rectified_sample;
166 } else {
167 peak += (rectified_sample - peak) * 130 >> 15;
168 }
169 leds.PaintPositiveBar(1, wav_db[peak >> 7] + 8192);
170
171 // Show status info on left side (or whole display in case of error).
172 switch (ui_state) {
173 case UI_STATE_WAITING:
174 {
175 bool on = system_clock.milliseconds() & 128;
176 if (on) {
177 for (uint8_t i = 0; i < 4; ++i) {
178 leds.set(i, 255, 255);
179 }
180 }
181 }
182 break;
183
184 case UI_STATE_RECEIVING:
185 {
186 uint8_t stage = (system_clock.milliseconds() >> 7) & 3;
187 leds.set(stage, 0, 255);
188 }
189 break;
190
191 case UI_STATE_ERROR:
192 {
193 bool on = system_clock.milliseconds() & 256;
194 for (uint8_t i = 0; i < 4; ++i) {
195 leds.set(i, on ? 255 : 0, 0);
196 }
197 }
198 break;
199
200 case UI_STATE_PACKET_OK:
201 {
202 for (uint8_t i = 0; i < 4; ++i) {
203 leds.set(i, 0, 255);
204 }
205 }
206 break;
207 }
208 leds.Write();
209 }
210
SysTick_Handler()211 void SysTick_Handler() {
212 static uint8_t divider = 0;
213
214 // SysTick is at 4kHz to get a fast bargraph refresh.
215 ++divider;
216 if ((divider & 3) == 0) {
217 system_clock.Tick();
218 system_clock.Tick(); // Tick global ms counter.
219 switches.Debounce();
220 if (switches.released(0)) {
221 switch_released = true;
222 }
223 adc.ScanPots();
224 gain = adc.pot(0) >> 11;
225 UpdateLeds();
226 }
227 }
228
229 uint16_t discard_samples = 8000;
230
TIM2_IRQHandler(void)231 void TIM2_IRQHandler(void) {
232 if (TIM_GetITStatus(TIM2, TIM_IT_Update) == RESET) {
233 return;
234 }
235
236 TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
237
238 if (!discard_samples) {
239 int32_t sample = adc.cv(0);
240 sample -= 32768;
241 sample = sample * gain >> 4;
242 sample = (sample >> 4) + 2048;
243 if (sample < 0) {
244 sample = 0;
245 } else if (sample > 4095) {
246 sample = 4095;
247 }
248 demodulator.PushSample(sample);
249 } else {
250 --discard_samples;
251 }
252 }
253
254 }
255
256 static uint32_t current_address;
257 static uint16_t packet_index;
258
ProgramPage(const uint8_t * data,size_t size)259 void ProgramPage(const uint8_t* data, size_t size) {
260 FLASH_Unlock();
261 FLASH_ErasePage(current_address);
262 const uint32_t* words = static_cast<const uint32_t*>(
263 static_cast<const void*>(data));
264 for (size_t written = 0; written < size; written += 4) {
265 FLASH_ProgramWord(current_address, *words++);
266 current_address += 4;
267 }
268 }
269
Init()270 void Init() {
271 sys.Init(false);
272 system_clock.Init();
273 adc.Init(true, NULL);
274 switches.Init();
275 leds.Init();
276 sys.StartTimers();
277 adc.Start();
278 TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);
279 }
280
InitializeReception()281 void InitializeReception() {
282 decoder.Init();
283 demodulator.Init(
284 kModulationRate / kSampleRate * 4294967296.0,
285 kSampleRate / kModulationRate,
286 2.0 * kSampleRate / kBitRate);
287 demodulator.SyncCarrier(true);
288 decoder.Reset();
289 current_address = kStartAddress;
290 packet_index = 0;
291 ui_state = UI_STATE_WAITING;
292 }
293
294 uint8_t rx_buffer[PAGE_SIZE];
295 const uint16_t kPacketsPerPage = PAGE_SIZE / kPacketSize;
296
main(void)297 int main(void) {
298 Init();
299 InitializeReception();
300
301 bool exit_updater = !switches.pressed_immediate(0);
302 while (!exit_updater) {
303 bool error = false;
304
305 if (demodulator.state() == DEMODULATOR_STATE_OVERFLOW) {
306 error = true;
307 } else {
308 demodulator.ProcessAtLeast(32);
309 }
310
311 while (demodulator.available() && !error && !exit_updater) {
312 uint8_t symbol = demodulator.NextSymbol();
313 PacketDecoderState state = decoder.ProcessSymbol(symbol);
314 switch (state) {
315 case PACKET_DECODER_STATE_OK:
316 {
317 ui_state = UI_STATE_RECEIVING;
318 memcpy(
319 rx_buffer + (packet_index % kPacketsPerPage) * kPacketSize,
320 decoder.packet_data(),
321 kPacketSize);
322 ++packet_index;
323 if ((packet_index % kPacketsPerPage) == 0) {
324 ui_state = UI_STATE_PACKET_OK;
325 ProgramPage(rx_buffer, PAGE_SIZE);
326 decoder.Reset();
327 demodulator.SyncCarrier(false);
328 ui_state = UI_STATE_RECEIVING;
329 } else {
330 decoder.Reset();
331 demodulator.SyncDecision();
332 }
333 }
334 break;
335 case PACKET_DECODER_STATE_ERROR_SYNC:
336 case PACKET_DECODER_STATE_ERROR_CRC:
337 error = true;
338 break;
339 case PACKET_DECODER_STATE_END_OF_TRANSMISSION:
340 exit_updater = true;
341 break;
342 default:
343 break;
344 }
345 }
346 if (error) {
347 ui_state = UI_STATE_ERROR;
348 switch_released = false;
349 while (!switch_released); // Polled in ISR
350 InitializeReception();
351 }
352 }
353
354 adc.DeInit();
355 Uninitialize();
356 JumpTo(kStartAddress);
357 while (1) { }
358 }
359