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