|
- // Copyright 2015 Olivier Gillet.
- //
- // Author: Olivier Gillet (ol.gillet@gmail.com)
- //
- // Permission is hereby granted, free of charge, to any person obtaining a copy
- // of this software and associated documentation files (the "Software"), to deal
- // in the Software without restriction, including without limitation the rights
- // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- // copies of the Software, and to permit persons to whom the Software is
- // furnished to do so, subject to the following conditions:
- //
- // The above copyright notice and this permission notice shall be included in
- // all copies or substantial portions of the Software.
- //
- // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- // THE SOFTWARE.
- //
- // See http://creativecommons.org/licenses/MIT/ for more information.
- //
- // -----------------------------------------------------------------------------
- //
- // User interface.
-
- #include "marbles/ui.h"
-
- #include <algorithm>
-
- #include "stmlib/system/system_clock.h"
-
- #include "marbles/drivers/clock_inputs.h"
- #include "marbles/cv_reader.h"
- #include "marbles/scale_recorder.h"
- #include "marbles/settings.h"
-
- namespace marbles {
-
- const int32_t kLongPressDuration = 2000;
-
- using namespace std;
- using namespace stmlib;
-
- /* static */
- const LedColor Ui::palette_[4] = {
- LED_COLOR_GREEN,
- LED_COLOR_YELLOW,
- LED_COLOR_RED,
- LED_COLOR_OFF
- };
-
- /* static */
- AlternateKnobMapping Ui::alternate_knob_mappings_[ADC_CHANNEL_LAST];
-
- void Ui::Init(
- Settings* settings,
- CvReader* cv_reader,
- ScaleRecorder* scale_recorder,
- ClockInputs* clock_inputs) {
- settings_ = settings;
- cv_reader_ = cv_reader;
- scale_recorder_ = scale_recorder;
- clock_inputs_ = clock_inputs;
-
- leds_.Init();
- switches_.Init();
- queue_.Init();
-
- // Initialize generator from settings_->state();
- fill(&pot_value_[0], &pot_value_[ADC_CHANNEL_LAST], 0.0f);
-
- State* state = settings_->mutable_state();
- alternate_knob_mappings_[ADC_CHANNEL_T_BIAS].unlock_switch = SWITCH_T_MODEL;
- alternate_knob_mappings_[ADC_CHANNEL_T_BIAS].destination = &state->t_pulse_width_mean;
- alternate_knob_mappings_[ADC_CHANNEL_T_JITTER].unlock_switch = SWITCH_T_MODEL;
- alternate_knob_mappings_[ADC_CHANNEL_T_JITTER].destination = &state->t_pulse_width_std;
- alternate_knob_mappings_[ADC_CHANNEL_T_RATE].unlock_switch = SWITCH_X_MODE;
- alternate_knob_mappings_[ADC_CHANNEL_T_RATE].destination = &state->y_divider;
- alternate_knob_mappings_[ADC_CHANNEL_X_SPREAD].unlock_switch = SWITCH_X_MODE;
- alternate_knob_mappings_[ADC_CHANNEL_X_SPREAD].destination = &state->y_spread;
- alternate_knob_mappings_[ADC_CHANNEL_X_BIAS].unlock_switch = SWITCH_X_MODE;
- alternate_knob_mappings_[ADC_CHANNEL_X_BIAS].destination = &state->y_bias;
- alternate_knob_mappings_[ADC_CHANNEL_X_STEPS].unlock_switch = SWITCH_X_MODE;
- alternate_knob_mappings_[ADC_CHANNEL_X_STEPS].destination = &state->y_steps;
-
- setting_modification_flag_ = false;
- output_test_mode_ = false;
-
- if (switches_.pressed_immediate(SWITCH_X_MODE)) {
- if (state->color_blind == 1) {
- state->color_blind = 0;
- } else {
- state->color_blind = 1;
- }
- settings_->SaveState();
- }
-
- deja_vu_lock_ = false;
- }
-
- void Ui::SaveState() {
- settings_->SaveState();
- }
-
- void Ui::Poll() {
- // 1kHz.
- system_clock.Tick();
- switches_.Debounce();
-
- for (int i = 0; i < SWITCH_LAST; ++i) {
- if (switches_.just_pressed(Switch(i))) {
- queue_.AddEvent(CONTROL_SWITCH, i, 0);
- press_time_[i] = system_clock.milliseconds();
- ignore_release_[i] = false;
- }
- if (switches_.pressed(Switch(i)) && !ignore_release_[i]) {
- int32_t pressed_time = system_clock.milliseconds() - press_time_[i];
- if (pressed_time > kLongPressDuration && !setting_modification_flag_) {
- queue_.AddEvent(CONTROL_SWITCH, i, pressed_time);
- ignore_release_[i] = true;
- }
- }
- if (switches_.released(Switch(i)) && !ignore_release_[i]) {
- queue_.AddEvent(
- CONTROL_SWITCH,
- i,
- system_clock.milliseconds() - press_time_[i] + 1);
- ignore_release_[i] = true;
- }
- }
-
- UpdateLEDs();
- }
-
- /* static */
- LedColor Ui::MakeColor(uint8_t value, bool color_blind) {
- bool slow_blink = (system_clock.milliseconds() & 255) > 128;
-
- uint8_t bank = value >= 3 ? 1 : 0;
- value -= bank * 3;
-
- LedColor color = palette_[value];
- if (color_blind) {
- uint8_t pwm_counter = system_clock.milliseconds() & 15;
- uint8_t triangle = (system_clock.milliseconds() >> 5) & 31;
- triangle = triangle < 16 ? triangle : 31 - triangle;
-
- if (value == 0) {
- color = pwm_counter < (4 + (triangle >> 2))
- ? LED_COLOR_GREEN
- : LED_COLOR_OFF;
- } else if (value == 1) {
- color = LED_COLOR_YELLOW;
- } else {
- color = pwm_counter == 0 ? LED_COLOR_RED : LED_COLOR_OFF;
- }
- }
-
- return slow_blink || !bank ? color : LED_COLOR_OFF;
- }
-
- void Ui::UpdateLEDs() {
- bool blink = (system_clock.milliseconds() & 127) > 64;
- bool slow_blink = (system_clock.milliseconds() & 255) > 128;
- bool fast_blink = (system_clock.milliseconds() & 63) > 32;
- const State& state = settings_->state();
- bool cb = state.color_blind == 1;
-
- LedColor scale_color = state.x_scale < 3
- ? (slow_blink ? palette_[state.x_scale] : LED_COLOR_OFF)
- : (fast_blink ? palette_[state.x_scale - 3] : LED_COLOR_OFF);
-
- if (cb) {
- int poly_counter = (system_clock.milliseconds() >> 6) % 12;
- if ((poly_counter >> 1) < (state.x_scale + 1) && (poly_counter & 1)) {
- scale_color = LED_COLOR_YELLOW;
- } else {
- scale_color = LED_COLOR_OFF;
- }
- }
-
- leds_.Clear();
-
- int slow_triangle = (system_clock.milliseconds() & 1023) >> 5;
- slow_triangle = slow_triangle >= 16 ? 31 - slow_triangle : slow_triangle;
- int pw = system_clock.milliseconds() & 15;
- bool deja_vu_glow = !deja_vu_lock_ || (slow_triangle >= pw);
-
- switch (mode_) {
- case UI_MODE_NORMAL:
- case UI_MODE_RECORD_SCALE:
- {
- leds_.set(LED_T_MODEL, MakeColor(state.t_model, cb));
- leds_.set(LED_T_RANGE, MakeColor(state.t_range, cb));
- leds_.set(LED_T_DEJA_VU,
- state.t_deja_vu && deja_vu_glow ?
- LED_COLOR_GREEN : LED_COLOR_OFF);
- leds_.set(LED_X_CONTROL_MODE, MakeColor(state.x_control_mode, cb));
- leds_.set(LED_X_DEJA_VU,
- state.x_deja_vu && deja_vu_glow ?
- LED_COLOR_GREEN : LED_COLOR_OFF);
-
- if (mode_ == UI_MODE_NORMAL) {
- leds_.set(LED_X_RANGE,
- state.x_register_mode
- ? LED_COLOR_OFF
- : MakeColor(state.x_range, cb));
- leds_.set(LED_X_EXT,
- state.x_register_mode ? LED_COLOR_GREEN : LED_COLOR_OFF);
- } else {
- leds_.set(LED_X_RANGE, scale_color);
- leds_.set(LED_X_EXT, LED_COLOR_GREEN);
- }
- }
- break;
-
- case UI_MODE_SELECT_SCALE:
- leds_.set(LED_X_RANGE, scale_color);
- break;
-
- case UI_MODE_CALIBRATION_1:
- leds_.set(LED_T_RANGE, blink ? MakeColor(0, cb) : LED_COLOR_OFF);
- break;
-
- case UI_MODE_CALIBRATION_2:
- leds_.set(LED_T_RANGE, blink ? MakeColor(1, cb) : LED_COLOR_OFF);
- break;
-
- case UI_MODE_CALIBRATION_3:
- leds_.set(LED_X_RANGE, blink ? MakeColor(0, cb) : LED_COLOR_OFF);
- break;
-
- case UI_MODE_CALIBRATION_4:
- leds_.set(LED_X_RANGE, blink ? MakeColor(1, cb) : LED_COLOR_OFF);
- break;
-
- case UI_MODE_PANIC:
- leds_.set(LED_T_MODEL, blink ? LED_COLOR_RED : LED_COLOR_OFF);
- leds_.set(LED_T_RANGE, !blink ? LED_COLOR_RED : LED_COLOR_OFF);
- leds_.set(LED_X_CONTROL_MODE, !blink ? LED_COLOR_RED : LED_COLOR_OFF);
- leds_.set(LED_X_RANGE, blink ? LED_COLOR_RED : LED_COLOR_OFF);
- break;
- }
- leds_.Write();
- }
-
- void Ui::FlushEvents() {
- queue_.Flush();
- }
-
- void Ui::OnSwitchPressed(const Event& e) {
-
- }
-
- void Ui::OnSwitchReleased(const Event& e) {
- if (setting_modification_flag_) {
- for (int i = 0; i < ADC_CHANNEL_LAST; ++i) {
- cv_reader_->mutable_channel(i)->UnlockPot();
- }
- setting_modification_flag_ = false;
- return;
- }
-
- // Check if the other switch is still pressed.
- if (e.control_id == SWITCH_T_RANGE && switches_.pressed(SWITCH_X_RANGE)) {
- mode_ = UI_MODE_CALIBRATION_1;
- ignore_release_[SWITCH_T_RANGE] = ignore_release_[SWITCH_X_RANGE] = true;
- return;
- }
-
- State* state = settings_->mutable_state();
- switch (e.control_id) {
- case SWITCH_T_DEJA_VU:
- state->t_deja_vu = !state->t_deja_vu;
- break;
-
- case SWITCH_X_DEJA_VU:
- state->x_deja_vu = !state->x_deja_vu;
- break;
-
- case SWITCH_T_MODEL:
- {
- uint8_t bank = state->t_model / 3;
- if (e.data >= kLongPressDuration) {
- if (!bank) {
- state->t_model += 3;
- }
- } else {
- if (bank) {
- state->t_model -= 3;
- } else {
- state->t_model = (state->t_model + 1) % 3;
- }
- }
- SaveState();
- }
- break;
-
- case SWITCH_T_RANGE:
- {
- if (mode_ >= UI_MODE_CALIBRATION_1 && mode_ <= UI_MODE_CALIBRATION_4) {
- NextCalibrationStep();
- } else {
- state->t_range = (state->t_range + 1) % 3;
- }
- SaveState();
- }
- break;
-
- case SWITCH_X_MODE:
- state->x_control_mode = (state->x_control_mode + 1) % 3;
- SaveState();
- break;
-
- case SWITCH_X_EXT:
- if (mode_ == UI_MODE_RECORD_SCALE) {
- int scale_index = settings_->state().x_scale;
- bool success = true;
- if (e.data >= kLongPressDuration) {
- settings_->ResetScale(scale_index);
- } else {
- success = scale_recorder_->ExtractScale(
- settings_->mutable_scale(scale_index));
- }
- if (success) {
- settings_->SavePersistentData();
- settings_->set_dirty_scale_index(scale_index);
- }
- mode_ = UI_MODE_NORMAL;
- } else if (e.data >= kLongPressDuration) {
- mode_ = UI_MODE_RECORD_SCALE;
- scale_recorder_->Clear();
- } else {
- state->x_register_mode = !state->x_register_mode;
- SaveState();
- }
- break;
-
- case SWITCH_X_RANGE:
- if (mode_ >= UI_MODE_CALIBRATION_1 && mode_ <= UI_MODE_CALIBRATION_4) {
- NextCalibrationStep();
- } else if (e.data >= kLongPressDuration) {
- if (mode_ == UI_MODE_NORMAL) {
- mode_ = UI_MODE_SELECT_SCALE;
- }
- } else if (mode_ == UI_MODE_SELECT_SCALE) {
- state->x_scale = (state->x_scale + 1) % kNumScales;
- } else {
- if (!state->x_register_mode) {
- state->x_range = (state->x_range + 1) % 3;
- }
- }
- SaveState();
- break;
- }
- }
-
- void Ui::TerminateScaleRecording() {
- for (int i = 0; i < ADC_CHANNEL_LAST; ++i) {
- cv_reader_->mutable_channel(i)->UnlockPot();
- }
- mode_ = UI_MODE_NORMAL;
- }
-
- void Ui::NextCalibrationStep() {
- switch (mode_) {
- case UI_MODE_CALIBRATION_1:
- cv_reader_->CalibrateOffsets();
- cv_reader_->CalibrateRateC1();
- mode_ = UI_MODE_CALIBRATION_2;
- break;
-
- case UI_MODE_CALIBRATION_2:
- cv_reader_->CalibrateRateC3();
- mode_ = UI_MODE_CALIBRATION_3;
- break;
-
- case UI_MODE_CALIBRATION_3:
- cv_reader_->CalibrateSpreadC1();
- mode_ = UI_MODE_CALIBRATION_4;
- break;
-
- case UI_MODE_CALIBRATION_4:
- if (cv_reader_->CalibrateSpreadC3()) {
- settings_->SavePersistentData();
- mode_ = UI_MODE_NORMAL;
- } else {
- mode_ = UI_MODE_PANIC;
- }
- break;
-
- default:
- break;
- }
- }
-
- void Ui::UpdateHiddenParameters() {
- // Check if some pots have been moved.
- for (int i = 0; i < ADC_CHANNEL_LAST; ++i) {
- float new_value = cv_reader_->channel(i).unscaled_pot();
- float old_value = pot_value_[i];
- bool changed = fabs(new_value - old_value) >= 0.008f;
- if (changed) {
- pot_value_[i] = new_value;
- AlternateKnobMapping mapping = alternate_knob_mappings_[i];
- if (switches_.pressed(mapping.unlock_switch)) {
- if (mapping.unlock_switch == SWITCH_T_RANGE && new_value < 0.1f) {
- new_value = 0.0f;
- }
- *mapping.destination = static_cast<uint8_t>(new_value * 255.0f);
- cv_reader_->mutable_channel(i)->LockPot();
-
- // The next time a switch is released, we unlock the pots.
- setting_modification_flag_ = true;
- }
- }
- }
- }
-
- void Ui::DoEvents() {
- while (queue_.available()) {
- Event e = queue_.PullEvent();
- if (e.control_type == CONTROL_SWITCH) {
- if (e.data == 0) {
- OnSwitchPressed(e);
- } else {
- OnSwitchReleased(e);
- }
- }
- }
-
- UpdateHiddenParameters();
-
- if (queue_.idle_time() > 800 && mode_ == UI_MODE_PANIC) {
- mode_ = UI_MODE_NORMAL;
- }
- if (mode_ == UI_MODE_SELECT_SCALE) {
- if (queue_.idle_time() > 4000) {
- mode_ = UI_MODE_NORMAL;
- queue_.Touch();
- }
- } else if (queue_.idle_time() > 1000) {
- queue_.Touch();
- }
- }
-
- uint8_t Ui::HandleFactoryTestingRequest(uint8_t command) {
- uint8_t argument = command & 0x1f;
- command = command >> 5;
- uint8_t reply = 0;
- switch (command) {
- case FACTORY_TESTING_READ_POT:
- case FACTORY_TESTING_READ_CV:
- reply = cv_reader_->adc_value(argument);
- break;
-
- case FACTORY_TESTING_READ_NORMALIZATION:
- reply = clock_inputs_->is_normalized(ClockInput(argument)) ? 255 : 0;
- break;
-
- case FACTORY_TESTING_READ_GATE:
- reply = argument >= SWITCH_LAST
- ? clock_inputs_->value(ClockInput(argument - SWITCH_LAST))
- : switches_.pressed(Switch(argument));
- break;
-
- case FACTORY_TESTING_GENERATE_TEST_SIGNALS:
- output_test_mode_ = static_cast<bool>(argument);
- fill(
- &output_test_forced_dac_code_[0],
- &output_test_forced_dac_code_[4],
- 0);
- break;
-
- case FACTORY_TESTING_CALIBRATE:
- if (argument == 0) {
- // Revert all settings before getting into calibration mode.
- settings_->mutable_state()->t_deja_vu = 0;
- settings_->mutable_state()->x_deja_vu = 0;
- settings_->mutable_state()->t_model = 0;
- settings_->mutable_state()->t_range = 1;
- settings_->mutable_state()->x_control_mode = 0;
- settings_->mutable_state()->x_range = 2;
- settings_->mutable_state()->x_register_mode = 0;
- settings_->SavePersistentData();
-
- mode_ = UI_MODE_CALIBRATION_1;
- } else {
- NextCalibrationStep();
- }
- {
- const CalibrationData& cal = settings_->calibration_data();
- float voltage = (argument & 1) == 0 ? 1.0f : 3.0f;
- for (int i = 0; i < 4; ++i) {
- output_test_forced_dac_code_[i] = static_cast<uint16_t>(
- voltage * cal.dac_scale[i] + cal.dac_offset[i]);
- }
- }
- queue_.Touch();
- break;
-
- case FACTORY_TESTING_FORCE_DAC_CODE:
- {
- int channel = argument >> 2;
- int step = argument & 0x3;
- if (step == 0) {
- output_test_forced_dac_code_[channel] = 0xaf35;
- } else if (step == 1) {
- output_test_forced_dac_code_[channel] = 0x1d98;
- } else {
- CalibrationData* cal = settings_->mutable_calibration_data();
- cal->dac_offset[channel] = static_cast<float>(
- calibration_data_ & 0xffff);
- cal->dac_scale[channel] = static_cast<float>(
- calibration_data_ >> 16) * -0.125f;
- output_test_forced_dac_code_[channel] = static_cast<uint16_t>(cal->dac_scale[channel] + cal->dac_offset[channel]);
- settings_->SavePersistentData();
- }
- }
- break;
-
- case FACTORY_TESTING_WRITE_CALIBRATION_DATA_NIBBLE:
- calibration_data_ <<= 4;
- calibration_data_ |= argument & 0xf;
- break;
- }
- return reply;
- }
-
- } // namespace marbles
|