1 // Copyright 2013 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 "tides/ui.h"
30 
31 #include "stmlib/system/storage.h"
32 #include "stmlib/system/system_clock.h"
33 
34 #include "tides/cv_scaler.h"
35 #include "tides/generator.h"
36 
37 namespace tides {
38 
39 const int32_t kLongPressDuration = 1000;
40 
41 using namespace stmlib;
42 
43 Storage<0x801fc00, 4> mode_storage;
44 
Init(Generator * generator,CvScaler * cv_scaler)45 void Ui::Init(Generator* generator, CvScaler* cv_scaler) {
46   factory_testing_switch_.Init();
47   leds_.Init();
48   switches_.Init();
49   mode_ = factory_testing_switch_.Read()
50       ? UI_MODE_NORMAL
51       : UI_MODE_FACTORY_TESTING;
52 
53   generator_ = generator;
54   cv_scaler_ = cv_scaler;
55 
56   if (!mode_storage.ParsimoniousLoad(&settings_, &version_token_)) {
57     mode_counter_ = 1;
58     range_counter_ = 2;
59     generator->set_sync(false);
60   } else {
61     mode_counter_ = settings_.mode;
62     range_counter_ = 2 - settings_.range;
63     generator->set_sync(settings_.sync);
64   }
65 
66   UpdateMode();
67   UpdateRange();
68   leds_.set_value(32768, 32768);
69 }
70 
SaveState()71 void Ui::SaveState() {
72   settings_.mode = generator_->mode();
73   settings_.range = generator_->range();
74   settings_.sync = generator_->sync();
75   mode_storage.ParsimoniousSave(settings_, &version_token_);
76 }
77 
78 const uint16_t thresholds[ADC_CHANNEL_LAST][2] = {
79   { 0, 64000 },
80   { 16384, 49152 },
81   { 16384, 49152 },
82   { 4096, 61440 },
83   { 4096, 61440 },
84   { 4096, 61440 },
85   { 4096, 61440 },
86 };
87 
UpdateFactoryTestingFlags(uint8_t gate_input_flags,const uint16_t * adc_values)88 void Ui::UpdateFactoryTestingFlags(
89     uint8_t gate_input_flags,
90     const uint16_t* adc_values) {
91   red_ = switches_.pressed(1);
92   green_ = switches_.pressed(0);
93   orange_ = gate_input_flags & CONTROL_GATE;
94   orange_ |= gate_input_flags & CONTROL_FREEZE;
95   orange_ |= gate_input_flags & CONTROL_CLOCK;
96 
97   for (uint16_t i = 0; i < ADC_CHANNEL_LAST; ++i) {
98     uint16_t value = adc_values[i];
99     if (i == ADC_CHANNEL_FM_ATTENUVERTER) {
100       value = ~value;
101     }
102     green_ |= value < thresholds[i][0];
103     if (i == 0) {
104       orange_ |= value > thresholds[i][1];
105     } else {
106       red_ |= value > thresholds[i][1];
107     }
108   }
109 }
110 
Poll()111 void Ui::Poll() {
112   system_clock.Tick();
113   switches_.Debounce();
114 
115   for (uint8_t i = 0; i < kNumSwitches; ++i) {
116     if (switches_.just_pressed(i)) {
117       queue_.AddEvent(CONTROL_SWITCH, i, 0);
118       press_time_[i] = system_clock.milliseconds();
119     }
120     if (switches_.pressed(i) && press_time_[i] != 0) {
121       int32_t pressed_time = system_clock.milliseconds() - press_time_[i];
122       if (pressed_time > kLongPressDuration) {
123         queue_.AddEvent(CONTROL_SWITCH, i, pressed_time);
124         press_time_[i] = 0;
125       }
126     }
127     if (switches_.released(i) && press_time_[i] != 0) {
128       queue_.AddEvent(
129           CONTROL_SWITCH,
130           i,
131           system_clock.milliseconds() - press_time_[i] + 1);
132       press_time_[i] = 0;
133     }
134   }
135 
136   switch (mode_) {
137     case UI_MODE_NORMAL:
138       {
139         GeneratorMode mode = generator_->mode();
140         leds_.set_mode(mode == GENERATOR_MODE_AR, mode == GENERATOR_MODE_AD);
141 
142         GeneratorRange range = generator_->range();
143         switch (range) {
144           case GENERATOR_RANGE_LOW:
145             leds_.set_rate(0, 65535);
146             break;
147           case GENERATOR_RANGE_MEDIUM:
148             if (generator_->sync()) {
149               leds_.set_rate(8192, 16384);
150             } else {
151               leds_.set_rate(0);
152             }
153             break;
154           case GENERATOR_RANGE_HIGH:
155             leds_.set_rate(65535, 0);
156             break;
157         }
158         bool blink_rate_led = generator_->sync() && \
159             system_clock.milliseconds() & 128;
160         if (blink_rate_led) {
161           leds_.set_rate(0);
162         }
163       }
164       break;
165 
166     case UI_MODE_CALIBRATION_C2:
167       leds_.set_mode(true);
168       leds_.set_rate(65535);
169       leds_.set_value(65535);
170       break;
171 
172     case UI_MODE_CALIBRATION_C4:
173       leds_.set_mode(false, true);
174       leds_.set_rate(0, 65535);
175       leds_.set_value(0, 65535);
176       break;
177 
178     case UI_MODE_PAQUES:
179       leds_.set_mode(true, false);
180       leds_.set_rate(65535, 0);
181       leds_.set_value(65535, 0);
182       break;
183 
184     case UI_MODE_FACTORY_TESTING:
185       if (orange_) {
186         leds_.set_mode(true, true);
187         leds_.set_rate(65535, 65535);
188         leds_.set_value(65535, 65535);
189       } else if (red_) {
190         leds_.set_mode(true, 0);
191         leds_.set_rate(65535, 0);
192         leds_.set_value(65535, 0);
193       } else if (green_) {
194         leds_.set_mode(false, true);
195         leds_.set_rate(0, 65535);
196         leds_.set_value(0, 65535);
197       } else {
198         leds_.set_mode(false, false);
199         leds_.set_rate(0, 0);
200         leds_.set_value(0, 0);
201       }
202       break;
203   }
204 
205   leds_.Write();
206 }
207 
UpdateMode()208 inline void Ui::UpdateMode() {
209   uint8_t i = mode_counter_ & 3;
210   if (i == 3) {
211     i = 1;
212   }
213   generator_->set_mode(static_cast<GeneratorMode>(i));
214   SaveState();
215 }
216 
UpdateRange()217 inline void Ui::UpdateRange() {
218   uint8_t i = range_counter_ & 3;
219   if (i == 3) {
220     i = 1;
221   }
222   generator_->set_range(static_cast<GeneratorRange>(2 - i));
223   SaveState();
224 }
225 
FlushEvents()226 void Ui::FlushEvents() {
227   queue_.Flush();
228 }
229 
OnSwitchPressed(const Event & e)230 void Ui::OnSwitchPressed(const Event& e) {
231   switch (e.control_id) {
232     case 0:
233       break;
234 
235     case 1:
236       break;
237   }
238 }
239 
OnSwitchReleased(const Event & e)240 void Ui::OnSwitchReleased(const Event& e) {
241   if (mode_ == UI_MODE_FACTORY_TESTING) {
242     return;
243   } else if (mode_ == UI_MODE_PAQUES) {
244     mode_ = UI_MODE_NORMAL;
245   } else if (mode_ == UI_MODE_CALIBRATION_C2) {
246     if (e.data > kLongPressDuration) {
247       ++long_press_counter_;
248     }
249     if (e.control_id == 0) {
250       cv_scaler_->CaptureCalibrationValues();
251       mode_ = UI_MODE_CALIBRATION_C4;
252     } else {
253       mode_ = UI_MODE_NORMAL;
254     }
255   } else if (mode_ == UI_MODE_CALIBRATION_C4) {
256     mode_ = UI_MODE_NORMAL;
257     if (e.control_id == 0) {
258       cv_scaler_->Calibrate();
259     } else if (e.control_id == 1 && long_press_counter_ == 1 &&
260                e.data > kLongPressDuration) {
261       mode_ = UI_MODE_PAQUES;
262     }
263   } else {
264     long_press_counter_ = 0;
265     switch (e.control_id) {
266       case 0:
267         if (e.data > kLongPressDuration &&
268             cv_scaler_->can_enter_calibration()) {
269           mode_ = UI_MODE_CALIBRATION_C2;
270         } else {
271           ++mode_counter_;
272           UpdateMode();
273         }
274         break;
275 
276       case 1:
277         if (e.data > kLongPressDuration) {
278           generator_->set_sync(!generator_->sync());
279           SaveState();
280         } else {
281           ++range_counter_;
282           UpdateRange();
283         }
284         break;
285     }
286   }
287 }
288 
DoEvents()289 void Ui::DoEvents() {
290   while (queue_.available()) {
291     Event e = queue_.PullEvent();
292     if (e.control_type == CONTROL_SWITCH) {
293       if (e.data == 0) {
294         OnSwitchPressed(e);
295       } else {
296         OnSwitchReleased(e);
297       }
298     }
299   }
300   if (queue_.idle_time() > 1000) {
301     queue_.Touch();
302   }
303 }
304 
305 }  // namespace tides
306