You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

382 lines
10.0KB

  1. // Copyright 2014 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. #include "warps/ui.h"
  29. #include <algorithm>
  30. #include "stmlib/system/system_clock.h"
  31. #include "stmlib/dsp/units.h"
  32. #include "warps/cv_scaler.h"
  33. namespace warps {
  34. using namespace std;
  35. using namespace stmlib;
  36. /* static */
  37. const uint8_t Ui::palette_[10][3] = {
  38. { 0, 192, 64 },
  39. { 64, 255, 0 },
  40. { 255, 255, 0 },
  41. { 255, 64, 0 },
  42. { 255, 0, 0 },
  43. { 255, 0, 64 },
  44. { 255, 0, 255 },
  45. { 0, 0, 255 },
  46. { 0, 255, 192 },
  47. { 0, 255, 192 },
  48. };
  49. /* static */
  50. const uint8_t Ui::easter_egg_palette_[10][3] = {
  51. { 0, 0, 64 },
  52. { 0, 0, 255 },
  53. { 0, 255, 192 },
  54. { 0, 192, 64 },
  55. { 64, 255, 0 },
  56. { 255, 255, 0 },
  57. { 255, 192, 0 },
  58. { 255, 64, 0 },
  59. { 255, 0, 0 },
  60. { 255, 0, 0 },
  61. };
  62. void Ui::Init(Settings* settings, CvScaler* cv_scaler, Modulator* modulator) {
  63. leds_.Init();
  64. switches_.Init();
  65. mode_ = UI_MODE_NORMAL;
  66. settings_ = settings;
  67. cv_scaler_ = cv_scaler;
  68. modulator_ = modulator;
  69. modulator_->set_easter_egg(settings_->state().boot_in_easter_egg_mode);
  70. carrier_shape_ = settings_->state().carrier_shape;
  71. UpdateCarrierShape();
  72. }
  73. void Ui::UpdateCarrierShape() {
  74. modulator_->mutable_parameters()->carrier_shape = carrier_shape_;
  75. settings_->mutable_state()->carrier_shape = carrier_shape_;
  76. }
  77. void Ui::Poll() {
  78. // Called at 1.6kHz instead of 1kHz, so the "milliseconds" clock actually runs
  79. // 1.6x faster. Not a big deal since it is used only for controlling LED
  80. // blinking rate and detecting long button presses.
  81. system_clock.Tick();
  82. switches_.Debounce();
  83. if (switches_.just_pressed(0)) {
  84. queue_.AddEvent(CONTROL_SWITCH, 0, 0);
  85. press_time_ = system_clock.milliseconds();
  86. }
  87. if (switches_.pressed(0) && press_time_) {
  88. if (cv_scaler_->ready_for_calibration() && (system_clock.milliseconds() - press_time_) >= 4800) {
  89. queue_.AddEvent(CONTROL_SWITCH, 1, 0);
  90. press_time_ = 0;
  91. } else if ((system_clock.milliseconds() - press_time_) >= 9600) {
  92. queue_.AddEvent(CONTROL_SWITCH, 2, 0);
  93. press_time_ = 0;
  94. }
  95. }
  96. if (switches_.released(0) && press_time_) {
  97. queue_.AddEvent(
  98. CONTROL_SWITCH,
  99. 0,
  100. system_clock.milliseconds() - press_time_ + 1);
  101. }
  102. bool blink = (system_clock.milliseconds() & 127) > 64;
  103. bool slow_blink = (system_clock.milliseconds() & 255) > 128;
  104. switch (mode_) {
  105. case UI_MODE_NORMAL:
  106. {
  107. uint8_t rgb[3];
  108. float zone;
  109. const Parameters& p = modulator_->parameters();
  110. const uint8_t (*palette)[3];
  111. if (modulator_->easter_egg()) {
  112. zone = p.phase_shift;
  113. palette = easter_egg_palette_;
  114. } else {
  115. zone = p.modulation_algorithm;
  116. palette = palette_;
  117. }
  118. zone *= 8.0f;
  119. MAKE_INTEGRAL_FRACTIONAL(zone);
  120. int32_t zone_fractional_i = static_cast<int32_t>(
  121. zone_fractional * 256.0f);
  122. for (int32_t i = 0; i < 3; ++i) {
  123. int32_t a = palette[zone_integral][i];
  124. int32_t b = palette[zone_integral + 1][i];
  125. rgb[i] = a + ((b - a) * zone_fractional_i >> 8);
  126. }
  127. leds_.set_main(rgb[0], rgb[1], rgb[2]);
  128. leds_.set_osc(
  129. carrier_shape_ >= 2 ? 255 : 0,
  130. carrier_shape_ > 0 && carrier_shape_ <= 2 ? 255 : 0);
  131. }
  132. break;
  133. case UI_MODE_CALIBRATION_C1:
  134. leds_.set_main(0, blink ? 255 : 0, blink ? 64 : 0);
  135. leds_.set_osc(blink ? 255 : 0, blink ? 255 : 0);
  136. break;
  137. case UI_MODE_CALIBRATION_C3:
  138. leds_.set_main(blink ? 255 : 0, 0, blink ? 32 : 0);
  139. leds_.set_osc(blink ? 255 : 0, 0);
  140. break;
  141. case UI_MODE_CALIBRATION_LOW:
  142. leds_.set_main(slow_blink ? 255 : 0, 0, 0);
  143. leds_.set_osc(slow_blink ? 255 : 0, 0);
  144. break;
  145. case UI_MODE_CALIBRATION_HIGH:
  146. leds_.set_main(0, slow_blink ? 255 : 0, 0);
  147. leds_.set_osc(0, slow_blink ? 255 : 0);
  148. break;
  149. case UI_MODE_PANIC:
  150. case UI_MODE_CALIBRATION_ERROR:
  151. leds_.set_osc(blink ? 255 : 0, 0);
  152. leds_.set_main(blink ? 255 : 0, 0, 0);
  153. break;
  154. case UI_MODE_EASTER_EGG_DANCE:
  155. {
  156. leds_.set_osc(0, blink ? 255 : 0);
  157. uint8_t color = (system_clock.milliseconds() >> 9) % 9;
  158. leds_.set_main(
  159. easter_egg_palette_[color][0],
  160. easter_egg_palette_[color][1],
  161. easter_egg_palette_[color][2]);
  162. }
  163. break;
  164. }
  165. if (modulator_->bypass()) {
  166. uint16_t red = system_clock.milliseconds() & 4095;
  167. uint16_t green = (system_clock.milliseconds() + 1333) & 4095;
  168. uint16_t blue = (system_clock.milliseconds() + 2667) & 4095;
  169. green = green < 2048 ? green : 4095 - green;
  170. red = red < 2048 ? red : 4095 - red;
  171. blue = blue < 2048 ? blue : 4095 - blue;
  172. leds_.set_osc(255, 255);
  173. leds_.set_main(red >> 3, green >> 3, blue >> 3);
  174. }
  175. leds_.Write();
  176. }
  177. bool Ui::DetectSecretHandshake() {
  178. for (int32_t i = 0; i < 5; ++i) {
  179. secret_handshake_[i] = secret_handshake_[i + 1];
  180. }
  181. secret_handshake_[5] = cv_scaler_->easter_egg_digit();
  182. uint8_t expected[6] = { 2, 4, 3, 6, 1, 5 };
  183. return equal(
  184. &secret_handshake_[0],
  185. &secret_handshake_[6],
  186. &expected[0]);
  187. }
  188. void Ui::OnSwitchPressed(const Event& e) {
  189. switch (e.control_id) {
  190. case 0:
  191. switch (mode_) {
  192. case UI_MODE_CALIBRATION_C1:
  193. CalibrateC1();
  194. break;
  195. case UI_MODE_CALIBRATION_C3:
  196. CalibrateC3();
  197. break;
  198. case UI_MODE_CALIBRATION_LOW:
  199. CalibrateLow();
  200. break;
  201. case UI_MODE_CALIBRATION_HIGH:
  202. CalibrateHigh();
  203. break;
  204. default:
  205. if (!DetectSecretHandshake()) {
  206. carrier_shape_ = (carrier_shape_ + 1) & 3;
  207. } else {
  208. bool easter = !modulator_->easter_egg();
  209. modulator_->set_easter_egg(easter);
  210. settings_->mutable_state()->boot_in_easter_egg_mode = easter;
  211. carrier_shape_ = 1;
  212. mode_ = UI_MODE_EASTER_EGG_DANCE;
  213. }
  214. UpdateCarrierShape();
  215. settings_->Save();
  216. break;
  217. }
  218. break;
  219. case 1:
  220. StartCalibration();
  221. break;
  222. case 2:
  223. StartNormalizationCalibration();
  224. break;
  225. default:
  226. break;
  227. }
  228. }
  229. void Ui::OnSwitchReleased(const Event& e) {
  230. }
  231. void Ui::StartCalibration() {
  232. cv_scaler_->StartCalibration();
  233. mode_ = UI_MODE_CALIBRATION_C1;
  234. }
  235. void Ui::CalibrateC1() {
  236. cv_scaler_->CalibrateC1();
  237. cv_scaler_->CalibrateOffsets();
  238. mode_ = UI_MODE_CALIBRATION_C3;
  239. }
  240. void Ui::CalibrateC3() {
  241. if (cv_scaler_->CalibrateC3()) {
  242. settings_->Save();
  243. mode_ = UI_MODE_NORMAL;
  244. } else {
  245. mode_ = UI_MODE_CALIBRATION_ERROR;
  246. }
  247. }
  248. void Ui::StartNormalizationCalibration() {
  249. cv_scaler_->StartNormalizationCalibration();
  250. mode_ = UI_MODE_CALIBRATION_LOW;
  251. }
  252. void Ui::CalibrateLow() {
  253. cv_scaler_->CalibrateLow();
  254. mode_ = UI_MODE_CALIBRATION_HIGH;
  255. }
  256. void Ui::CalibrateHigh() {
  257. if (cv_scaler_->CalibrateHigh()) {
  258. settings_->Save();
  259. mode_ = UI_MODE_NORMAL;
  260. } else {
  261. mode_ = UI_MODE_CALIBRATION_ERROR;
  262. }
  263. }
  264. void Ui::DoEvents() {
  265. while (queue_.available()) {
  266. Event e = queue_.PullEvent();
  267. if (e.control_type == CONTROL_SWITCH) {
  268. if (e.data == 0) {
  269. OnSwitchPressed(e);
  270. } else {
  271. OnSwitchReleased(e);
  272. }
  273. }
  274. }
  275. if (mode_ == UI_MODE_EASTER_EGG_DANCE || mode_ == UI_MODE_CALIBRATION_ERROR) {
  276. if (queue_.idle_time() > 6000) {
  277. mode_ = UI_MODE_NORMAL;
  278. }
  279. } else {
  280. if (queue_.idle_time() > 1000) {
  281. queue_.Touch();
  282. }
  283. }
  284. }
  285. uint8_t Ui::HandleFactoryTestingRequest(uint8_t command) {
  286. uint8_t argument = command & 0x1f;
  287. command = command >> 5;
  288. uint8_t reply = 0;
  289. switch (command) {
  290. case FACTORY_TESTING_READ_POT:
  291. case FACTORY_TESTING_READ_CV:
  292. reply = cv_scaler_->adc_value(argument);
  293. break;
  294. case FACTORY_TESTING_READ_NORMALIZATION:
  295. reply = cv_scaler_->normalization(argument);
  296. break;
  297. case FACTORY_TESTING_READ_GATE:
  298. return switches_.pressed(argument);
  299. break;
  300. case FACTORY_TESTING_SET_BYPASS:
  301. modulator_->set_bypass(argument);
  302. break;
  303. case FACTORY_TESTING_CALIBRATE:
  304. {
  305. switch (argument) {
  306. case 0:
  307. StartCalibration();
  308. break;
  309. case 1:
  310. CalibrateC1();
  311. break;
  312. case 2:
  313. CalibrateC3();
  314. break;
  315. case 3:
  316. StartNormalizationCalibration();
  317. break;
  318. case 4:
  319. CalibrateLow();
  320. break;
  321. case 5:
  322. CalibrateHigh();
  323. carrier_shape_ = 0;
  324. UpdateCarrierShape();
  325. break;
  326. }
  327. }
  328. break;
  329. }
  330. return reply;
  331. }
  332. } // namespace warps