1 // Copyright 2015 Emilie Gillet.
2 //
3 // Author: Emilie Gillet (emilie.o.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 // -----------------------------------------------------------------------------
26 //
27 // User interface.
28
29 #include "marbles/ui.h"
30
31 #include <algorithm>
32
33 #include "stmlib/system/system_clock.h"
34
35 #include "marbles/drivers/clock_inputs.h"
36 #include "marbles/cv_reader.h"
37 #include "marbles/scale_recorder.h"
38
39 namespace marbles {
40
41 const int32_t kLongPressDuration = 2000;
42
43 using namespace std;
44 using namespace stmlib;
45
46 /* static */
47 const LedColor Ui::palette_[4] = {
48 LED_COLOR_GREEN,
49 LED_COLOR_YELLOW,
50 LED_COLOR_RED,
51 LED_COLOR_OFF
52 };
53
54 /* static */
55 AlternateKnobMapping Ui::alternate_knob_mappings_[ADC_CHANNEL_LAST];
56
Init(Settings * settings,CvReader * cv_reader,ScaleRecorder * scale_recorder,ClockInputs * clock_inputs)57 void Ui::Init(
58 Settings* settings,
59 CvReader* cv_reader,
60 ScaleRecorder* scale_recorder,
61 ClockInputs* clock_inputs) {
62 settings_ = settings;
63 cv_reader_ = cv_reader;
64 scale_recorder_ = scale_recorder;
65 clock_inputs_ = clock_inputs;
66
67 leds_.Init();
68 switches_.Init();
69 queue_.Init();
70
71 // Initialize generator from settings_->state();
72 fill(&pot_value_[0], &pot_value_[ADC_CHANNEL_LAST], 0.0f);
73
74 State* state = settings_->mutable_state();
75 alternate_knob_mappings_[ADC_CHANNEL_T_BIAS].unlock_switch = SWITCH_T_MODEL;
76 alternate_knob_mappings_[ADC_CHANNEL_T_BIAS].destination = &state->t_pulse_width_mean;
77 alternate_knob_mappings_[ADC_CHANNEL_T_JITTER].unlock_switch = SWITCH_T_MODEL;
78 alternate_knob_mappings_[ADC_CHANNEL_T_JITTER].destination = &state->t_pulse_width_std;
79 alternate_knob_mappings_[ADC_CHANNEL_T_RATE].unlock_switch = SWITCH_X_MODE;
80 alternate_knob_mappings_[ADC_CHANNEL_T_RATE].destination = &state->y_divider;
81 alternate_knob_mappings_[ADC_CHANNEL_X_SPREAD].unlock_switch = SWITCH_X_MODE;
82 alternate_knob_mappings_[ADC_CHANNEL_X_SPREAD].destination = &state->y_spread;
83 alternate_knob_mappings_[ADC_CHANNEL_X_BIAS].unlock_switch = SWITCH_X_MODE;
84 alternate_knob_mappings_[ADC_CHANNEL_X_BIAS].destination = &state->y_bias;
85 alternate_knob_mappings_[ADC_CHANNEL_X_STEPS].unlock_switch = SWITCH_X_MODE;
86 alternate_knob_mappings_[ADC_CHANNEL_X_STEPS].destination = &state->y_steps;
87
88 setting_modification_flag_ = false;
89 output_test_mode_ = false;
90
91 if (switches_.pressed_immediate(SWITCH_X_MODE)) {
92 if (state->color_blind == 1) {
93 state->color_blind = 0;
94 } else {
95 state->color_blind = 1;
96 }
97 settings_->SaveState();
98 }
99
100 if (switches_.pressed_immediate(SWITCH_X_DEJA_VU)) {
101 settings_->ProgramOptionBytes();
102 }
103
104 deja_vu_lock_ = false;
105 }
106
SaveState()107 void Ui::SaveState() {
108 settings_->SaveState();
109 }
110
Poll()111 void Ui::Poll() {
112 // 1kHz.
113 system_clock.Tick();
114 switches_.Debounce();
115
116 for (int i = 0; i < SWITCH_LAST; ++i) {
117 if (switches_.just_pressed(Switch(i))) {
118 queue_.AddEvent(CONTROL_SWITCH, i, 0);
119 press_time_[i] = system_clock.milliseconds();
120 ignore_release_[i] = false;
121 }
122 if (switches_.pressed(Switch(i)) && !ignore_release_[i]) {
123 int32_t pressed_time = system_clock.milliseconds() - press_time_[i];
124 if (pressed_time > kLongPressDuration && !setting_modification_flag_) {
125 queue_.AddEvent(CONTROL_SWITCH, i, pressed_time);
126 ignore_release_[i] = true;
127 }
128 }
129 if (switches_.released(Switch(i)) && !ignore_release_[i]) {
130 queue_.AddEvent(
131 CONTROL_SWITCH,
132 i,
133 system_clock.milliseconds() - press_time_[i] + 1);
134 ignore_release_[i] = true;
135 }
136 }
137
138 UpdateLEDs();
139 }
140
141 /* static */
MakeColor(uint8_t value,bool color_blind)142 LedColor Ui::MakeColor(uint8_t value, bool color_blind) {
143 bool slow_blink = (system_clock.milliseconds() & 255) > 128;
144
145 uint8_t bank = value >= 3 ? 1 : 0;
146 value -= bank * 3;
147
148 LedColor color = palette_[value];
149 if (color_blind) {
150 uint8_t pwm_counter = system_clock.milliseconds() & 15;
151 uint8_t triangle = (system_clock.milliseconds() >> 5) & 31;
152 triangle = triangle < 16 ? triangle : 31 - triangle;
153
154 if (value == 0) {
155 color = pwm_counter < (4 + (triangle >> 2))
156 ? LED_COLOR_GREEN
157 : LED_COLOR_OFF;
158 } else if (value == 1) {
159 color = LED_COLOR_YELLOW;
160 } else {
161 color = pwm_counter == 0 ? LED_COLOR_RED : LED_COLOR_OFF;
162 }
163 }
164
165 return slow_blink || !bank ? color : LED_COLOR_OFF;
166 }
167
168 /* static */
DejaVuColor(DejaVuState state,bool lock)169 LedColor Ui::DejaVuColor(DejaVuState state, bool lock) {
170 if (state == DEJA_VU_OFF) {
171 return LED_COLOR_OFF;
172 } else if (state == DEJA_VU_ON) {
173 if (lock) {
174 int slow_triangle = (system_clock.milliseconds() & 1023) >> 5;
175 slow_triangle = slow_triangle >= 16 ? 31 - slow_triangle : slow_triangle;
176 int pw = system_clock.milliseconds() & 15;
177 return slow_triangle >= pw ? LED_COLOR_GREEN : LED_COLOR_OFF;
178 } else {
179 return LED_COLOR_GREEN;
180 }
181 } else {
182 int fast_triangle = (system_clock.milliseconds() & 511) >> 4;
183 fast_triangle = fast_triangle >= 16 ? 31 - fast_triangle : fast_triangle;
184 int pw = system_clock.milliseconds() & 15;
185
186 return fast_triangle >= pw ? LED_COLOR_GREEN : LED_COLOR_OFF;
187 }
188 }
189
UpdateLEDs()190 void Ui::UpdateLEDs() {
191 bool blink = (system_clock.milliseconds() & 127) > 64;
192 bool slow_blink = (system_clock.milliseconds() & 255) > 128;
193 bool fast_blink = (system_clock.milliseconds() & 63) > 32;
194 const State& state = settings_->state();
195 bool cb = state.color_blind == 1;
196
197 LedColor scale_color = state.x_scale < 3
198 ? (slow_blink ? palette_[state.x_scale] : LED_COLOR_OFF)
199 : (fast_blink ? palette_[state.x_scale - 3] : LED_COLOR_OFF);
200
201 if (cb) {
202 int poly_counter = (system_clock.milliseconds() >> 6) % 12;
203 if ((poly_counter >> 1) < (state.x_scale + 1) && (poly_counter & 1)) {
204 scale_color = LED_COLOR_YELLOW;
205 } else {
206 scale_color = LED_COLOR_OFF;
207 }
208 }
209
210 leds_.Clear();
211
212 switch (mode_) {
213 case UI_MODE_NORMAL:
214 case UI_MODE_RECORD_SCALE:
215 {
216 leds_.set(LED_T_MODEL, MakeColor(state.t_model, cb));
217 leds_.set(LED_T_RANGE, MakeColor(state.t_range, cb));
218 leds_.set(
219 LED_T_DEJA_VU,
220 DejaVuColor(DejaVuState(state.t_deja_vu), deja_vu_lock_));
221
222 leds_.set(LED_X_CONTROL_MODE, MakeColor(state.x_control_mode, cb));
223 leds_.set(
224 LED_X_DEJA_VU,
225 DejaVuColor(DejaVuState(state.x_deja_vu), deja_vu_lock_));
226
227 if (mode_ == UI_MODE_NORMAL) {
228 leds_.set(LED_X_RANGE,
229 state.x_register_mode
230 ? LED_COLOR_OFF
231 : MakeColor(state.x_range, cb));
232 leds_.set(LED_X_EXT,
233 state.x_register_mode ? LED_COLOR_GREEN : LED_COLOR_OFF);
234 } else {
235 leds_.set(LED_X_RANGE, scale_color);
236 leds_.set(LED_X_EXT, LED_COLOR_GREEN);
237 }
238 }
239 break;
240
241 case UI_MODE_SELECT_SCALE:
242 leds_.set(LED_X_RANGE, scale_color);
243 break;
244
245 case UI_MODE_CALIBRATION_1:
246 leds_.set(LED_T_RANGE, blink ? MakeColor(0, cb) : LED_COLOR_OFF);
247 break;
248
249 case UI_MODE_CALIBRATION_2:
250 leds_.set(LED_T_RANGE, blink ? MakeColor(1, cb) : LED_COLOR_OFF);
251 break;
252
253 case UI_MODE_CALIBRATION_3:
254 leds_.set(LED_X_RANGE, blink ? MakeColor(0, cb) : LED_COLOR_OFF);
255 break;
256
257 case UI_MODE_CALIBRATION_4:
258 leds_.set(LED_X_RANGE, blink ? MakeColor(1, cb) : LED_COLOR_OFF);
259 break;
260
261 case UI_MODE_PANIC:
262 leds_.set(LED_T_MODEL, blink ? LED_COLOR_RED : LED_COLOR_OFF);
263 leds_.set(LED_T_RANGE, !blink ? LED_COLOR_RED : LED_COLOR_OFF);
264 leds_.set(LED_X_CONTROL_MODE, !blink ? LED_COLOR_RED : LED_COLOR_OFF);
265 leds_.set(LED_X_RANGE, blink ? LED_COLOR_RED : LED_COLOR_OFF);
266 break;
267 }
268 leds_.Write();
269 }
270
FlushEvents()271 void Ui::FlushEvents() {
272 queue_.Flush();
273 }
274
OnSwitchPressed(const Event & e)275 void Ui::OnSwitchPressed(const Event& e) {
276
277 }
278
OnSwitchReleased(const Event & e)279 void Ui::OnSwitchReleased(const Event& e) {
280 if (setting_modification_flag_) {
281 for (int i = 0; i < ADC_CHANNEL_LAST; ++i) {
282 cv_reader_->mutable_channel(i)->UnlockPot();
283 }
284 setting_modification_flag_ = false;
285 return;
286 }
287
288 // Check if the other switch is still pressed.
289 if (e.control_id == SWITCH_T_RANGE && switches_.pressed(SWITCH_X_RANGE)) {
290 mode_ = UI_MODE_CALIBRATION_1;
291 ignore_release_[SWITCH_T_RANGE] = ignore_release_[SWITCH_X_RANGE] = true;
292 return;
293 }
294
295 State* state = settings_->mutable_state();
296 switch (e.control_id) {
297 case SWITCH_T_DEJA_VU:
298 if (state->t_deja_vu == DEJA_VU_OFF) {
299 state->t_deja_vu = e.data >= kLongPressDuration
300 ? DEJA_VU_LOCKED
301 : DEJA_VU_ON;
302 } else if (state->t_deja_vu == DEJA_VU_LOCKED) {
303 state->t_deja_vu = DEJA_VU_ON;
304 } else {
305 state->t_deja_vu = e.data >= kLongPressDuration
306 ? DEJA_VU_LOCKED
307 : DEJA_VU_OFF;
308 }
309 break;
310
311 case SWITCH_X_DEJA_VU:
312 if (state->x_deja_vu == DEJA_VU_OFF) {
313 state->x_deja_vu = e.data >= kLongPressDuration
314 ? DEJA_VU_LOCKED
315 : DEJA_VU_ON;
316 } else if (state->x_deja_vu == DEJA_VU_LOCKED) {
317 state->x_deja_vu = DEJA_VU_ON;
318 } else {
319 state->x_deja_vu = e.data >= kLongPressDuration
320 ? DEJA_VU_LOCKED
321 : DEJA_VU_OFF;
322 }
323 break;
324
325 case SWITCH_T_MODEL:
326 {
327 uint8_t bank = state->t_model / 3;
328 if (e.data >= kLongPressDuration) {
329 if (!bank) {
330 state->t_model += 3;
331 }
332 } else {
333 if (bank) {
334 state->t_model -= 3;
335 } else {
336 state->t_model = (state->t_model + 1) % 3;
337 }
338 }
339 SaveState();
340 }
341 break;
342
343 case SWITCH_T_RANGE:
344 {
345 if (mode_ >= UI_MODE_CALIBRATION_1 && mode_ <= UI_MODE_CALIBRATION_4) {
346 NextCalibrationStep();
347 } else {
348 state->t_range = (state->t_range + 1) % 3;
349 }
350 SaveState();
351 }
352 break;
353
354 case SWITCH_X_MODE:
355 state->x_control_mode = (state->x_control_mode + 1) % 3;
356 SaveState();
357 break;
358
359 case SWITCH_X_EXT:
360 if (mode_ == UI_MODE_RECORD_SCALE) {
361 int scale_index = settings_->state().x_scale;
362 bool success = true;
363 if (e.data >= kLongPressDuration) {
364 settings_->ResetScale(scale_index);
365 } else {
366 success = scale_recorder_->ExtractScale(
367 settings_->mutable_scale(scale_index));
368 }
369 if (success) {
370 settings_->SavePersistentData();
371 settings_->set_dirty_scale_index(scale_index);
372 }
373 mode_ = UI_MODE_NORMAL;
374 } else if (e.data >= kLongPressDuration) {
375 mode_ = UI_MODE_RECORD_SCALE;
376 scale_recorder_->Clear();
377 } else {
378 state->x_register_mode = !state->x_register_mode;
379 SaveState();
380 }
381 break;
382
383 case SWITCH_X_RANGE:
384 if (mode_ >= UI_MODE_CALIBRATION_1 && mode_ <= UI_MODE_CALIBRATION_4) {
385 NextCalibrationStep();
386 } else if (e.data >= kLongPressDuration) {
387 if (mode_ == UI_MODE_NORMAL) {
388 mode_ = UI_MODE_SELECT_SCALE;
389 }
390 } else if (mode_ == UI_MODE_SELECT_SCALE) {
391 state->x_scale = (state->x_scale + 1) % kNumScales;
392 } else {
393 if (!state->x_register_mode) {
394 state->x_range = (state->x_range + 1) % 3;
395 }
396 }
397 SaveState();
398 break;
399 }
400 }
401
TerminateScaleRecording()402 void Ui::TerminateScaleRecording() {
403 for (int i = 0; i < ADC_CHANNEL_LAST; ++i) {
404 cv_reader_->mutable_channel(i)->UnlockPot();
405 }
406 mode_ = UI_MODE_NORMAL;
407 }
408
NextCalibrationStep()409 void Ui::NextCalibrationStep() {
410 switch (mode_) {
411 case UI_MODE_CALIBRATION_1:
412 cv_reader_->CalibrateOffsets();
413 cv_reader_->CalibrateRateC1();
414 mode_ = UI_MODE_CALIBRATION_2;
415 break;
416
417 case UI_MODE_CALIBRATION_2:
418 cv_reader_->CalibrateRateC3();
419 mode_ = UI_MODE_CALIBRATION_3;
420 break;
421
422 case UI_MODE_CALIBRATION_3:
423 cv_reader_->CalibrateSpreadC1();
424 mode_ = UI_MODE_CALIBRATION_4;
425 break;
426
427 case UI_MODE_CALIBRATION_4:
428 if (cv_reader_->CalibrateSpreadC3()) {
429 settings_->SavePersistentData();
430 mode_ = UI_MODE_NORMAL;
431 } else {
432 mode_ = UI_MODE_PANIC;
433 }
434 break;
435
436 default:
437 break;
438 }
439 }
440
UpdateHiddenParameters()441 void Ui::UpdateHiddenParameters() {
442 // Check if some pots have been moved.
443 for (int i = 0; i < ADC_CHANNEL_LAST; ++i) {
444 float new_value = cv_reader_->channel(i).unscaled_pot();
445 float old_value = pot_value_[i];
446 bool changed = fabs(new_value - old_value) >= 0.008f;
447 if (changed) {
448 pot_value_[i] = new_value;
449 AlternateKnobMapping mapping = alternate_knob_mappings_[i];
450 if (switches_.pressed(mapping.unlock_switch)) {
451 if (mapping.unlock_switch == SWITCH_T_RANGE && new_value < 0.1f) {
452 new_value = 0.0f;
453 }
454 *mapping.destination = static_cast<uint8_t>(new_value * 255.0f);
455 cv_reader_->mutable_channel(i)->LockPot();
456
457 // The next time a switch is released, we unlock the pots.
458 setting_modification_flag_ = true;
459 }
460 }
461 }
462 }
463
DoEvents()464 void Ui::DoEvents() {
465 while (queue_.available()) {
466 Event e = queue_.PullEvent();
467 if (e.control_type == CONTROL_SWITCH) {
468 if (e.data == 0) {
469 OnSwitchPressed(e);
470 } else {
471 OnSwitchReleased(e);
472 }
473 }
474 }
475
476 UpdateHiddenParameters();
477
478 if (queue_.idle_time() > 800 && mode_ == UI_MODE_PANIC) {
479 mode_ = UI_MODE_NORMAL;
480 }
481 if (mode_ == UI_MODE_SELECT_SCALE) {
482 if (queue_.idle_time() > 4000) {
483 mode_ = UI_MODE_NORMAL;
484 queue_.Touch();
485 }
486 } else if (queue_.idle_time() > 1000) {
487 queue_.Touch();
488 }
489 }
490
HandleFactoryTestingRequest(uint8_t command)491 uint8_t Ui::HandleFactoryTestingRequest(uint8_t command) {
492 uint8_t argument = command & 0x1f;
493 command = command >> 5;
494 uint8_t reply = 0;
495 switch (command) {
496 case FACTORY_TESTING_READ_POT:
497 case FACTORY_TESTING_READ_CV:
498 reply = cv_reader_->adc_value(argument);
499 break;
500
501 case FACTORY_TESTING_READ_NORMALIZATION:
502 reply = clock_inputs_->is_normalized(ClockInput(argument)) ? 255 : 0;
503 break;
504
505 case FACTORY_TESTING_READ_GATE:
506 reply = argument >= SWITCH_LAST
507 ? clock_inputs_->value(ClockInput(argument - SWITCH_LAST))
508 : switches_.pressed(Switch(argument));
509 break;
510
511 case FACTORY_TESTING_GENERATE_TEST_SIGNALS:
512 output_test_mode_ = static_cast<bool>(argument);
513 fill(
514 &output_test_forced_dac_code_[0],
515 &output_test_forced_dac_code_[4],
516 0);
517 break;
518
519 case FACTORY_TESTING_CALIBRATE:
520 if (argument == 0) {
521 // Revert all settings before getting into calibration mode.
522 settings_->mutable_state()->t_deja_vu = 0;
523 settings_->mutable_state()->x_deja_vu = 0;
524 settings_->mutable_state()->t_model = 0;
525 settings_->mutable_state()->t_range = 1;
526 settings_->mutable_state()->x_control_mode = 0;
527 settings_->mutable_state()->x_range = 2;
528 settings_->mutable_state()->x_register_mode = 0;
529 settings_->SavePersistentData();
530
531 mode_ = UI_MODE_CALIBRATION_1;
532 } else {
533 NextCalibrationStep();
534 }
535 {
536 const CalibrationData& cal = settings_->calibration_data();
537 float voltage = (argument & 1) == 0 ? 1.0f : 3.0f;
538 for (int i = 0; i < 4; ++i) {
539 output_test_forced_dac_code_[i] = static_cast<uint16_t>(
540 voltage * cal.dac_scale[i] + cal.dac_offset[i]);
541 }
542 }
543 queue_.Touch();
544 break;
545
546 case FACTORY_TESTING_FORCE_DAC_CODE:
547 {
548 int channel = argument >> 2;
549 int step = argument & 0x3;
550 if (step == 0) {
551 output_test_forced_dac_code_[channel] = 0xaf35;
552 } else if (step == 1) {
553 output_test_forced_dac_code_[channel] = 0x1d98;
554 } else {
555 CalibrationData* cal = settings_->mutable_calibration_data();
556 cal->dac_offset[channel] = static_cast<float>(
557 calibration_data_ & 0xffff);
558 cal->dac_scale[channel] = static_cast<float>(
559 calibration_data_ >> 16) * -0.125f;
560 output_test_forced_dac_code_[channel] = static_cast<uint16_t>(cal->dac_scale[channel] + cal->dac_offset[channel]);
561 settings_->SavePersistentData();
562 }
563 }
564 break;
565
566 case FACTORY_TESTING_WRITE_CALIBRATION_DATA_NIBBLE:
567 calibration_data_ <<= 4;
568 calibration_data_ |= argument & 0xf;
569 break;
570 }
571 return reply;
572 }
573
574 } // namespace marbles
575