|
|
@ -10,6 +10,7 @@ |
|
|
|
#include <cstdint> |
|
|
|
#include <cstdint> |
|
|
|
#include <initializer_list> |
|
|
|
#include <initializer_list> |
|
|
|
#include <mutex> |
|
|
|
#include <mutex> |
|
|
|
|
|
|
|
#include <variant> |
|
|
|
|
|
|
|
|
|
|
|
#include "assert.h" |
|
|
|
#include "assert.h" |
|
|
|
#include "driver/gpio.h" |
|
|
|
#include "driver/gpio.h" |
|
|
@ -27,24 +28,55 @@ namespace drivers { |
|
|
|
static constexpr char kTag[] = "haptics"; |
|
|
|
static constexpr char kTag[] = "haptics"; |
|
|
|
static constexpr uint8_t kHapticsAddress = 0x5A; |
|
|
|
static constexpr uint8_t kHapticsAddress = 0x5A; |
|
|
|
|
|
|
|
|
|
|
|
Haptics::Haptics() { |
|
|
|
Haptics::Haptics(const std::variant<ErmMotor, LraMotor>& motor) { |
|
|
|
PowerUp(); |
|
|
|
PowerUp(); |
|
|
|
|
|
|
|
|
|
|
|
// Put into ERM Open Loop:
|
|
|
|
// TODO: Break out into helper functions
|
|
|
|
// (§8.5.4.1 Programming for ERM Open-Loop Operation)
|
|
|
|
// TODO: Use LRA closed loop instead, loading in calibration data from NVS, or
|
|
|
|
// - Turn off N_ERM_LRA first
|
|
|
|
// running calibration + storing the result first if necessary.
|
|
|
|
WriteRegister(Register::kControl1, |
|
|
|
|
|
|
|
static_cast<uint8_t>(RegisterDefaults::kControl1) & |
|
|
|
if (std::holds_alternative<ErmMotor>(motor)) { |
|
|
|
(~ControlMask::kNErmLra)); |
|
|
|
ESP_LOGI(kTag, "Setting up ERM motor..."); |
|
|
|
// - Turn on ERM_OPEN_LOOP
|
|
|
|
|
|
|
|
WriteRegister(Register::kControl3, |
|
|
|
// Put into ERM Open Loop:
|
|
|
|
static_cast<uint8_t>(RegisterDefaults::kControl3) | |
|
|
|
// (§8.5.4.1 Programming for ERM Open-Loop Operation)
|
|
|
|
ControlMask::kErmOpenLoop); |
|
|
|
|
|
|
|
|
|
|
|
// - Turn off N_ERM_LRA first
|
|
|
|
// Set library
|
|
|
|
WriteRegister(Register::kFeedbackControl, |
|
|
|
// TODO(robin): try the other libraries and test response. C is marginal, D
|
|
|
|
static_cast<uint8_t>(RegisterDefaults::kFeedbackControl) & |
|
|
|
// too much?
|
|
|
|
(~ControlMask::kNErmLra)); |
|
|
|
WriteRegister(Register::kWaveformLibrary, static_cast<uint8_t>(kDefaultLibrary)); |
|
|
|
|
|
|
|
|
|
|
|
// - Turn on ERM_OPEN_LOOP
|
|
|
|
|
|
|
|
WriteRegister(Register::kControl3, |
|
|
|
|
|
|
|
static_cast<uint8_t>(RegisterDefaults::kControl3) | |
|
|
|
|
|
|
|
ControlMask::kErmOpenLoop); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Set library
|
|
|
|
|
|
|
|
// TODO(robin): try the other libraries and test response. C is marginal, D
|
|
|
|
|
|
|
|
// too much?
|
|
|
|
|
|
|
|
WriteRegister(Register::kWaveformLibrary, static_cast<uint8_t>(kDefaultErmLibrary)); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
} else if (std::holds_alternative<LraMotor>(motor)) { |
|
|
|
|
|
|
|
ESP_LOGI(kTag, "Setting up LRA motor..."); |
|
|
|
|
|
|
|
// TODO:
|
|
|
|
|
|
|
|
// auto lraInit = std::get<LraMotor>(motor);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Put into LRA Open Loop:
|
|
|
|
|
|
|
|
// (§8.5.4.1 Programming for LRA Open-Loop Operation)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// - Turn on N_ERM_LRA first
|
|
|
|
|
|
|
|
WriteRegister(Register::kFeedbackControl, |
|
|
|
|
|
|
|
static_cast<uint8_t>(RegisterDefaults::kFeedbackControl) & |
|
|
|
|
|
|
|
(ControlMask::kNErmLra)); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// - Turn on LRA_OPEN_LOOP
|
|
|
|
|
|
|
|
WriteRegister(Register::kControl3, |
|
|
|
|
|
|
|
static_cast<uint8_t>(RegisterDefaults::kControl3) | |
|
|
|
|
|
|
|
ControlMask::kLraOpenLoop); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Set library; only option is the LRA one for, well, LRA motors.
|
|
|
|
|
|
|
|
WriteRegister(Register::kWaveformLibrary, static_cast<uint8_t>(Library::LRA)); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Set mode (internal trigger, on writing 1 to Go register)
|
|
|
|
// Set mode (internal trigger, on writing 1 to Go register)
|
|
|
|
WriteRegister(Register::kMode, static_cast<uint8_t>(Mode::kInternalTrigger)); |
|
|
|
WriteRegister(Register::kMode, static_cast<uint8_t>(Mode::kInternalTrigger)); |
|
|
@ -93,13 +125,13 @@ auto Haptics::SetWaveformEffect(Effect effect) -> void { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
auto Haptics::TourEffects() -> void { |
|
|
|
auto Haptics::TourEffects() -> void { |
|
|
|
TourEffects(Effect::kFirst, Effect::kLast, kDefaultLibrary); |
|
|
|
TourEffects(Effect::kFirst, Effect::kLast, kDefaultErmLibrary); |
|
|
|
} |
|
|
|
} |
|
|
|
auto Haptics::TourEffects(Library lib) -> void { |
|
|
|
auto Haptics::TourEffects(Library lib) -> void { |
|
|
|
TourEffects(Effect::kFirst, Effect::kLast, lib); |
|
|
|
TourEffects(Effect::kFirst, Effect::kLast, lib); |
|
|
|
} |
|
|
|
} |
|
|
|
auto Haptics::TourEffects(Effect from, Effect to) -> void { |
|
|
|
auto Haptics::TourEffects(Effect from, Effect to) -> void { |
|
|
|
TourEffects(from, to, kDefaultLibrary); |
|
|
|
TourEffects(from, to, kDefaultErmLibrary); |
|
|
|
} |
|
|
|
} |
|
|
|
auto Haptics::TourEffects(Effect from, Effect to, Library lib) -> void { |
|
|
|
auto Haptics::TourEffects(Effect from, Effect to, Library lib) -> void { |
|
|
|
ESP_LOGI(kTag, "With library #%u...", static_cast<uint8_t>(lib)); |
|
|
|
ESP_LOGI(kTag, "With library #%u...", static_cast<uint8_t>(lib)); |
|
|
|