Merge branch 'main' of codeberg.org:cool-tech-zone/tangara-fw
This commit is contained in:
@@ -234,7 +234,7 @@ auto TrackTags::genres(const std::string_view s) -> void {
|
||||
std::string src = {s.data(), s.size()};
|
||||
char* token = std::strtok(src.data(), kGenreDelimiters);
|
||||
|
||||
auto trim_and_add = [=](std::string_view s) {
|
||||
auto trim_and_add = [this](std::string_view s) {
|
||||
std::string copy = {s.data(), s.size()};
|
||||
|
||||
// Trim the left
|
||||
|
||||
+1
-1
@@ -18,7 +18,7 @@ static const adc_bitwidth_t kAdcBitWidth = ADC_BITWIDTH_12;
|
||||
static const adc_unit_t kAdcUnit = ADC_UNIT_1;
|
||||
// Max battery voltage should be a little over 2V due to our divider, so we need
|
||||
// the max attenuation to properly handle the full range.
|
||||
static const adc_atten_t kAdcAttenuation = ADC_ATTEN_DB_11;
|
||||
static const adc_atten_t kAdcAttenuation = ADC_ATTEN_DB_12;
|
||||
// Corresponds to SENSOR_VP.
|
||||
static const adc_channel_t kAdcChannel = ADC_CHANNEL_0;
|
||||
|
||||
|
||||
@@ -438,7 +438,8 @@ void Disabled::react(const events::Enable&) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ((err = esp_bluedroid_init() != ESP_OK)) {
|
||||
esp_bluedroid_config_t cfg = BT_BLUEDROID_INIT_CONFIG_DEFAULT();
|
||||
if ((err = esp_bluedroid_init_with_cfg(&cfg) != ESP_OK)) {
|
||||
ESP_LOGE(kTag, "initialize bluedroid failed %s", esp_err_to_name(err));
|
||||
return;
|
||||
}
|
||||
|
||||
+49
-17
@@ -10,6 +10,7 @@
|
||||
#include <cstdint>
|
||||
#include <initializer_list>
|
||||
#include <mutex>
|
||||
#include <variant>
|
||||
|
||||
#include "assert.h"
|
||||
#include "driver/gpio.h"
|
||||
@@ -27,24 +28,55 @@ namespace drivers {
|
||||
static constexpr char kTag[] = "haptics";
|
||||
static constexpr uint8_t kHapticsAddress = 0x5A;
|
||||
|
||||
Haptics::Haptics() {
|
||||
Haptics::Haptics(const std::variant<ErmMotor, LraMotor>& motor) {
|
||||
PowerUp();
|
||||
|
||||
// Put into ERM Open Loop:
|
||||
// (§8.5.4.1 Programming for ERM Open-Loop Operation)
|
||||
// - Turn off N_ERM_LRA first
|
||||
WriteRegister(Register::kControl1,
|
||||
static_cast<uint8_t>(RegisterDefaults::kControl1) &
|
||||
(~ControlMask::kNErmLra));
|
||||
// - Turn on ERM_OPEN_LOOP
|
||||
WriteRegister(Register::kControl3,
|
||||
static_cast<uint8_t>(RegisterDefaults::kControl3) |
|
||||
ControlMask::kErmOpenLoop);
|
||||
// TODO: Break out into helper functions
|
||||
// TODO: Use LRA closed loop instead, loading in calibration data from NVS, or
|
||||
// running calibration + storing the result first if necessary.
|
||||
|
||||
// Set library
|
||||
// TODO(robin): try the other libraries and test response. C is marginal, D
|
||||
// too much?
|
||||
WriteRegister(Register::kWaveformLibrary, static_cast<uint8_t>(kDefaultLibrary));
|
||||
if (std::holds_alternative<ErmMotor>(motor)) {
|
||||
ESP_LOGI(kTag, "Setting up ERM motor...");
|
||||
|
||||
// Put into ERM Open Loop:
|
||||
// (§8.5.4.1 Programming for ERM Open-Loop Operation)
|
||||
|
||||
// - Turn off N_ERM_LRA first
|
||||
WriteRegister(Register::kFeedbackControl,
|
||||
static_cast<uint8_t>(RegisterDefaults::kFeedbackControl) &
|
||||
(~ControlMask::kNErmLra));
|
||||
|
||||
// - 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)
|
||||
WriteRegister(Register::kMode, static_cast<uint8_t>(Mode::kInternalTrigger));
|
||||
@@ -93,13 +125,13 @@ auto Haptics::SetWaveformEffect(Effect effect) -> void {
|
||||
|
||||
|
||||
auto Haptics::TourEffects() -> void {
|
||||
TourEffects(Effect::kFirst, Effect::kLast, kDefaultLibrary);
|
||||
TourEffects(Effect::kFirst, Effect::kLast, kDefaultErmLibrary);
|
||||
}
|
||||
auto Haptics::TourEffects(Library lib) -> void {
|
||||
TourEffects(Effect::kFirst, Effect::kLast, lib);
|
||||
}
|
||||
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 {
|
||||
ESP_LOGI(kTag, "With library #%u...", static_cast<uint8_t>(lib));
|
||||
|
||||
@@ -11,13 +11,24 @@
|
||||
#include <mutex>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <variant>
|
||||
|
||||
namespace drivers {
|
||||
|
||||
typedef std::monostate ErmMotor;
|
||||
struct LraMotor {
|
||||
// TODO: fill out with calibration data from https://www.ti.com/lit/ds/symlink/drv2605l.pdf
|
||||
bool hi;
|
||||
};
|
||||
|
||||
class Haptics {
|
||||
public:
|
||||
static auto Create() -> Haptics* { return new Haptics(); }
|
||||
Haptics();
|
||||
static auto Create(const std::variant<ErmMotor, LraMotor>& motor)
|
||||
-> Haptics* {
|
||||
return new Haptics(motor);
|
||||
}
|
||||
|
||||
Haptics(const std::variant<ErmMotor, LraMotor>& motor);
|
||||
~Haptics();
|
||||
|
||||
// Not copyable or movable.
|
||||
@@ -169,11 +180,12 @@ class Haptics {
|
||||
B = 2, // 3V, Rise: 40-60ms, Brake: 5-15ms
|
||||
C = 3, // 3V, Rise: 60-80ms, Brake: 10-20ms
|
||||
D = 4, // 3V, Rise: 100-140ms, Brake: 15-25ms
|
||||
E = 5 // 3V, Rise: >140ms, Brake: >30ms
|
||||
// 6 is LRA-only, 7 is 4.5V+
|
||||
E = 5, // 3V, Rise: >140ms, Brake: >30ms
|
||||
LRA = 6
|
||||
// 7 is 4.5V+
|
||||
};
|
||||
|
||||
static constexpr Library kDefaultLibrary = Library::C;
|
||||
static constexpr Library kDefaultErmLibrary = Library::C;
|
||||
|
||||
auto PowerDown() -> void;
|
||||
auto Reset() -> void;
|
||||
@@ -214,10 +226,12 @@ class Haptics {
|
||||
};
|
||||
|
||||
struct ControlMask {
|
||||
// Control1
|
||||
// FeedbackControl
|
||||
static constexpr uint8_t kNErmLra = 0b10000000;
|
||||
|
||||
// Control3
|
||||
static constexpr uint8_t kErmOpenLoop = 0b00100000;
|
||||
static constexpr uint8_t kLraOpenLoop = 0b00000001;
|
||||
};
|
||||
|
||||
// §8.6 Register Map
|
||||
@@ -257,12 +271,12 @@ class Haptics {
|
||||
|
||||
// A bunch of different options, not grouped
|
||||
// in any particular sensible way
|
||||
kControl1 = 0x1A,
|
||||
kControl2 = 0x1B,
|
||||
kControl3 = 0x1C,
|
||||
kControl4 = 0x1D,
|
||||
kControl5 = 0x1E,
|
||||
kControl6 = 0x1F,
|
||||
kFeedbackControl = 0x1A,
|
||||
kControl1 = 0x1B,
|
||||
kControl2 = 0x1C,
|
||||
kControl3 = 0x1D,
|
||||
kControl4 = 0x1E,
|
||||
kControl5 = 0x1F,
|
||||
|
||||
kSupplyVoltageMonitor = 0x21, // "VBAT"
|
||||
kLraResonancePeriod = 0x22,
|
||||
@@ -295,12 +309,12 @@ class Haptics {
|
||||
kOverdriveClampVoltage = 0x8C,
|
||||
kAutoCalibrationCompensationResult = 0x0C,
|
||||
kAutoCalibrationBackEmfResult = 0x6C,
|
||||
kControl1 = 0x36,
|
||||
kControl2 = 0x93,
|
||||
kControl3 = 0xF5,
|
||||
kControl4 = 0xA0,
|
||||
kControl5 = 0x20,
|
||||
kControl6 = 0x80,
|
||||
kFeedbackControl = 0x36,
|
||||
kControl1 = 0x93,
|
||||
kControl2 = 0xF5,
|
||||
kControl3 = 0xA0,
|
||||
kControl4 = 0x20,
|
||||
kControl5 = 0x80,
|
||||
kSupplyVoltageMonitor = 0,
|
||||
kLraResonancePeriod = 0,
|
||||
};
|
||||
|
||||
@@ -68,6 +68,7 @@ class NvsStorage {
|
||||
auto Read() -> void;
|
||||
auto Write() -> bool;
|
||||
|
||||
// Hardware Compatibility
|
||||
auto LockPolarity() -> bool;
|
||||
auto LockPolarity(bool) -> void;
|
||||
|
||||
@@ -76,6 +77,10 @@ class NvsStorage {
|
||||
auto DisplaySize(std::pair<std::optional<uint16_t>, std::optional<uint16_t>>)
|
||||
-> void;
|
||||
|
||||
auto HapticMotorIsErm() -> bool;
|
||||
auto HapticMotorIsErm(bool) -> void;
|
||||
// /Hardware Compatibility
|
||||
|
||||
auto PreferredBluetoothDevice() -> std::optional<bluetooth::MacAndName>;
|
||||
auto PreferredBluetoothDevice(std::optional<bluetooth::MacAndName>) -> void;
|
||||
|
||||
@@ -130,6 +135,7 @@ class NvsStorage {
|
||||
Setting<uint8_t> lock_polarity_;
|
||||
Setting<uint16_t> display_cols_;
|
||||
Setting<uint16_t> display_rows_;
|
||||
Setting<uint8_t> haptic_motor_type_;
|
||||
|
||||
Setting<uint8_t> brightness_;
|
||||
Setting<uint8_t> sensitivity_;
|
||||
|
||||
@@ -39,6 +39,7 @@ static constexpr char kKeyScrollSensitivity[] = "scroll";
|
||||
static constexpr char kKeyLockPolarity[] = "lockpol";
|
||||
static constexpr char kKeyDisplayCols[] = "dispcols";
|
||||
static constexpr char kKeyDisplayRows[] = "disprows";
|
||||
static constexpr char kKeyHapticMotorType[] = "hapticmtype";
|
||||
static constexpr char kKeyDbAutoIndex[] = "dbautoindex";
|
||||
|
||||
static auto nvs_get_string(nvs_handle_t nvs, const char* key)
|
||||
@@ -166,6 +167,7 @@ NvsStorage::NvsStorage(nvs_handle_t handle)
|
||||
lock_polarity_(kKeyLockPolarity),
|
||||
display_cols_(kKeyDisplayCols),
|
||||
display_rows_(kKeyDisplayRows),
|
||||
haptic_motor_type_(kKeyHapticMotorType),
|
||||
brightness_(kKeyBrightness),
|
||||
sensitivity_(kKeyScrollSensitivity),
|
||||
amp_max_vol_(kKeyAmpMaxVolume),
|
||||
@@ -188,6 +190,7 @@ auto NvsStorage::Read() -> void {
|
||||
lock_polarity_.read(handle_);
|
||||
display_cols_.read(handle_);
|
||||
display_rows_.read(handle_);
|
||||
haptic_motor_type_.read(handle_),
|
||||
brightness_.read(handle_);
|
||||
sensitivity_.read(handle_);
|
||||
amp_max_vol_.read(handle_);
|
||||
@@ -205,6 +208,7 @@ auto NvsStorage::Write() -> bool {
|
||||
lock_polarity_.write(handle_);
|
||||
display_cols_.write(handle_);
|
||||
display_rows_.write(handle_);
|
||||
haptic_motor_type_.write(handle_),
|
||||
brightness_.write(handle_);
|
||||
sensitivity_.write(handle_);
|
||||
amp_max_vol_.write(handle_);
|
||||
@@ -243,6 +247,16 @@ auto NvsStorage::LockPolarity(bool p) -> void {
|
||||
lock_polarity_.set(p);
|
||||
}
|
||||
|
||||
auto NvsStorage::HapticMotorIsErm() -> bool {
|
||||
std::lock_guard<std::mutex> lock{mutex_};
|
||||
return haptic_motor_type_.get().value_or(0) > 0;
|
||||
}
|
||||
|
||||
auto NvsStorage::HapticMotorIsErm(bool p) -> void {
|
||||
std::lock_guard<std::mutex> lock{mutex_};
|
||||
haptic_motor_type_.set(p);
|
||||
}
|
||||
|
||||
auto NvsStorage::DisplaySize()
|
||||
-> std::pair<std::optional<uint16_t>, std::optional<uint16_t>> {
|
||||
std::lock_guard<std::mutex> lock{mutex_};
|
||||
|
||||
@@ -34,6 +34,13 @@ static auto samd(lua_State* L) -> int {
|
||||
return 1;
|
||||
}
|
||||
|
||||
static auto update_samd(lua_State* L) -> int {
|
||||
Bridge* instance = Bridge::Get(L);
|
||||
auto& samd = instance->services().samd();
|
||||
samd.ResetToFlashSamd();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static auto collator(lua_State* L) -> int {
|
||||
Bridge* instance = Bridge::Get(L);
|
||||
auto& collator = instance->services().collator();
|
||||
@@ -45,6 +52,7 @@ static auto collator(lua_State* L) -> int {
|
||||
static const struct luaL_Reg kVersionFuncs[] = {{"esp", esp},
|
||||
{"samd", samd},
|
||||
{"collator", collator},
|
||||
{"update_samd", update_samd},
|
||||
{NULL, NULL}};
|
||||
|
||||
static auto lua_version(lua_State* L) -> int {
|
||||
|
||||
@@ -62,6 +62,10 @@ auto Booting::entry() -> void {
|
||||
sServices->nvs(
|
||||
std::unique_ptr<drivers::NvsStorage>(drivers::NvsStorage::OpenSync()));
|
||||
|
||||
// HACK: tell the unit that it has an ERM motor (we will likely default to
|
||||
// LRAs in future, but all the current units in the field use ERMs.)
|
||||
sServices->nvs().HapticMotorIsErm(true);
|
||||
|
||||
// HACK: fix up the switch polarity on newer dev units
|
||||
// sServices->nvs().LockPolarity(false);
|
||||
|
||||
@@ -85,7 +89,11 @@ auto Booting::entry() -> void {
|
||||
sServices->samd(std::unique_ptr<drivers::Samd>(drivers::Samd::Create()));
|
||||
sServices->touchwheel(
|
||||
std::unique_ptr<drivers::TouchWheel>{drivers::TouchWheel::Create()});
|
||||
sServices->haptics(std::make_unique<drivers::Haptics>());
|
||||
sServices->haptics(std::make_unique<drivers::Haptics>(
|
||||
sServices->nvs().HapticMotorIsErm()
|
||||
? std::variant<drivers::ErmMotor, drivers::LraMotor>(
|
||||
drivers::ErmMotor())
|
||||
: drivers::LraMotor()));
|
||||
|
||||
auto adc = drivers::AdcBattery::Create();
|
||||
sServices->battery(std::make_unique<battery::Battery>(
|
||||
|
||||
Reference in New Issue
Block a user