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 //
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 const uint8_t kMagicNumber = 42;
41
42 using namespace stmlib;
43
44 Storage<0x801fc00, 4> mode_storage;
45
Init(Generator * generator,CvScaler * cv_scaler)46 void Ui::Init(Generator* generator, CvScaler* cv_scaler) {
47 factory_testing_switch_.Init();
48 leds_.Init();
49 switches_.Init();
50 mode_ = factory_testing_switch_.Read()
51 ? UI_MODE_NORMAL
52 : UI_MODE_FACTORY_TESTING;
53
54 ignore_releases_ = 0;
55
56 if (switches_.pressed_immediate(1)) {
57 mode_ = UI_MODE_CALIBRATION_C2;
58 ignore_releases_ = 1;
59 }
60
61 generator->feature_mode_ = Generator::FEAT_MODE_FUNCTION;
62
63 generator_ = generator;
64 cv_scaler_ = cv_scaler;
65
66 if (!mode_storage.ParsimoniousLoad(&settings_, &version_token_) ||
67 settings_.magic_number != kMagicNumber) {
68 settings_.magic_number = kMagicNumber;
69 mode_counter_ = 1;
70 range_counter_ = 2;
71 cv_scaler_->quantize_ = 0;
72 generator->set_sync(false);
73 } else {
74 mode_counter_ = settings_.mode;
75 range_counter_ = 2 - settings_.range;
76 cv_scaler_->quantize_ = settings_.quantize;
77 generator->feature_mode_ = static_cast<Generator::FeatureMode>(settings_.feature_mode);
78 generator->set_sync(settings_.sync);
79 }
80
81 UpdateMode();
82 UpdateRange();
83 leds_.set_value(32768, 32768);
84 }
85
SaveState()86 void Ui::SaveState() {
87 settings_.mode = generator_->mode();
88 settings_.range = generator_->range();
89 settings_.sync = generator_->sync();
90 settings_.feature_mode = generator_->feature_mode_;
91 settings_.quantize = cv_scaler_->quantize_;
92 mode_storage.ParsimoniousSave(settings_, &version_token_);
93 }
94
95 const uint16_t thresholds[ADC_CHANNEL_LAST][2] = {
96 { 0, 64000 },
97 { 16384, 49152 },
98 { 16384, 49152 },
99 { 4096, 61440 },
100 { 4096, 61440 },
101 { 4096, 61440 },
102 { 4096, 61440 },
103 };
104
UpdateFactoryTestingFlags(uint8_t gate_input_flags,const uint16_t * adc_values)105 void Ui::UpdateFactoryTestingFlags(
106 uint8_t gate_input_flags,
107 const uint16_t* adc_values) {
108 red_ = switches_.pressed(1);
109 green_ = switches_.pressed(0);
110 orange_ = gate_input_flags & CONTROL_GATE;
111 orange_ |= gate_input_flags & CONTROL_FREEZE;
112 orange_ |= gate_input_flags & CONTROL_CLOCK;
113
114 for (uint16_t i = 0; i < ADC_CHANNEL_LAST; ++i) {
115 uint16_t value = adc_values[i];
116 if (i == ADC_CHANNEL_FM_ATTENUVERTER) {
117 value = ~value;
118 }
119 green_ |= value < thresholds[i][0];
120 if (i == 0) {
121 orange_ |= value > thresholds[i][1];
122 } else {
123 red_ |= value > thresholds[i][1];
124 }
125 }
126 }
127
Poll()128 void Ui::Poll() {
129 system_clock.Tick();
130 switches_.Debounce();
131
132 for (uint8_t i = 0; i < kNumSwitches; ++i) {
133 if (switches_.just_pressed(i)) {
134 queue_.AddEvent(CONTROL_SWITCH, i, 0);
135 press_time_[i] = system_clock.milliseconds();
136 }
137 if (switches_.pressed(i) && press_time_[i] != 0) {
138 int32_t pressed_time = system_clock.milliseconds() - press_time_[i];
139 if (pressed_time > kLongPressDuration) {
140 queue_.AddEvent(CONTROL_SWITCH, i, pressed_time);
141 press_time_[i] = 0;
142 }
143 }
144 if (switches_.released(i) && press_time_[i] != 0) {
145 queue_.AddEvent(
146 CONTROL_SWITCH,
147 i,
148 system_clock.milliseconds() - press_time_[i] + 1);
149 press_time_[i] = 0;
150 }
151 }
152
153 switch (mode_) {
154 case UI_MODE_FEATURE_SWITCH:
155 {
156 bool blink = system_clock.milliseconds() & 32;
157 switch (generator_->feature_mode_) {
158 case Generator::FEAT_MODE_FUNCTION:
159 leds_.set_mode(blink);
160 leds_.set_value(0);
161 leds_.set_rate(0);
162 break;
163 case Generator::FEAT_MODE_HARMONIC:
164 leds_.set_mode(0);
165 leds_.set_value(blink ? 65535 : 0);
166 leds_.set_rate(0);
167 break;
168 case Generator::FEAT_MODE_RANDOM:
169 leds_.set_mode(0);
170 leds_.set_value(0);
171 leds_.set_rate(blink ? 65535 : 0);
172 break;
173 }
174 }
175 break;
176 case UI_MODE_QUANTIZE:
177 {
178 bool led1 = cv_scaler_->quantize_ & 1;
179 bool led2 = cv_scaler_->quantize_ & 2;
180 bool led3 = cv_scaler_->quantize_ & 4;
181 uint16_t on = ((system_clock.milliseconds() & 16) &&
182 (system_clock.milliseconds() & 8) &&
183 (system_clock.milliseconds() & 4) &&
184 (system_clock.milliseconds() & 2)) * 65535;
185 uint16_t off = 0;
186 leds_.set_mode(0, led1 ? on : off);
187 leds_.set_value(0, led2 ? on : off);
188 leds_.set_rate(0, led3 ? on : off);
189 }
190 break;
191 case UI_MODE_NORMAL:
192 {
193 GeneratorMode mode = generator_->mode();
194 leds_.set_mode(mode == GENERATOR_MODE_AR, mode == GENERATOR_MODE_AD);
195
196 GeneratorRange range = generator_->range();
197 switch (range) {
198 case GENERATOR_RANGE_LOW:
199 leds_.set_rate(0, 65535);
200 break;
201 case GENERATOR_RANGE_MEDIUM:
202 if (generator_->sync()) {
203 leds_.set_rate(8192, 16384);
204 } else {
205 leds_.set_rate(0);
206 }
207 break;
208 case GENERATOR_RANGE_HIGH:
209 leds_.set_rate(65535, 0);
210 break;
211 }
212 bool blink_rate_led = generator_->sync() && \
213 system_clock.milliseconds() & 128;
214 if (blink_rate_led) {
215 leds_.set_rate(0);
216 }
217 }
218 break;
219
220 case UI_MODE_CALIBRATION_C2:
221 leds_.set_mode(true);
222 leds_.set_rate(65535);
223 leds_.set_value(65535);
224 break;
225
226 case UI_MODE_CALIBRATION_C4:
227 leds_.set_mode(false, true);
228 leds_.set_rate(0, 65535);
229 leds_.set_value(0, 65535);
230 break;
231
232 case UI_MODE_FACTORY_TESTING:
233 if (orange_) {
234 leds_.set_mode(true, true);
235 leds_.set_rate(65535, 65535);
236 leds_.set_value(65535, 65535);
237 } else if (red_) {
238 leds_.set_mode(true, 0);
239 leds_.set_rate(65535, 0);
240 leds_.set_value(65535, 0);
241 } else if (green_) {
242 leds_.set_mode(false, true);
243 leds_.set_rate(0, 65535);
244 leds_.set_value(0, 65535);
245 } else {
246 leds_.set_mode(false, false);
247 leds_.set_rate(0, 0);
248 leds_.set_value(0, 0);
249 }
250 break;
251 }
252
253 leds_.Write();
254 }
255
UpdateMode()256 inline void Ui::UpdateMode() {
257 uint8_t i = mode_counter_ & 3;
258 if (i == 3) {
259 i = 1;
260 }
261 generator_->set_mode(static_cast<GeneratorMode>(i));
262 SaveState();
263 }
264
UpdateRange()265 inline void Ui::UpdateRange() {
266 uint8_t i = range_counter_ & 3;
267 if (i == 3) {
268 i = 1;
269 }
270 generator_->set_range(static_cast<GeneratorRange>(2 - i));
271 SaveState();
272 }
273
FlushEvents()274 void Ui::FlushEvents() {
275 queue_.Flush();
276 }
277
OnSwitchPressed(const Event & e)278 void Ui::OnSwitchPressed(const Event& e) {
279 // double press -> feature switch mode
280 if ((e.control_id == 0 && switches_.pressed_immediate(1)) ||
281 (e.control_id == 1 && switches_.pressed_immediate(0))) {
282 mode_ = UI_MODE_FEATURE_SWITCH;
283 ignore_releases_ = 2;
284 }
285 }
286
OnSwitchReleased(const Event & e)287 void Ui::OnSwitchReleased(const Event& e) {
288
289 // hack for double presses
290 if (ignore_releases_ > 0) {
291 ignore_releases_--;
292 return;
293 }
294
295 if (mode_ == UI_MODE_FACTORY_TESTING) {
296 return;
297 } else if (mode_ == UI_MODE_FEATURE_SWITCH) {
298 uint8_t feat = generator_->feature_mode_;
299 int8_t dir = e.control_id == 0 ? -1 : 1;
300 int8_t mode = (feat + dir) % 3;
301 if (mode == -1) mode = 2;
302 generator_->feature_mode_ = static_cast<Generator::FeatureMode>(mode);
303 UpdateMode();
304 UpdateRange();
305 } else if (mode_ == UI_MODE_QUANTIZE) {
306 if (e.data > kLongPressDuration) {
307 mode_ = UI_MODE_NORMAL;
308 } else {
309 uint8_t q = cv_scaler_->quantize_;
310 int8_t dir = e.control_id == 0 ? -1 : 1;
311 int8_t quant = (q + dir) % 8;
312 if (quant == -1) quant = 7;
313 cv_scaler_->quantize_ = quant;
314 SaveState();
315 }
316 } else if (mode_ == UI_MODE_CALIBRATION_C2) {
317 if (e.data > kLongPressDuration) {
318 ++long_press_counter_;
319 }
320 if (e.control_id == 0) {
321 cv_scaler_->CaptureCalibrationValues();
322 mode_ = UI_MODE_CALIBRATION_C4;
323 } else {
324 mode_ = UI_MODE_NORMAL;
325 }
326 } else if (mode_ == UI_MODE_CALIBRATION_C4) {
327 mode_ = UI_MODE_NORMAL;
328 if (e.control_id == 0) {
329 cv_scaler_->Calibrate();
330 }
331 } else {
332 long_press_counter_ = 0;
333 switch (e.control_id) {
334 case 0:
335 if (e.data > kLongPressDuration) {
336 mode_ = UI_MODE_QUANTIZE;
337 } else {
338 ++mode_counter_;
339 UpdateMode();
340 }
341 break;
342
343 case 1:
344 if (e.data > kLongPressDuration) {
345 generator_->set_sync(!generator_->sync());
346 SaveState();
347 } else {
348 ++range_counter_;
349 UpdateRange();
350 }
351 break;
352 }
353 }
354 }
355
DoEvents()356 void Ui::DoEvents() {
357 while (queue_.available()) {
358 Event e = queue_.PullEvent();
359 if (e.control_type == CONTROL_SWITCH) {
360 if (e.data == 0) {
361 OnSwitchPressed(e);
362 } else {
363 OnSwitchReleased(e);
364 }
365 }
366 }
367 if (queue_.idle_time() > 2000) {
368 queue_.Touch();
369 if (mode_ == UI_MODE_FEATURE_SWITCH)
370 mode_ = UI_MODE_NORMAL;
371 }
372 }
373
374 } // namespace tides
375