Skip to content
Open
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
13 changes: 12 additions & 1 deletion config/template.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,16 @@
"pins": []
},
"can": {
"enabled": true,
"enabled": false,
"buses": [
"can1"
]
},
"gpio": {
"enabled": false,
"read_pins": [],
"write_pins": []
},
"i2c": {
"enabled": false,
"buses": []
Expand Down Expand Up @@ -45,6 +50,12 @@
"motor_controller": {
"enabled": true,
"bus": "can1"
},
"testrig": {
"enabled": true,
"precharge_relay_gpio_pin": 30,
"controller_relay_gpio_pin": 60,
"main_relay_gpio_pin": 61
}
}
}
Expand Down
274 changes: 273 additions & 1 deletion lib/debug/repl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,14 @@

namespace hyped::debug {

Repl::Repl(core::ILogger &logger) : logger_(logger), i2c_(), spi_(), pwm_(), adc_(), uart_()
Repl::Repl(core::ILogger &logger)
: logger_(logger),
i2c_(),
spi_(),
pwm_(),
adc_(),
uart_(),
gpio_(io::HardwareGpio(logger))
{
}

Expand Down Expand Up @@ -117,6 +124,36 @@ std::optional<std::unique_ptr<Repl>> Repl::fromFile(const std::string &path)
return std::nullopt;
}
}
if (!io.HasMember("gpio")) {
logger_.log(core::LogLevel::kFatal, "Missing required field 'io.gpio' in configuration file");
return std::nullopt;
}
const auto gpio = io["gpio"].GetObject();
if (!gpio.HasMember("enabled")) {
logger_.log(core::LogLevel::kFatal,
"Missing required field 'io.gpio.enabled' in configuration file");
return std::nullopt;
}
if (gpio["enabled"].GetBool()) {
if (!gpio.HasMember("read_pins")) {
logger_.log(core::LogLevel::kFatal,
"Missing required field 'io.gpio.read_pins' in configuration file");
return std::nullopt;
}
const auto read_pins = gpio["read_pins"].GetArray();
for (auto &pin : read_pins) {
repl->addGpioReadCommands(pin.GetUint());
}
if (!gpio.HasMember("write_pins")) {
logger_.log(core::LogLevel::kFatal,
"Missing required field 'io.gpio.write_pins' in configuration file");
return std::nullopt;
}
const auto write_pins = gpio["write_pins"].GetArray();
for (auto &pin : write_pins) {
repl->addGpioWriteCommands(pin.GetUint());
}
}
const auto buses = i2c["buses"].GetArray();
for (auto &bus : buses) {
repl->addI2cCommands(bus.GetUint());
Expand Down Expand Up @@ -283,6 +320,41 @@ std::optional<std::unique_ptr<Repl>> Repl::fromFile(const std::string &path)
const auto bus = motor_controller["bus"].GetString();
repl->addMotorControllerCommands(bus);
}
if (!motors.HasMember("testrig")) {
logger_.log(core::LogLevel::kFatal,
"Missing required field 'debugger.testrig' in configuration file");
return std::nullopt;
}
const auto testrig = motors["testrig"].GetObject();
if (!testrig.HasMember("enabled")) {
logger_.log(core::LogLevel::kFatal,
"Missing required field 'testrig.enabled' in configuration file");
return std::nullopt;
}
if (testrig["enabled"].GetBool()) {
if (!testrig.HasMember("precharge_relay_gpio_pin")) {
logger_.log(core::LogLevel::kFatal,
"Missing required field 'testrig.precharge_relay_gpio_pin' in configuration "
"file");
return std::nullopt;
}
const auto precharge_relay_gpio_pin = testrig["precharge_relay_gpio_pin"].GetUint();
if (!testrig.HasMember("controller_relay_gpio_pin")) {
logger_.log(
core::LogLevel::kFatal,
"Missing required field 'testrig.controller_relay_gpio_pin' in configuration file");
return std::nullopt;
}
const auto controller_relay_gpio_pin = testrig["controller_relay_gpio_pin"].GetUint();
if (!testrig.HasMember("main_relay_gpio_pin")) {
logger_.log(core::LogLevel::kFatal,
"Missing required field 'testrig.main_relay_gpio_pin' in configuration file");
return std::nullopt;
}
const auto main_relay_gpio_pin = testrig["main_relay_gpio_pin"].GetUint();
repl->addMotorTestrigCommands(
precharge_relay_gpio_pin, controller_relay_gpio_pin, main_relay_gpio_pin);
}
return repl;
}

Expand Down Expand Up @@ -393,6 +465,74 @@ void Repl::addCanCommands(const std::string &bus)
addCommand(can_write_command);
}

void Repl::addGpioReadCommands(const std::uint8_t pin)
{
const auto optional_gpio_reader = gpio_.getReader(pin, io::Edge::kNone);
if (!optional_gpio_reader) {
logger_.log(core::LogLevel::kFatal, "Failed to create GPIO reader on pin %d", pin);
return;
}
const auto gpio_reader = std::move(*optional_gpio_reader);
Command gpio_read_command;
std::stringstream identifier;
identifier << "gpio " << static_cast<int>(pin) << " read";
gpio_read_command.name = identifier.str();
std::stringstream description;
description << "Read from GPIO pin " << static_cast<int>(pin);
gpio_read_command.description = description.str();
gpio_read_command.handler = [this, gpio_reader, pin]() {
const auto value = gpio_reader->read();
if (!value) {
logger_.log(core::LogLevel::kFatal, "Failed to read from GPIO pin %d", pin);
return;
}
logger_.log(
core::LogLevel::kDebug, "GPIO value from pin %d: %d", pin, static_cast<std::uint8_t>(*value));
};
}

void Repl::addGpioWriteCommands(const std::uint8_t pin)
{
const auto optional_gpio_writer = gpio_.getWriter(pin, io::Edge::kNone);
if (!optional_gpio_writer) {
logger_.log(core::LogLevel::kFatal, "Failed to create GPIO writer on pin %d", pin);
return;
}
const auto gpio_writer = std::move(*optional_gpio_writer);
Command gpio_write_command;
std::stringstream identifier;
identifier << "gpio " << static_cast<int>(pin) << " write";
gpio_write_command.name = identifier.str();
std::stringstream description;
description << "Write to GPIO pin " << static_cast<int>(pin);
gpio_write_command.description = description.str();
gpio_write_command.handler = [this, gpio_writer, pin]() {
std::cout << "Enter GPIO value: ";
std::uint16_t value;
std::cin >> std::hex >> value;
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
core::DigitalSignal signal;
switch (value) {
case 0:
signal = core::DigitalSignal::kLow;
break;
case 1:
signal = core::DigitalSignal::kHigh;
break;
default:
logger_.log(core::LogLevel::kFatal, "Invalid GPIO value: %d, must be 0 or 1", value);
break;
}
const auto result = gpio_writer->write(signal);
if (result == core::Result::kFailure) {
logger_.log(core::LogLevel::kFatal, "Failed to write to GPIO pin %d", pin);
return;
}
logger_.log(core::LogLevel::kDebug, "Wrote %d to GPIO pin %d", value, pin);
};
addCommand(gpio_write_command);
}

void Repl::addI2cCommands(const std::uint8_t bus)
{
const auto optional_i2c = getI2c(bus);
Expand Down Expand Up @@ -879,6 +1019,138 @@ void Repl::addMotorControllerCommands(const std::string &bus)
addCommand(frequency_time_command);
}

void Repl::addMotorTestrigCommands(const std::uint8_t precharge_relay_gpio_pin,
const std::uint8_t controller_relay_gpio_pin,
const std::uint8_t main_relay_gpio_pin)
{
const auto optional_precharge_relay_gpio
= gpio_.getWriter(precharge_relay_gpio_pin, io::Edge::kNone);
if (!optional_precharge_relay_gpio) {
logger_.log(
core::LogLevel::kFatal, "Failed to get GPIO instance on pin %d", precharge_relay_gpio_pin);
return;
}
const auto precharge_relay_gpio = std::move(*optional_precharge_relay_gpio);
const auto optional_controller_relay_gpio
= gpio_.getWriter(controller_relay_gpio_pin, io::Edge::kNone);
if (!optional_controller_relay_gpio) {
logger_.log(
core::LogLevel::kFatal, "Failed to get GPIO instance on pin %d", controller_relay_gpio_pin);
return;
}
const auto controller_relay_gpio = std::move(*optional_controller_relay_gpio);
const auto optional_main_relay_gpio = gpio_.getWriter(main_relay_gpio_pin, io::Edge::kNone);
if (!optional_main_relay_gpio) {
logger_.log(
core::LogLevel::kFatal, "Failed to get GPIO instance on pin %d", main_relay_gpio_pin);
return;
}
const auto main_relay_gpio = std::move(*optional_main_relay_gpio);
Command testrig_precharge_relay_gpio_command;
testrig_precharge_relay_gpio_command.name = "set precharge relay gpio";
testrig_precharge_relay_gpio_command.description = "Set precharge gpio to value";
testrig_precharge_relay_gpio_command.handler = [this, precharge_relay_gpio] {
std::uint16_t value;
std::cout << "Value: ";
std::cin >> value;
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
core::DigitalSignal signal;
switch (value) {
case 0:
signal = core::DigitalSignal::kLow;
break;
case 1:
signal = core::DigitalSignal::kHigh;
break;
default:
logger_.log(core::LogLevel::kFatal, "Invalid GPIO value: %d, must be 0 or 1", value);
break;
}
const core::Result result = precharge_relay_gpio->write(signal);
if (result == core::Result::kFailure) {
logger_.log(core::LogLevel::kFatal, "Failed to set GPIO 1");
return;
}
};
addCommand(testrig_precharge_relay_gpio_command);
Command testrig_controller_relay_gpio_command;
testrig_controller_relay_gpio_command.name = "set controller relay gpio";
testrig_controller_relay_gpio_command.description = "Set controller relay gpio to value";
testrig_controller_relay_gpio_command.handler = [this, controller_relay_gpio] {
std::uint16_t value;
std::cout << "Value: ";
std::cin >> value;
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
core::DigitalSignal signal;
switch (value) {
case 0:
signal = core::DigitalSignal::kLow;
break;
case 1:
signal = core::DigitalSignal::kHigh;
break;
default:
logger_.log(core::LogLevel::kFatal, "Invalid GPIO value: %d, must be 0 or 1", value);
break;
}
const core::Result result = controller_relay_gpio->write(signal);
if (result == core::Result::kFailure) {
logger_.log(core::LogLevel::kFatal, "Failed to set GPIO 2");
return;
}
};
addCommand(testrig_controller_relay_gpio_command);
Command testrig_main_relay_gpio_command;
testrig_main_relay_gpio_command.name = "set main relay gpio";
testrig_main_relay_gpio_command.description = "Set main relay gpio to value";
testrig_main_relay_gpio_command.handler = [this, main_relay_gpio] {
std::uint16_t value;
std::cout << "Value: ";
std::cin >> value;
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
core::DigitalSignal signal;
switch (value) {
case 0:
signal = core::DigitalSignal::kLow;
break;
case 1:
signal = core::DigitalSignal::kHigh;
break;
default:
logger_.log(core::LogLevel::kFatal, "Invalid GPIO value: %d, must be 0 or 1", value);
break;
}
const core::Result result = main_relay_gpio->write(signal);
if (result == core::Result::kFailure) {
logger_.log(core::LogLevel::kFatal, "Failed to set GPIO 3");
return;
}
};
addCommand(testrig_main_relay_gpio_command);
Command testrig_stop_all_command;
testrig_stop_all_command.name = "stop";
testrig_stop_all_command.description = "Stop all relays";
testrig_stop_all_command.handler =
[this, precharge_relay_gpio, controller_relay_gpio, main_relay_gpio] {
const core::Result precharge_result = precharge_relay_gpio->write(core::DigitalSignal::kLow);
if (precharge_result == core::Result::kFailure) {
logger_.log(core::LogLevel::kFatal, "Failed to set GPIO 1");
return;
}
const core::Result controller_result
= controller_relay_gpio->write(core::DigitalSignal::kLow);
if (controller_result == core::Result::kFailure) {
logger_.log(core::LogLevel::kFatal, "Failed to set GPIO 2");
return;
}
const core::Result main_result = main_relay_gpio->write(core::DigitalSignal::kLow);
if (main_result == core::Result::kFailure) {
logger_.log(core::LogLevel::kFatal, "Failed to set GPIO 3");
return;
}
};
}

std::optional<std::shared_ptr<io::IAdc>> Repl::getAdc(const std::uint8_t bus)
{
const auto adc = adc_.find(bus);
Expand Down
8 changes: 7 additions & 1 deletion lib/debug/repl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,13 +49,18 @@ class Repl {
void addHelpCommand();
void addAdcCommands(const std::uint8_t pin);
void addCanCommands(const std::string &bus);
void addGpioReadCommands(const std::uint8_t pin);
void addGpioWriteCommands(const std::uint8_t pin);
void addI2cCommands(const std::uint8_t bus);
void addPwmCommands(const std::uint8_t module, const std::uint32_t period);
void addSpiCommands(const std::uint8_t bus);
void addAccelerometerCommands(const std::uint8_t bus, const std::uint8_t device_address);
void addTemperatureCommands(const std::uint8_t bus, const std::uint8_t device_address);
void addUartCommands(const std::uint8_t bus);
void addMotorControllerCommands(const std::string &bus);
void addMotorTestrigCommands(const std::uint8_t precharge_relay_gpio_pin,
const std::uint8_t gpio_pin_2,
const std::uint8_t gpio_pin_3);

/**
* @brief Get the Adc object associated with the given pin or create a new one if it doesn't exist
Expand Down Expand Up @@ -125,8 +130,9 @@ class Repl {

core::ILogger &logger_;
std::map<std::string, Command> command_map_;
std::unordered_map<std::string, std::shared_ptr<io::ICan>> can_;
std::unordered_map<std::uint8_t, std::shared_ptr<io::IAdc>> adc_;
std::unordered_map<std::string, std::shared_ptr<io::ICan>> can_;
io::HardwareGpio gpio_;
std::unordered_map<std::uint8_t, std::shared_ptr<io::II2c>> i2c_;
std::unordered_map<io::PwmModule, std::shared_ptr<io::Pwm>> pwm_;
std::unordered_map<io::SpiBus, std::shared_ptr<io::ISpi>> spi_;
Expand Down
Loading