Skip to content
Open
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 43 additions & 0 deletions lib/interfaces/include/RotaryEncoderInterface.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
#ifndef ROTARYENCODERINTERFACE_H
#define ROTARYENCODERINTERFACE_H

#include <Arduino.h>
#include <Encoder.h> //LOOK INTO INCLUDE MORE
#include "CCUData.h"

#include "etl/singleton.h"
#include <etl/delegate.h>

#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 float encoder_value = 0;
unsigned long last_button_press = 0;
const float max_value = 120;
const float 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<RotaryEncoderInterface>;

#endif
3 changes: 3 additions & 0 deletions lib/interfaces/src/DisplayInterface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
47 changes: 47 additions & 0 deletions lib/interfaces/src/RotaryEncoderInterface.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
#include "RotaryEncoderInterface.h"
#include "CCUData.h"

const int bounce_delay = 50;

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 += 1.0;
}
} else {
if (_encoder_data.encoder_value > _encoder_data.min_value) {
_encoder_data.encoder_value -= 1.0;
}
}
}

void RotaryEncoderInterface::setupEncoder() {
_encoder_data.encoder_value = 0;
_encoder_data.state = false;
pinMode(CLK, INPUT_PULLUP);
pinMode(DT, INPUT_PULLUP);
pinMode(SW, INPUT_PULLUP);

attachInterrupt(digitalPinToInterrupt(2), RotaryEncoderInterface::isr1, FALLING);
}

void RotaryEncoderInterface::updateEncoder() {
int btn_state = digitalRead(SW);

noInterrupts();
float current_value = _encoder_data.encoder_value;
_ccu_data.encoder_value = current_value;
interrupts();

if (btn_state == LOW) {
if (millis() - _encoder_data.last_button_press > bounce_delay) {
_encoder_data.state = !_encoder_data.state;
}
_encoder_data.last_button_press = millis();
}
}
63 changes: 63 additions & 0 deletions lib/mock_interfaces/RotaryEncoderInterface.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
#ifndef ROTARYENCODERINTERFACE_H
#define ROTARYENCODERINTERFACE_H

#include "CCUData.h"
#include "mockArduino.h"

#include "etl/singleton.h"
#include <etl/delegate.h>

#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 float encoder_value = 0;
unsigned long last_button_press = 0;
const float max_value = 120;
const float min_value = 0;
};

class RotaryEncoderInterface
{
public:
RotaryEncoderInterface(CCUData &ccu_data) :
_ccu_data(ccu_data) {};

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; };

private:
rotary_encoder_s _encoder_data;
CCUData &_ccu_data;
};

using RotaryEncoderInterfaceInstance = etl::singleton<RotaryEncoderInterface>;

#endif
2 changes: 2 additions & 0 deletions lib/systems/include/MainChargeSystem.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@

#include "ACUInterface.h"

#include "RotaryEncoderInterface.h"

#include "SharedFirmwareTypes.h"

#ifdef TEENSY_OPT_SMALLEST_CODE
Expand Down
10 changes: 9 additions & 1 deletion lib/systems/src/MainChargeSystem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +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 = false;
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)
Expand All @@ -30,7 +32,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;
}

Expand All @@ -39,6 +45,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 == 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
}
Expand Down
4 changes: 3 additions & 1 deletion lib/utilities/CCUData.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ enum class ChargingState_e
{
NOT_CHARGING = 0,
CHARGING =1,
DONE_CHARGING =2
DONE_CHARGING =2,
MANUAL_CHARGING =3
};

struct CCUData
Expand All @@ -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;
Expand Down
1 change: 1 addition & 0 deletions test/test_charge_cycle.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

#include "MainChargeSystem.h"
#include "ACUInterface.h"
#include "RotaryEncoderInterface.h"
#include "ChargerInterface.h"
#include <gtest/gtest.h>
#include <iostream>
Expand Down
3 changes: 2 additions & 1 deletion test/test_maincharge.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include <gtest/gtest.h>
#include <gmock/gmock.h>
#include "test_charge_cycle.h"
#include "test_rotary_encoder.h"



Expand All @@ -11,4 +12,4 @@ int main(int argc, char **argv)
// Do nothing (always return 0 and allow PlatformIO to parse result)
}
return 0;
}
}
Loading