From 1e2c0b58998d86f23cc527227325654e63774ce3 Mon Sep 17 00:00:00 2001 From: Noah Jaye Date: Fri, 5 Dec 2025 14:39:08 -0500 Subject: [PATCH 1/8] Clear out mcal sil. start sockets --- lib/mcal/sil/README | 1 - lib/mcal/sil/adc.hpp | 45 ---- lib/mcal/sil/analog_input.hpp | 22 ++ lib/mcal/sil/analog_output.hpp | 22 ++ lib/mcal/sil/can.hpp | 125 +-------- lib/mcal/sil/client/client.cc | 202 --------------- lib/mcal/sil/client/client.h | 38 --- lib/mcal/sil/client/signals.proto | 99 ------- lib/mcal/sil/gpio.hpp | 58 ++--- lib/mcal/sil/pwm.hpp | 45 ---- projects/lvcontroller/platformio.ini | 24 +- projects/lvcontroller/src/fans/fans.cc | 6 +- projects/lvcontroller/src/main.cc | 5 +- .../src/platforms/sil/bindings.cc | 243 ++++++++++++++++++ .../platforms/sil/proto/lvcontroller.proto | 45 ++++ 15 files changed, 385 insertions(+), 595 deletions(-) delete mode 100644 lib/mcal/sil/README delete mode 100644 lib/mcal/sil/adc.hpp create mode 100644 lib/mcal/sil/analog_input.hpp create mode 100644 lib/mcal/sil/analog_output.hpp delete mode 100644 lib/mcal/sil/client/client.cc delete mode 100644 lib/mcal/sil/client/client.h delete mode 100644 lib/mcal/sil/client/signals.proto delete mode 100644 lib/mcal/sil/pwm.hpp create mode 100644 projects/lvcontroller/src/platforms/sil/bindings.cc create mode 100644 projects/lvcontroller/src/platforms/sil/proto/lvcontroller.proto diff --git a/lib/mcal/sil/README b/lib/mcal/sil/README deleted file mode 100644 index d58971d74..000000000 --- a/lib/mcal/sil/README +++ /dev/null @@ -1 +0,0 @@ -In progress \ No newline at end of file diff --git a/lib/mcal/sil/adc.hpp b/lib/mcal/sil/adc.hpp deleted file mode 100644 index b2938412d..000000000 --- a/lib/mcal/sil/adc.hpp +++ /dev/null @@ -1,45 +0,0 @@ -/// @author Samuel parent -/// @date 2024-05-01 - -#pragma once - -#include -#include - -#include "client.h" -#include "periph/adc.hpp" - -namespace mcal::raspi { - -class ADCInput : public macfe::periph::ADCInput { -public: - ADCInput(std::string ecu_name, std::string sig_name, - val::sil::SilClient& sil_client) - : ecu_name_(ecu_name), sig_name_(sig_name), sil_client_(sil_client) {} - - void Register() { - sil_client_.RegisterAnalogInput(ecu_name_, sig_name_); - } - - void Start() override {} - - uint32_t Read() override { - double adc_voltage = sil_client_.ReadAdcVoltage(ecu_name_, sig_name_); - - return voltage_to_adc.Evaluate(adc_voltage); - } - -private: - static constexpr double kMaxVoltage = 3.3; - static constexpr uint8_t kNumAdcBits = 12; - static constexpr uint32_t kMaxAdcValue = (1 << kNumAdcBits) - 1; - static constexpr double kVoltsToAdc = (kMaxAdcValue / kMaxVoltage); - - macfe::util::LinearMap voltage_to_adc{kVoltsToAdc, 0}; - - std::string ecu_name_; - std::string sig_name_; - val::sil::SilClient& sil_client_; -}; - -} // namespace mcal::raspi diff --git a/lib/mcal/sil/analog_input.hpp b/lib/mcal/sil/analog_input.hpp new file mode 100644 index 000000000..8e80ef909 --- /dev/null +++ b/lib/mcal/sil/analog_input.hpp @@ -0,0 +1,22 @@ +#pragma once + +#include +#include +#include + +#include "lvcontroller.pb.h" +#include "periph/analog_input.hpp" + +namespace mcal::sil { + +class AnalogInput : public macfe::periph::AnalogInput { +private: + float* input_; + +public: + AnalogInput(float* input) : input_(input) {} + float ReadVoltage() { + return *input_; + } +}; +} // namespace mcal::sil \ No newline at end of file diff --git a/lib/mcal/sil/analog_output.hpp b/lib/mcal/sil/analog_output.hpp new file mode 100644 index 000000000..eea771d01 --- /dev/null +++ b/lib/mcal/sil/analog_output.hpp @@ -0,0 +1,22 @@ +#pragma once + +#include +#include +#include + +#include "lvcontroller.pb.h" +#include "periph/analog_output.hpp" + +namespace mcal::sil { + +class AnalogOutput : public macfe::periph::AnalogOutput { +private: + float* output_; + +public: + AnalogOutput(float* output) : output_(output) {} + void SetVoltage(float voltage) override { + *output_ = voltage; + } +}; +} // namespace mcal::sil \ No newline at end of file diff --git a/lib/mcal/sil/can.hpp b/lib/mcal/sil/can.hpp index a4ebccdfa..86799b258 100644 --- a/lib/mcal/sil/can.hpp +++ b/lib/mcal/sil/can.hpp @@ -1,139 +1,38 @@ -/// @author Samuel Parent -/// @date 2023-01-12 - #pragma once -#include -#include -#include -#include -#include -#include -#include -#include #include #include -#include #include #include #include -#include -#include -#include "can/raw_can_msg.hpp" +#include "can/msg.hpp" #include "periph/can.hpp" -#include "third-party/etl/include/etl/queue.h" -namespace mcal::raspi { +namespace mcal::sil { class CanBase : public macfe::periph::CanBase { public: - CanBase(std::string can_iface) : iface_(can_iface) { - program_start_ = std::chrono::steady_clock::now(); - }; + CanBase(std::string can_iface) : iface_(can_iface) {}; void Setup() { - // Create a socket - sock_ = socket(PF_CAN, SOCK_RAW, CAN_RAW); - if (sock_ < 0) { - perror("Error creating socket"); - return; - } - - // Specify the can interface - strncpy(ifreq_.ifr_name, iface_.c_str(), sizeof(ifreq_.ifr_name) - 1); - std::cout << std::format("can interface: {}", iface_) << std::endl; - - ioctl(sock_, SIOCGIFINDEX, &ifreq_); - - // Bind the socket to the can interface - sock_addr_.can_family = AF_CAN; - sock_addr_.can_ifindex = ifreq_.ifr_ifindex; - - int bind_status = - bind(sock_, (struct sockaddr*)&sock_addr_, sizeof(sock_addr_)); - if (bind_status < 0) { - perror("Error binding socket"); - close(sock_); - } - - reader_thread_ = std::thread(&CanBase::StartReading, this); - } - - void Send(const macfe::can::RawCanMsg& can_tx_msg) { - frame_.can_id = can_tx_msg.header.id; - frame_.can_dlc = can_tx_msg.header.data_len; - memcpy((uint8_t*)frame_.data, can_tx_msg.data, 8); - - ssize_t bytes_written = write(sock_, &frame_, sizeof(struct can_frame)); - if (bytes_written != sizeof(struct can_frame)) { - perror("Error writing to socket"); - close(sock_); - } } - void ReadQueue(macfe::can::RawCanMsg can_rx_msgs[], size_t len) { - uint16_t msg_idx = 0; - { - std::lock_guard lock(queue_mtx_); - while (!can_queue_.empty() && (msg_idx < len)) { - can_rx_msgs[msg_idx] = can_queue_.front(); - can_queue_.pop(); - msg_idx++; - } - } + void Send(const macfe::can::RawMessage& msg) override { + // std::cout << std::format("CanBase {}: Sending\n| {}", iface_, msg) + // << std::endl; } private: - static constexpr uint8_t kMaxMsgBytes = 8; - - struct sockaddr_can sock_addr_; - struct ifreq ifreq_; - struct can_frame frame_; std::string iface_; - int sock_; - - std::queue can_queue_; - std::mutex queue_mtx_; - std::thread reader_thread_; - - std::chrono::steady_clock::time_point program_start_; - - inline uint32_t get_tick() { - std::chrono::milliseconds elapsed_ms = - std::chrono::duration_cast( - std::chrono::steady_clock::now() - program_start_); - return static_cast(elapsed_ms.count()); - } - void StartReading() { - struct can_frame frame; - - while (true) { - ssize_t bytesRead = - recv(sock_, &frame, sizeof(struct can_frame), 0); - if (bytesRead == -1) { - perror("Error reading from CAN socket"); - continue; - } - - macfe::can::RawCanMsg rawMsg; - rawMsg.header.id = frame.can_id; - rawMsg.header.data_len = frame.can_dlc; - rawMsg.header.is_extended_frame = frame.can_id & CAN_EFF_FLAG; - rawMsg.tick_timestamp = get_tick(); - - std::copy(frame.data, frame.data + kMaxMsgBytes, rawMsg.data); - - // Add to the queue - { - std::lock_guard lock(queue_mtx_); - can_queue_.push(rawMsg); - } - } + uint32_t GetTimestamp() const override { + using namespace std::chrono; + // auto t = system_clock::now().time_since_epoch(); + // auto ms = duration_cast(4).count(); + return 4; } }; - -} // namespace mcal::raspi +} // namespace mcal::sil \ No newline at end of file diff --git a/lib/mcal/sil/client/client.cc b/lib/mcal/sil/client/client.cc deleted file mode 100644 index db5378e72..000000000 --- a/lib/mcal/sil/client/client.cc +++ /dev/null @@ -1,202 +0,0 @@ -/// @author Samuel Parent -/// @date 2024-05-01 - -#include "client.h" - -#include -#include -#include - -#include -#include -#include - -#include "signals.grpc.pb.h" -#include "signals.pb.h" - -namespace val::sil { - -SilClient::SilClient(std::string addr) : addr_(addr) {} - -void SilClient::Connect() { - stub_ = signals::Signals::NewStub( - grpc::CreateChannel(addr_, grpc::InsecureChannelCredentials())); -} - -void SilClient::RegisterDigitalInput(std::string ecu_name, - std::string sig_name) { - grpc::Status status; - grpc::ClientContext context; - signals::RegisterSignalRequest register_request; - signals::RegisterSignalResponse register_response; - - register_request.set_ecu_name(ecu_name); - register_request.set_signal_name(sig_name); - register_request.set_signal_direction( - signals::SignalDirection::SIGNAL_DIRECTION_INPUT); - register_request.set_signal_type(signals::SignalType::SIGNAL_TYPE_DIGITAL); - - status = - stub_->RegisterSignal(&context, register_request, ®ister_response); - if (!status.ok()) { - std::cout << std::format("{}: {}", status.error_code(), - status.error_message()) - << std::endl; - } - if (!register_response.status()) { - std::cout << std::format("register signal error: {}", - register_response.error()) - << std::endl; - } -} - -void SilClient::RegisterDigitalOutput(std::string ecu_name, - std::string sig_name) { - grpc::Status status; - grpc::ClientContext context; - signals::RegisterSignalRequest register_request; - signals::RegisterSignalResponse register_response; - - register_request.set_ecu_name(ecu_name); - register_request.set_signal_name(sig_name); - register_request.set_signal_direction( - signals::SignalDirection::SIGNAL_DIRECTION_OUTPUT); - register_request.set_signal_type(signals::SignalType::SIGNAL_TYPE_DIGITAL); - - status = - stub_->RegisterSignal(&context, register_request, ®ister_response); - if (!status.ok()) { - std::cout << std::format("{}: {}", status.error_code(), - status.error_message()) - << std::endl; - } - - if (!register_response.status()) { - std::cout << std::format("register signal error: {}", - register_response.error()) - << std::endl; - } -} - -void SilClient::RegisterAnalogInput(std::string ecu_name, - std::string sig_name) { - grpc::Status status; - grpc::ClientContext context; - signals::RegisterSignalRequest register_request; - signals::RegisterSignalResponse register_response; - - register_request.set_ecu_name(ecu_name); - register_request.set_signal_name(sig_name); - register_request.set_signal_direction( - signals::SignalDirection::SIGNAL_DIRECTION_INPUT); - register_request.set_signal_type(signals::SignalType::SIGNAL_TYPE_ANALOG); - - status = - stub_->RegisterSignal(&context, register_request, ®ister_response); - if (!status.ok()) { - std::cout << std::format("{}: {}", status.error_code(), - status.error_message()) - << std::endl; - } - - if (!register_response.status()) { - std::cout << std::format("register signal error: {}", - register_response.error()) - << std::endl; - } -} - -void SilClient::SetDigitalLevel(std::string ecu_name, std::string sig_name, - bool level) { - grpc::Status status; - grpc::ClientContext context; - signals::WriteSignalRequest write_request; - signals::WriteSignalResponse write_response; - - write_request.set_ecu_name(ecu_name); - write_request.set_signal_name(sig_name); - write_request.mutable_value_digital()->set_level(level); - - status = stub_->WriteSignal(&context, write_request, &write_response); - if (!status.ok()) { - std::cout << std::format("{}: {}", status.error_code(), - status.error_message()) - << std::endl; - return; - } - - if (!write_response.status()) { - std::cout << std::format("write response error: {}", - write_response.error()) - << std::endl; - return; - } -} - -bool SilClient::ReadDigitalLevel(std::string ecu_name, std::string sig_name) { - grpc::Status status; - grpc::ClientContext context; - signals::ReadSignalRequest read_request; - signals::ReadSignalResponse read_response; - - read_request.set_ecu_name(ecu_name); - read_request.set_signal_name(sig_name); - read_request.set_signal_type(signals::SignalType::SIGNAL_TYPE_DIGITAL); - read_request.set_signal_direction( - signals::SignalDirection::SIGNAL_DIRECTION_INPUT); - - status = stub_->ReadSignal(&context, read_request, &read_response); - if (!status.ok()) { - std::cout << std::format("{}: {}", status.error_code(), - status.error_message()) - << std::endl; - return false; - } - - if (!read_response.status()) { - std::cout << std::format("write reponse error: {}", - read_response.error()) - << std::endl; - return false; - } - - return read_response.value_digital().level(); -} - -double SilClient::ReadAdcVoltage(std::string ecu_name, std::string sig_name) { - grpc::Status status; - grpc::ClientContext context; - signals::ReadSignalRequest read_request; - signals::ReadSignalResponse read_response; - - read_request.set_ecu_name(ecu_name); - read_request.set_signal_name(sig_name); - read_request.set_signal_type(signals::SignalType::SIGNAL_TYPE_ANALOG); - read_request.set_signal_direction( - signals::SignalDirection::SIGNAL_DIRECTION_INPUT); - - status = stub_->ReadSignal(&context, read_request, &read_response); - if (!status.ok()) { - std::cout << std::format("{}: {}", status.error_code(), - status.error_message()) - << std::endl; - return 0.0; - } - - if (!read_response.status()) { - std::cout << std::format("write response error: {}", - read_response.error()) - << std::endl; - return 0.0; - } - - if (!read_response.has_value_analog()) { - std::cout << std::format("expected adc value got: {}", - read_response.value_case()) - << std::endl; - } - - return read_response.value_analog().voltage(); -} - -} // namespace val::sil diff --git a/lib/mcal/sil/client/client.h b/lib/mcal/sil/client/client.h deleted file mode 100644 index 3da05d14e..000000000 --- a/lib/mcal/sil/client/client.h +++ /dev/null @@ -1,38 +0,0 @@ -/// @author Samuel Parent -/// @date 2024-05-01 - -#pragma once - -#include - -#include -#include -#include - -#include "grpcpp/channel.h" -#include "signals.grpc.pb.h" -#include "signals.pb.h" - -namespace val::sil { - -class SilClient { -public: - SilClient(std::string server_addr); - - void Connect(); - - void RegisterDigitalInput(std::string ecu_name, std::string sig_name); - void RegisterDigitalOutput(std::string ecu_name, std::string sig_name); - void RegisterAnalogInput(std::string ecu_name, std::string sig_name); - - bool ReadDigitalLevel(std::string ecu_name, std::string sig_name); - double ReadAdcVoltage(std::string ecu_name, std::string sig_name); - void SetDigitalLevel(std::string ecu_name, std::string sig_name, - bool level); - -private: - std::string addr_; - std::unique_ptr stub_; -}; - -} // namespace val::sil diff --git a/lib/mcal/sil/client/signals.proto b/lib/mcal/sil/client/signals.proto deleted file mode 100644 index 97586f1e4..000000000 --- a/lib/mcal/sil/client/signals.proto +++ /dev/null @@ -1,99 +0,0 @@ -syntax = "proto3"; - -package signals; - -option go_package = ".sil"; - -service Signals { - rpc EnumerateRegisteredSignals(EnumerateRegisteredSignalsRequest) - returns (EnumerateRegisteredSignalsResponse) {} - rpc WriteSignal(WriteSignalRequest) returns (WriteSignalResponse) {} - rpc ReadSignal(ReadSignalRequest) returns (ReadSignalResponse) {} - rpc RegisterSignal(RegisterSignalRequest) returns (RegisterSignalResponse) { - } -} - -enum SignalType { - SIGNAL_TYPE_UNKNOWN = 0; - SIGNAL_TYPE_ANALOG = 1; - SIGNAL_TYPE_DIGITAL = 2; - SIGNAL_TYPE_PWM = 3; -} - -enum SignalDirection { - SIGNAL_DIRECTION_UNKNOWN = 0; - SIGNAL_DIRECTION_INPUT = 1; - SIGNAL_DIRECTION_OUTPUT = 2; -} - -message AnalogSignal { - double voltage = 1; -} - -message PwmSignal { - uint32 duty_cycle = 1; - uint32 frequency = 2; -} - -message DigitalSignal { - bool level = 1; -} - -message SignalInfo { - string ecu_name = 1; - string signal_name = 2; - SignalType signal_type = 3; - SignalDirection signal_direction = 4; -} - -message EnumerateRegisteredSignalsRequest {} - -message EnumerateRegisteredSignalsResponse { - bool status = 1; - string error = 2; - repeated SignalInfo signals = 3; -} - -message WriteSignalRequest { - string ecu_name = 1; - string signal_name = 2; - oneof value { - AnalogSignal value_analog = 3; - DigitalSignal value_digital = 4; - PwmSignal value_pwm = 5; - } -} - -message WriteSignalResponse { - bool status = 1; - string error = 2; -} - -message ReadSignalRequest { - string ecu_name = 1; - string signal_name = 2; - SignalType signal_type = 3; - SignalDirection signal_direction = 4; -} - -message ReadSignalResponse { - bool status = 1; - string error = 2; - oneof value { - AnalogSignal value_analog = 3; - DigitalSignal value_digital = 4; - PwmSignal value_pwm = 5; - } -} - -message RegisterSignalRequest { - string ecu_name = 1; - string signal_name = 2; - SignalType signal_type = 3; - SignalDirection signal_direction = 4; -} - -message RegisterSignalResponse { - bool status = 1; - string error = 2; -} diff --git a/lib/mcal/sil/gpio.hpp b/lib/mcal/sil/gpio.hpp index 90dd0682f..bff5a2a49 100644 --- a/lib/mcal/sil/gpio.hpp +++ b/lib/mcal/sil/gpio.hpp @@ -1,66 +1,40 @@ -/// @author Samuel Parent -/// @date 2023-12-10 - #pragma once -#include #include +#include #include +#include "lvcontroller.pb.h" #include "periph/gpio.hpp" -#include "validation/sil/sil_client.h" -namespace mcal::raspi { +namespace mcal::sil { class DigitalInput : public macfe::periph::DigitalInput { -public: - DigitalInput(std::string ecu_name, std::string sig_name, - val::sil::SilClient& sil_client) - : ecu_name_(ecu_name), sig_name_(sig_name), sil_client_(sil_client) {} +private: + bool* input_; - void Register() { - sil_client_.RegisterDigitalInput(ecu_name_, sig_name_); - } +public: + DigitalInput(bool* input) : input_(input) {} bool Read() override { - return sil_client_.ReadDigitalLevel(ecu_name_, sig_name_); + return *input_; } - -private: - std::string ecu_name_; - std::string sig_name_; - val::sil::SilClient& sil_client_; }; class DigitalOutput : public macfe::periph::DigitalOutput { -public: - DigitalOutput(std::string ecu_name, std::string sig_name, - val::sil::SilClient& sil_client) - : ecu_name_(ecu_name), sig_name_(sig_name), sil_client_(sil_client) {} - - void Register() { - sil_client_.RegisterDigitalOutput(ecu_name_, sig_name_); - } +private: + bool* output_; - void Set(bool level) override { - std::cout << std::format("setting {}.{} {}", ecu_name_, sig_name_, - level) - << std::endl; - return sil_client_.SetDigitalLevel(ecu_name_, sig_name_, level); +public: + DigitalOutput(bool* output) : output_(output) {} + void Set(bool value) override { + *output_ = value; } - void SetHigh() override { Set(true); } - void SetLow() override { - return sil_client_.SetDigitalLevel(ecu_name_, sig_name_, true); + Set(false); } - -private: - std::string ecu_name_; - std::string sig_name_; - val::sil::SilClient& sil_client_; }; - -} // namespace mcal::raspi +} // namespace mcal::sil \ No newline at end of file diff --git a/lib/mcal/sil/pwm.hpp b/lib/mcal/sil/pwm.hpp deleted file mode 100644 index 10f9fc1bc..000000000 --- a/lib/mcal/sil/pwm.hpp +++ /dev/null @@ -1,45 +0,0 @@ -/// @author Samuel Parent -/// @date 2023-05-21 - -#pragma once - -#include -#include -#include - -#include "periph/pwm.hpp" - -namespace mcal::raspi { - -class PWMOutput : public macfe::periph::PWMOutput { -public: - PWMOutput(std::string name) : name_(name) {} - - void Start() override { - std::cout << std::format("Starting PWM {}", name_) << std::endl; - } - - void Stop() override { - std::cout << std::format("Stopping PWM {}", name_) << std::endl; - } - - void SetDutyCycle(float duty_cycle) override { - duty_cycle_ = macfe::util::Clamper::Evaluate(duty_cycle, 0, 100); - - std::cout << std::format("Setting PWM {} to {:.3g}%", name_, - duty_cycle_) - << std::endl; - } - float GetDutyCycle() override { - std::cout << std::format("PWM {} has duty cycle {:.3f} Hz", name_, - duty_cycle_) - << std::endl; - return duty_cycle_; - } - -private: - std::string name_; - float duty_cycle_; -}; - -} // namespace mcal::raspi diff --git a/projects/lvcontroller/platformio.ini b/projects/lvcontroller/platformio.ini index 078c43e40..24fd7834d 100644 --- a/projects/lvcontroller/platformio.ini +++ b/projects/lvcontroller/platformio.ini @@ -5,6 +5,8 @@ description = "Low Voltage Controller" [env] build_type = debug debug_build_flags = -g + +[common] lib_deps = Embedded Template Library@^20 cangen=file://../../scripts/cangen @@ -17,8 +19,6 @@ check_src_filters = + - + - -[common] build_src_filter = +<**/*.*> ; Exclude top-level platforms/ and mcal/ - each `env` will re-add what it needs @@ -39,6 +39,7 @@ platform_packages = framework = stm32cube board = nucleo_f767zi upload_protocol = stlink +lib_deps = ${common.lib_deps} build_src_filter = ${common.build_src_filter} + @@ -54,6 +55,7 @@ extra_scripts = [env:cli] platform = native +lib_deps = ${common.lib_deps} build_src_filter = ${common.build_src_filter} + @@ -61,4 +63,20 @@ build_src_filter = build_flags = ${common.flags} extra_scripts = - ${common.extra_scripts} \ No newline at end of file + ${common.extra_scripts} + +[env:sil] +platform = native +lib_deps = + ${common.lib_deps} + Nanopb +build_src_filter = + ${common.build_src_filter} + + + + + - + +build_flags = + ${common.flags} + -Wno-error=unused-private-field ; timestamp issue +custom_nanopb_protos = + diff --git a/projects/lvcontroller/src/fans/fans.cc b/projects/lvcontroller/src/fans/fans.cc index 5e9af7ea7..4b62d4d1a 100644 --- a/projects/lvcontroller/src/fans/fans.cc +++ b/projects/lvcontroller/src/fans/fans.cc @@ -21,11 +21,11 @@ bool IsAtSetpoint(void) { } void Init(void) { - bindings::powertrain_fan_pwm.Start(); + // bindings::powertrain_fan_pwm.Start(); power_setpoint = 0; current_power = 0; - bindings::powertrain_fan_pwm.SetDutyCycle(power_setpoint); + // bindings::powertrain_fan_pwm.SetDutyCycle(power_setpoint); } static void UpdateEnabled(void) { @@ -50,7 +50,7 @@ static void UpdateStep(void) { current_power += step; // TODO: should the duty be inverted? - bindings::powertrain_fan_pwm.SetDutyCycle(current_power); + // bindings::powertrain_fan_pwm.SetDutyCycle(current_power); } void Update_100Hz(void) { diff --git a/projects/lvcontroller/src/main.cc b/projects/lvcontroller/src/main.cc index 9951dd7f0..2559692b7 100644 --- a/projects/lvcontroller/src/main.cc +++ b/projects/lvcontroller/src/main.cc @@ -1,7 +1,7 @@ /// @author Blake Freer /// @date 2023-12-25 - #include +#include #include #include "bindings.hpp" @@ -246,16 +246,13 @@ void task_100hz(void) { int main(void) { bindings::Initialize(); - accumulator::Init(); fans::Init(); fsm::Init(); motor_controller::Init(); - scheduler::register_task(task_100hz, 10); scheduler::register_task(task_10hz, 100); scheduler::register_task(task_1hz, 1000); - scheduler::run(); while (true) continue; diff --git a/projects/lvcontroller/src/platforms/sil/bindings.cc b/projects/lvcontroller/src/platforms/sil/bindings.cc new file mode 100644 index 000000000..e22aad531 --- /dev/null +++ b/projects/lvcontroller/src/platforms/sil/bindings.cc @@ -0,0 +1,243 @@ +/// @author Noah Jaye +/// @date 2025-10-31 + +#include "bindings.hpp" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "lvcontroller.pb.h" +#include "mcal/sil/analog_input.hpp" +#include "mcal/sil/analog_output.hpp" +#include "mcal/sil/can.hpp" +#include "mcal/sil/gpio.hpp" +#include "pb_decode.h" +#include "pb_encode.h" +#include "periph/gpio.hpp" + +Output outputs = Output_init_zero; + +Input inputs = Input_init_zero; +std::thread wt; +std::thread rt; +std::thread ct; + +namespace mcal { +using namespace mcal::sil; +// Tractive System Status Indicator +DigitalOutput tssi_en{&outputs.tssi_en}; +DigitalOutput tssi_red_signal{&outputs.tssi_red_signal}; +DigitalOutput tssi_green_signal{&outputs.tssi_green_signal}; +DigitalInput imd_fault{&inputs.imd_fault}; +DigitalInput bms_fault{&inputs.bms_fault}; + +// Powertrain Cooling +DigitalOutput powertrain_pump1_en{&outputs.powertrain_pump1_en}; +DigitalOutput powertrain_pump2_en{&outputs.powertrain_pump2_en}; +DigitalOutput powertrain_fan1_en{&outputs.powertrain_fan1_en}; +DigitalOutput powertrain_fan2_en{&outputs.powertrain_fan2_en}; + +// Motor Controller (i.e. Inverters) +DigitalOutput motor_controller_en{&outputs.motor_controller_en}; +DigitalOutput motor_ctrl_precharge_en{&outputs.motor_ctrl_precharge_en}; +DigitalOutput motor_ctrl_switch_en{&outputs.motor_ctrl_switch_en}; + +// Subsystems +DigitalOutput accumulator_en{&outputs.accumulator_en}; +DigitalOutput front_controller_en{&outputs.front_controller_en}; +DigitalOutput imu_gps_en{&outputs.imu_gps_en}; +DigitalOutput shutdown_circuit_en{&outputs.shutdown_circuit_en}; + +// DCDC System Measurement; +DigitalOutput dcdc_en{&outputs.dcdc_en}; +DigitalOutput dcdc_sense_select{&outputs.dcdc_sense_select}; +AnalogInput dcdc_sense{&inputs.dcdc_sense}; + +// Other IO +DigitalOutput brake_light_en{&outputs.brake_light_en}; +AnalogInput suspension_travel3{&inputs.suspension_travel3}; +AnalogInput suspension_travel4{&inputs.suspension_travel4}; +CanBase veh_can_base{"vcan0"}; + +} // namespace mcal +int port = 11001; +static bool write_callback(pb_ostream_t* stream, const uint8_t* buf, + size_t count) { + int fd = (intptr_t)stream->state; + bool result = send(fd, buf, count, 0) == count; + return result; +} + +static bool read_callback(pb_istream_t* stream, uint8_t* buf, size_t count) { + int fd = (intptr_t)stream->state; + int result; + + if (count == 0) return true; + + result = recv(fd, buf, count, 0); + std::cout << "Buffer: " << buf << std::endl; + std::cout << "Result: " << result << std::endl; + if (result == 0) stream->bytes_left = 0; /* EOF */ + std::cout << "Bytes left: " << stream->bytes_left << std::endl; + return result == count; +} + +void writerThread(int sockfd) { + while (true) { + pb_ostream_t ostream = { + .callback = &write_callback, + .state = (void*)(intptr_t)sockfd, + .max_size = SIZE_MAX, + .bytes_written = 0, + }; + // transmit that the message has started + int msg_start[1] = {1}; + + // TODO rm this + static bool flipper = true; + mcal::tssi_green_signal.Set(flipper); + mcal::front_controller_en.Set(!flipper); + mcal::imu_gps_en.Set(flipper); + flipper = !flipper; + // TODO until this + + send(sockfd, &msg_start, sizeof(msg_start), 0); + if (pb_encode(&ostream, &Output_msg, &outputs) != 0) { + std::cout << "Error with the writer encoding: " + << PB_GET_ERROR(&ostream) << std::strerror(errno) + << std::endl; + } + // transmit that the message has ended + int msg_end[1] = {2}; + send(sockfd, &msg_end, sizeof(msg_end), 0); + std::this_thread::sleep_for(std::chrono::milliseconds(3000)); + } + close(sockfd); +} +void readerThread(int sockfd) { + while (true) { + std::cout << "Reading" << std::endl; + /*pb_istream_t istream = { + .callback = &read_callback, + .state = (void*)(intptr_t)sockfd, + .bytes_left = SIZE_MAX, + };*/ + // uint8_t biggerbuffer[1024]; + uint8_t buffer[2]; + ssize_t result = recv(sockfd, buffer, sizeof(buffer), 0); + std::cout << "Read bytes" << result << std::endl; + for (int i = 0; i < result; i++) { + std::cout << (int)buffer[i] << std::endl; + } + /*if (pb_decode(&istream, &Input_msg, &inputs) != 0) { + std::cout << "Error to follow" << std::endl; + std::cout << "Error in the reader decode" << PB_GET_ERROR(&istream) + << std::endl; + }*/ + std::cout << "imd_fault" << inputs.imd_fault << std::endl; + std::cout << "bms_fault" << inputs.bms_fault << std::endl; + std::this_thread::sleep_for(std::chrono::milliseconds(1000)); + } + std::cout << "This shouldn't print in the reader" << std::endl; + close(sockfd); +} +void connectServer() { + int sockfd = 0; + bool has_connected = false; + while (!has_connected) { + sockfd = socket(AF_INET, SOCK_STREAM, 0); + struct sockaddr_in servaddr{}; + servaddr.sin_family = AF_INET; + servaddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + servaddr.sin_port = htons(port); + if (connect(sockfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) == + 0) { + has_connected = true; + } else { + std::cerr << "Error to follow" << std::endl; + std::cerr << "Error with the connection: " << std::strerror(errno) + << std::endl; + close(sockfd); + std::this_thread::sleep_for(std::chrono::milliseconds(250)); + } + } + // wt = std::thread(writerThread, sockfd); + rt = std::thread(readerThread, sockfd); +} +namespace bindings { +using namespace macfe::periph; + +// Tractive System Status Indicator +DigitalOutput& tssi_en = mcal::tssi_en; +DigitalOutput& tssi_red_signal = mcal::tssi_red_signal; +DigitalOutput& tssi_green_signal = mcal::tssi_green_signal; +DigitalInput& imd_fault = mcal::imd_fault; +DigitalInput& bms_fault = mcal::bms_fault; + +// Powertrain Cooling +DigitalOutput& powertrain_pump1_en = mcal::powertrain_pump1_en; +DigitalOutput& powertrain_pump2_en = mcal::powertrain_pump2_en; +DigitalOutput& powertrain_fan1_en = mcal::powertrain_fan1_en; +DigitalOutput& powertrain_fan2_en = mcal::powertrain_fan2_en; + +// Motor Controller (Inverters) +DigitalOutput& motor_controller_en = mcal::motor_controller_en; +DigitalOutput& motor_ctrl_precharge_en = mcal::motor_ctrl_precharge_en; +DigitalOutput& motor_ctrl_switch_en = mcal::motor_ctrl_switch_en; + +// Subsystems +DigitalOutput& accumulator_en = mcal::accumulator_en; +DigitalOutput& front_controller_en = mcal::front_controller_en; +DigitalOutput& imu_gps_en = mcal::imu_gps_en; +DigitalOutput& shutdown_circuit_en = mcal::shutdown_circuit_en; + +// DCDC System +DigitalOutput& dcdc_en = mcal::dcdc_en; +DigitalOutput& dcdc_sense_select = mcal::dcdc_sense_select; +AnalogInput& dcdc_sense = mcal::dcdc_sense; + +// Other IO +DigitalOutput& brake_light_en = mcal::brake_light_en; +AnalogInput& suspension_travel3 = mcal::suspension_travel3; +AnalogInput& suspension_travel4 = mcal::suspension_travel4; +CanBase& veh_can_base = mcal::veh_can_base; // clang-format on + +void Initialize() { + std::cout << "Initializing SIL\n"; + connectServer(); +} + +// copied luai +int GetTick() { + using namespace std::chrono; + long now = + duration_cast(system_clock::now().time_since_epoch()) + .count(); + static long start = now; // only set on first call + + return now - start; +} + +void DelayMS(int ms) { + std::this_thread::sleep_for(std::chrono::milliseconds(ms)); +} + +// copied luai +void SoftwareReset() { + std::cout << "Performing software reset. Will not proceed." << std::endl; + while (true) continue; +} + +// ask for most recent struct from outer program +// https://pubs.opengroup.org/onlinepubs/009695199/basedefs/sys/select.h.html + +} // namespace bindings diff --git a/projects/lvcontroller/src/platforms/sil/proto/lvcontroller.proto b/projects/lvcontroller/src/platforms/sil/proto/lvcontroller.proto new file mode 100644 index 000000000..6b9cbed49 --- /dev/null +++ b/projects/lvcontroller/src/platforms/sil/proto/lvcontroller.proto @@ -0,0 +1,45 @@ +syntax = "proto3"; +option go_package = "./gotobuf"; + +message Output { + // Tractive system status indicator + bool tssi_en = 1; + bool tssi_red_signal = 2; + bool tssi_green_signal = 3; + + // Powertrain cooling + bool powertrain_pump1_en = 4; + bool powertrain_pump2_en = 5; + bool powertrain_fan1_en = 6; + bool powertrain_fan2_en = 7; + float powertrain_fan_pwm = 8; + + // Motor Controller + bool motor_controller_en = 9; + bool motor_ctrl_precharge_en = 10; + bool motor_ctrl_switch_en = 11; + + // Subsystems + bool accumulator_en = 12; + bool front_controller_en = 13; + bool imu_gps_en = 14; + bool shutdown_circuit_en = 15; + + // DCDC System & measurement + bool dcdc_en = 16; + bool dcdc_sense_select = 17; + + // Other + bool brake_light_en = 18; +} + +message Input { + // Tractive system status indicator + bool imd_fault = 1; + bool bms_fault = 2; + + // DCDC System & Measurement + float dcdc_sense = 3; + float suspension_travel3 = 4; + float suspension_travel4 = 5; +} \ No newline at end of file From 53732b6a6c65ce3d635fefb9fd20b29f22203adc Mon Sep 17 00:00:00 2001 From: Noah Jaye Date: Fri, 5 Dec 2025 15:02:52 -0500 Subject: [PATCH 2/8] Adding Cobs message framing.` --- projects/lvcontroller/lib/cobs | 1 + .../src/platforms/sil/bindings.cc | 39 ++++++++++--------- .../platforms/sil/proto/lvcontroller.proto | 1 + 3 files changed, 23 insertions(+), 18 deletions(-) create mode 120000 projects/lvcontroller/lib/cobs diff --git a/projects/lvcontroller/lib/cobs b/projects/lvcontroller/lib/cobs new file mode 120000 index 000000000..3ffa7772f --- /dev/null +++ b/projects/lvcontroller/lib/cobs @@ -0,0 +1 @@ +../../../lib/cobs \ No newline at end of file diff --git a/projects/lvcontroller/src/platforms/sil/bindings.cc b/projects/lvcontroller/src/platforms/sil/bindings.cc index e22aad531..4203b1565 100644 --- a/projects/lvcontroller/src/platforms/sil/bindings.cc +++ b/projects/lvcontroller/src/platforms/sil/bindings.cc @@ -15,6 +15,7 @@ #include #include +#include "cobs.hpp" #include "lvcontroller.pb.h" #include "mcal/sil/analog_input.hpp" #include "mcal/sil/analog_output.hpp" @@ -23,10 +24,9 @@ #include "pb_decode.h" #include "pb_encode.h" #include "periph/gpio.hpp" +lvcontroller_Output outputs = lvcontroller_Output_init_zero; -Output outputs = Output_init_zero; - -Input inputs = Input_init_zero; +lvcontroller_Input inputs = lvcontroller_Input_init_zero; std::thread wt; std::thread rt; std::thread ct; @@ -111,7 +111,7 @@ void writerThread(int sockfd) { // TODO until this send(sockfd, &msg_start, sizeof(msg_start), 0); - if (pb_encode(&ostream, &Output_msg, &outputs) != 0) { + if (pb_encode(&ostream, &lvcontroller_Output_msg, &outputs) == 0) { std::cout << "Error with the writer encoding: " << PB_GET_ERROR(&ostream) << std::strerror(errno) << std::endl; @@ -124,6 +124,9 @@ void writerThread(int sockfd) { close(sockfd); } void readerThread(int sockfd) { + uint8_t cobsBuffer[2048] = {0}; + // Input_size is a useful thing to know about + macfe::cobs::Decoder decoder(cobsBuffer); while (true) { std::cout << "Reading" << std::endl; /*pb_istream_t istream = { @@ -131,21 +134,21 @@ void readerThread(int sockfd) { .state = (void*)(intptr_t)sockfd, .bytes_left = SIZE_MAX, };*/ - // uint8_t biggerbuffer[1024]; - uint8_t buffer[2]; - ssize_t result = recv(sockfd, buffer, sizeof(buffer), 0); - std::cout << "Read bytes" << result << std::endl; - for (int i = 0; i < result; i++) { - std::cout << (int)buffer[i] << std::endl; + uint8_t byte; + ssize_t result = recv(sockfd, &byte, 1, 0); + if (decoder.Decode(&byte, result)) { + lvcontroller_Input inputs_temp; + pb_istream_t istream = + pb_istream_from_buffer(decoder.buffer, decoder.length); + if (pb_decode(&istream, &lvcontroller_Input_msg, &inputs_temp)) { + inputs = inputs_temp; + } else { + std::cerr << "Failed to decode inputs" << std::endl; + } + decoder = macfe::cobs::Decoder(cobsBuffer); + std::cout << "imd_fault" << inputs.imd_fault << std::endl; + std::cout << "bms_fault" << inputs.bms_fault << std::endl; } - /*if (pb_decode(&istream, &Input_msg, &inputs) != 0) { - std::cout << "Error to follow" << std::endl; - std::cout << "Error in the reader decode" << PB_GET_ERROR(&istream) - << std::endl; - }*/ - std::cout << "imd_fault" << inputs.imd_fault << std::endl; - std::cout << "bms_fault" << inputs.bms_fault << std::endl; - std::this_thread::sleep_for(std::chrono::milliseconds(1000)); } std::cout << "This shouldn't print in the reader" << std::endl; close(sockfd); diff --git a/projects/lvcontroller/src/platforms/sil/proto/lvcontroller.proto b/projects/lvcontroller/src/platforms/sil/proto/lvcontroller.proto index 6b9cbed49..9b92b8a4d 100644 --- a/projects/lvcontroller/src/platforms/sil/proto/lvcontroller.proto +++ b/projects/lvcontroller/src/platforms/sil/proto/lvcontroller.proto @@ -1,4 +1,5 @@ syntax = "proto3"; +package lvcontroller; option go_package = "./gotobuf"; message Output { From a1582ee8541e7115fa03e2ff998c3a7bb304efc6 Mon Sep 17 00:00:00 2001 From: Noah Jaye Date: Sat, 6 Dec 2025 22:32:20 -0500 Subject: [PATCH 3/8] Send data with COBS --- .../src/platforms/sil/bindings.cc | 63 ++++++------------- 1 file changed, 18 insertions(+), 45 deletions(-) diff --git a/projects/lvcontroller/src/platforms/sil/bindings.cc b/projects/lvcontroller/src/platforms/sil/bindings.cc index 4203b1565..a10810018 100644 --- a/projects/lvcontroller/src/platforms/sil/bindings.cc +++ b/projects/lvcontroller/src/platforms/sil/bindings.cc @@ -70,37 +70,10 @@ CanBase veh_can_base{"vcan0"}; } // namespace mcal int port = 11001; -static bool write_callback(pb_ostream_t* stream, const uint8_t* buf, - size_t count) { - int fd = (intptr_t)stream->state; - bool result = send(fd, buf, count, 0) == count; - return result; -} - -static bool read_callback(pb_istream_t* stream, uint8_t* buf, size_t count) { - int fd = (intptr_t)stream->state; - int result; - if (count == 0) return true; - - result = recv(fd, buf, count, 0); - std::cout << "Buffer: " << buf << std::endl; - std::cout << "Result: " << result << std::endl; - if (result == 0) stream->bytes_left = 0; /* EOF */ - std::cout << "Bytes left: " << stream->bytes_left << std::endl; - return result == count; -} - -void writerThread(int sockfd) { +void writerThread(int fd) { while (true) { - pb_ostream_t ostream = { - .callback = &write_callback, - .state = (void*)(intptr_t)sockfd, - .max_size = SIZE_MAX, - .bytes_written = 0, - }; // transmit that the message has started - int msg_start[1] = {1}; // TODO rm this static bool flipper = true; @@ -109,33 +82,34 @@ void writerThread(int sockfd) { mcal::imu_gps_en.Set(flipper); flipper = !flipper; // TODO until this - - send(sockfd, &msg_start, sizeof(msg_start), 0); + uint8_t cobsBuffer[2048] = {0}; + pb_ostream_t ostream = + pb_ostream_from_buffer(cobsBuffer, sizeof(cobsBuffer)); if (pb_encode(&ostream, &lvcontroller_Output_msg, &outputs) == 0) { std::cout << "Error with the writer encoding: " << PB_GET_ERROR(&ostream) << std::strerror(errno) << std::endl; } - // transmit that the message has ended - int msg_end[1] = {2}; - send(sockfd, &msg_end, sizeof(msg_end), 0); + uint8_t encodedBuffer[2048] = {0}; + int msg_size = macfe::cobs::Encode(cobsBuffer, ostream.bytes_written, + encodedBuffer); + std::cout << "ENCB: " << std::endl; + for (int i = 0; i < 100; i++) { + std::cout << " " << (int)encodedBuffer[i]; + } + std::cout << std::endl; + send(fd, encodedBuffer, msg_size, 0); std::this_thread::sleep_for(std::chrono::milliseconds(3000)); } - close(sockfd); + close(fd); } -void readerThread(int sockfd) { +void readerThread(int fd) { uint8_t cobsBuffer[2048] = {0}; // Input_size is a useful thing to know about macfe::cobs::Decoder decoder(cobsBuffer); while (true) { - std::cout << "Reading" << std::endl; - /*pb_istream_t istream = { - .callback = &read_callback, - .state = (void*)(intptr_t)sockfd, - .bytes_left = SIZE_MAX, - };*/ uint8_t byte; - ssize_t result = recv(sockfd, &byte, 1, 0); + ssize_t result = recv(fd, &byte, 1, 0); if (decoder.Decode(&byte, result)) { lvcontroller_Input inputs_temp; pb_istream_t istream = @@ -150,8 +124,7 @@ void readerThread(int sockfd) { std::cout << "bms_fault" << inputs.bms_fault << std::endl; } } - std::cout << "This shouldn't print in the reader" << std::endl; - close(sockfd); + close(fd); } void connectServer() { int sockfd = 0; @@ -173,7 +146,7 @@ void connectServer() { std::this_thread::sleep_for(std::chrono::milliseconds(250)); } } - // wt = std::thread(writerThread, sockfd); + wt = std::thread(writerThread, sockfd); rt = std::thread(readerThread, sockfd); } namespace bindings { From c913f62599f80f338e4e612027f83de094880d6d Mon Sep 17 00:00:00 2001 From: Blake Freer Date: Mon, 8 Dec 2025 20:37:28 -0500 Subject: [PATCH 4/8] Fix flags in platformio --- projects/lvcontroller/platformio.ini | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/projects/lvcontroller/platformio.ini b/projects/lvcontroller/platformio.ini index 24fd7834d..078687375 100644 --- a/projects/lvcontroller/platformio.ini +++ b/projects/lvcontroller/platformio.ini @@ -5,11 +5,6 @@ description = "Low Voltage Controller" [env] build_type = debug debug_build_flags = -g - -[common] -lib_deps = - Embedded Template Library@^20 - cangen=file://../../scripts/cangen ; Static Code Analysis ; Initial Check found NO high severity defects check_tool = clangtidy @@ -19,6 +14,11 @@ check_src_filters = + - + + +[common] +lib_deps = + Embedded Template Library@^20 + cangen=file://../../scripts/cangen build_src_filter = +<**/*.*> ; Exclude top-level platforms/ and mcal/ - each `env` will re-add what it needs @@ -69,7 +69,7 @@ extra_scripts = platform = native lib_deps = ${common.lib_deps} - Nanopb + nanopb/Nanopb build_src_filter = ${common.build_src_filter} + @@ -78,5 +78,5 @@ build_src_filter = build_flags = ${common.flags} - -Wno-error=unused-private-field ; timestamp issue + custom_nanopb_protos = + From 8e670f96426f5ff5879e6b2c56f6af08fb3b4510 Mon Sep 17 00:00:00 2001 From: Blake Freer Date: Mon, 8 Dec 2025 22:02:41 -0500 Subject: [PATCH 5/8] Fix Nanopb bug with PlatformIO See the comment in `platformio.ini` The bug is described in https://github.com/nanopb/nanopb/issues/818 --- projects/lvcontroller/platformio.ini | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/projects/lvcontroller/platformio.ini b/projects/lvcontroller/platformio.ini index 078687375..ac65c4be3 100644 --- a/projects/lvcontroller/platformio.ini +++ b/projects/lvcontroller/platformio.ini @@ -1,6 +1,7 @@ [platformio] name = "LV Controller" description = "Low Voltage Controller" +include_dir = include [env] build_type = debug @@ -17,7 +18,7 @@ check_src_filters = [common] lib_deps = - Embedded Template Library@^20 + etlcpp/Embedded Template Library@^20.44.1 cangen=file://../../scripts/cangen build_src_filter = +<**/*.*> @@ -70,6 +71,12 @@ platform = native lib_deps = ${common.lib_deps} nanopb/Nanopb + ; https://github.com/nanopb/nanopb/issues/818 + ; Nanopb has a weird PlatformIO bug where a separate lib_dep + ; (ETL, in our case) causes Nanopb to forget a `-I` compile + ; flag. The build fails since cannot be found. + ; If this happens, try bumping the ETL (an other library) + ; versions to their latest. build_src_filter = ${common.build_src_filter} + From dc58f51c3f1d205908c49f03b151a8ba32bd723f Mon Sep 17 00:00:00 2001 From: Noah Jaye Date: Thu, 11 Dec 2025 21:37:05 -0500 Subject: [PATCH 6/8] Add pwm to protobuf --- lib/mcal/sil/analog_input.hpp | 5 -- lib/mcal/sil/analog_output.hpp | 5 -- lib/mcal/sil/gpio.hpp | 5 -- lib/mcal/sil/pwm.hpp | 36 +++++++++++++ projects/lvcontroller/src/fans/fans.cc | 6 +-- projects/lvcontroller/src/main.cc | 5 +- .../src/platforms/sil/bindings.cc | 52 ++++--------------- .../platforms/sil/proto/lvcontroller.proto | 10 +++- 8 files changed, 62 insertions(+), 62 deletions(-) create mode 100644 lib/mcal/sil/pwm.hpp diff --git a/lib/mcal/sil/analog_input.hpp b/lib/mcal/sil/analog_input.hpp index 8e80ef909..f37b37881 100644 --- a/lib/mcal/sil/analog_input.hpp +++ b/lib/mcal/sil/analog_input.hpp @@ -1,10 +1,5 @@ #pragma once -#include -#include -#include - -#include "lvcontroller.pb.h" #include "periph/analog_input.hpp" namespace mcal::sil { diff --git a/lib/mcal/sil/analog_output.hpp b/lib/mcal/sil/analog_output.hpp index eea771d01..cc7192ad7 100644 --- a/lib/mcal/sil/analog_output.hpp +++ b/lib/mcal/sil/analog_output.hpp @@ -1,10 +1,5 @@ #pragma once -#include -#include -#include - -#include "lvcontroller.pb.h" #include "periph/analog_output.hpp" namespace mcal::sil { diff --git a/lib/mcal/sil/gpio.hpp b/lib/mcal/sil/gpio.hpp index bff5a2a49..94bdb8fb8 100644 --- a/lib/mcal/sil/gpio.hpp +++ b/lib/mcal/sil/gpio.hpp @@ -1,10 +1,5 @@ #pragma once -#include -#include -#include - -#include "lvcontroller.pb.h" #include "periph/gpio.hpp" namespace mcal::sil { diff --git a/lib/mcal/sil/pwm.hpp b/lib/mcal/sil/pwm.hpp new file mode 100644 index 000000000..69a2218fd --- /dev/null +++ b/lib/mcal/sil/pwm.hpp @@ -0,0 +1,36 @@ +#pragma once + +#include + +#include "lvcontroller.pb.h" +#include "periph/pwm.hpp" +namespace mcal::sil { + +class PWMOutput : public macfe::periph::PWMOutput { +private: + lvcontroller_PWM* output_struct_; + +public: + PWMOutput(lvcontroller_PWM* output_struct) + : output_struct_(output_struct) {} + void Start() { + std::cout << "Starting PWM" << std::endl; + } + void Stop() { + std::cout << "Stopping PWM" << std::endl; + } + void SetDutyCycle(float duty_cycle) { + output_struct_->duty_cycle = + std::max(0, std::min(100, duty_cycle)); + } + float GetDutyCycle() { + return output_struct_->duty_cycle; + } + void SetFrequency(float frequency) { + output_struct_->frequency_hz = std::min(0, frequency); + } + float GetFrequency() { + return output_struct_->frequency_hz; + } +}; +} // namespace mcal::sil \ No newline at end of file diff --git a/projects/lvcontroller/src/fans/fans.cc b/projects/lvcontroller/src/fans/fans.cc index 4b62d4d1a..5e9af7ea7 100644 --- a/projects/lvcontroller/src/fans/fans.cc +++ b/projects/lvcontroller/src/fans/fans.cc @@ -21,11 +21,11 @@ bool IsAtSetpoint(void) { } void Init(void) { - // bindings::powertrain_fan_pwm.Start(); + bindings::powertrain_fan_pwm.Start(); power_setpoint = 0; current_power = 0; - // bindings::powertrain_fan_pwm.SetDutyCycle(power_setpoint); + bindings::powertrain_fan_pwm.SetDutyCycle(power_setpoint); } static void UpdateEnabled(void) { @@ -50,7 +50,7 @@ static void UpdateStep(void) { current_power += step; // TODO: should the duty be inverted? - // bindings::powertrain_fan_pwm.SetDutyCycle(current_power); + bindings::powertrain_fan_pwm.SetDutyCycle(current_power); } void Update_100Hz(void) { diff --git a/projects/lvcontroller/src/main.cc b/projects/lvcontroller/src/main.cc index 2559692b7..9951dd7f0 100644 --- a/projects/lvcontroller/src/main.cc +++ b/projects/lvcontroller/src/main.cc @@ -1,7 +1,7 @@ /// @author Blake Freer /// @date 2023-12-25 + #include -#include #include #include "bindings.hpp" @@ -246,13 +246,16 @@ void task_100hz(void) { int main(void) { bindings::Initialize(); + accumulator::Init(); fans::Init(); fsm::Init(); motor_controller::Init(); + scheduler::register_task(task_100hz, 10); scheduler::register_task(task_10hz, 100); scheduler::register_task(task_1hz, 1000); + scheduler::run(); while (true) continue; diff --git a/projects/lvcontroller/src/platforms/sil/bindings.cc b/projects/lvcontroller/src/platforms/sil/bindings.cc index a10810018..c027142a1 100644 --- a/projects/lvcontroller/src/platforms/sil/bindings.cc +++ b/projects/lvcontroller/src/platforms/sil/bindings.cc @@ -3,14 +3,8 @@ #include "bindings.hpp" -#include #include -#include -#include -#include #include -#include -#include #include #include @@ -21,15 +15,13 @@ #include "mcal/sil/analog_output.hpp" #include "mcal/sil/can.hpp" #include "mcal/sil/gpio.hpp" +#include "mcal/sil/pwm.hpp" #include "pb_decode.h" #include "pb_encode.h" -#include "periph/gpio.hpp" lvcontroller_Output outputs = lvcontroller_Output_init_zero; - lvcontroller_Input inputs = lvcontroller_Input_init_zero; std::thread wt; std::thread rt; -std::thread ct; namespace mcal { using namespace mcal::sil; @@ -45,6 +37,7 @@ DigitalOutput powertrain_pump1_en{&outputs.powertrain_pump1_en}; DigitalOutput powertrain_pump2_en{&outputs.powertrain_pump2_en}; DigitalOutput powertrain_fan1_en{&outputs.powertrain_fan1_en}; DigitalOutput powertrain_fan2_en{&outputs.powertrain_fan2_en}; +PWMOutput powertrain_fan_pwm{&outputs.powertrain_fan_pwm}; // Motor Controller (i.e. Inverters) DigitalOutput motor_controller_en{&outputs.motor_controller_en}; @@ -73,39 +66,23 @@ int port = 11001; void writerThread(int fd) { while (true) { - // transmit that the message has started - - // TODO rm this - static bool flipper = true; - mcal::tssi_green_signal.Set(flipper); - mcal::front_controller_en.Set(!flipper); - mcal::imu_gps_en.Set(flipper); - flipper = !flipper; - // TODO until this uint8_t cobsBuffer[2048] = {0}; pb_ostream_t ostream = pb_ostream_from_buffer(cobsBuffer, sizeof(cobsBuffer)); if (pb_encode(&ostream, &lvcontroller_Output_msg, &outputs) == 0) { - std::cout << "Error with the writer encoding: " + std::cout << "Error with the outputs encoding: " << PB_GET_ERROR(&ostream) << std::strerror(errno) << std::endl; } uint8_t encodedBuffer[2048] = {0}; int msg_size = macfe::cobs::Encode(cobsBuffer, ostream.bytes_written, encodedBuffer); - std::cout << "ENCB: " << std::endl; - for (int i = 0; i < 100; i++) { - std::cout << " " << (int)encodedBuffer[i]; - } - std::cout << std::endl; send(fd, encodedBuffer, msg_size, 0); - std::this_thread::sleep_for(std::chrono::milliseconds(3000)); } close(fd); } void readerThread(int fd) { uint8_t cobsBuffer[2048] = {0}; - // Input_size is a useful thing to know about macfe::cobs::Decoder decoder(cobsBuffer); while (true) { uint8_t byte; @@ -120,8 +97,6 @@ void readerThread(int fd) { std::cerr << "Failed to decode inputs" << std::endl; } decoder = macfe::cobs::Decoder(cobsBuffer); - std::cout << "imd_fault" << inputs.imd_fault << std::endl; - std::cout << "bms_fault" << inputs.bms_fault << std::endl; } } close(fd); @@ -139,7 +114,6 @@ void connectServer() { 0) { has_connected = true; } else { - std::cerr << "Error to follow" << std::endl; std::cerr << "Error with the connection: " << std::strerror(errno) << std::endl; close(sockfd); @@ -164,6 +138,7 @@ DigitalOutput& powertrain_pump1_en = mcal::powertrain_pump1_en; DigitalOutput& powertrain_pump2_en = mcal::powertrain_pump2_en; DigitalOutput& powertrain_fan1_en = mcal::powertrain_fan1_en; DigitalOutput& powertrain_fan2_en = mcal::powertrain_fan2_en; +PWMOutput& powertrain_fan_pwm = mcal::powertrain_fan_pwm; // Motor Controller (Inverters) DigitalOutput& motor_controller_en = mcal::motor_controller_en; @@ -192,28 +167,23 @@ void Initialize() { connectServer(); } -// copied luai int GetTick() { using namespace std::chrono; - long now = + static long start = duration_cast(system_clock::now().time_since_epoch()) - .count(); - static long start = now; // only set on first call - - return now - start; + .count(); // only set on first call + return duration_cast(system_clock::now().time_since_epoch()) + .count() - + start; } - +// TODO Send PWM over threads, finish conversion void DelayMS(int ms) { std::this_thread::sleep_for(std::chrono::milliseconds(ms)); } -// copied luai void SoftwareReset() { std::cout << "Performing software reset. Will not proceed." << std::endl; while (true) continue; } -// ask for most recent struct from outer program -// https://pubs.opengroup.org/onlinepubs/009695199/basedefs/sys/select.h.html - -} // namespace bindings +} // namespace bindings \ No newline at end of file diff --git a/projects/lvcontroller/src/platforms/sil/proto/lvcontroller.proto b/projects/lvcontroller/src/platforms/sil/proto/lvcontroller.proto index 9b92b8a4d..1649890a7 100644 --- a/projects/lvcontroller/src/platforms/sil/proto/lvcontroller.proto +++ b/projects/lvcontroller/src/platforms/sil/proto/lvcontroller.proto @@ -2,6 +2,11 @@ syntax = "proto3"; package lvcontroller; option go_package = "./gotobuf"; +message PWM { + float frequency_hz = 1; + float duty_cycle = 2; +} + message Output { // Tractive system status indicator bool tssi_en = 1; @@ -13,7 +18,8 @@ message Output { bool powertrain_pump2_en = 5; bool powertrain_fan1_en = 6; bool powertrain_fan2_en = 7; - float powertrain_fan_pwm = 8; + + PWM powertrain_fan_pwm = 8; // Motor Controller bool motor_controller_en = 9; @@ -43,4 +49,4 @@ message Input { float dcdc_sense = 3; float suspension_travel3 = 4; float suspension_travel4 = 5; -} \ No newline at end of file +} From 3f382302e0ad24f70418508b30fe142e5faf6f1b Mon Sep 17 00:00:00 2001 From: Noah Jaye Date: Mon, 9 Mar 2026 09:51:30 -0400 Subject: [PATCH 7/8] stashsh --- projects/lvcontroller/platformio.ini | 1 + 1 file changed, 1 insertion(+) diff --git a/projects/lvcontroller/platformio.ini b/projects/lvcontroller/platformio.ini index ac65c4be3..f5c4fca23 100644 --- a/projects/lvcontroller/platformio.ini +++ b/projects/lvcontroller/platformio.ini @@ -30,6 +30,7 @@ flags = -Werror -Wall -Wno-unused-function ; having problems with unused MPU_Config() + -Wno-unused-private-field ; timestamp_ issue in cangen extra_scripts = pre:../../scripts/build/generate_git_hash.py From 292dd61fbf065481a45d199a98fb14ff81cb65ac Mon Sep 17 00:00:00 2001 From: Noah Jaye Date: Sun, 10 May 2026 15:57:46 -0400 Subject: [PATCH 8/8] Don't check stm32 code --- .github/workflows/pr-format-check.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/pr-format-check.yml b/.github/workflows/pr-format-check.yml index a9c458265..c04259126 100644 --- a/.github/workflows/pr-format-check.yml +++ b/.github/workflows/pr-format-check.yml @@ -14,4 +14,5 @@ jobs: uses: jidicula/clang-format-action@v4.15.0 with: check-path: '.' - clang-format-version: '20' \ No newline at end of file + clang-format-version: '20' + exclude-regex: '.*/platforms/stm32/Core/.*' \ No newline at end of file