From d0dc8e0b27e0398268fc9d72e61f875ed3f204e7 Mon Sep 17 00:00:00 2001 From: Arianna R Date: Sun, 2 Nov 2025 16:30:39 -0500 Subject: [PATCH 01/12] added rotary enc manual charging state & integrated --- .../include/RotaryEncoderInterface.h | 37 ++++++++++++++ lib/interfaces/src/RotaryEncoderInterface.cpp | 50 +++++++++++++++++++ lib/systems/src/MainChargeSystem.cpp | 9 +++- lib/utilities/CCUData.h | 2 + 4 files changed, 97 insertions(+), 1 deletion(-) create mode 100644 lib/interfaces/include/RotaryEncoderInterface.h create mode 100644 lib/interfaces/src/RotaryEncoderInterface.cpp diff --git a/lib/interfaces/include/RotaryEncoderInterface.h b/lib/interfaces/include/RotaryEncoderInterface.h new file mode 100644 index 0000000..9a15dc2 --- /dev/null +++ b/lib/interfaces/include/RotaryEncoderInterface.h @@ -0,0 +1,37 @@ +#ifndef ROTARYENCODERINTERFACE_H +#define ROTARYENCODERINTERFACE_H + +#include //LOOK INTO INCLUDE MORE +#include "CCUData.h" + +#include "etl/singleton.h" +#include + +#define CLK 2 //change based on actual pin used +#define DT 3 //change based on actual pin used +#define SW 4 //change based on actual pin used + +struct rotary_encoder_s { + volatile bool state = false; + volatile int encoder_value = 0; + unsigned long last_button_press = 0; + constexpr int max_value = 120; + constexpr int min_value = 0; +}; + +class RotaryEncoderInterface +{ +public: + void setupEncoder(); + void updateEncoder(CCUData &_ccu_data); + void isr1(); + + bool isButtonPressed() const { return _encoder_data.state; } +private: + rotary_encoder_s _encoder_data; + CCU_Data &_ccu_data; +} + +using RotaryEncoderInterface = etl::singleton; + +#endif \ No newline at end of file diff --git a/lib/interfaces/src/RotaryEncoderInterface.cpp b/lib/interfaces/src/RotaryEncoderInterface.cpp new file mode 100644 index 0000000..52c8778 --- /dev/null +++ b/lib/interfaces/src/RotaryEncoderInterface.cpp @@ -0,0 +1,50 @@ +#include "RotaryEncoderInterface.h" +#include "CCUData.h" + +void RotaryEncoderInterface::setupEncoder() { + _encoder_data.encoder_value = 0; + _encoder_data.state = false; + Serial.begin(9600); + pinMode(CLK, INPUT_PULLUP); + pinMode(DT, INPUT_PULLUP); + pinMode(SW, INPUT_PULLUP); + + attachInterrupt(digitalPinToInterrupt(2), isr1, FALLING); +} + +void RotaryEncoderInterface::updateEncoder(CCUData& _ccu_data) { + static int prev_value = -1; + + int btn_state = digitalRead(SW); + + noInterrupts(); + int current_value = _encoder_data.encoder_value; + _ccu_data.encoder_value = current_value; + interrupts(); + + if (current_value != prev_value) { + Serial.println(current_value); + } + prev_value = current_value; + + if (btn_state == LOW) { + if (millis() - last_button_press > 50) { + _encoder_data.state = true; //or = !_encoder_data.state + Serial.println("Button pressed") + } + _encoder_data.last_button_press = millis(); + } +} + +void RotaryEncoderInterface::isr1() { + int dt_value = digitalRead(DT); + if (dt_value == HIGH) { + if (_encoder_data.encoder_value < _encoder_data.max_value) { + _encoder_data.encoder_value++; + } + } else { + if (_encoder_data.encoder_value > _encoder_data.min_value) { + _encoder_data.encoder_value--; + } + } +} \ No newline at end of file diff --git a/lib/systems/src/MainChargeSystem.cpp b/lib/systems/src/MainChargeSystem.cpp index dab602b..2fafdfe 100644 --- a/lib/systems/src/MainChargeSystem.cpp +++ b/lib/systems/src/MainChargeSystem.cpp @@ -22,6 +22,7 @@ void MainChargeSystem::calculate_charge_current() { * If acu_state = 2, we should/are safe to be charging */ bool acu_shutdown_low = ACUInterfaceInstance::instance().get_latest_data().acu_state == 1; //NOLINT + bool rotary_state = RotaryEncoderInterface::instance().isButtonPressed() bool voltage_reached = (high_voltage >= _ccu_data.cutoff_voltage) || (ACUInterfaceInstance::instance().get_latest_data().total_voltage > _ccu_data.max_pack_voltage); //NOLINT if (shutdown_low || acu_shutdown_low) @@ -30,7 +31,11 @@ void MainChargeSystem::calculate_charge_current() { } else if(voltage_reached) { _ccu_data.charging_state = ChargingState_e::DONE_CHARGING; - } else { + } else if(rotary_state) + { + _ccu_data.charging_state = ChargingState_e::MANUAL_CHARGING; + } + else { _ccu_data.charging_state = ChargingState_e::CHARGING; } @@ -39,6 +44,8 @@ void MainChargeSystem::calculate_charge_current() { if (voltage_reached || shutdown_low || acu_shutdown_low) { //ACU will cause a BMS fault if there is a cell or board temp that is too high _ccu_data.calculated_charge_current = 0; _ccu_data.balancing_enabled = false; + } else if(_ccu_data.charging_state == ChargerState_e::MANUAL_CHARGING) { + _ccu_data.calculated_charge_current = _ccu_data.encoder_value; } else { _ccu_data.calculated_charge_current = _ccu_data.charger_current_max; // 120 = 3.4 amps } diff --git a/lib/utilities/CCUData.h b/lib/utilities/CCUData.h index db904aa..5e4f65c 100644 --- a/lib/utilities/CCUData.h +++ b/lib/utilities/CCUData.h @@ -8,6 +8,7 @@ enum class ChargingState_e NOT_CHARGING = 0, CHARGING =1, DONE_CHARGING =2 + MANUAL_CHARGING =3; }; struct CCUData @@ -19,6 +20,7 @@ struct CCUData static constexpr float charger_current_max = 120; //120 = 3.4 amps static constexpr float safe_charging_current = 15; float calculated_charge_current = 0; + float encoder_value = 0; static constexpr float min_pack_voltage = 403; //need to double check this number static constexpr float max_pack_voltage = 530; static constexpr const int SHDN_E_READ = 4; From 6530fb66dc517a6b38dabc639c528aa3bd4d800b Mon Sep 17 00:00:00 2001 From: Arianna R Date: Sun, 2 Nov 2025 17:37:59 -0500 Subject: [PATCH 02/12] changes --- .../include/RotaryEncoderInterface.h | 21 ++++++---- lib/interfaces/src/RotaryEncoderInterface.cpp | 40 +++++++++++-------- lib/systems/include/MainChargeSystem.h | 2 + lib/systems/src/MainChargeSystem.cpp | 4 +- lib/utilities/CCUData.h | 4 +- 5 files changed, 42 insertions(+), 29 deletions(-) diff --git a/lib/interfaces/include/RotaryEncoderInterface.h b/lib/interfaces/include/RotaryEncoderInterface.h index 9a15dc2..f1c68ea 100644 --- a/lib/interfaces/include/RotaryEncoderInterface.h +++ b/lib/interfaces/include/RotaryEncoderInterface.h @@ -15,23 +15,28 @@ struct rotary_encoder_s { volatile bool state = false; volatile int encoder_value = 0; unsigned long last_button_press = 0; - constexpr int max_value = 120; - constexpr int min_value = 0; + const int max_value = 120; + const int min_value = 0; }; class RotaryEncoderInterface { public: + RotaryEncoderInterface(CCUData &ccu_data) : + _ccu_data(ccu_data) {}; + void setupEncoder(); - void updateEncoder(CCUData &_ccu_data); - void isr1(); + void updateEncoder(); + static void isr1(); + void set_enc_value(int dt_value); + + bool isButtonPressed() const { return _encoder_data.state; }; - bool isButtonPressed() const { return _encoder_data.state; } private: rotary_encoder_s _encoder_data; - CCU_Data &_ccu_data; -} + CCUData &_ccu_data; +}; -using RotaryEncoderInterface = etl::singleton; +using RotaryEncoderInterfaceInstance = etl::singleton; #endif \ No newline at end of file diff --git a/lib/interfaces/src/RotaryEncoderInterface.cpp b/lib/interfaces/src/RotaryEncoderInterface.cpp index 52c8778..471de5a 100644 --- a/lib/interfaces/src/RotaryEncoderInterface.cpp +++ b/lib/interfaces/src/RotaryEncoderInterface.cpp @@ -1,6 +1,25 @@ #include "RotaryEncoderInterface.h" #include "CCUData.h" + + +static void RotaryEncoderInterface::isr1() { + int dt_value = digitalRead(DT); + RotaryEncoderInterfaceInstance::instance().set_enc_value(dt_value); +} + +void RotaryEncoderInterface::set_enc_value(int dt_value) { + if (dt_value == HIGH) { + if (_encoder_data.encoder_value < _encoder_data.max_value) { + _encoder_data.encoder_value++; + } + } else { + if (_encoder_data.encoder_value > _encoder_data.min_value) { + _encoder_data.encoder_value--; + } + } +} + void RotaryEncoderInterface::setupEncoder() { _encoder_data.encoder_value = 0; _encoder_data.state = false; @@ -9,10 +28,10 @@ void RotaryEncoderInterface::setupEncoder() { pinMode(DT, INPUT_PULLUP); pinMode(SW, INPUT_PULLUP); - attachInterrupt(digitalPinToInterrupt(2), isr1, FALLING); + attachInterrupt(digitalPinToInterrupt(2), RotaryEncoderInterface::isr1, FALLING); } -void RotaryEncoderInterface::updateEncoder(CCUData& _ccu_data) { +void RotaryEncoderInterface::updateEncoder() { static int prev_value = -1; int btn_state = digitalRead(SW); @@ -28,23 +47,10 @@ void RotaryEncoderInterface::updateEncoder(CCUData& _ccu_data) { prev_value = current_value; if (btn_state == LOW) { - if (millis() - last_button_press > 50) { + if (millis() - _encoder_data.last_button_press > 50) { _encoder_data.state = true; //or = !_encoder_data.state - Serial.println("Button pressed") + Serial.println("Button pressed"); } _encoder_data.last_button_press = millis(); } -} - -void RotaryEncoderInterface::isr1() { - int dt_value = digitalRead(DT); - if (dt_value == HIGH) { - if (_encoder_data.encoder_value < _encoder_data.max_value) { - _encoder_data.encoder_value++; - } - } else { - if (_encoder_data.encoder_value > _encoder_data.min_value) { - _encoder_data.encoder_value--; - } - } } \ No newline at end of file diff --git a/lib/systems/include/MainChargeSystem.h b/lib/systems/include/MainChargeSystem.h index 89fb32d..886ae78 100644 --- a/lib/systems/include/MainChargeSystem.h +++ b/lib/systems/include/MainChargeSystem.h @@ -5,6 +5,8 @@ #include "ACUInterface.h" +#include "RotaryEncoderInterface.h" + #include "SharedFirmwareTypes.h" #ifdef TEENSY_OPT_SMALLEST_CODE diff --git a/lib/systems/src/MainChargeSystem.cpp b/lib/systems/src/MainChargeSystem.cpp index 2fafdfe..5cf7b5c 100644 --- a/lib/systems/src/MainChargeSystem.cpp +++ b/lib/systems/src/MainChargeSystem.cpp @@ -22,7 +22,7 @@ void MainChargeSystem::calculate_charge_current() { * If acu_state = 2, we should/are safe to be charging */ bool acu_shutdown_low = ACUInterfaceInstance::instance().get_latest_data().acu_state == 1; //NOLINT - bool rotary_state = RotaryEncoderInterface::instance().isButtonPressed() + bool rotary_state = RotaryEncoderInterfaceInstance::instance().isButtonPressed(); bool voltage_reached = (high_voltage >= _ccu_data.cutoff_voltage) || (ACUInterfaceInstance::instance().get_latest_data().total_voltage > _ccu_data.max_pack_voltage); //NOLINT if (shutdown_low || acu_shutdown_low) @@ -44,7 +44,7 @@ void MainChargeSystem::calculate_charge_current() { if (voltage_reached || shutdown_low || acu_shutdown_low) { //ACU will cause a BMS fault if there is a cell or board temp that is too high _ccu_data.calculated_charge_current = 0; _ccu_data.balancing_enabled = false; - } else if(_ccu_data.charging_state == ChargerState_e::MANUAL_CHARGING) { + } else if(_ccu_data.charging_state == ChargingState_e::MANUAL_CHARGING) { _ccu_data.calculated_charge_current = _ccu_data.encoder_value; } else { _ccu_data.calculated_charge_current = _ccu_data.charger_current_max; // 120 = 3.4 amps diff --git a/lib/utilities/CCUData.h b/lib/utilities/CCUData.h index 5e4f65c..8c8c5c0 100644 --- a/lib/utilities/CCUData.h +++ b/lib/utilities/CCUData.h @@ -7,8 +7,8 @@ enum class ChargingState_e { NOT_CHARGING = 0, CHARGING =1, - DONE_CHARGING =2 - MANUAL_CHARGING =3; + DONE_CHARGING =2, + MANUAL_CHARGING =3 }; struct CCUData From b80266fa307c97eb89201a2e8f655a8d6679409d Mon Sep 17 00:00:00 2001 From: Arianna R Date: Sun, 2 Nov 2025 18:07:08 -0500 Subject: [PATCH 03/12] added rotaryencoderinterface.h to mock library --- lib/mock_interfaces/RotaryEncoderInterface.h | 42 ++++++++++++++++++++ test/test_charge_cycle.h | 1 + 2 files changed, 43 insertions(+) create mode 100644 lib/mock_interfaces/RotaryEncoderInterface.h diff --git a/lib/mock_interfaces/RotaryEncoderInterface.h b/lib/mock_interfaces/RotaryEncoderInterface.h new file mode 100644 index 0000000..08ade2d --- /dev/null +++ b/lib/mock_interfaces/RotaryEncoderInterface.h @@ -0,0 +1,42 @@ +#ifndef ROTARYENCODERINTERFACE_H +#define ROTARYENCODERINTERFACE_H + +// #include //LOOK INTO INCLUDE MORE +#include "CCUData.h" + +#include "etl/singleton.h" +#include + +#define CLK 2 //change based on actual pin used +#define DT 3 //change based on actual pin used +#define SW 4 //change based on actual pin used + +struct rotary_encoder_s { + volatile bool state = false; + volatile int encoder_value = 0; + unsigned long last_button_press = 0; + const int max_value = 120; + const int min_value = 0; +}; + +class RotaryEncoderInterface +{ +public: + RotaryEncoderInterface(CCUData &ccu_data) : + _ccu_data(ccu_data) {}; + + void setupEncoder(); + void updateEncoder(); + static void isr1(); + void set_enc_value(int dt_value); + + bool isButtonPressed() const { return _encoder_data.state; }; + +private: + rotary_encoder_s _encoder_data; + CCUData &_ccu_data; +}; + +using RotaryEncoderInterfaceInstance = etl::singleton; + +#endif \ No newline at end of file diff --git a/test/test_charge_cycle.h b/test/test_charge_cycle.h index d8e4629..44e9e9b 100644 --- a/test/test_charge_cycle.h +++ b/test/test_charge_cycle.h @@ -3,6 +3,7 @@ #include "MainChargeSystem.h" #include "ACUInterface.h" +#include "RotaryEncoderInterface.h" #include "ChargerInterface.h" #include #include From c58758b20aff90a23d5edc710c641bf722993a88 Mon Sep 17 00:00:00 2001 From: Arianna R Date: Sun, 2 Nov 2025 18:34:53 -0500 Subject: [PATCH 04/12] fixed pio tests --- lib/interfaces/include/RotaryEncoderInterface.h | 8 ++++---- lib/interfaces/src/RotaryEncoderInterface.cpp | 15 +++++++-------- lib/systems/src/MainChargeSystem.cpp | 3 ++- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/lib/interfaces/include/RotaryEncoderInterface.h b/lib/interfaces/include/RotaryEncoderInterface.h index f1c68ea..07ee393 100644 --- a/lib/interfaces/include/RotaryEncoderInterface.h +++ b/lib/interfaces/include/RotaryEncoderInterface.h @@ -13,10 +13,10 @@ struct rotary_encoder_s { volatile bool state = false; - volatile int encoder_value = 0; + volatile float encoder_value = 0; unsigned long last_button_press = 0; - const int max_value = 120; - const int min_value = 0; + const float max_value = 120; + const float min_value = 0; }; class RotaryEncoderInterface @@ -30,7 +30,7 @@ class RotaryEncoderInterface static void isr1(); void set_enc_value(int dt_value); - bool isButtonPressed() const { return _encoder_data.state; }; + rotary_encoder_s isButtonPressed() const { return _encoder_data; }; private: rotary_encoder_s _encoder_data; diff --git a/lib/interfaces/src/RotaryEncoderInterface.cpp b/lib/interfaces/src/RotaryEncoderInterface.cpp index 471de5a..aeeb4f2 100644 --- a/lib/interfaces/src/RotaryEncoderInterface.cpp +++ b/lib/interfaces/src/RotaryEncoderInterface.cpp @@ -1,9 +1,9 @@ #include "RotaryEncoderInterface.h" #include "CCUData.h" +const int bounce_delay = 50; - -static void RotaryEncoderInterface::isr1() { +void RotaryEncoderInterface::isr1() { int dt_value = digitalRead(DT); RotaryEncoderInterfaceInstance::instance().set_enc_value(dt_value); } @@ -11,11 +11,11 @@ static void RotaryEncoderInterface::isr1() { void RotaryEncoderInterface::set_enc_value(int dt_value) { if (dt_value == HIGH) { if (_encoder_data.encoder_value < _encoder_data.max_value) { - _encoder_data.encoder_value++; + _encoder_data.encoder_value += 1.0; } } else { if (_encoder_data.encoder_value > _encoder_data.min_value) { - _encoder_data.encoder_value--; + _encoder_data.encoder_value -= 1.0; } } } @@ -23,7 +23,6 @@ void RotaryEncoderInterface::set_enc_value(int dt_value) { void RotaryEncoderInterface::setupEncoder() { _encoder_data.encoder_value = 0; _encoder_data.state = false; - Serial.begin(9600); pinMode(CLK, INPUT_PULLUP); pinMode(DT, INPUT_PULLUP); pinMode(SW, INPUT_PULLUP); @@ -32,12 +31,12 @@ void RotaryEncoderInterface::setupEncoder() { } void RotaryEncoderInterface::updateEncoder() { - static int prev_value = -1; + static float prev_value = -1; int btn_state = digitalRead(SW); noInterrupts(); - int current_value = _encoder_data.encoder_value; + float current_value = _encoder_data.encoder_value; _ccu_data.encoder_value = current_value; interrupts(); @@ -47,7 +46,7 @@ void RotaryEncoderInterface::updateEncoder() { prev_value = current_value; if (btn_state == LOW) { - if (millis() - _encoder_data.last_button_press > 50) { + if (millis() - _encoder_data.last_button_press > bounce_delay) { _encoder_data.state = true; //or = !_encoder_data.state Serial.println("Button pressed"); } diff --git a/lib/systems/src/MainChargeSystem.cpp b/lib/systems/src/MainChargeSystem.cpp index 5cf7b5c..ed20af1 100644 --- a/lib/systems/src/MainChargeSystem.cpp +++ b/lib/systems/src/MainChargeSystem.cpp @@ -22,7 +22,8 @@ void MainChargeSystem::calculate_charge_current() { * If acu_state = 2, we should/are safe to be charging */ bool acu_shutdown_low = ACUInterfaceInstance::instance().get_latest_data().acu_state == 1; //NOLINT - bool rotary_state = RotaryEncoderInterfaceInstance::instance().isButtonPressed(); + bool rotary_state = false; + rotary_state = RotaryEncoderInterfaceInstance::instance().isButtonPressed().state; bool voltage_reached = (high_voltage >= _ccu_data.cutoff_voltage) || (ACUInterfaceInstance::instance().get_latest_data().total_voltage > _ccu_data.max_pack_voltage); //NOLINT if (shutdown_low || acu_shutdown_low) From 54f7e12f4a414dcbbb3b4d4eacac8c065a66ae3a Mon Sep 17 00:00:00 2001 From: Arianna R Date: Sun, 2 Nov 2025 18:38:30 -0500 Subject: [PATCH 05/12] fixed bool --- lib/interfaces/include/RotaryEncoderInterface.h | 2 +- lib/systems/src/MainChargeSystem.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/interfaces/include/RotaryEncoderInterface.h b/lib/interfaces/include/RotaryEncoderInterface.h index 07ee393..ff3c8d2 100644 --- a/lib/interfaces/include/RotaryEncoderInterface.h +++ b/lib/interfaces/include/RotaryEncoderInterface.h @@ -30,7 +30,7 @@ class RotaryEncoderInterface static void isr1(); void set_enc_value(int dt_value); - rotary_encoder_s isButtonPressed() const { return _encoder_data; }; + bool isButtonPressed() const { return _encoder_data.state; }; private: rotary_encoder_s _encoder_data; diff --git a/lib/systems/src/MainChargeSystem.cpp b/lib/systems/src/MainChargeSystem.cpp index ed20af1..0f27f04 100644 --- a/lib/systems/src/MainChargeSystem.cpp +++ b/lib/systems/src/MainChargeSystem.cpp @@ -23,7 +23,7 @@ void MainChargeSystem::calculate_charge_current() { */ bool acu_shutdown_low = ACUInterfaceInstance::instance().get_latest_data().acu_state == 1; //NOLINT bool rotary_state = false; - rotary_state = RotaryEncoderInterfaceInstance::instance().isButtonPressed().state; + rotary_state = RotaryEncoderInterfaceInstance::instance().isButtonPressed(); bool voltage_reached = (high_voltage >= _ccu_data.cutoff_voltage) || (ACUInterfaceInstance::instance().get_latest_data().total_voltage > _ccu_data.max_pack_voltage); //NOLINT if (shutdown_low || acu_shutdown_low) From effa201d044f9371fa820f0838bb5af97ca191e6 Mon Sep 17 00:00:00 2001 From: Arianna R Date: Sun, 9 Nov 2025 12:22:27 -0500 Subject: [PATCH 06/12] added display visibility for manual charging, deleted serial code, incl ext. libs (arduino) --- lib/interfaces/include/RotaryEncoderInterface.h | 1 + lib/interfaces/src/DisplayInterface.cpp | 3 +++ lib/interfaces/src/RotaryEncoderInterface.cpp | 10 +--------- 3 files changed, 5 insertions(+), 9 deletions(-) diff --git a/lib/interfaces/include/RotaryEncoderInterface.h b/lib/interfaces/include/RotaryEncoderInterface.h index ff3c8d2..cc28895 100644 --- a/lib/interfaces/include/RotaryEncoderInterface.h +++ b/lib/interfaces/include/RotaryEncoderInterface.h @@ -1,6 +1,7 @@ #ifndef ROTARYENCODERINTERFACE_H #define ROTARYENCODERINTERFACE_H +#include #include //LOOK INTO INCLUDE MORE #include "CCUData.h" diff --git a/lib/interfaces/src/DisplayInterface.cpp b/lib/interfaces/src/DisplayInterface.cpp index 7814307..8e3f9b9 100644 --- a/lib/interfaces/src/DisplayInterface.cpp +++ b/lib/interfaces/src/DisplayInterface.cpp @@ -20,6 +20,9 @@ void DisplayInterface::display_data() { if (_ccu_data.charging_state == ChargingState_e::CHARGING) { Display.print("Charging at "); Display.println(_ccu_data.calculated_charge_current); + } else if (_ccu_data.charging_state == ChargingState_e::MANUAL_CHARGING) { + Display.print("Charging (M) at "); + Display.println(_ccu_data.calculated_charge_current); } else if (_ccu_data.charging_state == ChargingState_e::DONE_CHARGING) { Display.println("Done charging!"); } else { diff --git a/lib/interfaces/src/RotaryEncoderInterface.cpp b/lib/interfaces/src/RotaryEncoderInterface.cpp index aeeb4f2..a571ea0 100644 --- a/lib/interfaces/src/RotaryEncoderInterface.cpp +++ b/lib/interfaces/src/RotaryEncoderInterface.cpp @@ -31,8 +31,6 @@ void RotaryEncoderInterface::setupEncoder() { } void RotaryEncoderInterface::updateEncoder() { - static float prev_value = -1; - int btn_state = digitalRead(SW); noInterrupts(); @@ -40,15 +38,9 @@ void RotaryEncoderInterface::updateEncoder() { _ccu_data.encoder_value = current_value; interrupts(); - if (current_value != prev_value) { - Serial.println(current_value); - } - prev_value = current_value; - if (btn_state == LOW) { if (millis() - _encoder_data.last_button_press > bounce_delay) { - _encoder_data.state = true; //or = !_encoder_data.state - Serial.println("Button pressed"); + _encoder_data.state = !_encoder_data.state; } _encoder_data.last_button_press = millis(); } From ef691f9998f68acfb6379354926a95a74a0e4ad7 Mon Sep 17 00:00:00 2001 From: Emil Bajit Date: Sun, 9 Nov 2025 15:37:08 -0500 Subject: [PATCH 07/12] Created rotary encoder unit tests, implemented mock rotary encoder interface --- lib/mock_interfaces/RotaryEncoderInterface.h | 39 +++-- test/test_maincharge.cpp | 3 +- test/test_rotary_encoder.h | 157 +++++++++++++++++++ 3 files changed, 189 insertions(+), 10 deletions(-) create mode 100644 test/test_rotary_encoder.h diff --git a/lib/mock_interfaces/RotaryEncoderInterface.h b/lib/mock_interfaces/RotaryEncoderInterface.h index 08ade2d..77517d0 100644 --- a/lib/mock_interfaces/RotaryEncoderInterface.h +++ b/lib/mock_interfaces/RotaryEncoderInterface.h @@ -1,8 +1,8 @@ #ifndef ROTARYENCODERINTERFACE_H #define ROTARYENCODERINTERFACE_H -// #include //LOOK INTO INCLUDE MORE #include "CCUData.h" +#include "mockArduino.h" #include "etl/singleton.h" #include @@ -13,10 +13,10 @@ struct rotary_encoder_s { volatile bool state = false; - volatile int encoder_value = 0; + volatile float encoder_value = 0; unsigned long last_button_press = 0; - const int max_value = 120; - const int min_value = 0; + const float max_value = 120; + const float min_value = 0; }; class RotaryEncoderInterface @@ -25,10 +25,31 @@ class RotaryEncoderInterface RotaryEncoderInterface(CCUData &ccu_data) : _ccu_data(ccu_data) {}; - void setupEncoder(); - void updateEncoder(); - static void isr1(); - void set_enc_value(int dt_value); + inline void setupEncoder() { + _encoder_data.encoder_value = 0; + _encoder_data.state = false; + } + + inline void updateEncoder() { + // Sync internal encoder value to CCUData (matching real implementation) + _ccu_data.encoder_value = _encoder_data.encoder_value; + } + + static inline void isr1() { + // Mock implementation - no-op + } + + inline void set_enc_value(int dt_value) { + if (dt_value == HIGH) { + if (_encoder_data.encoder_value < _encoder_data.max_value) { + _encoder_data.encoder_value += 1.0f; + } + } else { + if (_encoder_data.encoder_value > _encoder_data.min_value) { + _encoder_data.encoder_value -= 1.0f; + } + } + } bool isButtonPressed() const { return _encoder_data.state; }; @@ -39,4 +60,4 @@ class RotaryEncoderInterface using RotaryEncoderInterfaceInstance = etl::singleton; -#endif \ No newline at end of file +#endif diff --git a/test/test_maincharge.cpp b/test/test_maincharge.cpp index d252508..df6c84f 100644 --- a/test/test_maincharge.cpp +++ b/test/test_maincharge.cpp @@ -1,6 +1,7 @@ #include #include #include "test_charge_cycle.h" +#include "test_rotary_encoder.h" @@ -11,4 +12,4 @@ int main(int argc, char **argv) // Do nothing (always return 0 and allow PlatformIO to parse result) } return 0; -} \ No newline at end of file +} diff --git a/test/test_rotary_encoder.h b/test/test_rotary_encoder.h new file mode 100644 index 0000000..7f4ca77 --- /dev/null +++ b/test/test_rotary_encoder.h @@ -0,0 +1,157 @@ +#ifndef TEST_ROTARY_ENCODER_H +#define TEST_ROTARY_ENCODER_H + +#include +#include +#include "RotaryEncoderInterface.h" +#include "CCUData.h" + +using ::testing::Return; + +class RotaryEncoderTest : public ::testing::Test { +protected: + CCUData ccu_data; + RotaryEncoderInterface encoder{ccu_data}; + + void SetUp() override { + // Reset CCUData before each test + ccu_data.encoder_value = 0; + encoder.setupEncoder(); + } + + // Helper to simulate encoder update cycle + void rotateEncoder(int direction) { + encoder.set_enc_value(direction); + encoder.updateEncoder(); + } +}; + +// Test: Encoder increments on positive DT value (HIGH=1) +TEST_F(RotaryEncoderTest, IncrementOnClockwise) { + float initial_value = ccu_data.encoder_value; + rotateEncoder(HIGH); + + EXPECT_EQ(ccu_data.encoder_value, initial_value + 1); +} + +// Test: Encoder decrements on negative DT value (LOW=0) +TEST_F(RotaryEncoderTest, DecrementOnCounterClockwise) { + // ccu_data encoder value initially at 0, so we need to set it to 1 so it can decrement properly + rotateEncoder(HIGH); + float initial_value = ccu_data.encoder_value; + rotateEncoder(LOW); + + EXPECT_EQ(ccu_data.encoder_value, initial_value - 1); +} + +// Test: Multiple increments in sequence +TEST_F(RotaryEncoderTest, MultipleClockwiseSteps) { + for (int i = 0; i < 5; i++) { + rotateEncoder(HIGH); + } + + EXPECT_EQ(ccu_data.encoder_value, 5.0f); +} + +// Test: Multiple decrements in sequence +TEST_F(RotaryEncoderTest, MultipleCounterClockwiseSteps) { + // First increment to 10 + for (int i = 0; i < 10; i++) { + rotateEncoder(HIGH); + } + EXPECT_EQ(ccu_data.encoder_value, 10.0f); + + // Now decrement by 3 + for (int i = 0; i < 3; i++) { + rotateEncoder(LOW); + } + + EXPECT_EQ(ccu_data.encoder_value, 7.0f); +} + +// Test: Button press returns initial state +TEST_F(RotaryEncoderTest, ButtonInitiallyNotPressed) { + EXPECT_FALSE(encoder.isButtonPressed()); +} + +// Test: Alternating CW and CCW rotations +TEST_F(RotaryEncoderTest, AlternatingDirections) { + rotateEncoder(HIGH); // +1 + rotateEncoder(HIGH); // +1 + rotateEncoder(LOW); // -1 + rotateEncoder(LOW); // -1 + rotateEncoder(HIGH); // +1 + + EXPECT_EQ(ccu_data.encoder_value, 1.0f); +} + +// Test: Maximum value clamping at 120 +TEST_F(RotaryEncoderTest, MaxValueClamping) { + // Increment to 120 + for (int i = 0; i < 120; i++) { + rotateEncoder(HIGH); + } + EXPECT_EQ(ccu_data.encoder_value, 120.0f); + + // Try to increment beyond max + rotateEncoder(HIGH); + + // Should stay at 120, not exceed + EXPECT_EQ(ccu_data.encoder_value, 120.0f); +} + +// Test: Minimum value clamping at 0 +TEST_F(RotaryEncoderTest, MinValueClamping) { + // Already at 0 from SetUp + EXPECT_EQ(ccu_data.encoder_value, 0.0f); + + rotateEncoder(LOW); + + // Should stay at 0, not go negative + EXPECT_EQ(ccu_data.encoder_value, 0.0f); +} + +// Test: Full range sweep from 0 to max +TEST_F(RotaryEncoderTest, FullRangeClockwise) { + ccu_data.encoder_value = 0.0f; + + for (int i = 0; i < 120; i++) { + rotateEncoder(HIGH); + } + + EXPECT_EQ(ccu_data.encoder_value, 120.0f); +} + +// Test: Full range sweep from max to 0 +TEST_F(RotaryEncoderTest, FullRangeCounterClockwise) { + // First go to 120 + for (int i = 0; i < 120; i++) { + rotateEncoder(HIGH); + } + EXPECT_EQ(ccu_data.encoder_value, 120.0f); + + // Now go back to 0 + for (int i = 0; i < 120; i++) { + rotateEncoder(LOW); + } + + EXPECT_EQ(ccu_data.encoder_value, 0.0f); +} + +// Test: Value stays within valid range during complex rotation pattern +TEST_F(RotaryEncoderTest, BoundaryBehaviorComplex) { + // First go to 118 + for (int i = 0; i < 118; i++) { + rotateEncoder(HIGH); + } + + rotateEncoder(HIGH); // 119 + rotateEncoder(HIGH); // 120 + rotateEncoder(HIGH); // 120 (clamped) + rotateEncoder(LOW); // 119 + rotateEncoder(LOW); // 118 + + EXPECT_EQ(ccu_data.encoder_value, 118.0f); +} + +#endif // TEST_ROTARY_ENCODER_H From 996a3180eea756754dc8d0c1ab008d1f65be427c Mon Sep 17 00:00:00 2001 From: Arianna R Date: Sun, 9 Nov 2025 18:58:04 -0500 Subject: [PATCH 08/12] minor style fixes --- .../include/RotaryEncoderInterface.h | 10 ++++---- lib/interfaces/src/RotaryEncoderInterface.cpp | 23 +++++++++++-------- 2 files changed, 19 insertions(+), 14 deletions(-) diff --git a/lib/interfaces/include/RotaryEncoderInterface.h b/lib/interfaces/include/RotaryEncoderInterface.h index cc28895..c36654a 100644 --- a/lib/interfaces/include/RotaryEncoderInterface.h +++ b/lib/interfaces/include/RotaryEncoderInterface.h @@ -2,15 +2,15 @@ #define ROTARYENCODERINTERFACE_H #include -#include //LOOK INTO INCLUDE MORE +#include #include "CCUData.h" #include "etl/singleton.h" #include -#define CLK 2 //change based on actual pin used -#define DT 3 //change based on actual pin used -#define SW 4 //change based on actual pin used +#define CLK 21 //change based on actual pin used +#define DT 20 //change based on actual pin used +#define SW 19 //change based on actual pin used struct rotary_encoder_s { volatile bool state = false; @@ -24,7 +24,7 @@ class RotaryEncoderInterface { public: RotaryEncoderInterface(CCUData &ccu_data) : - _ccu_data(ccu_data) {}; + _ccu_data(ccu_data) {Serial.begin(9600);}; void setupEncoder(); void updateEncoder(); diff --git a/lib/interfaces/src/RotaryEncoderInterface.cpp b/lib/interfaces/src/RotaryEncoderInterface.cpp index a571ea0..057db6f 100644 --- a/lib/interfaces/src/RotaryEncoderInterface.cpp +++ b/lib/interfaces/src/RotaryEncoderInterface.cpp @@ -1,15 +1,15 @@ #include "RotaryEncoderInterface.h" #include "CCUData.h" -const int bounce_delay = 50; +const int bounce_delay = 50; //Found based on research, subject to change void RotaryEncoderInterface::isr1() { - int dt_value = digitalRead(DT); - RotaryEncoderInterfaceInstance::instance().set_enc_value(dt_value); + int enc_b_value = digitalRead(DT); + RotaryEncoderInterfaceInstance::instance().set_enc_value(enc_b_value); } -void RotaryEncoderInterface::set_enc_value(int dt_value) { - if (dt_value == HIGH) { +void RotaryEncoderInterface::set_enc_value(int enc_b_value) { + if (enc_b_value == HIGH) { if (_encoder_data.encoder_value < _encoder_data.max_value) { _encoder_data.encoder_value += 1.0; } @@ -31,16 +31,21 @@ void RotaryEncoderInterface::setupEncoder() { } void RotaryEncoderInterface::updateEncoder() { + static float prev_value = -1; int btn_state = digitalRead(SW); - noInterrupts(); - float current_value = _encoder_data.encoder_value; - _ccu_data.encoder_value = current_value; - interrupts(); + _ccu_data.encoder_value = _encoder_data.encoder_value; + + if (_encoder_data.encoder_value != prev_value) { + Serial.print("Current value: "); + Serial.println(_encoder_data.encoder_value); + } + prev_value = _encoder_data.encoder_value; if (btn_state == LOW) { if (millis() - _encoder_data.last_button_press > bounce_delay) { _encoder_data.state = !_encoder_data.state; + Serial.println("Button pressed!"); } _encoder_data.last_button_press = millis(); } From ba279452b20d8627f000c0b06fa730e7aed82d09 Mon Sep 17 00:00:00 2001 From: Arianna R Date: Sun, 9 Nov 2025 19:19:08 -0500 Subject: [PATCH 09/12] deleted rotary_enc tests --- test/test_maincharge.cpp | 1 - test/test_rotary_encoder.h | 157 ------------------------------------- 2 files changed, 158 deletions(-) delete mode 100644 test/test_rotary_encoder.h diff --git a/test/test_maincharge.cpp b/test/test_maincharge.cpp index df6c84f..571001d 100644 --- a/test/test_maincharge.cpp +++ b/test/test_maincharge.cpp @@ -1,7 +1,6 @@ #include #include #include "test_charge_cycle.h" -#include "test_rotary_encoder.h" diff --git a/test/test_rotary_encoder.h b/test/test_rotary_encoder.h deleted file mode 100644 index 7f4ca77..0000000 --- a/test/test_rotary_encoder.h +++ /dev/null @@ -1,157 +0,0 @@ -#ifndef TEST_ROTARY_ENCODER_H -#define TEST_ROTARY_ENCODER_H - -#include -#include -#include "RotaryEncoderInterface.h" -#include "CCUData.h" - -using ::testing::Return; - -class RotaryEncoderTest : public ::testing::Test { -protected: - CCUData ccu_data; - RotaryEncoderInterface encoder{ccu_data}; - - void SetUp() override { - // Reset CCUData before each test - ccu_data.encoder_value = 0; - encoder.setupEncoder(); - } - - // Helper to simulate encoder update cycle - void rotateEncoder(int direction) { - encoder.set_enc_value(direction); - encoder.updateEncoder(); - } -}; - -// Test: Encoder increments on positive DT value (HIGH=1) -TEST_F(RotaryEncoderTest, IncrementOnClockwise) { - float initial_value = ccu_data.encoder_value; - rotateEncoder(HIGH); - - EXPECT_EQ(ccu_data.encoder_value, initial_value + 1); -} - -// Test: Encoder decrements on negative DT value (LOW=0) -TEST_F(RotaryEncoderTest, DecrementOnCounterClockwise) { - // ccu_data encoder value initially at 0, so we need to set it to 1 so it can decrement properly - rotateEncoder(HIGH); - float initial_value = ccu_data.encoder_value; - rotateEncoder(LOW); - - EXPECT_EQ(ccu_data.encoder_value, initial_value - 1); -} - -// Test: Multiple increments in sequence -TEST_F(RotaryEncoderTest, MultipleClockwiseSteps) { - for (int i = 0; i < 5; i++) { - rotateEncoder(HIGH); - } - - EXPECT_EQ(ccu_data.encoder_value, 5.0f); -} - -// Test: Multiple decrements in sequence -TEST_F(RotaryEncoderTest, MultipleCounterClockwiseSteps) { - // First increment to 10 - for (int i = 0; i < 10; i++) { - rotateEncoder(HIGH); - } - EXPECT_EQ(ccu_data.encoder_value, 10.0f); - - // Now decrement by 3 - for (int i = 0; i < 3; i++) { - rotateEncoder(LOW); - } - - EXPECT_EQ(ccu_data.encoder_value, 7.0f); -} - -// Test: Button press returns initial state -TEST_F(RotaryEncoderTest, ButtonInitiallyNotPressed) { - EXPECT_FALSE(encoder.isButtonPressed()); -} - -// Test: Alternating CW and CCW rotations -TEST_F(RotaryEncoderTest, AlternatingDirections) { - rotateEncoder(HIGH); // +1 - rotateEncoder(HIGH); // +1 - rotateEncoder(LOW); // -1 - rotateEncoder(LOW); // -1 - rotateEncoder(HIGH); // +1 - - EXPECT_EQ(ccu_data.encoder_value, 1.0f); -} - -// Test: Maximum value clamping at 120 -TEST_F(RotaryEncoderTest, MaxValueClamping) { - // Increment to 120 - for (int i = 0; i < 120; i++) { - rotateEncoder(HIGH); - } - EXPECT_EQ(ccu_data.encoder_value, 120.0f); - - // Try to increment beyond max - rotateEncoder(HIGH); - - // Should stay at 120, not exceed - EXPECT_EQ(ccu_data.encoder_value, 120.0f); -} - -// Test: Minimum value clamping at 0 -TEST_F(RotaryEncoderTest, MinValueClamping) { - // Already at 0 from SetUp - EXPECT_EQ(ccu_data.encoder_value, 0.0f); - - rotateEncoder(LOW); - - // Should stay at 0, not go negative - EXPECT_EQ(ccu_data.encoder_value, 0.0f); -} - -// Test: Full range sweep from 0 to max -TEST_F(RotaryEncoderTest, FullRangeClockwise) { - ccu_data.encoder_value = 0.0f; - - for (int i = 0; i < 120; i++) { - rotateEncoder(HIGH); - } - - EXPECT_EQ(ccu_data.encoder_value, 120.0f); -} - -// Test: Full range sweep from max to 0 -TEST_F(RotaryEncoderTest, FullRangeCounterClockwise) { - // First go to 120 - for (int i = 0; i < 120; i++) { - rotateEncoder(HIGH); - } - EXPECT_EQ(ccu_data.encoder_value, 120.0f); - - // Now go back to 0 - for (int i = 0; i < 120; i++) { - rotateEncoder(LOW); - } - - EXPECT_EQ(ccu_data.encoder_value, 0.0f); -} - -// Test: Value stays within valid range during complex rotation pattern -TEST_F(RotaryEncoderTest, BoundaryBehaviorComplex) { - // First go to 118 - for (int i = 0; i < 118; i++) { - rotateEncoder(HIGH); - } - - rotateEncoder(HIGH); // 119 - rotateEncoder(HIGH); // 120 - rotateEncoder(HIGH); // 120 (clamped) - rotateEncoder(LOW); // 119 - rotateEncoder(LOW); // 118 - - EXPECT_EQ(ccu_data.encoder_value, 118.0f); -} - -#endif // TEST_ROTARY_ENCODER_H From 928ac9fedca0eb41cfd497c5007734ded2ee9122 Mon Sep 17 00:00:00 2001 From: Arianna R Date: Thu, 20 Nov 2025 20:52:07 -0500 Subject: [PATCH 10/12] added tasks for rotary encoder interface usage --- include/CCUTasks.h | 2 ++ lib/interfaces/src/RotaryEncoderInterface.cpp | 3 ++- lib/utilities/CCUData.h | 4 ++++ src/CCUTasks.cpp | 7 +++++++ src/main.cpp | 8 ++++++-- 5 files changed, 21 insertions(+), 3 deletions(-) diff --git a/include/CCUTasks.h b/include/CCUTasks.h index 897ebc7..13112c1 100644 --- a/include/CCUTasks.h +++ b/include/CCUTasks.h @@ -48,6 +48,8 @@ HT_TASK::TaskResponse calculate_charge_current(const unsigned long& sysMicros, c HT_TASK::TaskResponse print_data(const unsigned long& sysMicros, const HT_TASK::TaskInfo& taskInfo); +HT_TASK::TaskResponse update_encoder(const unsigned long& sysMicros, const HT_TASK::TaskInfo& taskInfo); + #endif \ No newline at end of file diff --git a/lib/interfaces/src/RotaryEncoderInterface.cpp b/lib/interfaces/src/RotaryEncoderInterface.cpp index 057db6f..c1bb4bb 100644 --- a/lib/interfaces/src/RotaryEncoderInterface.cpp +++ b/lib/interfaces/src/RotaryEncoderInterface.cpp @@ -1,6 +1,7 @@ #include "RotaryEncoderInterface.h" #include "CCUData.h" + const int bounce_delay = 50; //Found based on research, subject to change void RotaryEncoderInterface::isr1() { @@ -27,7 +28,7 @@ void RotaryEncoderInterface::setupEncoder() { pinMode(DT, INPUT_PULLUP); pinMode(SW, INPUT_PULLUP); - attachInterrupt(digitalPinToInterrupt(2), RotaryEncoderInterface::isr1, FALLING); + attachInterrupt(digitalPinToInterrupt(DT), RotaryEncoderInterface::isr1, FALLING); } void RotaryEncoderInterface::updateEncoder() { diff --git a/lib/utilities/CCUData.h b/lib/utilities/CCUData.h index 8c8c5c0..2ccfe29 100644 --- a/lib/utilities/CCUData.h +++ b/lib/utilities/CCUData.h @@ -61,6 +61,10 @@ namespace CCUConstants constexpr unsigned long SEND_ALL_DATA_PERIOD = 1000; constexpr unsigned long HT_SCHED_CAN_PERIOD = 100000; + constexpr unsigned long ROTARY_ENC_PERIOD = 100000; + constexpr unsigned long ROTARY_ENC_PRIORITY = 14; + + /* CAN Constants */ const uint32_t CAN_BAUDRATE = 1000000; //CAN for ACU const uint32_t CHARGER_CAN_BAUDRATE = 500000; //CAN for charger diff --git a/src/CCUTasks.cpp b/src/CCUTasks.cpp index d330364..bef181e 100644 --- a/src/CCUTasks.cpp +++ b/src/CCUTasks.cpp @@ -15,6 +15,8 @@ HT_TASK::TaskResponse intitialize_all_interfaces() EnergyMeterInterfaceInstance::create(); + RotaryEncoderInterfaceInstance::create(ccu_data); //NOLINT (necessary for passing ccu_data struct as a reference) + WatchdogInstance::create(); WatchdogInstance::instance().init(); @@ -31,6 +33,11 @@ HT_TASK::TaskResponse intitialize_all_interfaces() } +// MOVE IN FUTURE IF NECESSARY +HT_TASK::TaskResponse update_encoder(const unsigned long& sysMicros, const HT_TASK::TaskInfo& taskInfo) { + RotaryEncoderInterfaceInstance::instance().updateEncoder(); + return HT_TASK::TaskResponse::YIELD; +} HT_TASK::TaskResponse run_read_dial_task(const unsigned long& sysMicros, const HT_TASK::TaskInfo& taskInfo) { diff --git a/src/main.cpp b/src/main.cpp index c375909..6c40801 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -15,6 +15,7 @@ #include "CCUTasks.h" #include "SystemTimeInterface.h" #include "DisplayInterface.h" +#include "RotaryEncoderInterface.h" FlexCAN_Type CHARGER_CAN; //placed here after debugging @@ -24,11 +25,12 @@ FlexCAN_Type ACU_CAN; /* Parameters */ ACUAllData_s acu_all_data; - /* Systems */ namespace qn = qindesign::network; //setup of qn namespace qn::EthernetUDP udp; //setup of qn namespace +/* Rotary Encoder Setup */ +RotaryEncoderInterface& enc = RotaryEncoderInterfaceInstance::instance(); /* Scheduler Setup */ HT_SCHED::Scheduler& scheduler = HT_SCHED::Scheduler::getInstance(); @@ -49,7 +51,7 @@ HT_TASK::Task kick_watchdog_task(init_kick_watchdog, run_kick_watchdog, CCUConst HT_TASK::Task debug_print_task(HT_TASK::DUMMY_FUNCTION, print_data, CCUConstants::UPDATE_DISPLAY_PRIORITY, CCUConstants::UPDATE_DISPLAY_PERIOD); HT_TASK::Task tick_state_machine_task(HT_TASK::DUMMY_FUNCTION, tick_state_machine, CCUConstants::TICK_STATE_MACHINE_PRIORITY, CCUConstants::TICK_STATE_MACHINE_PERIOD); HT_TASK::Task calculate_charge_current_task(HT_TASK::DUMMY_FUNCTION, calculate_charge_current, CCUConstants::TICK_STATE_MACHINE_PRIORITY, CCUConstants::TICK_STATE_MACHINE_PERIOD); - +HT_TASK::Task update_encoder_task(HT_TASK::DUMMY_FUNCTION, update_encoder, CCUConstants::ROTARY_ENC_PRIORITY, CCUConstants::ROTARY_ENC_PERIOD); void setup() { @@ -73,9 +75,11 @@ void setup() { //scheduler.schedule(tick_state_machine_task); //this task times out watchdog for some reason (state machine would be nice to have but isn't a priority for CCU to work) scheduler.schedule(calculate_charge_current_task); scheduler.schedule(update_display_task); + scheduler.schedule(update_encoder_task); handle_CAN_setup(ACU_CAN, CCUConstants::CAN_BAUDRATE, &CCUCANInterfaceImpl::on_acu_can_receive); handle_CAN_setup(CHARGER_CAN, CCUConstants::CHARGER_CAN_BAUDRATE, &CCUCANInterfaceImpl::on_charger_can_receive); + enc.setupEncoder(); } From 906f29e733d0ef8dcdf4cff0ea3d497ef29f5978 Mon Sep 17 00:00:00 2001 From: Arianna R Date: Thu, 20 Nov 2025 20:58:15 -0500 Subject: [PATCH 11/12] deleted mock interrupt routine (testing on hardware) --- lib/mock_interfaces/RotaryEncoderInterface.h | 4 ---- 1 file changed, 4 deletions(-) diff --git a/lib/mock_interfaces/RotaryEncoderInterface.h b/lib/mock_interfaces/RotaryEncoderInterface.h index 77517d0..16f4bf9 100644 --- a/lib/mock_interfaces/RotaryEncoderInterface.h +++ b/lib/mock_interfaces/RotaryEncoderInterface.h @@ -35,10 +35,6 @@ class RotaryEncoderInterface _ccu_data.encoder_value = _encoder_data.encoder_value; } - static inline void isr1() { - // Mock implementation - no-op - } - inline void set_enc_value(int dt_value) { if (dt_value == HIGH) { if (_encoder_data.encoder_value < _encoder_data.max_value) { From d44bce013b826b0c1b0f863745c2a4552a58ccb1 Mon Sep 17 00:00:00 2001 From: Arianna R Date: Fri, 12 Dec 2025 14:37:27 -0600 Subject: [PATCH 12/12] final changes after hardware testing: added debouncing for ISR & changed interrupt to call once per rotation --- lib/interfaces/include/RotaryEncoderInterface.h | 6 +++--- lib/interfaces/src/RotaryEncoderInterface.cpp | 15 ++++++++++----- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/lib/interfaces/include/RotaryEncoderInterface.h b/lib/interfaces/include/RotaryEncoderInterface.h index c36654a..17e8c9d 100644 --- a/lib/interfaces/include/RotaryEncoderInterface.h +++ b/lib/interfaces/include/RotaryEncoderInterface.h @@ -8,9 +8,9 @@ #include "etl/singleton.h" #include -#define CLK 21 //change based on actual pin used -#define DT 20 //change based on actual pin used -#define SW 19 //change based on actual pin used +#define CLK 21 +#define DT 20 +#define SW 19 struct rotary_encoder_s { volatile bool state = false; diff --git a/lib/interfaces/src/RotaryEncoderInterface.cpp b/lib/interfaces/src/RotaryEncoderInterface.cpp index c1bb4bb..8d1d22c 100644 --- a/lib/interfaces/src/RotaryEncoderInterface.cpp +++ b/lib/interfaces/src/RotaryEncoderInterface.cpp @@ -2,11 +2,17 @@ #include "CCUData.h" -const int bounce_delay = 50; //Found based on research, subject to change +const int bounce_delay = 200; //Worked best during testing to minimize switch bouncing +volatile unsigned long last_interrupt_time = 0; void RotaryEncoderInterface::isr1() { - int enc_b_value = digitalRead(DT); - RotaryEncoderInterfaceInstance::instance().set_enc_value(enc_b_value); + unsigned long current_time = millis(); + if (current_time - last_interrupt_time > bounce_delay) { + int enc_b_value = digitalRead(DT); + RotaryEncoderInterfaceInstance::instance().set_enc_value(enc_b_value); + last_interrupt_time = current_time; + } + } void RotaryEncoderInterface::set_enc_value(int enc_b_value) { @@ -27,8 +33,7 @@ void RotaryEncoderInterface::setupEncoder() { pinMode(CLK, INPUT_PULLUP); pinMode(DT, INPUT_PULLUP); pinMode(SW, INPUT_PULLUP); - - attachInterrupt(digitalPinToInterrupt(DT), RotaryEncoderInterface::isr1, FALLING); + attachInterrupt(digitalPinToInterrupt(CLK), RotaryEncoderInterface::isr1, FALLING); } void RotaryEncoderInterface::updateEncoder() {