295 lines
4.7 KiB
C
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;
|
||
|
|
}
|