Files
TX/source/direct.c
2025-08-26 16:10:47 -05:00

295 lines
4.7 KiB
C

#include "direct.h"
#include "driver.h"
#include "ports.h"
#include "fgen.h"
#include "utils.h"
#include "System/system.h"
extern SYSTEM_DATA_t sys;
enum
{
SET_ALKALINE = 0,
SET_LITHIUM,
SET_HF,
NUM_SETPOINTS
};
static float _setpoints[NUM_SETPOINTS][POWER_LEVEL_COUNT] = {
{ 0.010, 0.050, 0.100, 0.150, 0.200 }, // Alkaline
{ 0.010, 0.050, 0.150, 0.400, 1.000 }, // Lithium
{ 0.010, 0.050, 0.100, 0.150, 0.200 } // HF
};
static const float DIRECT_KP = 10.1f;
static const float DIRECT_KI = 10.5f;
static const float DIRECT_KD = 0.0f;
enum
{
KP = 0,
KI,
KD,
TERM_COUNT
};
typedef struct
{
float k[TERM_COUNT];
float err;
float output;
float err_int;
float setpoint;
bool enabled;
} Controller_t;
static FREQUENCY_t * setFrequency(ACCESSORY_t *accy, FREQUENCY_t *freq)
{
// is this an appropriate frequency? if not, return one that is
return freq;
}
static int setPower(ACCESSORY_t *accy, PowerLevel_t power)
{
FREQUENCY_t *f = driver_getFrequency();
PowerLevel_t prevPower = driver_getPowerLevel();
Controller_t *controller = (Controller_t*)accy->data;
if (prevPower == POWER_LEVEL_0 && power > POWER_LEVEL_0)
{
driver_bypass(true);
driver_isolateOutput(false);
controller->enabled = true;
}
else
if (prevPower > POWER_LEVEL_0 && power == POWER_LEVEL_0)
{
driver_bypass(false);
driver_isolateOutput(true);
driver_setAmplitude(0);
controller->enabled = false;
}
if (driver_isLowFreq())
{
if (sys.batteryType == ALKALINE)
{
controller->setpoint = _setpoints[SET_ALKALINE][power];
}
else
{
controller->setpoint = _setpoints[SET_LITHIUM][power];
}
}
else
{
controller->setpoint = _setpoints[SET_HF][power];
}
#if 0
driver_setAmplitude(power * 20);
if (prevPower == POWER_LEVEL_0 && power > POWER_LEVEL_0)
{
driver_bypass(true);
driver_isolateOutput(false);
}
else
if (prevPower > POWER_LEVEL_0 && power == POWER_LEVEL_0)
{
driver_bypass(false);
driver_isolateOutput(true);
}
#endif
return 0;
}
static void regulate(ACCESSORY_t *accy)
{
Controller_t *c = (Controller_t*)accy->data;
// check for disconnect
if (accy->loadConnected)
{
if (sys.adc.Ohms_slowfilt > 10000)
{
driver_setAmplitude(20);
accy->loadConnected = false;
c->enabled = false;
}
}
else
{
if (sys.adc.Ohms_slowfilt < 3000)
{
driver_setAmplitude(20);
accy->loadConnected = true;
c->enabled = true;
}
}
if (!c->enabled)
{
return;
}
#if 0
float err = c->setpoint - sys.adc.I_OUT_SlowFilt;
float err_int = c->err_int + err;
c->output = err * c->k[KP] + err_int * c->k[KI];
if (c->output > 180.0f)
{
c->output = 180.0f;
}
else
{
c->err_int = err_int;
}
driver_setAmplitude((uint8_t)(c->output + 0.5f));
#endif
float targetCurrent = driver_maxLoadCurrent();
if (c->setpoint < targetCurrent)
{
targetCurrent = c->setpoint;
}
int pot = driver_getAmplitude();
int newPot = 3;
if (pot > 0)
{
newPot = (targetCurrent / sys.adc.I_OUT_SlowFilt) * pot; // Request divided by Pot current contents
}
// limit change to 20
if (newPot - pot > 20)
{
newPot = pot + 20;
}
else
if (newPot - pot < -20)
{
newPot = pot - 20;
}
if (newPot > 255)
{
newPot = 255;
}
// limit if the estimated voltage is over the maximum
driver_setAmplitude((uint8_t)newPot);
}
static void _stateInit(ACCESSORY_t *accy)
{
FREQUENCY_t *freq = driver_getFrequency();
if (accy->initState)
{
accy->setFrequency = setFrequency;
accy->setPower = setPower;
accy->signalPath = SIGNAL_PATH_AMP;
accy->driveVoltage[LOW_FREQ] = V_36V;
accy->driveVoltage[HIGH_FREQ] = V_24V;
driver_setFrequency(freq);
driver_broadcastOn(true);
ACCY_setTimeout(accy, 500);
}
if (ACCY_timedOut(accy))
{
accy->state = PORT_STATE_WAIT_FOR_DRIVER;
}
}
int direct_service(ACCESSORY_t *accy)
{
switch (accy->state)
{
case PORT_STATE_INIT:
{
_stateInit(accy);
break;
}
case PORT_STATE_DEINIT:
{
if (accy->initState)
{
accy->stateTimer = sys.systemTime + 500;
}
if (sys.systemTime >= accy->stateTimer)
{
accy->state = PORT_STATE_STANDBY;
}
break;
}
case PORT_STATE_WAIT_FOR_DRIVER:
{
if (driver_outputReady())
{
accy->state = PORT_STATE_RUNNING;
}
break;
}
case PORT_STATE_RUNNING:
{
if (accy->initState)
{
Controller_t *controller = (Controller_t*)accy->data;
controller->k[KP] = DIRECT_KP;
controller->k[KI] = DIRECT_KI;
controller->k[KD] = DIRECT_KD;
controller->err_int = 0.0f;
controller->enabled = false;
setPower(accy, driver_getPowerLevel());
}
regulate(accy);
break;
}
default:
return -1;
}
return 0;
}