boothifier/src/PWM_Output.cpp

108 lines
2.8 KiB
C++

#include "PWM_Output.h"
#include <Arduino.h>
#include "global.h"
static const char* tag = "pwmout";
PWM_Output::PWM_Output(int8_t pin, uint8_t ch, uint8_t res, uint32_t freq, float maxDuty, bool visionCorrected){
this->currDuty = 0;
this->ch = ch;
this->maxDuty = maxDuty;
this->visionCorrected = visionCorrected;
this->freq = freq;
this->pin = pin;
setResolution(res);
pinMode(pin, OUTPUT);
uint32_t actualFreq = ledcSetup(ch, freq, res);
if (actualFreq != freq) {
ESP_LOGE(tag, "pwmOut-> ch:%d ledcSetup failed! Requested freq: %d, Actual freq: %d", ch, freq, actualFreq);
// continue but mark as uninitialized to prevent usage
this->initialized = false;
return;
}
ledcAttachPin(pin, ch);
setOutput(this->currDuty);
this->initialized = true;
}
void PWM_Output::setMaxDuty(float duty) {
// add any validation or constraints here
if(duty < 0) {
duty = 0.0;
}
else if(duty > 100.0) {
duty = 100.0;
}
maxDuty = duty;
}
// Range is 0 to 100%
void PWM_Output::setOutput(float duty){
if(!this->initialized){
ESP_LOGW(tag, "setOutput called on uninitialized PWM_Output (ch=%d)", this->ch);
return;
}
// Clamp the duty cycle to the range [0.0, maxDuty]
if (duty < 0.0) {
duty = 0.0;
} else if (duty > maxDuty) {
duty = maxDuty;
}
// calculate correct duty value
int outDutyVal;
if(this->visionCorrected){
outDutyVal = linearizeOutput(duty);
} else {
outDutyVal = static_cast<int>(duty * this->standardFactor);
}
// Clamp to valid resolution range [0, (1<<res)-1]
int maxVal = (this->res >= 31) ? INT32_MAX : ((1 << this->res) - 1);
if (outDutyVal < 0) outDutyVal = 0;
if (outDutyVal > maxVal) outDutyVal = maxVal;
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 > 0){
this->freq = newFreq;
} else {
ESP_LOGW(tag, "ledcChangeFrequency failed for ch:%d requested:%u", this->ch, fq);
}
}
}
void PWM_Output::setResolution(uint8_t res){
this->res = res;
if(this->res < 4) this->res = 4;
if(this->res > 16) this->res = 16;
// Use the clamped resolution when computing factors
int maxVal = (this->res >= 31) ? INT32_MAX : ((1 << this->res) - 1);
this->standardFactor = static_cast<float>(maxVal) * 0.01f;
this->visionFactor = static_cast<float>(maxVal) * 0.0001f;
ESP_LOGD(tag, "factor=%f, vision=%f", this->standardFactor, this->visionFactor);
}
int PWM_Output::linearizeOutput(float inp){
if (inp < 0.0) {
inp = 0.0;
} else if (inp > 100.0) {
inp = 100.0;
}
return static_cast<int>(inp * inp * this->visionFactor);
}
int PWM_Output::getOutVal(void){
return ledcRead(this->ch);
}