diff --git a/src/components/motor/MotorController.cpp b/src/components/motor/MotorController.cpp index b25e6bc829..40c9b642bc 100644 --- a/src/components/motor/MotorController.cpp +++ b/src/components/motor/MotorController.cpp @@ -8,6 +8,9 @@ APP_TIMER_DEF(longVibTimer); using namespace Pinetime::Controllers; +constexpr MotorController::Tune MotorController::tunes[]; + + MotorController::MotorController(Controllers::Settings& settingsController) : settingsController {settingsController} { } @@ -16,24 +19,54 @@ void MotorController::Init() { nrf_gpio_pin_set(pinMotor); app_timer_init(); - app_timer_create(&shortVibTimer, APP_TIMER_MODE_SINGLE_SHOT, StopMotor); + app_timer_create(&shortVibTimer, APP_TIMER_MODE_SINGLE_SHOT, Vibrate); app_timer_create(&longVibTimer, APP_TIMER_MODE_REPEATED, Ring); } void MotorController::Ring(void* p_context) { auto* motorController = static_cast(p_context); - motorController->RunForDuration(50); + motorController->VibrateTune(TuneType::RING); } void MotorController::RunForDuration(uint8_t motorDuration) { if (settingsController.GetVibrationStatus() == Controllers::Settings::Vibration::OFF) { return; } + StopTune(); + ScheduleVibrateTimer(motorDuration, true); +} + + +void MotorController::StopTune() { + step = 255; +} + +void MotorController::ScheduleTune(TuneType tune) { + step = 0; + runningTune = tune; +} + +/** +* schedule next vibrate timer tick with or without vibration +*/ + +void MotorController::ScheduleVibrateTimer(uint8_t motorDuration, bool vibrate) { + if (vibrate) { + nrf_gpio_pin_clear(pinMotor); + } else { + nrf_gpio_pin_set(pinMotor); + } + app_timer_start(shortVibTimer, APP_TIMER_TICKS(motorDuration), this); +} - nrf_gpio_pin_clear(pinMotor); - app_timer_start(shortVibTimer, APP_TIMER_TICKS(motorDuration), nullptr); +void MotorController::VibrateTune(TuneType tune) { + if (settingsController.GetVibrationStatus() == Controllers::Settings::Vibration::OFF) + return; + ScheduleTune(tune); + Vibrate(this); } + void MotorController::StartRinging() { if (settingsController.GetVibrationStatus() == Controllers::Settings::Vibration::OFF) { return; @@ -47,6 +80,18 @@ void MotorController::StopRinging() { nrf_gpio_pin_set(pinMotor); } -void MotorController::StopMotor(void* p_context) { - nrf_gpio_pin_set(pinMotor); + +void MotorController::Vibrate(void* p_context) { + auto* motorC = static_cast(p_context); + auto* runningTune = &tunes[motorC->runningTune]; + + nrf_gpio_pin_set(pinMotor); //turn off vibration + + //scedule next tune tick + if (motorC->step < 8 && motorC->step < runningTune->length) { + bool vibrate = ((1 << motorC->step) & runningTune->tune) > 0; + motorC->step++; + + motorC->ScheduleVibrateTimer(runningTune->tempo, vibrate); + } } diff --git a/src/components/motor/MotorController.h b/src/components/motor/MotorController.h index d2c9fe5f2c..3d3dba0916 100644 --- a/src/components/motor/MotorController.h +++ b/src/components/motor/MotorController.h @@ -7,19 +7,46 @@ namespace Pinetime { namespace Controllers { static constexpr uint8_t pinMotor = 16; - + + class MotorController { + + public: + enum TuneType : uint8_t { + NOTIFICATION, + SHORT, + RING + }; + MotorController(Controllers::Settings& settingsController); void Init(); void RunForDuration(uint8_t motorDuration); void StartRinging(); static void StopRinging(); + void VibrateTune(TuneType tune); private: - static void Ring(void* p_context); + struct Tune { + uint8_t tune; + uint8_t length; + uint8_t tempo; + }; Controllers::Settings& settingsController; - static void StopMotor(void* p_context); + TuneType runningTune = TuneType::SHORT; + uint8_t step = 255; + + static constexpr Tune tunes[] = { + [TuneType::NOTIFICATION] = {.tune = 0b00101001, .length = 6, .tempo = 50}, + [TuneType::SHORT] = {.tune = 0b00000001, .length = 2, .tempo = 35}, + [TuneType::RING] = {.tune = 0b00001111, .length = 8, .tempo = 50}, + }; + + static void Vibrate(void* p_context); + static void Ring(void* p_context); + void ScheduleVibrateTimer(uint8_t motorDuration, bool vibrate); + void StopTune(); + void ScheduleTune(TuneType tune); }; } } diff --git a/src/displayapp/screens/Notifications.cpp b/src/displayapp/screens/Notifications.cpp index c061c1469d..f36586d3c6 100644 --- a/src/displayapp/screens/Notifications.cpp +++ b/src/displayapp/screens/Notifications.cpp @@ -40,7 +40,7 @@ Notifications::Notifications(DisplayApp* app, if (notification.category == Controllers::NotificationManager::Categories::IncomingCall) { motorController.StartRinging(); } else { - motorController.RunForDuration(35); + motorController.VibrateTune(Controllers::MotorController::TuneType::NOTIFICATION); timeoutLine = lv_line_create(lv_scr_act(), nullptr); lv_obj_set_style_local_line_width(timeoutLine, LV_LINE_PART_MAIN, LV_STATE_DEFAULT, 3); diff --git a/src/displayapp/screens/settings/QuickSettings.cpp b/src/displayapp/screens/settings/QuickSettings.cpp index 54e2f3e22e..802c98f1c3 100644 --- a/src/displayapp/screens/settings/QuickSettings.cpp +++ b/src/displayapp/screens/settings/QuickSettings.cpp @@ -143,7 +143,7 @@ void QuickSettings::OnButtonEvent(lv_obj_t* object, lv_event_t event) { if (lv_obj_get_state(btn3, LV_BTN_PART_MAIN) & LV_STATE_CHECKED) { settingsController.SetVibrationStatus(Controllers::Settings::Vibration::ON); - motorController.RunForDuration(35); + motorController.VibrateTune(Controllers::MotorController::TuneType::NOTIFICATION); lv_label_set_text_static(btn3_lvl, Symbols::notificationsOn); } else { settingsController.SetVibrationStatus(Controllers::Settings::Vibration::OFF); diff --git a/src/systemtask/SystemTask.cpp b/src/systemtask/SystemTask.cpp index 3553f449fd..f2137f9c87 100644 --- a/src/systemtask/SystemTask.cpp +++ b/src/systemtask/SystemTask.cpp @@ -272,7 +272,7 @@ void SystemTask::Work() { if (isSleeping && !isWakingUp) { GoToRunning(); } - motorController.RunForDuration(35); + motorController.VibrateTune(Controllers::MotorController::TuneType::SHORT); displayApp.PushMessage(Pinetime::Applications::Display::Messages::TimerDone); break; case Messages::BleConnected: @@ -325,7 +325,7 @@ void SystemTask::Work() { stepCounterMustBeReset = true; break; case Messages::OnChargingEvent: - motorController.RunForDuration(15); + motorController.VibrateTune(motorController.TuneType::SHORT); // Battery level is updated on every message - there's no need to do anything break;