Skip to content

wip cover UI #17

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 11 commits into
base: feature/high-level-service
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .devcontainer/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
cmake make \
gdb-multiarch && \
ln -s /usr/bin/nm /usr/bin/nm-multiarch && \
ln -s /usr/bin/objdump /usr/bin/objdump-multiarch
ln -s /usr/bin/objdump /usr/bin/objdump-multiarch && \
echo 'source /usr/share/bash-completion/completions/git' >> /home/dev/.bashrc

USER $USERNAME
2 changes: 1 addition & 1 deletion .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"vscode": {
"extensions": [
"ms-vscode.cpptools-extension-pack",
"marus25.cortex-debug",
"marus25.cortex-debug"
]
}
}
Expand Down
3 changes: 3 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,10 @@ target_sources(${CMAKE_PROJECT_NAME} PRIVATE
src/drivers/input/input_driver.cpp
src/drivers/input/gpio_input_driver.cpp
src/drivers/input/worx_input_driver.cpp
src/drivers/input/yardforce_input_driver.cpp
$<$<CONFIG:Debug>:src/drivers/input/simulated_input_driver.cpp>
# YardForce Cover UI Driver
src/drivers/ui/YardForceCoverUI/yardforce_cover_ui_driver.cpp
# Raw driver debug interface
src/debug/debug_tcp_interface.cpp
src/debug/debug_udp_interface.cpp
Expand Down
29 changes: 4 additions & 25 deletions boards/XCORE/board_utils.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#include "board_utils.hpp"

#include <etl/crc16_genibus.h>
#include <crc_lookup_map.hpp>

#pragma pack(push, 1)
struct LineParams {
Expand All @@ -10,10 +10,6 @@ struct LineParams {
};
#pragma pack(pop)

constexpr uint16_t crc16(const char* str) {
return etl::crc16_genibus(str, str + strlen(str)).value();
}

constexpr uint32_t ports[] = {GPIOA_BASE, GPIOB_BASE, GPIOC_BASE, GPIOD_BASE,
GPIOE_BASE, GPIOF_BASE, GPIOG_BASE, GPIOH_BASE};

Expand Down Expand Up @@ -123,28 +119,11 @@ constexpr LineParams lines[] = {
{crc16("OSC_OUT"), port_idx('H'), 1},
};

static_assert(
[] {
constexpr size_t count = sizeof(lines) / sizeof(LineParams);
for (size_t i = 0; i < count; i++) {
for (size_t j = i + 1; j < count; j++) {
if (lines[i].crc == lines[j].crc) {
return false;
}
}
}
return true;
}(),
"CRC16 values are not unique");
static_assert(HasUniqueCrcs(lines), "CRC16 values are not unique");

ioline_t GetIoLineByName(const char* name) {
uint16_t crc = crc16(name);
for (const auto& line : lines) {
if (line.crc == crc) {
return PAL_LINE(ports[line.port], line.pad);
}
}
return PAL_NOLINE;
auto* line = LookupByName(name, lines);
return line != nullptr ? PAL_LINE(ports[line->port], line->pad) : PAL_NOLINE;
}

UARTDriver* GetUARTDriverByIndex(uint8_t index) {
Expand Down
2 changes: 1 addition & 1 deletion ext/xbot_framework
2 changes: 2 additions & 0 deletions robots/include/yardforce_robot.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#define YARDFORCE_ROBOT_HPP

#include <drivers/charger/bq_2576/bq_2576.hpp>
#include <drivers/ui/YardForceCoverUI/yardforce_cover_ui_driver.hpp>

#include "robot.hpp"

Expand Down Expand Up @@ -36,6 +37,7 @@ class YardForceRobot : public MowerRobot {

private:
BQ2576 charger_{};
YardForceCoverUIDriver cover_ui_driver_{};
};

#endif // YARDFORCE_ROBOT_HPP
2 changes: 2 additions & 0 deletions robots/src/yardforce_robot.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ void YardForceRobot::InitPlatform() {
InitMotors();
charger_.setI2C(&I2CD1);
power_service.SetDriver(&charger_);
input_service.RegisterInputDriver("yardforce", &cover_ui_driver_.GetInputDriver());
cover_ui_driver_.Start(&UARTD7);
}

bool YardForceRobot::IsHardwareSupported() {
Expand Down
2 changes: 1 addition & 1 deletion services
36 changes: 36 additions & 0 deletions src/crc_lookup_map.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
#ifndef LOOKUP_HPP
#define LOOKUP_HPP

#include <etl/crc16_genibus.h>

#include <cstdint>
#include <cstring>

constexpr uint16_t crc16(const char* str) {
return etl::crc16_genibus(str, str + strlen(str)).value();
}

template <typename T, size_t N>
constexpr bool HasUniqueCrcs(const T (&arr)[N]) {
for (size_t i = 0; i < N; i++) {
for (size_t j = i + 1; j < N; j++) {
if (arr[i].crc == arr[j].crc) {
return false;
}
}
}
return true;
}

template <typename T, size_t N>
const T* LookupByName(const char* name, const T (&arr)[N]) {
uint16_t crc = crc16(name);
for (const auto& item : arr) {
if (item.crc == crc) {
return &item;
}
}
return nullptr;
}

#endif // LOOKUP_HPP
1 change: 0 additions & 1 deletion src/drivers/input/gpio_input_driver.hpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
#ifndef GPIO_INPUT_DRIVER_HPP
#define GPIO_INPUT_DRIVER_HPP

#include <etl/vector.h>
#include <hal.h>

#include "input_driver.hpp"
Expand Down
26 changes: 23 additions & 3 deletions src/drivers/input/input_driver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,23 +5,43 @@

namespace xbot::driver::input {

bool Input::Update(bool new_active) {
bool Input::Update(bool new_active, uint32_t predate) {
if (invert) {
new_active = !new_active;
}
bool expected = !new_active;
if (active.compare_exchange_strong(expected, new_active)) {
const uint32_t now = xbot::service::system::getTimeMicros();
const uint32_t now = xbot::service::system::getTimeMicros() - predate;
if (new_active) {
active_since = now;
input_service.OnInputChanged(*this, true, 0);
} else {
const uint32_t duration = ActiveDuration(now);
if (emergency_reason != 0 && duration >= emergency_delay_ms * 1'000) {
emergency_pending = true;
}
input_service.OnInputChanged(*this, false, duration);
}
input_service.OnInputChanged(*this, new_active, ActiveDuration(now));
chEvtBroadcastFlags(&mower_events, MowerEvents::INPUTS_CHANGED);
return true;
}
return false;
}

bool Input::GetAndClearPendingEmergency() {
bool only_if_pending = true;
return emergency_pending.compare_exchange_strong(only_if_pending, false);
}

void Input::InjectPress(bool long_press) {
InjectPress(input_service.GetPressDelay(long_press));
}

void Input::InjectPress(uint32_t duration) {
Update(true, duration);
Update(false);
}

void InputDriver::AddInput(Input* input) {
if (inputs_head_ == nullptr) {
inputs_head_ = input;
Expand Down
29 changes: 21 additions & 8 deletions src/drivers/input/input_driver.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,23 +26,33 @@ struct Input {
struct {
uint8_t bit;
} worx;

struct {
bool button : 1;
uint8_t id_or_bit : 7;
} yardforce;
};

// State
bool IsActive() const {
return active;
}

bool Update(bool new_active);
bool Update(bool new_active, uint32_t predate = 0);
bool GetAndClearPendingEmergency();

void InjectPress(bool long_press = false);
void InjectPress(uint32_t duration);

uint32_t ActiveDuration(const uint32_t now) const {
return now - active_since;
}

private:
etl::atomic<bool> active = false;
uint32_t active_since = 0;
Input* next_for_driver_ = nullptr;
etl::atomic<bool> active{false};
etl::atomic<bool> emergency_pending{false};
uint32_t active_since{0};
Input* next_for_driver_{nullptr};

friend class InputDriver;
friend struct InputIterable;
Expand Down Expand Up @@ -81,20 +91,23 @@ class InputDriver {
public:
virtual ~InputDriver() = default;
explicit InputDriver() = default;

void AddInput(Input* input);
void ClearInputs();
InputIterable Inputs() {
return InputIterable{inputs_head_};
}

virtual bool OnInputConfigValue(lwjson_stream_parser_t* jsp, const char* key, lwjson_stream_type_t type,
Input& input) = 0;

virtual bool OnStart() {
return true;
};
virtual void OnStop(){};

protected:
private:
Input* inputs_head_ = nullptr;
InputIterable Inputs() {
return InputIterable{inputs_head_};
}
};
} // namespace xbot::driver::input

Expand Down
2 changes: 0 additions & 2 deletions src/drivers/input/simulated_input_driver.hpp
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
#ifndef SIMULATED_INPUT_DRIVER_HPP
#define SIMULATED_INPUT_DRIVER_HPP

#include <etl/vector.h>

#include "input_driver.hpp"

namespace xbot::driver::input {
Expand Down
45 changes: 27 additions & 18 deletions src/drivers/input/worx_input_driver.cpp
Original file line number Diff line number Diff line change
@@ -1,42 +1,51 @@
#include "worx_input_driver.hpp"

#include <etl/crc16_genibus.h>
#include <etl/flat_map.h>
#include <etl/string.h>
#include <ulog.h>

#include <crc_lookup_map.hpp>
#include <json_stream.hpp>

#define IS_BIT_SET(x, bit) ((x & (1 << bit)) != 0)

namespace xbot::driver::input {

static const etl::flat_map<etl::string<13>, uint8_t, 8> INPUT_BITS = {
#pragma pack(push, 1)
namespace {
struct InputParams {
uint16_t crc;
uint8_t bit;
};
} // namespace
#pragma pack(pop)

static constexpr InputParams available_inputs[] = {
// Keys
{"start", 1},
{"home", 2},
{"back", 3},
{crc16("start"), 1},
{crc16("home"), 2},
{crc16("back"), 3},

// Halls
{"battery_cover", 9},
{"stop1", 10},
{"trapped1", 12},
{"trapped2", 13},
{"stop2", 15},
{crc16("battery_cover"), 9},
{crc16("stop1"), 10},
{crc16("trapped1"), 12},
{crc16("trapped2"), 13},
{crc16("stop2"), 15},
};

static_assert(HasUniqueCrcs(available_inputs), "CRC16 values are not unique");

bool WorxInputDriver::OnInputConfigValue(lwjson_stream_parser_t* jsp, const char* key, lwjson_stream_type_t type,
Input& input) {
if (strcmp(key, "id") == 0) {
JsonExpectType(STRING);
decltype(INPUT_BITS)::key_type input_id{jsp->data.str.buff};
auto bit_it = INPUT_BITS.find(input_id);
if (bit_it == INPUT_BITS.end()) {
ULOG_ERROR("Unknown Worx input ID \"%s\"", input_id.c_str());
return false;
const auto* id = jsp->data.str.buff;
if (auto* params = LookupByName(id, available_inputs)) {
input.worx.bit = params->bit;
return true;
}
input.worx.bit = bit_it->second;
return true;
ULOG_ERROR("Unknown ID \"%s\"", id);
return false;
}
ULOG_ERROR("Unknown attribute \"%s\"", key);
return false;
Expand Down
1 change: 0 additions & 1 deletion src/drivers/input/worx_input_driver.hpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
#ifndef WORX_INPUT_DRIVER_HPP
#define WORX_INPUT_DRIVER_HPP

#include <etl/vector.h>
#include <hal.h>

#include <services.hpp>
Expand Down
Loading
Loading