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 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..f37b37881 --- /dev/null +++ b/lib/mcal/sil/analog_input.hpp @@ -0,0 +1,17 @@ +#pragma once + +#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..cc7192ad7 --- /dev/null +++ b/lib/mcal/sil/analog_output.hpp @@ -0,0 +1,17 @@ +#pragma once + +#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..94bdb8fb8 100644 --- a/lib/mcal/sil/gpio.hpp +++ b/lib/mcal/sil/gpio.hpp @@ -1,66 +1,35 @@ -/// @author Samuel Parent -/// @date 2023-12-10 - #pragma once -#include -#include -#include - #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 index 10f9fc1bc..69a2218fd 100644 --- a/lib/mcal/sil/pwm.hpp +++ b/lib/mcal/sil/pwm.hpp @@ -1,45 +1,36 @@ -/// @author Samuel Parent -/// @date 2023-05-21 - #pragma once -#include #include -#include +#include "lvcontroller.pb.h" #include "periph/pwm.hpp" - -namespace mcal::raspi { +namespace mcal::sil { class PWMOutput : public macfe::periph::PWMOutput { -public: - PWMOutput(std::string name) : name_(name) {} +private: + lvcontroller_PWM* output_struct_; - void Start() override { - std::cout << std::format("Starting PWM {}", name_) << std::endl; +public: + PWMOutput(lvcontroller_PWM* output_struct) + : output_struct_(output_struct) {} + void Start() { + std::cout << "Starting PWM" << std::endl; } - - void Stop() override { - std::cout << std::format("Stopping PWM {}", name_) << std::endl; + void Stop() { + std::cout << "Stopping PWM" << 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; + void SetDutyCycle(float duty_cycle) { + output_struct_->duty_cycle = + std::max(0, std::min(100, duty_cycle)); } - float GetDutyCycle() override { - std::cout << std::format("PWM {} has duty cycle {:.3f} Hz", name_, - duty_cycle_) - << std::endl; - return 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; } - -private: - std::string name_; - float duty_cycle_; }; - -} // namespace mcal::raspi +} // namespace mcal::sil \ No newline at end of file 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/platformio.ini b/projects/lvcontroller/platformio.ini index 078c43e40..f5c4fca23 100644 --- a/projects/lvcontroller/platformio.ini +++ b/projects/lvcontroller/platformio.ini @@ -1,13 +1,11 @@ [platformio] name = "LV Controller" description = "Low Voltage Controller" +include_dir = include [env] build_type = debug debug_build_flags = -g -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 +17,9 @@ check_src_filters = + [common] +lib_deps = + etlcpp/Embedded Template Library@^20.44.1 + cangen=file://../../scripts/cangen build_src_filter = +<**/*.*> ; Exclude top-level platforms/ and mcal/ - each `env` will re-add what it needs @@ -29,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 @@ -39,6 +41,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 +57,7 @@ extra_scripts = [env:cli] platform = native +lib_deps = ${common.lib_deps} build_src_filter = ${common.build_src_filter} + @@ -61,4 +65,26 @@ 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/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} + + + + + - + +build_flags = + ${common.flags} + +custom_nanopb_protos = + diff --git a/projects/lvcontroller/src/platforms/sil/bindings.cc b/projects/lvcontroller/src/platforms/sil/bindings.cc new file mode 100644 index 000000000..c027142a1 --- /dev/null +++ b/projects/lvcontroller/src/platforms/sil/bindings.cc @@ -0,0 +1,189 @@ +/// @author Noah Jaye +/// @date 2025-10-31 + +#include "bindings.hpp" + +#include +#include + +#include +#include + +#include "cobs.hpp" +#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 "mcal/sil/pwm.hpp" +#include "pb_decode.h" +#include "pb_encode.h" +lvcontroller_Output outputs = lvcontroller_Output_init_zero; +lvcontroller_Input inputs = lvcontroller_Input_init_zero; +std::thread wt; +std::thread rt; + +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}; +PWMOutput powertrain_fan_pwm{&outputs.powertrain_fan_pwm}; + +// 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; + +void writerThread(int fd) { + while (true) { + 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 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); + send(fd, encodedBuffer, msg_size, 0); + } + close(fd); +} +void readerThread(int fd) { + uint8_t cobsBuffer[2048] = {0}; + macfe::cobs::Decoder decoder(cobsBuffer); + while (true) { + uint8_t byte; + ssize_t result = recv(fd, &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); + } + } + close(fd); +} +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 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; +PWMOutput& powertrain_fan_pwm = mcal::powertrain_fan_pwm; + +// 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(); +} + +int GetTick() { + using namespace std::chrono; + static long start = + duration_cast(system_clock::now().time_since_epoch()) + .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)); +} + +void SoftwareReset() { + std::cout << "Performing software reset. Will not proceed." << std::endl; + while (true) continue; +} + +} // 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 new file mode 100644 index 000000000..1649890a7 --- /dev/null +++ b/projects/lvcontroller/src/platforms/sil/proto/lvcontroller.proto @@ -0,0 +1,52 @@ +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; + 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; + + PWM 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; +}