1 // Copyright 2017 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 "tides2/ui.h"
30
31 #include <algorithm>
32
33 #include "stmlib/system/system_clock.h"
34
35 #include "tides2/factory_test.h"
36
37 using namespace std;
38 using namespace stmlib;
39
40 const int32_t kLongPressDuration = 1200;
41
42 namespace tides {
43
44 /* static */
45 const LedColor Ui::palette_[4] = {
46 LED_COLOR_GREEN,
47 LED_COLOR_YELLOW,
48 LED_COLOR_RED,
49 LED_COLOR_OFF
50 };
51
Init(Settings * settings,FactoryTest * factory_test)52 void Ui::Init(Settings* settings, FactoryTest* factory_test) {
53 leds_.Init();
54 switches_.Init();
55
56 system_clock.Init();
57
58 settings_ = settings;
59 factory_test_ = factory_test;
60 mode_ = UI_MODE_NORMAL;
61
62 if (switches_.pressed_immediate(SWITCH_SHIFT)) {
63 State* state = settings_->mutable_state();
64 if (state->color_blind == 1) {
65 state->color_blind = 0;
66 } else {
67 state->color_blind = 1;
68 }
69 settings_->SaveState();
70 }
71
72 queue_.Init();
73
74 fill(&press_time_[0], &press_time_[SWITCH_LAST], 0);
75 fill(&ignore_release_[0], &ignore_release_[SWITCH_LAST], false);
76 }
77
Poll()78 void Ui::Poll() {
79 system_clock.Tick();
80 UpdateLEDs();
81
82 switches_.Debounce();
83
84 for (int i = 0; i < SWITCH_LAST; ++i) {
85 Switch s = Switch(i);
86 if (switches_.just_pressed(s)) {
87 queue_.AddEvent(CONTROL_SWITCH, i, 0);
88 press_time_[i] = system_clock.milliseconds();
89 ignore_release_[i] = false;
90 }
91 if (switches_.pressed(s) && !ignore_release_[i]) {
92 int32_t pressed_time = system_clock.milliseconds() - press_time_[i];
93 if (pressed_time > kLongPressDuration) {
94 queue_.AddEvent(CONTROL_SWITCH, i, pressed_time);
95 ignore_release_[i] = true;
96 }
97 }
98 if (switches_.released(s) && !ignore_release_[i]) {
99 queue_.AddEvent(
100 CONTROL_SWITCH,
101 i,
102 system_clock.milliseconds() - press_time_[i] + 1);
103 ignore_release_[i] = true;
104 }
105 }
106 }
107
MakeColor(uint8_t value,bool color_blind)108 LedColor Ui::MakeColor(uint8_t value, bool color_blind) {
109 LedColor color = palette_[value];
110 if (color_blind) {
111 uint8_t pwm_counter = system_clock.milliseconds() & 15;
112 uint8_t triangle = (system_clock.milliseconds() >> 5) & 31;
113 triangle = triangle < 16 ? triangle : 31 - triangle;
114
115 if (value == 0) {
116 color = pwm_counter < (4 + (triangle >> 2))
117 ? LED_COLOR_GREEN
118 : LED_COLOR_OFF;
119 } else if (value == 1) {
120 color = LED_COLOR_YELLOW;
121 } else if (value == 2) {
122 color = pwm_counter == 0 ? LED_COLOR_RED : LED_COLOR_OFF;
123 }
124 }
125 return color;
126 }
127
UpdateLEDs()128 void Ui::UpdateLEDs() {
129 leds_.Clear();
130
131 bool blink = system_clock.milliseconds() & 256;
132
133 switch (mode_) {
134 case UI_MODE_NORMAL:
135 {
136 const State& s = settings_->state();
137 bool color_blind = s.color_blind == 1;
138
139 leds_.set(LED_MODE, MakeColor(s.mode, color_blind));
140 leds_.set(LED_RANGE, MakeColor(s.range, color_blind));
141 leds_.set(LED_SHIFT, MakeColor((s.output_mode + 3) % 4, color_blind));
142 }
143 break;
144
145 case UI_MODE_CALIBRATION_C1:
146 leds_.set(LED_RANGE, blink ? LED_COLOR_YELLOW : LED_COLOR_OFF);
147 break;
148
149 case UI_MODE_CALIBRATION_C3:
150 leds_.set(LED_SHIFT, blink ? LED_COLOR_YELLOW : LED_COLOR_OFF);
151 break;
152
153 case UI_MODE_FACTORY_TEST:
154 {
155 size_t counter = (system_clock.milliseconds() >> 8) % 3;
156 for (size_t i = 0; i < 3; ++i) {
157 leds_.set(Led(i), palette_[counter]);
158 }
159 }
160 break;
161 }
162 leds_.Write();
163 }
164
OnSwitchPressed(const Event & e)165 void Ui::OnSwitchPressed(const Event& e) {
166
167 }
168
OnSwitchReleased(const Event & e)169 void Ui::OnSwitchReleased(const Event& e) {
170 if (mode_ == UI_MODE_NORMAL && e.data >= kLongPressDuration) {
171 if ((e.control_id == SWITCH_RANGE && switches_.pressed(SWITCH_SHIFT)) ||
172 (e.control_id == SWITCH_SHIFT && switches_.pressed(SWITCH_RANGE))) {
173 mode_ = UI_MODE_CALIBRATION_C1;
174 factory_test_->Calibrate(0, 1.0f, 3.0f);
175 ignore_release_[SWITCH_RANGE] = ignore_release_[SWITCH_SHIFT] = true;
176 }
177 } else if (mode_ == UI_MODE_CALIBRATION_C1) {
178 factory_test_->Calibrate(1, 1.0f, 3.0f);
179 mode_ = UI_MODE_CALIBRATION_C3;
180 } else if (mode_ == UI_MODE_CALIBRATION_C3) {
181 factory_test_->Calibrate(2, 1.0f, 3.0f);
182 mode_ = UI_MODE_NORMAL;
183 } else {
184 State* s = settings_->mutable_state();
185 switch (e.control_id) {
186 case SWITCH_MODE:
187 s->mode = (s->mode + 1) % 3;
188 break;
189 case SWITCH_RANGE:
190 s->range = (s->range + 1) % 3;
191 break;
192 case SWITCH_SHIFT:
193 s->output_mode = (s->output_mode + 1) % 4;
194 break;
195 }
196 settings_->SaveState();
197 }
198 }
199
DoEvents()200 void Ui::DoEvents() {
201 while (queue_.available()) {
202 Event e = queue_.PullEvent();
203 if (e.control_type == CONTROL_SWITCH) {
204 if (e.data == 0) {
205 OnSwitchPressed(e);
206 } else {
207 OnSwitchReleased(e);
208 }
209 }
210 }
211
212 if (queue_.idle_time() > 1000) {
213 queue_.Touch();
214 }
215 }
216
217 } // namespace tides
218