New protocol namespace

This commit is contained in:
2021-06-28 10:55:50 +02:00
parent 7805059bdf
commit f93076c97b
17 changed files with 58 additions and 49 deletions

View File

@ -63,7 +63,7 @@ bool parseCanMessage(const can_message_t &message, Controller &controller)
{ {
switch (message.identifier) switch (message.identifier)
{ {
using namespace bobbycar::can; using namespace bobbycar::protocol::can;
case MotorController<isBack, false>::Feedback::DcLink: case MotorController<isBack, false>::Feedback::DcLink:
controller.feedback.left.dcLink = *((int16_t*)message.data); controller.feedback.left.dcLink = *((int16_t*)message.data);
return true; return true;
@ -200,7 +200,7 @@ void sendCanCommands()
return result; return result;
}; };
using namespace bobbycar::can; using namespace bobbycar::protocol::can;
send(MotorController<false, false>::Command::InpTgt, controllers.front.command.left.pwm); send(MotorController<false, false>::Command::InpTgt, controllers.front.command.left.pwm);
send(MotorController<false, true>::Command::InpTgt, controllers.front.command.right.pwm); send(MotorController<false, true>::Command::InpTgt, controllers.front.command.right.pwm);

View File

@ -10,9 +10,9 @@
namespace { namespace {
template<> template<>
class ChangeValueDisplay<ControlMode> : class ChangeValueDisplay<bobbycar::protocol::ControlMode> :
public MenuDisplay, public MenuDisplay,
public virtual AccessorInterface<ControlMode>, public virtual AccessorInterface<bobbycar::protocol::ControlMode>,
public virtual ActionInterface public virtual ActionInterface
{ {
using Base = MenuDisplay; using Base = MenuDisplay;
@ -23,8 +23,9 @@ public:
void start() override; void start() override;
}; };
ChangeValueDisplay<ControlMode>::ChangeValueDisplay() ChangeValueDisplay<bobbycar::protocol::ControlMode>::ChangeValueDisplay()
{ {
using bobbycar::protocol::ControlMode;
constructMenuItem<makeComponentArgs<MenuItem, SetValueAction<ControlMode>, StaticText<TEXT_OPENMODE>>>(ControlMode::OpenMode, *this, *this); constructMenuItem<makeComponentArgs<MenuItem, SetValueAction<ControlMode>, StaticText<TEXT_OPENMODE>>>(ControlMode::OpenMode, *this, *this);
constructMenuItem<makeComponentArgs<MenuItem, SetValueAction<ControlMode>, StaticText<TEXT_VOLTAGE>>>(ControlMode::Voltage, *this, *this); constructMenuItem<makeComponentArgs<MenuItem, SetValueAction<ControlMode>, StaticText<TEXT_VOLTAGE>>>(ControlMode::Voltage, *this, *this);
constructMenuItem<makeComponentArgs<MenuItem, SetValueAction<ControlMode>, StaticText<TEXT_SPEED>>>(ControlMode::Speed, *this, *this); constructMenuItem<makeComponentArgs<MenuItem, SetValueAction<ControlMode>, StaticText<TEXT_SPEED>>>(ControlMode::Speed, *this, *this);
@ -32,12 +33,13 @@ ChangeValueDisplay<ControlMode>::ChangeValueDisplay()
constructMenuItem<makeComponentArgs<MenuItem, BackProxyAction, StaticText<TEXT_BACK>, StaticMenuItemIcon<&icons::back>>>(*this); constructMenuItem<makeComponentArgs<MenuItem, BackProxyAction, StaticText<TEXT_BACK>, StaticMenuItemIcon<&icons::back>>>(*this);
} }
void ChangeValueDisplay<ControlMode>::start() void ChangeValueDisplay<bobbycar::protocol::ControlMode>::start()
{ {
Base::start(); Base::start();
switch (const auto value = getValue()) switch (const auto value = getValue())
{ {
using bobbycar::protocol::ControlMode;
case ControlMode::OpenMode: setSelectedIndex(0); break; case ControlMode::OpenMode: setSelectedIndex(0); break;
case ControlMode::Voltage: setSelectedIndex(1); break; case ControlMode::Voltage: setSelectedIndex(1); break;
case ControlMode::Speed: setSelectedIndex(2); break; case ControlMode::Speed: setSelectedIndex(2); break;

View File

@ -10,9 +10,9 @@
namespace { namespace {
template<> template<>
class ChangeValueDisplay<ControlType> : class ChangeValueDisplay<bobbycar::protocol::ControlType> :
public MenuDisplay, public MenuDisplay,
public virtual AccessorInterface<ControlType>, public virtual AccessorInterface<bobbycar::protocol::ControlType>,
public virtual ActionInterface public virtual ActionInterface
{ {
using Base = MenuDisplay; using Base = MenuDisplay;
@ -23,20 +23,22 @@ public:
void start() override; void start() override;
}; };
ChangeValueDisplay<ControlType>::ChangeValueDisplay() ChangeValueDisplay<bobbycar::protocol::ControlType>::ChangeValueDisplay()
{ {
using bobbycar::protocol::ControlType;
constructMenuItem<makeComponentArgs<MenuItem, SetValueAction<ControlType>, StaticText<TEXT_COMMUTATION>>>(ControlType::Commutation, *this, *this); constructMenuItem<makeComponentArgs<MenuItem, SetValueAction<ControlType>, StaticText<TEXT_COMMUTATION>>>(ControlType::Commutation, *this, *this);
constructMenuItem<makeComponentArgs<MenuItem, SetValueAction<ControlType>, StaticText<TEXT_SINUSOIDAL>>>(ControlType::Sinusoidal, *this, *this); constructMenuItem<makeComponentArgs<MenuItem, SetValueAction<ControlType>, StaticText<TEXT_SINUSOIDAL>>>(ControlType::Sinusoidal, *this, *this);
constructMenuItem<makeComponentArgs<MenuItem, SetValueAction<ControlType>, StaticText<TEXT_FIELDORIENTEDCONTROL>>>(ControlType::FieldOrientedControl, *this, *this); constructMenuItem<makeComponentArgs<MenuItem, SetValueAction<ControlType>, StaticText<TEXT_FIELDORIENTEDCONTROL>>>(ControlType::FieldOrientedControl, *this, *this);
constructMenuItem<makeComponentArgs<MenuItem, BackProxyAction, StaticText<TEXT_BACK>, StaticMenuItemIcon<&icons::back>>>(*this); constructMenuItem<makeComponentArgs<MenuItem, BackProxyAction, StaticText<TEXT_BACK>, StaticMenuItemIcon<&icons::back>>>(*this);
} }
void ChangeValueDisplay<ControlType>::start() void ChangeValueDisplay<bobbycar::protocol::ControlType>::start()
{ {
Base::start(); Base::start();
switch (const auto value = getValue()) switch (const auto value = getValue())
{ {
using bobbycar::protocol::ControlType;
case ControlType::Commutation: setSelectedIndex(0); break; case ControlType::Commutation: setSelectedIndex(0); break;
case ControlType::Sinusoidal: setSelectedIndex(1); break; case ControlType::Sinusoidal: setSelectedIndex(1); break;
case ControlType::FieldOrientedControl: setSelectedIndex(2); break; case ControlType::FieldOrientedControl: setSelectedIndex(2); break;

View File

@ -36,13 +36,13 @@ struct Controller {
#endif #endif
bool &enableLeft, &enableRight, &invertLeft, &invertRight; bool &enableLeft, &enableRight, &invertLeft, &invertRight;
Command command{}; bobbycar::protocol::serial::Command command{};
#ifdef FEATURE_CAN #ifdef FEATURE_CAN
millis_t lastCanFeedback{}; millis_t lastCanFeedback{};
#endif #endif
bool feedbackValid{}; bool feedbackValid{};
Feedback feedback{}; bobbycar::protocol::serial::Feedback feedback{};
#ifndef FEATURE_CAN #ifndef FEATURE_CAN
FeedbackParser parser{serial, feedbackValid, feedback}; FeedbackParser parser{serial, feedbackValid, feedback};

View File

@ -17,8 +17,8 @@ struct ControllerTexts
struct LedText : public virtual TextInterface { public: std::string text() const override { return "led: " + std::to_string(controller::get().command.led); } }; struct LedText : public virtual TextInterface { public: std::string text() const override { return "led: " + std::to_string(controller::get().command.led); } };
private: private:
struct LeftCommandGetter { static const MotorState &get() { return controller::get().command.left; } }; struct LeftCommandGetter { static const bobbycar::protocol::serial::MotorState &get() { return controller::get().command.left; } };
struct RightCommandGetter { static const MotorState &get() { return controller::get().command.right; } }; struct RightCommandGetter { static const bobbycar::protocol::serial::MotorState &get() { return controller::get().command.right; } };
template<typename MotorStateGetter> template<typename MotorStateGetter>
struct CommandTexts struct CommandTexts
@ -48,8 +48,8 @@ public:
struct TimeoutCntSerialText : public virtual TextInterface { public: std::string text() const override { std::string line{"timeoutCntSerial: "}; if (controller::get().feedbackValid) line += std::to_string(controller::get().feedback.timeoutCntSerial); return line; } }; struct TimeoutCntSerialText : public virtual TextInterface { public: std::string text() const override { std::string line{"timeoutCntSerial: "}; if (controller::get().feedbackValid) line += std::to_string(controller::get().feedback.timeoutCntSerial); return line; } };
private: private:
struct LeftFeedbackGetter { static const MotorFeedback &get() { return controller::get().feedback.left; } }; struct LeftFeedbackGetter { static const bobbycar::protocol::serial::MotorFeedback &get() { return controller::get().feedback.left; } };
struct RightFeedbackGetter { static const MotorFeedback &get() { return controller::get().feedback.right; } }; struct RightFeedbackGetter { static const bobbycar::protocol::serial::MotorFeedback &get() { return controller::get().feedback.right; } };
template<typename MotorFeedbackGetter> template<typename MotorFeedbackGetter>
struct FeedbackTexts struct FeedbackTexts

View File

@ -42,7 +42,7 @@ private:
const bool m_bootup{false}; const bool m_bootup{false};
ModeInterface *m_oldMode; ModeInterface *m_oldMode;
IgnoreInputMode m_mode{0, ControlType::FieldOrientedControl, ControlMode::Torque}; IgnoreInputMode m_mode{0, bobbycar::protocol::ControlType::FieldOrientedControl, bobbycar::protocol::ControlMode::Torque};
std::array<Label, 11> m_labels {{ std::array<Label, 11> m_labels {{
Label{25, 72}, // 100, 23 Label{25, 72}, // 100, 23

View File

@ -50,7 +50,7 @@ private:
int m_rotated; int m_rotated;
ModeInterface *m_oldMode; ModeInterface *m_oldMode;
IgnoreInputMode m_mode{0, ControlType::FieldOrientedControl, ControlMode::Speed}; IgnoreInputMode m_mode{0, bobbycar::protocol::ControlType::FieldOrientedControl, bobbycar::protocol::ControlMode::Speed};
}; };
void Lockscreen::start() void Lockscreen::start()

View File

@ -57,7 +57,7 @@ private:
{} {}
void start(); void start();
void redraw(const MotorFeedback &motor); void redraw(const bobbycar::protocol::serial::MotorFeedback &motor);
private: private:
Label m_labelError; Label m_labelError;
@ -246,7 +246,7 @@ void StatusDisplay::BoardStatus::MotorStatus::start()
m_labelHallSensors.start(); m_labelHallSensors.start();
} }
void StatusDisplay::BoardStatus::MotorStatus::redraw(const MotorFeedback &motor) void StatusDisplay::BoardStatus::MotorStatus::redraw(const bobbycar::protocol::serial::MotorFeedback &motor)
{ {
tft.setTextFont(4); tft.setTextFont(4);
tft.setTextColor(motor.error?TFT_RED:TFT_GREEN, TFT_BLACK); tft.setTextColor(motor.error?TFT_RED:TFT_GREEN, TFT_BLACK);

View File

@ -78,13 +78,13 @@ void DefaultMode::update()
lastTime = now; lastTime = now;
const auto pair = split(settings.defaultMode.modelMode); const auto pair = split(settings.defaultMode.modelMode);
for (MotorState &motor : motorsInController(controllers.front)) for (bobbycar::protocol::serial::MotorState &motor : motorsInController(controllers.front))
{ {
motor.ctrlTyp = pair.first; motor.ctrlTyp = pair.first;
motor.ctrlMod = pair.second; motor.ctrlMod = pair.second;
motor.pwm = pwm / 100. * settings.defaultMode.frontPercentage; motor.pwm = pwm / 100. * settings.defaultMode.frontPercentage;
} }
for (MotorState &motor : motorsInController(controllers.back)) for (bobbycar::protocol::serial::MotorState &motor : motorsInController(controllers.back))
{ {
motor.ctrlTyp = pair.first; motor.ctrlTyp = pair.first;
motor.ctrlMod = pair.second; motor.ctrlMod = pair.second;

View File

@ -66,10 +66,10 @@ void GametrakMode::update()
pwm = 0; pwm = 0;
} }
for (MotorState &motor : motors()) for (bobbycar::protocol::serial::MotorState &motor : motors())
{ {
motor.ctrlTyp = ControlType::FieldOrientedControl; motor.ctrlTyp = bobbycar::protocol::ControlType::FieldOrientedControl;
motor.ctrlMod = ControlMode::Speed; motor.ctrlMod = bobbycar::protocol::ControlMode::Speed;
motor.pwm = pwm; motor.pwm = pwm;
} }

View File

@ -10,7 +10,7 @@ namespace {
class IgnoreInputMode : public ModeInterface class IgnoreInputMode : public ModeInterface
{ {
public: public:
IgnoreInputMode(int16_t pwm, ControlType ctrlTyp, ControlMode ctrlMod) : IgnoreInputMode(int16_t pwm, bobbycar::protocol::ControlType ctrlTyp, bobbycar::protocol::ControlMode ctrlMod) :
m_pwm{pwm}, m_ctrlTyp{ctrlTyp}, m_ctrlMod{ctrlMod} m_pwm{pwm}, m_ctrlTyp{ctrlTyp}, m_ctrlMod{ctrlMod}
{ {
} }
@ -21,13 +21,13 @@ public:
private: private:
const int16_t m_pwm; const int16_t m_pwm;
const ControlType m_ctrlTyp; const bobbycar::protocol::ControlType m_ctrlTyp;
const ControlMode m_ctrlMod; const bobbycar::protocol::ControlMode m_ctrlMod;
}; };
void IgnoreInputMode::update() void IgnoreInputMode::update()
{ {
for (MotorState &motor : motors()) for (bobbycar::protocol::serial::MotorState &motor : motors())
{ {
motor.ctrlTyp = m_ctrlTyp; motor.ctrlTyp = m_ctrlTyp;
motor.ctrlMod = m_ctrlMod; motor.ctrlMod = m_ctrlMod;

View File

@ -96,7 +96,7 @@ void LarsmMode::update()
speed = CLAMP(speed, -1000, 1000); // clamp output speed = CLAMP(speed, -1000, 1000); // clamp output
} }
for (MotorState &motor : motors()) for (bobbycar::protocol::serial::MotorState &motor : motors())
{ {
const auto pair = split(settings.larsmMode.modelMode); const auto pair = split(settings.larsmMode.modelMode);
motor.ctrlTyp = pair.first; motor.ctrlTyp = pair.first;

View File

@ -43,7 +43,7 @@ void TempomatMode::update()
pwm += (gas/1000.) - (brems/1000.); pwm += (gas/1000.) - (brems/1000.);
for (MotorState &motor : motors()) for (bobbycar::protocol::serial::MotorState &motor : motors())
{ {
const auto pair = split(settings.tempomatMode.modelMode); const auto pair = split(settings.tempomatMode.modelMode);
motor.ctrlTyp = pair.first; motor.ctrlTyp = pair.first;

View File

@ -115,20 +115,20 @@ template<> struct nvsGetterHelper<bool> { static esp_err_t nvs_get(nvs_handle ha
*out_value = tempValue; *out_value = tempValue;
return err; return err;
}}; }};
template<> struct nvsGetterHelper<ControlType> { static esp_err_t nvs_get(nvs_handle handle, const char* key, ControlType* out_value) template<> struct nvsGetterHelper<bobbycar::protocol::ControlType> { static esp_err_t nvs_get(nvs_handle handle, const char* key, bobbycar::protocol::ControlType* out_value)
{ {
uint8_t tempValue; uint8_t tempValue;
esp_err_t err = nvs_get_u8(handle, key, &tempValue); esp_err_t err = nvs_get_u8(handle, key, &tempValue);
if (err == ESP_OK) if (err == ESP_OK)
*out_value = ControlType(tempValue); *out_value = bobbycar::protocol::ControlType(tempValue);
return err; return err;
}}; }};
template<> struct nvsGetterHelper<ControlMode> { static esp_err_t nvs_get(nvs_handle handle, const char* key, ControlMode* out_value) template<> struct nvsGetterHelper<bobbycar::protocol::ControlMode> { static esp_err_t nvs_get(nvs_handle handle, const char* key, bobbycar::protocol::ControlMode* out_value)
{ {
uint8_t tempValue; uint8_t tempValue;
esp_err_t err = nvs_get_u8(handle, key, &tempValue); esp_err_t err = nvs_get_u8(handle, key, &tempValue);
if (err == ESP_OK) if (err == ESP_OK)
*out_value = ControlMode(tempValue); *out_value = bobbycar::protocol::ControlMode(tempValue);
return err; return err;
}}; }};
template<> struct nvsGetterHelper<LarsmModeMode> { static esp_err_t nvs_get(nvs_handle handle, const char* key, LarsmModeMode* out_value) template<> struct nvsGetterHelper<LarsmModeMode> { static esp_err_t nvs_get(nvs_handle handle, const char* key, LarsmModeMode* out_value)
@ -197,11 +197,11 @@ template<> struct nvsSetterHelper<uint16_t> { static constexpr auto nvs_set = &n
template<> struct nvsSetterHelper<int32_t> { static constexpr auto nvs_set = &nvs_set_i32; }; template<> struct nvsSetterHelper<int32_t> { static constexpr auto nvs_set = &nvs_set_i32; };
template<> struct nvsSetterHelper<uint32_t> { static constexpr auto nvs_set = &nvs_set_u32; }; template<> struct nvsSetterHelper<uint32_t> { static constexpr auto nvs_set = &nvs_set_u32; };
template<> struct nvsSetterHelper<bool> { static constexpr auto nvs_set = &nvs_set_u8; }; template<> struct nvsSetterHelper<bool> { static constexpr auto nvs_set = &nvs_set_u8; };
template<> struct nvsSetterHelper<ControlType> { static esp_err_t nvs_set(nvs_handle handle, const char* key, ControlType value) template<> struct nvsSetterHelper<bobbycar::protocol::ControlType> { static esp_err_t nvs_set(nvs_handle handle, const char* key, bobbycar::protocol::ControlType value)
{ {
return nvs_set_u8(handle, key, uint8_t(value)); return nvs_set_u8(handle, key, uint8_t(value));
}}; }};
template<> struct nvsSetterHelper<ControlMode> { static esp_err_t nvs_set(nvs_handle handle, const char* key, ControlMode value) template<> struct nvsSetterHelper<bobbycar::protocol::ControlMode> { static esp_err_t nvs_set(nvs_handle handle, const char* key, bobbycar::protocol::ControlMode value)
{ {
return nvs_set_u8(handle, key, uint8_t(value)); return nvs_set_u8(handle, key, uint8_t(value));
}}; }};

View File

@ -16,8 +16,11 @@ enum class UnifiedModelMode : uint8_t
FocTorque FocTorque
}; };
std::pair<ControlType, ControlMode> split(UnifiedModelMode mode) std::pair<bobbycar::protocol::ControlType, bobbycar::protocol::ControlMode> split(UnifiedModelMode mode)
{ {
using bobbycar::protocol::ControlType;
using bobbycar::protocol::ControlMode;
switch (mode) switch (mode)
{ {
case UnifiedModelMode::Commutation: return std::make_pair(ControlType::Commutation, ControlMode::Voltage); case UnifiedModelMode::Commutation: return std::make_pair(ControlType::Commutation, ControlMode::Voltage);

View File

@ -87,7 +87,7 @@ float fixBoardTemp(int16_t value)
return value/10.; return value/10.;
} }
std::string hallString(const MotorFeedback &motor) std::string hallString(const bobbycar::protocol::serial::MotorFeedback &motor)
{ {
return std::string{} + (motor.hallA ? '1' : '0') + (motor.hallB ? '1' : '0') + (motor.hallC ? '1' : '0'); return std::string{} + (motor.hallA ? '1' : '0') + (motor.hallB ? '1' : '0') + (motor.hallC ? '1' : '0');
} }
@ -97,10 +97,11 @@ std::string to_string(const String &value)
return std::string{value.c_str(), value.length()}; return std::string{value.c_str(), value.length()};
} }
std::string to_string(ControlType value) std::string to_string(bobbycar::protocol::ControlType value)
{ {
switch (value) switch (value)
{ {
using namespace bobbycar::protocol;
case ControlType::Commutation: return "Commutation"; case ControlType::Commutation: return "Commutation";
case ControlType::Sinusoidal: return "Sinusoidal"; case ControlType::Sinusoidal: return "Sinusoidal";
case ControlType::FieldOrientedControl: return "FieldOrientedControl"; case ControlType::FieldOrientedControl: return "FieldOrientedControl";
@ -108,10 +109,11 @@ std::string to_string(ControlType value)
return "Unknown ControlType(" + std::to_string(int(value)) + ')'; return "Unknown ControlType(" + std::to_string(int(value)) + ')';
} }
std::string to_string(ControlMode value) std::string to_string(bobbycar::protocol::ControlMode value)
{ {
switch (value) switch (value)
{ {
using namespace bobbycar::protocol;
case ControlMode::OpenMode: return "OpenMode"; case ControlMode::OpenMode: return "OpenMode";
case ControlMode::Voltage: return "Voltage"; case ControlMode::Voltage: return "Voltage";
case ControlMode::Speed: return "Speed"; case ControlMode::Speed: return "Speed";
@ -161,27 +163,27 @@ std::string to_string(IPv6Address value)
return to_string(value.toString()); return to_string(value.toString());
} }
std::array<std::reference_wrapper<MotorState>, 2> motorsInController(Controller &controller) std::array<std::reference_wrapper<bobbycar::protocol::serial::MotorState>, 2> motorsInController(Controller &controller)
{ {
return {std::ref(controller.command.left), std::ref(controller.command.right)}; return {std::ref(controller.command.left), std::ref(controller.command.right)};
} }
std::array<std::reference_wrapper<const MotorState>, 2> motorsInController(const Controller &controller) std::array<std::reference_wrapper<const bobbycar::protocol::serial::MotorState>, 2> motorsInController(const Controller &controller)
{ {
return {std::ref(controller.command.left), std::ref(controller.command.right)}; return {std::ref(controller.command.left), std::ref(controller.command.right)};
} }
std::array<std::reference_wrapper<MotorFeedback>, 2> motorFeedbacksInController(Controller &controller) std::array<std::reference_wrapper<bobbycar::protocol::serial::MotorFeedback>, 2> motorFeedbacksInController(Controller &controller)
{ {
return {std::ref(controller.feedback.left), std::ref(controller.feedback.right)}; return {std::ref(controller.feedback.left), std::ref(controller.feedback.right)};
} }
std::array<std::reference_wrapper<const MotorFeedback>, 2> motorFeedbacksInController(const Controller &controller) std::array<std::reference_wrapper<const bobbycar::protocol::serial::MotorFeedback>, 2> motorFeedbacksInController(const Controller &controller)
{ {
return {std::ref(controller.feedback.left), std::ref(controller.feedback.right)}; return {std::ref(controller.feedback.left), std::ref(controller.feedback.right)};
} }
std::array<std::reference_wrapper<MotorState>, 4> motors() std::array<std::reference_wrapper<bobbycar::protocol::serial::MotorState>, 4> motors()
{ {
return { return {
std::ref(controllers.front.command.left), std::ref(controllers.front.command.right), std::ref(controllers.front.command.left), std::ref(controllers.front.command.right),
@ -191,7 +193,7 @@ std::array<std::reference_wrapper<MotorState>, 4> motors()
void fixCommonParams() void fixCommonParams()
{ {
for (MotorState &motor : motors()) for (bobbycar::protocol::serial::MotorState &motor : motors())
{ {
motor.iMotMax = settings.limits.iMotMax; motor.iMotMax = settings.limits.iMotMax;
motor.iDcMax = settings.limits.iDcMax; motor.iDcMax = settings.limits.iDcMax;
@ -203,7 +205,7 @@ void fixCommonParams()
if (settings.reverseBeep) if (settings.reverseBeep)
{ {
const auto x = motors(); const auto x = motors();
const auto shouldBeep = std::all_of(std::begin(x), std::end(x), [](const MotorState &motor){ return motor.pwm < 0; }); const auto shouldBeep = std::all_of(std::begin(x), std::end(x), [](const bobbycar::protocol::serial::MotorState &motor){ return motor.pwm < 0; });
if (shouldBeep != currentlyReverseBeeping) if (shouldBeep != currentlyReverseBeeping)
{ {