250 lines
6.6 KiB
C++
250 lines
6.6 KiB
C++
#include "my_board.h"
|
|
|
|
#include <ArduinoJson.h>
|
|
#include <FS.h>
|
|
#include <LittleFS.h>
|
|
#include "global.h"
|
|
#include "JsonConstrain.h"
|
|
|
|
static const char* tag = "board";
|
|
PWM_Output *pwmOut[4];
|
|
RAMP_Output *RearLightControl;
|
|
|
|
void Init_Board_Pins(void)
|
|
{
|
|
pinMode(BoardLED1, OUTPUT);
|
|
pinMode(BoardLED2, OUTPUT);
|
|
|
|
pinMode(Button1_Pin, INPUT_PULLUP);
|
|
pinMode(Button2_Pin, INPUT_PULLUP);
|
|
pinMode(Button3_Pin, INPUT_PULLUP);
|
|
|
|
ESP_LOGV(tag, "Board pins initialized...");
|
|
}
|
|
|
|
void Init_PWM_Outputs(void)
|
|
{
|
|
File file = LittleFS.open("/cfg/relays.json");
|
|
if(!file){
|
|
ESP_LOGE(tag, "Error opening relays.json...");
|
|
}else{
|
|
StaticJsonDocument<1024> doc;
|
|
DeserializationError error = deserializeJson(doc, file);
|
|
if(!error){
|
|
file.close();
|
|
if(error){ ESP_LOGE(tag, "relays.json deserialize error!.."); return;}
|
|
|
|
JsonArray jsArray = doc["relays"];
|
|
|
|
if(jsArray.isNull() || jsArray.size() < 1 || jsArray.size() > 4 ) { return; }
|
|
|
|
int x = 0;
|
|
for(JsonObject obj : jsArray){
|
|
//Default config if keys are not found
|
|
if (!obj.containsKey("pin") || !obj.containsKey("freq") || !obj.containsKey("max") || !obj.containsKey("default")) {
|
|
pwmOut[x] = new PWM_Output(0, x, 12, 500, 100.0, false);
|
|
ESP_LOGD(tag, "pwmOut[%d] default config", x);
|
|
x++;
|
|
continue;
|
|
}
|
|
|
|
int pin;
|
|
switch(x){
|
|
case 0:
|
|
pin = jsonConstrainInt(obj, "pin", 0, 48, RELAY1_Pin);
|
|
break;
|
|
case 1:
|
|
pin = jsonConstrainInt(obj, "pin", 0, 48, RELAY2_Pin);
|
|
break;
|
|
case 2:
|
|
pin = jsonConstrainInt(obj, "pin", 0, 48, RELAY3_Pin);
|
|
break;
|
|
default:
|
|
pin = jsonConstrainInt(obj, "pin", 0, 48, RELAY4_Pin);
|
|
}
|
|
|
|
int freq = jsonConstrainInt(obj, "freq", 100, 2000, 500);
|
|
float maxVal = jsonConstrainInt(obj, "max", 2.0, 100.0, 95);
|
|
float defaultVal = jsonConstrainInt(obj, "default", 0.0, 100.0, 40);
|
|
ESP_LOGD(tag, "pwmOut[%d]: freq:%d, max:%F, default:%F", x, freq, maxVal, defaultVal);
|
|
|
|
pwmOut[x] = new PWM_Output(pin, x, RELAY_RES, freq, maxVal, false);
|
|
pwmOut[x]->setOutput(defaultVal);
|
|
x++;
|
|
}
|
|
}else{
|
|
ESP_LOGE(tag, "Deserialization error on relays.json");
|
|
}
|
|
}
|
|
}
|
|
|
|
int linearizeLED(float inp){
|
|
if(inp > 100.0){ inp = 100.0;};
|
|
return (inp*inp*0.4095f);
|
|
}
|
|
|
|
/******************* PWM_Output Definition ********************/
|
|
|
|
// max: 0-100%
|
|
PWM_Output::PWM_Output(uint8_t pin, uint8_t ch, int res, uint32_t freq, float maxDuty, bool visionCorrected)
|
|
{
|
|
this->currDuty = 0;
|
|
this->ch = ch;
|
|
this->maxDuty = maxDuty;
|
|
this->visionCorrected = visionCorrected;
|
|
this->freq = freq;
|
|
this->res = res;
|
|
//this->msecRampRate = msecRampRate;
|
|
pinMode(pin, OUTPUT);
|
|
if(!ledcSetup(ch, freq, res)) {
|
|
ESP_LOGE(tag, "pwmOut-> ch:%d ledcSetup failed!", ch);
|
|
return;
|
|
}
|
|
ledcAttachPin(pin, ch);
|
|
setOutput(this->currDuty);
|
|
}
|
|
|
|
// Range is 0 to 100%
|
|
void PWM_Output::setOutput(float duty)
|
|
{
|
|
if(duty > maxDuty) { duty = maxDuty;}
|
|
|
|
// calculate correct duty value
|
|
int outDutyVal;
|
|
if(this->visionCorrected){ outDutyVal = linearizeLED(duty); }
|
|
else{ outDutyVal = duty * 40.95f; }
|
|
|
|
// FIXME pwm output ramp cause a freeze here
|
|
// Smooth Transition to final duty value
|
|
/*
|
|
if(msecRampRate){
|
|
int d = this->currOutVal;
|
|
float dutyInc = (outDutyVal - this->currOutVal)/msecRampRate;
|
|
for(;;){
|
|
d += dutyInc;
|
|
if(d < 0){d = 0;}
|
|
if(d > 4095){d = 4095;}
|
|
ledcWrite(this->ch, d);
|
|
if(d >= outDutyVal || d <= 0){ break; }
|
|
vTaskDelay(msecRampRate);
|
|
}
|
|
ledcWrite(this->ch, outDutyVal);
|
|
this->currOutVal = outDutyVal;
|
|
}
|
|
else{
|
|
*/
|
|
ledcWrite(this->ch, outDutyVal);
|
|
this->currOutVal = outDutyVal;
|
|
//}
|
|
|
|
this->currDuty = duty;
|
|
}
|
|
|
|
void PWM_Output::setFreq(uint32_t fq)
|
|
{
|
|
uint32_t newFreq;
|
|
|
|
if(this->freq != fq){
|
|
newFreq = ledcChangeFrequency(this->ch, fq, this->res);
|
|
if(newFreq){
|
|
this->freq = fq;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/******************* RAMP_Output Definition ********************/
|
|
|
|
|
|
|
|
void Initialize_Rear_Control(int relayIndex, int buttonIndex, int rampTime, int steps, float min, float max){
|
|
RearLightControl = new RAMP_Output(pwmOut[relayIndex], btn[buttonIndex], rampTime, steps, min, max);
|
|
}
|
|
|
|
RAMP_Output *RAMP_Output::instance = nullptr; // Initialize the static member variable
|
|
|
|
void longPressStartCallback(void){
|
|
xTimerStart(RearLightControl->timerHandle, 0);
|
|
}
|
|
|
|
void longPressStopCallback(void){
|
|
xTimerStop(RearLightControl->timerHandle, 0);
|
|
RAMP_Output::instance->SwitchDirection(); // Call the non-static member function using the stored instance
|
|
}
|
|
|
|
void SingleClickCallback(void){
|
|
RAMP_Output::instance->ClickOnOff();
|
|
}
|
|
|
|
void RAMP_Output::TimerCallback(TimerHandle_t xTimer) {
|
|
RearLightControl->IncrementTick();
|
|
}
|
|
|
|
RAMP_Output::RAMP_Output(PWM_Output *output, OneButton *button, int rampTime, int steps, float min, float max) {
|
|
this->Output = output;
|
|
this->Button = button;
|
|
this->rampTime = rampTime;
|
|
this->steps = steps;
|
|
this->min = min;
|
|
this->max = max;
|
|
this->stepSize = (max - min) / steps;
|
|
|
|
ESP_LOGD(tag, "Rear Lights: stepSize= %.2f", stepSize);
|
|
|
|
instance = this; // Store the instance in the static member variable
|
|
|
|
if (this->Button) {
|
|
this->Button->attachLongPressStart(longPressStartCallback);
|
|
this->Button->attachLongPressStop(longPressStopCallback);
|
|
this->Button->attachClick(SingleClickCallback);
|
|
} else {
|
|
Serial.println("Error: Button is nullptr");
|
|
}
|
|
|
|
Output->visionCorrected = true;
|
|
Output->currDuty = min;
|
|
Output->setOutput(min);
|
|
|
|
timerHandle = xTimerCreate("RampTimer", pdMS_TO_TICKS(rampTime/8), pdTRUE, this, TimerCallback);
|
|
}
|
|
|
|
void RAMP_Output::ClickOnOff(void) {
|
|
if(IsOn){
|
|
IsOn = false;
|
|
Output->setOutput(0);
|
|
}else{
|
|
IsOn = true;
|
|
Output->setOutput(lastDuty);
|
|
}
|
|
}
|
|
|
|
void RAMP_Output::IncrementTick(void) {
|
|
if (dirFwd) {
|
|
// Increment output value while ensuring it doesn't exceed max
|
|
float newValue = std::min(Output->currDuty + stepSize, max);
|
|
Output->setOutput( newValue);
|
|
lastDuty = newValue;
|
|
//ESP_LOGD(tag, "up: %.2f", newValue);
|
|
} else {
|
|
// Decrement output value while ensuring it doesn't go below min
|
|
float newValue = std::max(Output->currDuty - stepSize, min);
|
|
Output->setOutput( newValue );
|
|
lastDuty = newValue;
|
|
//ESP_LOGD(tag, "down: %.2f", newValue);
|
|
}
|
|
}
|
|
|
|
void RAMP_Output::SwitchDirection(void) {
|
|
dirFwd = !dirFwd;
|
|
}
|
|
|
|
// Add destructor to clean up resources
|
|
RAMP_Output::~RAMP_Output() {
|
|
xTimerDelete(timerHandle, 0);
|
|
// Add any other necessary cleanup here
|
|
}
|
|
|
|
|
|
|