1 // Copyright 2014 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 "elements/ui.h"
30 
31 #include <algorithm>
32 
33 #include "stmlib/system/system_clock.h"
34 
35 #include "elements/cv_scaler.h"
36 #include "elements/dsp/part.h"
37 
38 namespace elements {
39 
40 using namespace std;
41 using namespace stmlib;
42 
Init(Part * part,CvScaler * cv_scaler)43 void Ui::Init(Part* part, CvScaler* cv_scaler) {
44   leds_.Init();
45   switch_.Init();
46   mode_ = UI_MODE_NORMAL;  // UI_MODE_DISPLAY_MODEL;
47   part_ = part;
48   cv_scaler_ = cv_scaler;
49   part_->set_easter_egg(cv_scaler_->boot_in_easter_egg_mode());
50   part_->set_resonator_model(ResonatorModel(cv_scaler_->resonator_model()));
51 }
52 
Poll()53 void Ui::Poll() {
54   // 1kHz.
55   system_clock.Tick();
56   switch_.Debounce();
57   if (switch_.just_pressed()) {
58     queue_.AddEvent(CONTROL_SWITCH, 0, 0);
59     press_time_ = system_clock.milliseconds();
60   }
61 
62   if (switch_.pressed() && \
63       press_time_ &&
64       (system_clock.milliseconds() - press_time_) >= 3000) {
65     if (cv_scaler_->ready_for_calibration()) {
66       queue_.AddEvent(CONTROL_SWITCH, 1, 0);
67       press_time_ = 0;
68     } else if (cv_scaler_->resonator_high()) {
69       if (cv_scaler_->exciter_low()) {
70         queue_.AddEvent(CONTROL_SWITCH, 2, 0);
71       } else {
72         queue_.AddEvent(CONTROL_SWITCH, 3, 0);
73       }
74       press_time_ = 0;
75     }
76   }
77 
78   if (switch_.released() && press_time_) {
79     queue_.AddEvent(
80         CONTROL_SWITCH,
81         0,
82         system_clock.milliseconds() - press_time_ + 1);
83   }
84 
85   bool blink = (system_clock.milliseconds() & 127) > 64;
86   switch (mode_) {
87     case UI_MODE_NORMAL:
88       leds_.set_gate(part_->gate());
89       leds_.set_exciter(
90           lut_db_led_brightness[int32_t(part_->exciter_level() * 512.0f)]);
91       leds_.set_resonator(
92           lut_db_led_brightness[int32_t(part_->resonator_level() * 512.0f)]);
93       break;
94 
95     case UI_MODE_CALIBRATION_1:
96       leds_.set_gate(!blink);
97       leds_.set_exciter(blink ? 255 : 0);
98       leds_.set_resonator(0);
99       break;
100 
101     case UI_MODE_CALIBRATION_2:
102       leds_.set_gate(!blink);
103       leds_.set_exciter(0);
104       leds_.set_resonator(blink ? 255 : 0);
105       break;
106 
107     case UI_MODE_PANIC:
108       leds_.set_gate(blink);
109       leds_.set_exciter(blink ? 255 : 0);
110       leds_.set_resonator(blink ? 0 : 255);
111       break;
112 
113     case UI_MODE_DISPLAY_MODEL:
114       {
115         bool blink = (system_clock.milliseconds() & 255) > 128;
116         uint8_t count = ((system_clock.milliseconds()) >> 8) & 3;
117         bool pulse = (count <= part_->resonator_model()) && blink;
118         leds_.set_gate(pulse);
119         leds_.set_exciter(pulse ? 255 : 0);
120         leds_.set_resonator(pulse ? 255 : 0);
121       }
122       break;
123   }
124 
125   if (part_->bypass()) {
126     leds_.set_gate(true);
127     leds_.set_exciter(255);
128     leds_.set_resonator(255);
129   }
130 
131   leds_.Write();
132 }
133 
FlushEvents()134 void Ui::FlushEvents() {
135   queue_.Flush();
136 }
137 
OnSwitchPressed(const Event & e)138 void Ui::OnSwitchPressed(const Event& e) {
139   switch (e.control_id) {
140     case 0:
141       if (mode_ == UI_MODE_CALIBRATION_1) {
142         CalibrateC1();
143       } else if (mode_ == UI_MODE_CALIBRATION_2) {
144         CalibrateC3();
145       } else {
146         gate_ = true;
147       }
148       break;
149 
150     case 1:
151       mode_ = UI_MODE_CALIBRATION_1;
152       break;
153 
154     case 2:
155       part_->set_easter_egg(!part_->easter_egg());
156       cv_scaler_->set_boot_in_easter_egg_mode(part_->easter_egg());
157       cv_scaler_->SaveCalibration();
158       gate_ = false;
159       break;
160 
161     case 3:
162       part_->set_resonator_model(
163           ResonatorModel((part_->resonator_model() + 1) % 3));
164       cv_scaler_->set_resonator_model(part_->resonator_model());
165       cv_scaler_->SaveCalibration();
166       gate_ = false;
167       mode_ = UI_MODE_DISPLAY_MODEL;
168       break;
169 
170     default:
171       break;
172   }
173 }
174 
OnSwitchReleased(const Event & e)175 void Ui::OnSwitchReleased(const Event& e) {
176   gate_ = false;
177 }
178 
CalibrateC1()179 void Ui::CalibrateC1() {
180   cv_scaler_->CalibrateC1();
181   cv_scaler_->CalibrateOffsets();
182   mode_ = UI_MODE_CALIBRATION_2;
183 }
184 
CalibrateC3()185 void Ui::CalibrateC3() {
186   bool success = cv_scaler_->CalibrateC3();
187   if (success) {
188     cv_scaler_->SaveCalibration();
189     mode_ = UI_MODE_NORMAL;
190   } else {
191     mode_ = UI_MODE_PANIC;
192   }
193 }
194 
DoEvents()195 void Ui::DoEvents() {
196   while (queue_.available()) {
197     Event e = queue_.PullEvent();
198     if (e.control_type == CONTROL_SWITCH) {
199       if (e.data == 0) {
200         OnSwitchPressed(e);
201       } else {
202         OnSwitchReleased(e);
203       }
204     }
205   }
206   if (mode_ == UI_MODE_DISPLAY_MODEL) {
207     if (queue_.idle_time() > 4000) {
208       mode_ = UI_MODE_NORMAL;
209       queue_.Touch();
210     }
211   } else {
212     if (queue_.idle_time() > 800 && mode_ == UI_MODE_PANIC) {
213       mode_ = UI_MODE_NORMAL;
214     }
215     if (queue_.idle_time() > 1000) {
216       queue_.Touch();
217     }
218   }
219 }
220 
HandleFactoryTestingRequest(uint8_t command)221 uint8_t Ui::HandleFactoryTestingRequest(uint8_t command) {
222   uint8_t argument = command & 0x1f;
223   command = command >> 5;
224   uint8_t reply = 0;
225   switch (command) {
226     case FACTORY_TESTING_READ_POT:
227       reply = cv_scaler_->pot_value(argument);
228       break;
229 
230     case FACTORY_TESTING_READ_CV:
231       reply = cv_scaler_->cv_value(argument);
232       break;
233 
234     case FACTORY_TESTING_READ_GATE:
235       if (argument == 0x00) {
236         return gate_;
237       } else {
238         return cv_scaler_->gate();
239       }
240       break;
241 
242     case FACTORY_TESTING_SET_BYPASS:
243       part_->set_bypass(argument);
244       break;
245 
246     case FACTORY_TESTING_CALIBRATE:
247       if (argument == 0) {
248         mode_ = UI_MODE_CALIBRATION_1;
249       } else if (argument == 1) {
250         CalibrateC1();
251       } else {
252         CalibrateC3();
253 
254       }
255       break;
256   }
257   return reply;
258 }
259 
260 }  // namespace elements
261