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