From cb35439707bb79e93453624434d7a742d2ff2df4 Mon Sep 17 00:00:00 2001 From: Ben Hall Date: Sat, 9 Nov 2024 23:29:51 -0500 Subject: [PATCH] added in stats system and eeprom interface --- lib/interfaces/include/EEPROMInterface.h | 52 ++++++++++++++++++++ lib/interfaces/src/EEPROMInterface.cpp | 59 +++++++++++++++++++++++ lib/shared_data/include/SharedDataTypes.h | 17 +++++++ lib/systems/include/StatsSystem.h | 22 +++++++++ lib/systems/src/StatsSystem.cpp | 24 +++++++++ platformio.ini | 1 + src/main.cpp | 11 ++++- 7 files changed, 185 insertions(+), 1 deletion(-) create mode 100644 lib/interfaces/include/EEPROMInterface.h create mode 100644 lib/interfaces/src/EEPROMInterface.cpp create mode 100644 lib/systems/include/StatsSystem.h create mode 100644 lib/systems/src/StatsSystem.cpp diff --git a/lib/interfaces/include/EEPROMInterface.h b/lib/interfaces/include/EEPROMInterface.h new file mode 100644 index 00000000..8e17f1e3 --- /dev/null +++ b/lib/interfaces/include/EEPROMInterface.h @@ -0,0 +1,52 @@ +#ifndef __EEPROMINTERFACE_H__ +#define __EEPROMINTERFACE_H__ +#include +#include +#include + +// what this is: +// this interface will encompass any and all interfacing / writing of the eeprom on a micro platform (for now: teensy) + +// first goal of this interface: be able to keep a log of our mileage with intermittent updates of the current km driven. + +// we will be writing a struct to the memory that will contain the mileage data / any of the other +// data we will write and be able to read / recall from the eeprom + + +// this class will also manage the time in which we update the EEPROM values so that we can safely call the update function +// repeatedly without concern for the life of the underlying EEPROM. +class EEPROMInterface +{ + public: + struct params + { + unsigned int write_interval_ms; + }; + + EEPROMInterface(params p = {120000000}) : + _params(p) { + _last_write_time_millis = 0; + _last_written_distance_m = 0; + _eeprom_written_data = {}; + } + + /// @brief initialize the EEPROMInterface by reading the last written data from the EEPROM. + // reads first the size of the low level data in bytes (a uint16_t) and then + // proceeds to read that amount of data. + + /// @brief + /// @param reset_eeprom use this flag to write + void init(bool reset_eeprom); + + void update_eeprom(const SharedCarState_s & car_state); + EEPROMInterfaceData_s get_current_data(); + + private: + unsigned long _last_write_time_millis; + int _last_written_distance_m; + params _params; + std::byte _data_buffer[4284]; // 4284 bytes is the size of the EEPROM on the teensy41 + + EEPROMInterfaceData_s _eeprom_written_data; +}; +#endif // __EEPROMINTERFACE_H__ \ No newline at end of file diff --git a/lib/interfaces/src/EEPROMInterface.cpp b/lib/interfaces/src/EEPROMInterface.cpp new file mode 100644 index 00000000..7bc38283 --- /dev/null +++ b/lib/interfaces/src/EEPROMInterface.cpp @@ -0,0 +1,59 @@ +#include +#include +#include +#include +#include + +void EEPROMInterface::init(bool reset_eeprom) +{ + // we know that the first 2 bytes tell us the size of the previously written data + std::byte size_data[2]; + + // if the reset eeprom flag is set, the eeprom previously written data will stay initialized to all zeros + // so all previous data will be lost if there was any written as the new sums will not include this previous data. + if(!reset_eeprom) + { + uint16_t written_size; + + size_data[0] = static_cast(EEPROM.read(0)); + size_data[1] = static_cast(EEPROM.read(1)); + memcpy(&written_size, size_data, 2); + + // proceed to read out all of the existing data + + for(int i = 2; i < written_size; i++) + { + _data_buffer[i] = static_cast(EEPROM.read(i)); + } + + memcpy(&_eeprom_written_data, _data_buffer, written_size); + } + // go ahead and updating the written size to the current struct size as we are now finished using the data + uint16_t new_write_size = sizeof(LowLevelStatData_s); + memcpy(size_data, &new_write_size, 2); + EEPROM.write(0, static_cast(size_data[0])); + EEPROM.write(1, static_cast(size_data[1])); +} + +void EEPROMInterface::update_eeprom(const SharedCarState_s &car_state) +{ + + if(car_state.systick.millis - _last_write_time_millis > _params.write_interval_ms) + { + // distanc_m current_session_distance = car_state.low_level_stats.session_distance; + + // get the difference between the last written distance to the previous driven meters; + + auto diff = static_cast(abs(std::round(car_state.low_level_stats.session_distance)) - _last_written_distance_m); + _eeprom_written_data.current_driven_m += diff; + memcpy(_data_buffer, &_eeprom_written_data, sizeof(EEPROMInterfaceData_s)); + size_t byte_size_to_write = sizeof(EEPROMInterfaceData_s); + for(size_t i = 0; i < byte_size_to_write; i++) + { + EEPROM.write(i+2, static_cast(_data_buffer[i])); + } + + _last_written_distance_m = car_state.low_level_stats.session_distance; + _last_write_time_millis = car_state.systick.millis; + } +} \ No newline at end of file diff --git a/lib/shared_data/include/SharedDataTypes.h b/lib/shared_data/include/SharedDataTypes.h index 1c389f03..fe25c008 100644 --- a/lib/shared_data/include/SharedDataTypes.h +++ b/lib/shared_data/include/SharedDataTypes.h @@ -8,6 +8,7 @@ using speed_rpm = float; using torque_nm = float; +using distance_m = float; /// @brief Defines modes of torque limit to be processed in torque limit map for exact values. enum class TorqueLimit_e @@ -140,6 +141,21 @@ struct SteeringSystemData_s SteeringSystemStatus_e status; }; +/// @brief the struct that will be serialized and written into the memory of the eeprom +struct __attribute__((packed)) EEPROMInterfaceData_s +{ + uint32_t current_driven_m; +}; + +/// @brief low level stats. will contain things like current session +// driven meters, total faults occured during a session, etc. that will get written directly into the EEPROM +struct LowLevelStatData_s +{ + // this is needed since if we change this struct we need to ensure that we read garbage data from the EEPROM on init + uint16_t low_level_data_size_in_bytes; + distance_m session_distance; +}; + /// @brief car state struct that contains state of everything about the car including // things such as steering, drivetrain, current system time, vectornav / INS data, // etc. an instance of this struct is created in main and updated there by all of the systems @@ -158,6 +174,7 @@ struct SharedCarState_s DrivebrainData_s db_data; TorqueControllerMuxStatus tc_mux_status; bool drivebrain_timing_failure = false; + LowLevelStatData_s low_level_stats = {}; SharedCarState_s() = delete; SharedCarState_s(const SysTick_s &_systick, const SteeringSystemData_s &_steering_data, diff --git a/lib/systems/include/StatsSystem.h b/lib/systems/include/StatsSystem.h new file mode 100644 index 00000000..72f9273c --- /dev/null +++ b/lib/systems/include/StatsSystem.h @@ -0,0 +1,22 @@ +#ifndef __STATSSYSTEM_H__ +#define __STATSSYSTEM_H__ + +#include +#include + +class StatsSystem +{ + public: + StatsSystem() { + _prev_dt_s = 0.0f; + _last_stat_update_timestamp = 0; + _current_data = {}; + } + LowLevelStatData_s get_latest_vehicle_stats(const SharedCarState_s& veh_state); + private: + float _prev_dt_s; + unsigned long _last_stat_update_timestamp; + LowLevelStatData_s _current_data; + +}; +#endif // __STATSSYSTEM_H__ \ No newline at end of file diff --git a/lib/systems/src/StatsSystem.cpp b/lib/systems/src/StatsSystem.cpp new file mode 100644 index 00000000..1c3c4cf1 --- /dev/null +++ b/lib/systems/src/StatsSystem.cpp @@ -0,0 +1,24 @@ +#include + +LowLevelStatData_s StatsSystem::get_latest_vehicle_stats(const SharedCarState_s &veh_state) +{ + if (_last_stat_update_timestamp == 0) + { + _prev_dt_s = 0.0f; + _last_stat_update_timestamp = veh_state.systick.millis; + } + else + { + _prev_dt_s = (veh_state.systick.millis - _last_stat_update_timestamp) / 1000.0f; + } + + float avg_rpm = 0; + for (int i = 0; i < NUM_MOTORS; i++) + { + avg_rpm += veh_state.drivetrain_data.measuredSpeeds[i]; + } + + avg_rpm = avg_rpm / static_cast(NUM_MOTORS); + _current_data.session_distance += _prev_dt_s * (avg_rpm * RPM_TO_METERS_PER_SECOND); + return _current_data; +} \ No newline at end of file diff --git a/platformio.ini b/platformio.ini index 5ef95794..a0acfa84 100644 --- a/platformio.ini +++ b/platformio.ini @@ -58,6 +58,7 @@ monitor_speed = 115200 upload_protocol = teensy-cli extra_scripts = pre:extra_script.py lib_deps = + https://github.com/PaulStoffregen/EEPROM.git ${common.lib_deps_shared} Nanopb SPI diff --git a/src/main.cpp b/src/main.cpp index 9cbe128f..9ef75b47 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -29,6 +29,7 @@ #include "SABInterface.h" #include "VectornavInterface.h" #include "LoadCellInterface.h" +#include "EEPROMInterface.h" /* Systems */ #include "SysClock.h" @@ -40,6 +41,7 @@ #include "TorqueControllerMux.h" #include "TorqueControllers.h" #include "CASESystem.h" +#include "StatsSystem.h" // /* State machine */ #include "MCUStateMachine.h" @@ -208,6 +210,8 @@ struct inverters InvInt_t rr = InvInt_t(&CAN2_txBuffer, ID_MC4_SETPOINTS_COMMAND); } inv; +EEPROMInterface eeprom_interface; + // /* // SYSTEMS // */ @@ -321,6 +325,8 @@ TCMuxType torque_controller_mux({static_cast(&tc_simple), static_cast(&db_controller)}, {false, false, true, false, true}); +StatsSystem stats_system; + /* Declare state machine */ MCUStateMachine fsm(&buzzer, &drivetrain, &dashboard, &pedals_system, &torque_controller_mux, &safety_system); @@ -444,6 +450,10 @@ void loop() car_state_inst.drivebrain_timing_failure = db_controller.get_timing_failure_status(); hytech_msgs_MCUOutputData out_eth_msg = db_eth_interface.make_db_msg(car_state_inst); + car_state_inst.low_level_stats = stats_system.get_latest_vehicle_stats(car_state_inst); + + eeprom_interface.update_eeprom(car_state_inst); + handle_ethernet_interface_comms(curr_tick, out_eth_msg); tick_all_systems(curr_tick); @@ -545,7 +555,6 @@ void init_all_CAN_devices() void tick_all_interfaces(const SysTick_s ¤t_system_tick) { - TriggerBits_s t = current_system_tick.triggers; if (t.trigger10) // 10Hz {