From ef75e4e1f1e9d16153225cd2b9acd1c2d0c89bae Mon Sep 17 00:00:00 2001 From: Collin Kidder Date: Thu, 7 Jul 2016 13:46:55 -0400 Subject: [PATCH] Restylized all source files to be harmonized. --- BatteryManager.cpp | 28 +- BatteryManager.h | 50 +- BrusaMotorController.cpp | 366 ++++---- BrusaMotorController.h | 230 +++--- CanBrake.cpp | 244 +++--- CanBrake.h | 40 +- CanHandler.cpp | 254 +++--- CanHandler.h | 64 +- CanPIDListener.cpp | 440 +++++----- CanPIDListener.h | 30 +- CanThrottle.cpp | 240 +++--- CanThrottle.h | 42 +- CodaMotorController.cpp | 433 +++++----- CodaMotorController.h | 42 +- DCDCController.cpp | 101 +-- DCDCController.h | 32 +- Device.cpp | 34 +- Device.h | 32 +- DeviceManager.cpp | 334 ++++---- DeviceManager.h | 54 +- DeviceTypes.h | 62 +- DmocMotorController.cpp | 628 +++++++------- DmocMotorController.h | 70 +- ELM327Processor.cpp | 198 ++--- ELM327Processor.h | 12 +- ELM327_Emu.cpp | 146 ++-- ELM327_Emu.h | 22 +- EVIC.cpp | 707 ++++++++-------- EVIC.h | 94 +-- FaultCodes.h | 244 +++--- FaultHandler.cpp | 396 ++++----- FaultHandler.h | 58 +- Heartbeat.cpp | 88 +- Heartbeat.h | 18 +- Logger.cpp | 380 ++++----- Logger.h | 42 +- MemCache.cpp | 486 +++++------ MemCache.h | 88 +- MotorController.cpp | 794 +++++++++--------- MotorController.h | 268 +++--- OBD2Handler.cpp | 336 ++++---- OBD2Handler.h | 22 +- PotBrake.cpp | 176 ++-- PotBrake.h | 24 +- PotThrottle.cpp | 374 ++++----- PotThrottle.h | 40 +- PrefHandler.cpp | 240 +++--- PrefHandler.h | 44 +- SerialConsole.cpp | 1698 +++++++++++++++++++------------------- SerialConsole.h | 32 +- Sys_Messages.h | 16 +- ThinkBatteryManager.cpp | 246 +++--- ThinkBatteryManager.h | 26 +- Throttle.cpp | 182 ++-- Throttle.h | 70 +- ThrottleDetector.cpp | 532 ++++++------ ThrottleDetector.h | 104 +-- TickHandler.cpp | 198 ++--- TickHandler.h | 36 +- constants.h | 136 +-- eeprom_layout.h | 10 +- ichip_2128.cpp | 1576 ++++++++++++++++++----------------- ichip_2128.h | 124 +-- sys_io.cpp | 817 +++++++++--------- sys_io.h | 10 +- 65 files changed, 7573 insertions(+), 7387 deletions(-) diff --git a/BatteryManager.cpp b/BatteryManager.cpp index 95eb470..ebeea2c 100644 --- a/BatteryManager.cpp +++ b/BatteryManager.cpp @@ -24,22 +24,22 @@ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ + */ #include "BatteryManager.h" - -BatteryManager::BatteryManager() : Device() + +BatteryManager::BatteryManager() : Device() { - packVoltage = 0; - packCurrent = 0; + packVoltage = 0; + packCurrent = 0; } -BatteryManager::~BatteryManager() +BatteryManager::~BatteryManager() { } DeviceType BatteryManager::getType() { - return (DEVICE_BMS); + return (DEVICE_BMS); } void BatteryManager::handleTick() { @@ -47,11 +47,11 @@ void BatteryManager::handleTick() { void BatteryManager::setup() { #ifndef USE_HARD_CODED - if (prefsHandler->checksumValid()) { //checksum is good, read in the values stored in EEPROM - } - else { //checksum invalid. Reinitialize values and store to EEPROM - //prefsHandler->saveChecksum(); - } + if (prefsHandler->checksumValid()) { //checksum is good, read in the values stored in EEPROM + } + else { //checksum invalid. Reinitialize values and store to EEPROM + //prefsHandler->saveChecksum(); + } #else #endif @@ -62,12 +62,12 @@ void BatteryManager::setup() { int BatteryManager::getPackVoltage() { - return packVoltage; + return packVoltage; } signed int BatteryManager::getPackCurrent() { - return packCurrent; + return packCurrent; } diff --git a/BatteryManager.h b/BatteryManager.h index bf1d761..a1efb1d 100644 --- a/BatteryManager.h +++ b/BatteryManager.h @@ -24,8 +24,8 @@ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - + */ + #ifndef BATTMANAGE_H_ #define BATTMANAGE_H_ @@ -35,32 +35,32 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. class BatteryManager : public Device { public: - BatteryManager(); - ~BatteryManager(); - int getPackVoltage(); //in tenths of a volt - signed int getPackCurrent(); //in tenths of an amp - //bool allowCharging(); - //bool allowDischarging(); - DeviceType getType(); + BatteryManager(); + ~BatteryManager(); + int getPackVoltage(); //in tenths of a volt + signed int getPackCurrent(); //in tenths of an amp + //bool allowCharging(); + //bool allowDischarging(); + DeviceType getType(); void setup(); void handleTick(); - //a bunch of boolean functions. Derived classes must implment - //these functions to tell everyone else what they support - virtual bool hasPackVoltage() = 0; - virtual bool hasPackCurrent() = 0; - virtual bool hasTemperatures() = 0; - virtual bool isChargeOK() = 0; - virtual bool isDischargeOK() = 0; + //a bunch of boolean functions. Derived classes must implment + //these functions to tell everyone else what they support + virtual bool hasPackVoltage() = 0; + virtual bool hasPackCurrent() = 0; + virtual bool hasTemperatures() = 0; + virtual bool isChargeOK() = 0; + virtual bool isDischargeOK() = 0; protected: - int packVoltage; //tenths of a volt - signed int packCurrent; //tenths of an amp - int SOC; //state of charge in percent - int lowestCellV, highestCellV; //in mv - int lowestCellTemp, highestCellTemp; - //should be some form of discharge and charge limit. I don't know if it should be % or amps - //some BMS systems will report one way and some the other. - int dischargeLimit, chargeLimit; - bool allowCharge, allowDischarge; + int packVoltage; //tenths of a volt + signed int packCurrent; //tenths of an amp + int SOC; //state of charge in percent + int lowestCellV, highestCellV; //in mv + int lowestCellTemp, highestCellTemp; + //should be some form of discharge and charge limit. I don't know if it should be % or amps + //some BMS systems will report one way and some the other. + int dischargeLimit, chargeLimit; + bool allowCharge, allowDischarge; private: }; diff --git a/BrusaMotorController.cpp b/BrusaMotorController.cpp index 1c278c2..c012986 100644 --- a/BrusaMotorController.cpp +++ b/BrusaMotorController.cpp @@ -38,33 +38,33 @@ * Constructor */ BrusaMotorController::BrusaMotorController() : MotorController() { - prefsHandler = new PrefHandler(BRUSA_DMC5); - torqueAvailable = 0; - maxPositiveTorque = 0; - minNegativeTorque = 0; - limiterStateNumber = 0; + prefsHandler = new PrefHandler(BRUSA_DMC5); + torqueAvailable = 0; + maxPositiveTorque = 0; + minNegativeTorque = 0; + limiterStateNumber = 0; - tickCounter = 0; + tickCounter = 0; - commonName = "Brusa DMC5 Inverter"; + commonName = "Brusa DMC5 Inverter"; } /* * Setup the device if it is enabled in configuration. */ void BrusaMotorController::setup() { - TickHandler::getInstance()->detach(this); + TickHandler::getInstance()->detach(this); - Logger::info("add device: Brusa DMC5 (id: %X, %X)", BRUSA_DMC5, this); + Logger::info("add device: Brusa DMC5 (id: %X, %X)", BRUSA_DMC5, this); - loadConfiguration(); - MotorController::setup(); // run the parent class version of this function + loadConfiguration(); + MotorController::setup(); // run the parent class version of this function - // register ourselves as observer of 0x258-0x268 and 0x458 can frames - CanHandler::getInstanceEV()->attach(this, CAN_MASKED_ID_1, CAN_MASK_1, false); - CanHandler::getInstanceEV()->attach(this, CAN_MASKED_ID_2, CAN_MASK_2, false); + // register ourselves as observer of 0x258-0x268 and 0x458 can frames + CanHandler::getInstanceEV()->attach(this, CAN_MASKED_ID_1, CAN_MASK_1, false); + CanHandler::getInstanceEV()->attach(this, CAN_MASKED_ID_2, CAN_MASK_2, false); - TickHandler::getInstance()->attach(this, CFG_TICK_INTERVAL_MOTOR_CONTROLLER_BRUSA); + TickHandler::getInstance()->attach(this, CFG_TICK_INTERVAL_MOTOR_CONTROLLER_BRUSA); } /* @@ -74,15 +74,15 @@ void BrusaMotorController::setup() { * brake and decides which one to apply. */ void BrusaMotorController::handleTick() { - MotorController::handleTick(); // call parent - tickCounter++; - - sendControl(); // send CTRL every 20ms - if (tickCounter > 4) { - sendControl2(); // send CTRL_2 every 100ms - sendLimits(); // send LIMIT every 100ms - tickCounter = 0; - } + MotorController::handleTick(); // call parent + tickCounter++; + + sendControl(); // send CTRL every 20ms + if (tickCounter > 4) { + sendControl2(); // send CTRL_2 every 100ms + sendLimits(); // send LIMIT every 100ms + tickCounter = 0; + } } /* @@ -92,46 +92,46 @@ void BrusaMotorController::handleTick() { * in case errors were detected and requests the desired torque / speed. */ void BrusaMotorController::sendControl() { - BrusaMotorControllerConfiguration *config = (BrusaMotorControllerConfiguration *)getConfiguration(); - prepareOutputFrame(CAN_ID_CONTROL); - - speedRequested = 0; - torqueRequested = 0; - - outputFrame.data.bytes[0] = enablePositiveTorqueSpeed; // | enableNegativeTorqueSpeed; - if (faulted) { - outputFrame.data.bytes[0] |= clearErrorLatch; - } else { - if ((running || speedActual > 1000) && !getDigital(1)) { // see warning about field weakening current to prevent uncontrollable regen - outputFrame.data.bytes[0] |= enablePowerStage; - } - if (running) { - if (config->enableOscillationLimiter) - outputFrame.data.bytes[0] |= enableOscillationLimiter; - - if (powerMode == modeSpeed) { - outputFrame.data.bytes[0] |= enableSpeedMode; - speedRequested = throttleRequested * config->speedMax / 1000; - torqueRequested = config->torqueMax; // positive number used for both speed directions - } else { // torque mode - speedRequested = config->speedMax; // positive number used for both torque directions - torqueRequested = throttleRequested * config->torqueMax / 1000; - } - - // set the speed in rpm - outputFrame.data.bytes[2] = (speedRequested & 0xFF00) >> 8; - outputFrame.data.bytes[3] = (speedRequested & 0x00FF); - - // set the torque in 0.01Nm (GEVCU uses 0.1Nm -> multiply by 10) - outputFrame.data.bytes[4] = ((torqueRequested * 10) & 0xFF00) >> 8; - outputFrame.data.bytes[5] = ((torqueRequested * 10) & 0x00FF); - } - } - - if (Logger::isDebug()) - Logger::debug(BRUSA_DMC5, "requested Speed: %l rpm, requested Torque: %f Nm", speedRequested, (float)torqueRequested/10.0F); - - CanHandler::getInstanceEV()->sendFrame(outputFrame); + BrusaMotorControllerConfiguration *config = (BrusaMotorControllerConfiguration *)getConfiguration(); + prepareOutputFrame(CAN_ID_CONTROL); + + speedRequested = 0; + torqueRequested = 0; + + outputFrame.data.bytes[0] = enablePositiveTorqueSpeed; // | enableNegativeTorqueSpeed; + if (faulted) { + outputFrame.data.bytes[0] |= clearErrorLatch; + } else { + if ((running || speedActual > 1000) && !getDigital(1)) { // see warning about field weakening current to prevent uncontrollable regen + outputFrame.data.bytes[0] |= enablePowerStage; + } + if (running) { + if (config->enableOscillationLimiter) + outputFrame.data.bytes[0] |= enableOscillationLimiter; + + if (powerMode == modeSpeed) { + outputFrame.data.bytes[0] |= enableSpeedMode; + speedRequested = throttleRequested * config->speedMax / 1000; + torqueRequested = config->torqueMax; // positive number used for both speed directions + } else { // torque mode + speedRequested = config->speedMax; // positive number used for both torque directions + torqueRequested = throttleRequested * config->torqueMax / 1000; + } + + // set the speed in rpm + outputFrame.data.bytes[2] = (speedRequested & 0xFF00) >> 8; + outputFrame.data.bytes[3] = (speedRequested & 0x00FF); + + // set the torque in 0.01Nm (GEVCU uses 0.1Nm -> multiply by 10) + outputFrame.data.bytes[4] = ((torqueRequested * 10) & 0xFF00) >> 8; + outputFrame.data.bytes[5] = ((torqueRequested * 10) & 0x00FF); + } + } + + if (Logger::isDebug()) + Logger::debug(BRUSA_DMC5, "requested Speed: %l rpm, requested Torque: %f Nm", speedRequested, (float)torqueRequested/10.0F); + + CanHandler::getInstanceEV()->sendFrame(outputFrame); } /* @@ -140,19 +140,19 @@ void BrusaMotorController::sendControl() { * This message controls the mechanical power limits for motor- and regen-mode. */ void BrusaMotorController::sendControl2() { - BrusaMotorControllerConfiguration *config = (BrusaMotorControllerConfiguration *)getConfiguration(); - - prepareOutputFrame(CAN_ID_CONTROL_2); - outputFrame.data.bytes[0] = ((config->torqueSlewRate * 10) & 0xFF00) >> 8; - outputFrame.data.bytes[1] = ((config->torqueSlewRate * 10) & 0x00FF); - outputFrame.data.bytes[2] = (config->speedSlewRate & 0xFF00) >> 8; - outputFrame.data.bytes[3] = (config->speedSlewRate & 0x00FF); - outputFrame.data.bytes[4] = (config->maxMechanicalPowerMotor & 0xFF00) >> 8; - outputFrame.data.bytes[5] = (config->maxMechanicalPowerMotor & 0x00FF); - outputFrame.data.bytes[6] = (config->maxMechanicalPowerRegen & 0xFF00) >> 8; - outputFrame.data.bytes[7] = (config->maxMechanicalPowerRegen & 0x00FF); - - CanHandler::getInstanceEV()->sendFrame(outputFrame); + BrusaMotorControllerConfiguration *config = (BrusaMotorControllerConfiguration *)getConfiguration(); + + prepareOutputFrame(CAN_ID_CONTROL_2); + outputFrame.data.bytes[0] = ((config->torqueSlewRate * 10) & 0xFF00) >> 8; + outputFrame.data.bytes[1] = ((config->torqueSlewRate * 10) & 0x00FF); + outputFrame.data.bytes[2] = (config->speedSlewRate & 0xFF00) >> 8; + outputFrame.data.bytes[3] = (config->speedSlewRate & 0x00FF); + outputFrame.data.bytes[4] = (config->maxMechanicalPowerMotor & 0xFF00) >> 8; + outputFrame.data.bytes[5] = (config->maxMechanicalPowerMotor & 0x00FF); + outputFrame.data.bytes[6] = (config->maxMechanicalPowerRegen & 0xFF00) >> 8; + outputFrame.data.bytes[7] = (config->maxMechanicalPowerRegen & 0x00FF); + + CanHandler::getInstanceEV()->sendFrame(outputFrame); } /* @@ -161,19 +161,19 @@ void BrusaMotorController::sendControl2() { * This message controls the electrical limits in the controller. */ void BrusaMotorController::sendLimits() { - BrusaMotorControllerConfiguration *config = (BrusaMotorControllerConfiguration *)getConfiguration(); - - prepareOutputFrame(CAN_ID_LIMIT); - outputFrame.data.bytes[0] = (config->dcVoltLimitMotor & 0xFF00) >> 8; - outputFrame.data.bytes[1] = (config->dcVoltLimitMotor & 0x00FF); - outputFrame.data.bytes[2] = (config->dcVoltLimitRegen & 0xFF00) >> 8; - outputFrame.data.bytes[3] = (config->dcVoltLimitRegen & 0x00FF); - outputFrame.data.bytes[4] = (config->dcCurrentLimitMotor & 0xFF00) >> 8; - outputFrame.data.bytes[5] = (config->dcCurrentLimitMotor & 0x00FF); - outputFrame.data.bytes[6] = (config->dcCurrentLimitRegen & 0xFF00) >> 8; - outputFrame.data.bytes[7] = (config->dcCurrentLimitRegen & 0x00FF); - - CanHandler::getInstanceEV()->sendFrame(outputFrame); + BrusaMotorControllerConfiguration *config = (BrusaMotorControllerConfiguration *)getConfiguration(); + + prepareOutputFrame(CAN_ID_LIMIT); + outputFrame.data.bytes[0] = (config->dcVoltLimitMotor & 0xFF00) >> 8; + outputFrame.data.bytes[1] = (config->dcVoltLimitMotor & 0x00FF); + outputFrame.data.bytes[2] = (config->dcVoltLimitRegen & 0xFF00) >> 8; + outputFrame.data.bytes[3] = (config->dcVoltLimitRegen & 0x00FF); + outputFrame.data.bytes[4] = (config->dcCurrentLimitMotor & 0xFF00) >> 8; + outputFrame.data.bytes[5] = (config->dcCurrentLimitMotor & 0x00FF); + outputFrame.data.bytes[6] = (config->dcCurrentLimitRegen & 0xFF00) >> 8; + outputFrame.data.bytes[7] = (config->dcCurrentLimitRegen & 0x00FF); + + CanHandler::getInstanceEV()->sendFrame(outputFrame); } /* @@ -181,18 +181,18 @@ void BrusaMotorController::sendLimits() { * Re-sets all parameters in the re-used frame. */ void BrusaMotorController::prepareOutputFrame(uint32_t id) { - outputFrame.length = 8; - outputFrame.id = id; - outputFrame.extended = 0; - outputFrame.rtr = 0; - - outputFrame.data.bytes[1] = 0; - outputFrame.data.bytes[2] = 0; - outputFrame.data.bytes[3] = 0; - outputFrame.data.bytes[4] = 0; - outputFrame.data.bytes[5] = 0; - outputFrame.data.bytes[6] = 0; - outputFrame.data.bytes[7] = 0; + outputFrame.length = 8; + outputFrame.id = id; + outputFrame.extended = 0; + outputFrame.rtr = 0; + + outputFrame.data.bytes[1] = 0; + outputFrame.data.bytes[2] = 0; + outputFrame.data.bytes[3] = 0; + outputFrame.data.bytes[4] = 0; + outputFrame.data.bytes[5] = 0; + outputFrame.data.bytes[6] = 0; + outputFrame.data.bytes[7] = 0; } /* @@ -203,25 +203,25 @@ void BrusaMotorController::prepareOutputFrame(uint32_t id) { * the incoming message is processed. */ void BrusaMotorController::handleCanFrame( CAN_FRAME *frame) { - switch (frame->id) { - case CAN_ID_STATUS: - processStatus(frame->data.bytes); - break; - case CAN_ID_ACTUAL_VALUES: - processActualValues(frame->data.bytes); - break; - case CAN_ID_ERRORS: - processErrors(frame->data.bytes); - break; - case CAN_ID_TORQUE_LIMIT: - processTorqueLimit(frame->data.bytes); - break; - case CAN_ID_TEMP: - processTemperature(frame->data.bytes); - break; - default: - Logger::warn(BRUSA_DMC5, "received unknown frame id %X", frame->id); - } + switch (frame->id) { + case CAN_ID_STATUS: + processStatus(frame->data.bytes); + break; + case CAN_ID_ACTUAL_VALUES: + processActualValues(frame->data.bytes); + break; + case CAN_ID_ERRORS: + processErrors(frame->data.bytes); + break; + case CAN_ID_TORQUE_LIMIT: + processTorqueLimit(frame->data.bytes); + break; + case CAN_ID_TEMP: + processTemperature(frame->data.bytes); + break; + default: + Logger::warn(BRUSA_DMC5, "received unknown frame id %X", frame->id); + } } /* @@ -231,18 +231,18 @@ void BrusaMotorController::handleCanFrame( CAN_FRAME *frame) { * available and current torque and speed. */ void BrusaMotorController::processStatus(uint8_t data[]) { - statusBitfield1 = (uint32_t)(data[1] | (data[0] << 8)); - torqueAvailable = (int16_t)(data[3] | (data[2] << 8)) / 10; - torqueActual = (int16_t)(data[5] | (data[4] << 8)) / 10; - speedActual = (int16_t)(data[7] | (data[6] << 8)); - - if(Logger::isDebug()) - Logger::debug(BRUSA_DMC5, "status: %X, torque avail: %fNm, actual torque: %fNm, speed actual: %drpm", statusBitfield1, (float)torqueAvailable/100.0F, (float)torqueActual/100.0F, speedActual); - - ready = (statusBitfield1 & stateReady) != 0 ? true : false; - running = (statusBitfield1 & stateRunning) != 0 ? true : false; - faulted = (statusBitfield1 & errorFlag) != 0 ? true : false; - warning = (statusBitfield1 & warningFlag) != 0 ? true : false; + statusBitfield1 = (uint32_t)(data[1] | (data[0] << 8)); + torqueAvailable = (int16_t)(data[3] | (data[2] << 8)) / 10; + torqueActual = (int16_t)(data[5] | (data[4] << 8)) / 10; + speedActual = (int16_t)(data[7] | (data[6] << 8)); + + if(Logger::isDebug()) + Logger::debug(BRUSA_DMC5, "status: %X, torque avail: %fNm, actual torque: %fNm, speed actual: %drpm", statusBitfield1, (float)torqueAvailable/100.0F, (float)torqueActual/100.0F, speedActual); + + ready = (statusBitfield1 & stateReady) != 0 ? true : false; + running = (statusBitfield1 & stateRunning) != 0 ? true : false; + faulted = (statusBitfield1 & errorFlag) != 0 ? true : false; + warning = (statusBitfield1 & warningFlag) != 0 ? true : false; } /* @@ -252,13 +252,13 @@ void BrusaMotorController::processStatus(uint8_t data[]) { * applied mechanical power. */ void BrusaMotorController::processActualValues(uint8_t data[]) { - dcVoltage = (uint16_t)(data[1] | (data[0] << 8)); - dcCurrent = (int16_t)(data[3] | (data[2] << 8)); - acCurrent = (uint16_t)(data[5] | (data[4] << 8)) / 2.5; - mechanicalPower = (int16_t)(data[7] | (data[6] << 8)) / 6.25; + dcVoltage = (uint16_t)(data[1] | (data[0] << 8)); + dcCurrent = (int16_t)(data[3] | (data[2] << 8)); + acCurrent = (uint16_t)(data[5] | (data[4] << 8)) / 2.5; + mechanicalPower = (int16_t)(data[7] | (data[6] << 8)) / 6.25; - if (Logger::isDebug()) - Logger::debug(BRUSA_DMC5, "actual values: DC Volts: %fV, DC current: %fA, AC current: %fA, mechPower: %fkW", (float)dcVoltage / 10.0F, (float)dcCurrent / 10.0F, (float)acCurrent / 10.0F, (float)mechanicalPower / 10.0F); + if (Logger::isDebug()) + Logger::debug(BRUSA_DMC5, "actual values: DC Volts: %fV, DC current: %fA, AC current: %fA, mechPower: %fkW", (float)dcVoltage / 10.0F, (float)dcCurrent / 10.0F, (float)acCurrent / 10.0F, (float)mechanicalPower / 10.0F); } /* @@ -269,11 +269,11 @@ void BrusaMotorController::processActualValues(uint8_t data[]) { * (e.g. the webserver to display the various status flags) */ void BrusaMotorController::processErrors(uint8_t data[]) { - statusBitfield3 = (uint32_t)(data[1] | (data[0] << 8) | (data[5] << 16) | (data[4] << 24)); - statusBitfield2 = (uint32_t)(data[7] | (data[6] << 8)); + statusBitfield3 = (uint32_t)(data[1] | (data[0] << 8) | (data[5] << 16) | (data[4] << 24)); + statusBitfield2 = (uint32_t)(data[7] | (data[6] << 8)); - if (Logger::isDebug()) - Logger::debug(BRUSA_DMC5, "errors: %X, warning: %X", statusBitfield3, statusBitfield2); + if (Logger::isDebug()) + Logger::debug(BRUSA_DMC5, "errors: %X, warning: %X", statusBitfield3, statusBitfield2); } /* @@ -282,12 +282,12 @@ void BrusaMotorController::processErrors(uint8_t data[]) { * This message provides information about available torque. */ void BrusaMotorController::processTorqueLimit(uint8_t data[]) { - maxPositiveTorque = (int16_t)(data[1] | (data[0] << 8)) / 10; - minNegativeTorque = (int16_t)(data[3] | (data[2] << 8)) / 10; - limiterStateNumber = (uint8_t)data[4]; + maxPositiveTorque = (int16_t)(data[1] | (data[0] << 8)) / 10; + minNegativeTorque = (int16_t)(data[3] | (data[2] << 8)) / 10; + limiterStateNumber = (uint8_t)data[4]; - if (Logger::isDebug()) - Logger::debug(BRUSA_DMC5, "torque limit: max positive: %fNm, min negative: %fNm", (float) maxPositiveTorque / 10.0F, (float) minNegativeTorque / 10.0F, limiterStateNumber); + if (Logger::isDebug()) + Logger::debug(BRUSA_DMC5, "torque limit: max positive: %fNm, min negative: %fNm", (float) maxPositiveTorque / 10.0F, (float) minNegativeTorque / 10.0F, limiterStateNumber); } /* @@ -296,26 +296,26 @@ void BrusaMotorController::processTorqueLimit(uint8_t data[]) { * This message provides information about motor and inverter temperatures. */ void BrusaMotorController::processTemperature(uint8_t data[]) { - temperatureInverter = (int16_t)(data[1] | (data[0] << 8)) * 5; - temperatureMotor = (int16_t)(data[3] | (data[2] << 8)) * 5; - temperatureSystem = (int16_t)(data[4] - 50) * 10; + temperatureInverter = (int16_t)(data[1] | (data[0] << 8)) * 5; + temperatureMotor = (int16_t)(data[3] | (data[2] << 8)) * 5; + temperatureSystem = (int16_t)(data[4] - 50) * 10; - if (Logger::isDebug()) - Logger::debug(BRUSA_DMC5, "temperature: inverter: %fC, motor: %fC, system: %fC", (float)temperatureInverter / 10.0F, (float)temperatureMotor / 10.0F, (float)temperatureSystem / 10.0F); + if (Logger::isDebug()) + Logger::debug(BRUSA_DMC5, "temperature: inverter: %fC, motor: %fC, system: %fC", (float)temperatureInverter / 10.0F, (float)temperatureMotor / 10.0F, (float)temperatureSystem / 10.0F); } /* * Return the device id of this device */ DeviceId BrusaMotorController::getId() { - return BRUSA_DMC5; + return BRUSA_DMC5; } /* * Expose the tick interval of this controller */ uint32_t BrusaMotorController::getTickInterval() { - return CFG_TICK_INTERVAL_MOTOR_CONTROLLER_BRUSA; + return CFG_TICK_INTERVAL_MOTOR_CONTROLLER_BRUSA; } /* @@ -324,49 +324,49 @@ uint32_t BrusaMotorController::getTickInterval() { * If not available or the checksum is invalid, default values are chosen. */ void BrusaMotorController::loadConfiguration() { - BrusaMotorControllerConfiguration *config = (BrusaMotorControllerConfiguration *)getConfiguration(); + BrusaMotorControllerConfiguration *config = (BrusaMotorControllerConfiguration *)getConfiguration(); - if(!config) { // as lowest sub-class make sure we have a config object - config = new BrusaMotorControllerConfiguration(); - setConfiguration(config); - } + if(!config) { // as lowest sub-class make sure we have a config object + config = new BrusaMotorControllerConfiguration(); + setConfiguration(config); + } - MotorController::loadConfiguration(); // call parent + MotorController::loadConfiguration(); // call parent #ifdef USE_HARD_CODED - if (false) { + if (false) { #else // if (prefsHandler->checksumValid()) { //checksum is good, read in the values stored in EEPROM - if (false) { //TODO: use eeprom, not fixed values + if (false) { //TODO: use eeprom, not fixed values #endif - Logger::debug(BRUSA_DMC5, (char *)Constants::validChecksum); + Logger::debug(BRUSA_DMC5, (char *)Constants::validChecksum); // prefsHandler->read(EEMC_, &config->minimumLevel1); - } else { //checksum invalid. Reinitialize values and store to EEPROM - Logger::warn(BRUSA_DMC5, (char *)Constants::invalidChecksum); - config->maxMechanicalPowerMotor = 50000; - config->maxMechanicalPowerRegen = 0; //TODO: 50000; don't want regen yet ! - - config->dcVoltLimitMotor = 1000; - config->dcVoltLimitRegen = 0;//TODO: 1000; don't want regen yet !; - config->dcCurrentLimitMotor = 0; - config->dcCurrentLimitRegen = 0; - config->enableOscillationLimiter = false; - saveConfiguration(); - } - Logger::debug(BRUSA_DMC5, "Max mech power motor: %d kW, max mech power regen: %d ", config->maxMechanicalPowerMotor, config->maxMechanicalPowerRegen); - Logger::debug(BRUSA_DMC5, "DC limit motor: %d Volt, DC limit regen: %d Volt", config->dcVoltLimitMotor, config->dcVoltLimitRegen); - Logger::debug(BRUSA_DMC5, "DC limit motor: %d Amps, DC limit regen: %d Amps", config->dcCurrentLimitMotor, config->dcCurrentLimitRegen); + } else { //checksum invalid. Reinitialize values and store to EEPROM + Logger::warn(BRUSA_DMC5, (char *)Constants::invalidChecksum); + config->maxMechanicalPowerMotor = 50000; + config->maxMechanicalPowerRegen = 0; //TODO: 50000; don't want regen yet ! + + config->dcVoltLimitMotor = 1000; + config->dcVoltLimitRegen = 0;//TODO: 1000; don't want regen yet !; + config->dcCurrentLimitMotor = 0; + config->dcCurrentLimitRegen = 0; + config->enableOscillationLimiter = false; + saveConfiguration(); + } + Logger::debug(BRUSA_DMC5, "Max mech power motor: %d kW, max mech power regen: %d ", config->maxMechanicalPowerMotor, config->maxMechanicalPowerRegen); + Logger::debug(BRUSA_DMC5, "DC limit motor: %d Volt, DC limit regen: %d Volt", config->dcVoltLimitMotor, config->dcVoltLimitRegen); + Logger::debug(BRUSA_DMC5, "DC limit motor: %d Amps, DC limit regen: %d Amps", config->dcCurrentLimitMotor, config->dcCurrentLimitRegen); } /* * Store the current configuration parameters to EEPROM. */ void BrusaMotorController::saveConfiguration() { - BrusaMotorControllerConfiguration *config = (BrusaMotorControllerConfiguration *)getConfiguration(); + BrusaMotorControllerConfiguration *config = (BrusaMotorControllerConfiguration *)getConfiguration(); - MotorController::saveConfiguration(); // call parent + MotorController::saveConfiguration(); // call parent - //TODO: store to eeprom + //TODO: store to eeprom // prefsHandler->write(EEMC_, config->maxMechanicalPowerMotor); // prefsHandler->write(EEMC_, config->maxMechanicalPowerRegen); // prefsHandler->write(EEMC_, config->dcVoltLimitMotor); @@ -374,7 +374,7 @@ void BrusaMotorController::saveConfiguration() { // prefsHandler->write(EEMC_, config->dcCurrentLimitMotor); // prefsHandler->write(EEMC_, config->dcCurrentLimitRegen); // prefsHandler->write(EEMC_, config->enableOscillationLimiter); - prefsHandler->saveChecksum(); + prefsHandler->saveChecksum(); } diff --git a/BrusaMotorController.h b/BrusaMotorController.h index 10a49ca..6a5b40e 100644 --- a/BrusaMotorController.h +++ b/BrusaMotorController.h @@ -59,129 +59,129 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. class BrusaMotorControllerConfiguration : public MotorControllerConfiguration { public: - // DMC_CTRL2 - uint16_t maxMechanicalPowerMotor; // maximal mechanical power of motor in 4W steps - uint16_t maxMechanicalPowerRegen; // maximal mechanical power of regen in 4W steps + // DMC_CTRL2 + uint16_t maxMechanicalPowerMotor; // maximal mechanical power of motor in 4W steps + uint16_t maxMechanicalPowerRegen; // maximal mechanical power of regen in 4W steps - // DMC_LIM - uint16_t dcVoltLimitMotor; // minimum DC voltage limit for motoring in 0.1V - uint16_t dcVoltLimitRegen; // maximum DC voltage limit for regen in 0.1V - uint16_t dcCurrentLimitMotor; // current limit for motoring in 0.1A - uint16_t dcCurrentLimitRegen; // current limit for regen in 0.1A + // DMC_LIM + uint16_t dcVoltLimitMotor; // minimum DC voltage limit for motoring in 0.1V + uint16_t dcVoltLimitRegen; // maximum DC voltage limit for regen in 0.1V + uint16_t dcCurrentLimitMotor; // current limit for motoring in 0.1A + uint16_t dcCurrentLimitRegen; // current limit for regen in 0.1A - bool enableOscillationLimiter; // this will enable the DMC5 oscillation limiter (if also enabled by parameter) + bool enableOscillationLimiter; // this will enable the DMC5 oscillation limiter (if also enabled by parameter) }; class BrusaMotorController: public MotorController, CanObserver { public: - // Message id=0x258, DMC_TRQS - // The value is composed of 2 bytes: (data[1] << 0) | (data[0] << 8) - enum Status { - motorModelLimitation = 1 << 0, // 0x0001 - mechanicalPowerLimitation = 1 << 1, // 0x0002 - maxTorqueLimitation = 1 << 2, // 0x0004 - acCurrentLimitation = 1 << 3, // 0x0008 - temperatureLimitation = 1 << 4, // 0x0010 - speedLimitation = 1 << 5, // 0x0020 - voltageLimitation = 1 << 6, // 0x0040 - currentLimitation = 1 << 7, // 0x0080 - torqueLimitation = 1 << 8, // 0x0100 - errorFlag = 1 << 9, // 0x0200, see DMC_ERR - warningFlag = 1 << 10, // 0x0400, see DMC_ERR - slewRateLimitation = 1 << 12, // 0x1000 - motorTemperatureLimitation = 1 << 13, // 0x2000 - stateRunning = 1 << 14, // 0x4000 - stateReady = 1 << 15 // 0x8000 - }; - - // Message id=0x25a, DMC_ERR - // The value is composed of 2 bytes: (data[7] << 0) | (data[6] << 8) - enum Warning { - systemCheckActive = 1 << 0, // 0x0001 - externalShutdownPathAw2Off = 1 << 1, // 0x0002 - externalShutdownPathAw1Off = 1 << 2, // 0x0004 - oscillationLimitControllerActive = 1 << 3, // 0x0008 - driverShutdownPathActive = 1 << 10, // 0x0400 - powerMismatchDetected = 1 << 11, // 0x0800 - speedSensorSignal = 1 << 12, // 0x1000 - hvUndervoltage = 1 << 13, // 0x2000 - maximumModulationLimiter = 1 << 14, // 0x4000 - temperatureSensor = 1 << 15, // 0x8000 - }; - - // Message id=0x25a, DMC_ERR - // The error value is composed of 4 bytes : (data[1] << 0) | (data[0] << 8) | (data[5] << 16) | (data[4] << 24) - enum Error { - speedSensorSupply = 1 << 0, // 0x00000001, data[1] - speedSensor = 1 << 1, // 0x00000002, data[1] - canLimitMessageInvalid = 1 << 2, // 0x00000004, data[1] - canControlMessageInvalid = 1 << 3, // 0x00000008, data[1] - canLimitMessageLost = 1 << 4, // 0x00000010, data[1] - overvoltageSkyConverter = 1 << 5, // 0x00000020, data[1] - voltageMeasurement = 1 << 6, // 0x00000040, data[1] - shortCircuit = 1 << 7, // 0x00000080, data[1] - canControlMessageLost = 1 << 8, // 0x00000100, data[0] - overtemp = 1 << 9, // 0x00000200, data[0] - overtempMotor = 1 << 10, // 0x00000400, data[0] - overspeed = 1 << 11, // 0x00000800, data[0] - undervoltage = 1 << 12, // 0x00001000, data[0] - overvoltage = 1 << 13, // 0x00002000, data[0] - overcurrent = 1 << 14, // 0x00004000, data[0] - initalisation = 1 << 15, // 0x00008000, data[0] - analogInput = 1 << 16, // 0x00010000, data[5] - driverShutdown = 1 << 22, // 0x00400000, data[5] - powerMismatch = 1 << 23, // 0x00800000, data[5] - canControl2MessageLost = 1 << 24, // 0x01000000, data[4] - motorEeprom = 1 << 25, // 0x02000000, data[4] - storage = 1 << 26, // 0x04000000, data[4] - enablePinSignalLost = 1 << 27, // 0x08000000, data[4] - canCommunicationStartup = 1 << 28, // 0x10000000, data[4] - internalSupply = 1 << 29, // 0x20000000, data[4] - acOvercurrent = 1 << 30, // 0x40000000, data[4] - osTrap = 1 << 31 // 0x80000000, data[4] - }; - - // Message id=0x210, DMC_CTRL - // The value is composed of 1 byte : data[0] - enum Control { - enablePositiveTorqueSpeed = 1 << 0, // 0x01 - enableNegativeTorqueSpeed = 1 << 1, // 0x02 - clearErrorLatch = 1 << 3, // 0x08 - enableOscillationLimiter = 1 << 5, // 0x20 - enableSpeedMode = 1 << 6, // 0x40 - enablePowerStage = 1 << 7 // 0x80 - }; - - BrusaMotorController(); - void handleTick(); - void handleCanFrame(CAN_FRAME *frame); - void setup(); - DeviceId getId(); - uint32_t getTickInterval(); - - void loadConfiguration(); - void saveConfiguration(); + // Message id=0x258, DMC_TRQS + // The value is composed of 2 bytes: (data[1] << 0) | (data[0] << 8) + enum Status { + motorModelLimitation = 1 << 0, // 0x0001 + mechanicalPowerLimitation = 1 << 1, // 0x0002 + maxTorqueLimitation = 1 << 2, // 0x0004 + acCurrentLimitation = 1 << 3, // 0x0008 + temperatureLimitation = 1 << 4, // 0x0010 + speedLimitation = 1 << 5, // 0x0020 + voltageLimitation = 1 << 6, // 0x0040 + currentLimitation = 1 << 7, // 0x0080 + torqueLimitation = 1 << 8, // 0x0100 + errorFlag = 1 << 9, // 0x0200, see DMC_ERR + warningFlag = 1 << 10, // 0x0400, see DMC_ERR + slewRateLimitation = 1 << 12, // 0x1000 + motorTemperatureLimitation = 1 << 13, // 0x2000 + stateRunning = 1 << 14, // 0x4000 + stateReady = 1 << 15 // 0x8000 + }; + + // Message id=0x25a, DMC_ERR + // The value is composed of 2 bytes: (data[7] << 0) | (data[6] << 8) + enum Warning { + systemCheckActive = 1 << 0, // 0x0001 + externalShutdownPathAw2Off = 1 << 1, // 0x0002 + externalShutdownPathAw1Off = 1 << 2, // 0x0004 + oscillationLimitControllerActive = 1 << 3, // 0x0008 + driverShutdownPathActive = 1 << 10, // 0x0400 + powerMismatchDetected = 1 << 11, // 0x0800 + speedSensorSignal = 1 << 12, // 0x1000 + hvUndervoltage = 1 << 13, // 0x2000 + maximumModulationLimiter = 1 << 14, // 0x4000 + temperatureSensor = 1 << 15, // 0x8000 + }; + + // Message id=0x25a, DMC_ERR + // The error value is composed of 4 bytes : (data[1] << 0) | (data[0] << 8) | (data[5] << 16) | (data[4] << 24) + enum Error { + speedSensorSupply = 1 << 0, // 0x00000001, data[1] + speedSensor = 1 << 1, // 0x00000002, data[1] + canLimitMessageInvalid = 1 << 2, // 0x00000004, data[1] + canControlMessageInvalid = 1 << 3, // 0x00000008, data[1] + canLimitMessageLost = 1 << 4, // 0x00000010, data[1] + overvoltageSkyConverter = 1 << 5, // 0x00000020, data[1] + voltageMeasurement = 1 << 6, // 0x00000040, data[1] + shortCircuit = 1 << 7, // 0x00000080, data[1] + canControlMessageLost = 1 << 8, // 0x00000100, data[0] + overtemp = 1 << 9, // 0x00000200, data[0] + overtempMotor = 1 << 10, // 0x00000400, data[0] + overspeed = 1 << 11, // 0x00000800, data[0] + undervoltage = 1 << 12, // 0x00001000, data[0] + overvoltage = 1 << 13, // 0x00002000, data[0] + overcurrent = 1 << 14, // 0x00004000, data[0] + initalisation = 1 << 15, // 0x00008000, data[0] + analogInput = 1 << 16, // 0x00010000, data[5] + driverShutdown = 1 << 22, // 0x00400000, data[5] + powerMismatch = 1 << 23, // 0x00800000, data[5] + canControl2MessageLost = 1 << 24, // 0x01000000, data[4] + motorEeprom = 1 << 25, // 0x02000000, data[4] + storage = 1 << 26, // 0x04000000, data[4] + enablePinSignalLost = 1 << 27, // 0x08000000, data[4] + canCommunicationStartup = 1 << 28, // 0x10000000, data[4] + internalSupply = 1 << 29, // 0x20000000, data[4] + acOvercurrent = 1 << 30, // 0x40000000, data[4] + osTrap = 1 << 31 // 0x80000000, data[4] + }; + + // Message id=0x210, DMC_CTRL + // The value is composed of 1 byte : data[0] + enum Control { + enablePositiveTorqueSpeed = 1 << 0, // 0x01 + enableNegativeTorqueSpeed = 1 << 1, // 0x02 + clearErrorLatch = 1 << 3, // 0x08 + enableOscillationLimiter = 1 << 5, // 0x20 + enableSpeedMode = 1 << 6, // 0x40 + enablePowerStage = 1 << 7 // 0x80 + }; + + BrusaMotorController(); + void handleTick(); + void handleCanFrame(CAN_FRAME *frame); + void setup(); + DeviceId getId(); + uint32_t getTickInterval(); + + void loadConfiguration(); + void saveConfiguration(); private: - // DMC_TRQS2 - int16_t maxPositiveTorque; // max positive available torque in 0.01Nm -> divide by 100 to get Nm - int16_t minNegativeTorque; // minimum negative available torque in 0.01Nm - uint8_t limiterStateNumber; // state number of active limiter - - int tickCounter; // count how many times handleTick() was called - PowerMode powerMode; // the desired power mode - uint8_t controlBitField; // the control bit field to send via DMC_CTRL in data[0] - CAN_FRAME outputFrame; // the output CAN frame; - - void sendControl(); - void sendControl2(); - void sendLimits(); - void prepareOutputFrame(uint32_t); - void processStatus(uint8_t data[]); - void processActualValues(uint8_t data[]); - void processErrors(uint8_t data[]); - void processTorqueLimit(uint8_t data[]); - void processTemperature(uint8_t data[]); + // DMC_TRQS2 + int16_t maxPositiveTorque; // max positive available torque in 0.01Nm -> divide by 100 to get Nm + int16_t minNegativeTorque; // minimum negative available torque in 0.01Nm + uint8_t limiterStateNumber; // state number of active limiter + + int tickCounter; // count how many times handleTick() was called + PowerMode powerMode; // the desired power mode + uint8_t controlBitField; // the control bit field to send via DMC_CTRL in data[0] + CAN_FRAME outputFrame; // the output CAN frame; + + void sendControl(); + void sendControl2(); + void sendLimits(); + void prepareOutputFrame(uint32_t); + void processStatus(uint8_t data[]); + void processActualValues(uint8_t data[]); + void processErrors(uint8_t data[]); + void processTorqueLimit(uint8_t data[]); + void processTemperature(uint8_t data[]); }; #endif /* BRUSAMOTORCONTROLLER_H_ */ diff --git a/CanBrake.cpp b/CanBrake.cpp index 8eeb994..4b2ff69 100644 --- a/CanBrake.cpp +++ b/CanBrake.cpp @@ -27,55 +27,57 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include "CanBrake.h" CanBrake::CanBrake() : Throttle() { - prefsHandler = new PrefHandler(CANBRAKEPEDAL); + prefsHandler = new PrefHandler(CANBRAKEPEDAL); - rawSignal.input1 = 0; - rawSignal.input2 = 0; - rawSignal.input3 = 0; - ticksNoResponse = 255; // invalidate input signal until response is received - responseId = 0; - responseMask = 0x7ff; - responseExtended = false; + rawSignal.input1 = 0; + rawSignal.input2 = 0; + rawSignal.input3 = 0; + ticksNoResponse = 255; // invalidate input signal until response is received + responseId = 0; + responseMask = 0x7ff; + responseExtended = false; - commonName = "CANBus brake"; + commonName = "CANBus brake"; } void CanBrake::setup() { - TickHandler::getInstance()->detach(this); - - Logger::info("add device: CanBrake (id: %X, %X)", CANBRAKEPEDAL, this); - - loadConfiguration(); - Throttle::setup(); - - requestFrame.length = 0x08; - requestFrame.rtr = 0x00; - requestFrame.extended = 0x00; - - CanBrakeConfiguration *config = (CanBrakeConfiguration *)getConfiguration(); - switch (config->carType) { - case Volvo_S80_Gas: - // Request: dlc=0x8 fid=0x760 id=0x760 ide=0x0 rtr=0x0 data=0x03,0x22,0x2B,0x0D,0x00,0x00,0x00,0x00 (vida: [0x00, 0x00, 0x07, 0x60, 0x22, 0x2B, 0x0D]) - // Response: dlc=0x8 fid=0x768 id=0x768 ide=0x0 rtr=0x0 data=0x05,0x62,0x2B,0x0D,0x00,0x01,0x00,0x00 (vida: [0x00, 0x00, 0x07, 0x68, 0x62, 0x2B, 0x0D, 0x00, 0x01]), 6th byte - requestFrame.id = 0x760; - memcpy(requestFrame.data.bytes, (const uint8_t[]){ 0x03, 0x22, 0x2B, 0x0D, 0x00, 0x00, 0x00, 0x00 }, 8); - responseId = 0x768; - break; - case Volvo_V50_Diesel: - // Request: dlc=0x08 fid=0xFFFFE id=0x3FFFE ide=0x01 rtr=0x00 data=0xCD,0x11,0xA6,0x00,0x24,0x01,0x00,0x00 ([0x00, 0xf, 0xff, 0xfe, 0xcd, 0x11, 0xa6, 0x00, 0x24, 0x01, 0x00, 0x00]) - // Response: dlc=0x08 fid=0x400021 id=0x21 ide=0x01 rtr=0x00 data=0xCE,0x11,0xE6,0x00,0x24,0x03,0xFD,0x00 (vida: [0x00, 0x40, 0x00, 0x21, 0xce, 0x11, 0xe6, 0x00, 0x24, 0x03, 0xfd, 0x00]) + TickHandler::getInstance()->detach(this); + + Logger::info("add device: CanBrake (id: %X, %X)", CANBRAKEPEDAL, this); + + loadConfiguration(); + Throttle::setup(); + + requestFrame.length = 0x08; + requestFrame.rtr = 0x00; + requestFrame.extended = 0x00; + + CanBrakeConfiguration *config = (CanBrakeConfiguration *)getConfiguration(); + switch (config->carType) { + case Volvo_S80_Gas: + // Request: dlc=0x8 fid=0x760 id=0x760 ide=0x0 rtr=0x0 data=0x03,0x22,0x2B,0x0D,0x00,0x00,0x00,0x00 (vida: [0x00, 0x00, 0x07, 0x60, 0x22, 0x2B, 0x0D]) + // Response: dlc=0x8 fid=0x768 id=0x768 ide=0x0 rtr=0x0 data=0x05,0x62,0x2B,0x0D,0x00,0x01,0x00,0x00 (vida: [0x00, 0x00, 0x07, 0x68, 0x62, 0x2B, 0x0D, 0x00, 0x01]), 6th byte + requestFrame.id = 0x760; + memcpy(requestFrame.data.bytes, (const uint8_t[]) { + 0x03, 0x22, 0x2B, 0x0D, 0x00, 0x00, 0x00, 0x00 + }, 8); + responseId = 0x768; + break; + case Volvo_V50_Diesel: + // Request: dlc=0x08 fid=0xFFFFE id=0x3FFFE ide=0x01 rtr=0x00 data=0xCD,0x11,0xA6,0x00,0x24,0x01,0x00,0x00 ([0x00, 0xf, 0xff, 0xfe, 0xcd, 0x11, 0xa6, 0x00, 0x24, 0x01, 0x00, 0x00]) + // Response: dlc=0x08 fid=0x400021 id=0x21 ide=0x01 rtr=0x00 data=0xCE,0x11,0xE6,0x00,0x24,0x03,0xFD,0x00 (vida: [0x00, 0x40, 0x00, 0x21, 0xce, 0x11, 0xe6, 0x00, 0x24, 0x03, 0xfd, 0x00]) // requestFrame.id = 0x3FFFE; // requestFrame.ide = 0x01; // memcpy(requestFrame.data, (uint8_t[]){ 0xce, 0x11, 0xe6, 0x00, 0x24, 0x03, 0xfd, 0x00 }, 8); // responseId = 0x21; // responseExtended = true; - break; - default: - Logger::error(CANBRAKEPEDAL, "no valid car type defined."); - } + break; + default: + Logger::error(CANBRAKEPEDAL, "no valid car type defined."); + } - CanHandler::getInstanceCar()->attach(this, responseId, responseMask, responseExtended); - TickHandler::getInstance()->attach(this, CFG_TICK_INTERVAL_CAN_THROTTLE); + CanHandler::getInstanceCar()->attach(this, responseId, responseMask, responseExtended); + TickHandler::getInstance()->attach(this, CFG_TICK_INTERVAL_CAN_THROTTLE); } /* @@ -83,12 +85,12 @@ void CanBrake::setup() { * */ void CanBrake::handleTick() { - Throttle::handleTick(); // Call parent handleTick + Throttle::handleTick(); // Call parent handleTick - CanHandler::getInstanceCar()->sendFrame(requestFrame); + CanHandler::getInstanceCar()->sendFrame(requestFrame); - if (ticksNoResponse < 255) // make sure it doesn't overflow - ticksNoResponse++; + if (ticksNoResponse < 255) // make sure it doesn't overflow + ticksNoResponse++; } /* @@ -96,61 +98,61 @@ void CanBrake::handleTick() { * */ void CanBrake::handleCanFrame(CAN_FRAME *frame) { - CanBrakeConfiguration *config = (CanBrakeConfiguration *)getConfiguration(); - - if (frame->id == responseId) { - switch (config->carType) { - case Volvo_S80_Gas: - rawSignal.input1 = frame->data.bytes[5]; - break; - case Volvo_V50_Diesel: + CanBrakeConfiguration *config = (CanBrakeConfiguration *)getConfiguration(); + + if (frame->id == responseId) { + switch (config->carType) { + case Volvo_S80_Gas: + rawSignal.input1 = frame->data.bytes[5]; + break; + case Volvo_V50_Diesel: // rawSignal.input1 = (frame->data.bytes[5] + 1) * frame->data.bytes[6]; - break; - } - ticksNoResponse = 0; - } + break; + } + ticksNoResponse = 0; + } } RawSignalData* CanBrake::acquireRawSignal() { - return &rawSignal; // should have already happened in the background + return &rawSignal; // should have already happened in the background } bool CanBrake::validateSignal(RawSignalData* rawSignal) { - CanBrakeConfiguration *config = (CanBrakeConfiguration *) getConfiguration(); - - if (ticksNoResponse >= CFG_CANTHROTTLE_MAX_NUM_LOST_MSG) { - if (status == OK) - Logger::error(CANBRAKEPEDAL, "no response on position request received: %d ", ticksNoResponse); - status = ERR_MISC; - return false; - } - if (rawSignal->input1 > (config->maximumLevel1 + CFG_THROTTLE_TOLERANCE)) { - if (status == OK) - Logger::error(CANBRAKEPEDAL, (char *)Constants::valueOutOfRange, rawSignal->input1); - status = ERR_HIGH_T1; - return false; - } - if (rawSignal->input1 < (config->minimumLevel1 - CFG_THROTTLE_TOLERANCE)) { - if (status == OK) - Logger::error(CANBRAKEPEDAL, (char *)Constants::valueOutOfRange, rawSignal->input1); - status = ERR_LOW_T1; - return false; - } - - // all checks passed -> brake is working - if (status != OK) - Logger::info(CANBRAKEPEDAL, (char *)Constants::normalOperation); - status = OK; - return true; + CanBrakeConfiguration *config = (CanBrakeConfiguration *) getConfiguration(); + + if (ticksNoResponse >= CFG_CANTHROTTLE_MAX_NUM_LOST_MSG) { + if (status == OK) + Logger::error(CANBRAKEPEDAL, "no response on position request received: %d ", ticksNoResponse); + status = ERR_MISC; + return false; + } + if (rawSignal->input1 > (config->maximumLevel1 + CFG_THROTTLE_TOLERANCE)) { + if (status == OK) + Logger::error(CANBRAKEPEDAL, (char *)Constants::valueOutOfRange, rawSignal->input1); + status = ERR_HIGH_T1; + return false; + } + if (rawSignal->input1 < (config->minimumLevel1 - CFG_THROTTLE_TOLERANCE)) { + if (status == OK) + Logger::error(CANBRAKEPEDAL, (char *)Constants::valueOutOfRange, rawSignal->input1); + status = ERR_LOW_T1; + return false; + } + + // all checks passed -> brake is working + if (status != OK) + Logger::info(CANBRAKEPEDAL, (char *)Constants::normalOperation); + status = OK; + return true; } uint16_t CanBrake::calculatePedalPosition(RawSignalData* rawSignal) { - CanBrakeConfiguration *config = (CanBrakeConfiguration *) getConfiguration(); + CanBrakeConfiguration *config = (CanBrakeConfiguration *) getConfiguration(); - if (config->maximumLevel1 == 0) //brake processing disabled if max is 0 - return 0; + if (config->maximumLevel1 == 0) //brake processing disabled if max is 0 + return 0; - return normalizeAndConstrainInput(rawSignal->input1, config->minimumLevel1, config->maximumLevel1); + return normalizeAndConstrainInput(rawSignal->input1, config->minimumLevel1, config->maximumLevel1); } /* @@ -158,71 +160,71 @@ uint16_t CanBrake::calculatePedalPosition(RawSignalData* rawSignal) { * brake based regen. */ int16_t CanBrake::mapPedalPosition(int16_t pedalPosition) { - CanBrakeConfiguration *config = (CanBrakeConfiguration *) getConfiguration(); - int16_t brakeLevel, range; + CanBrakeConfiguration *config = (CanBrakeConfiguration *) getConfiguration(); + int16_t brakeLevel, range; - if (pedalPosition == 0) // if brake not pressed, return 0, not minimumRegen ! - return 0; + if (pedalPosition == 0) // if brake not pressed, return 0, not minimumRegen ! + return 0; - range = config->maximumRegen - config->minimumRegen; - brakeLevel = -10 * range * pedalPosition / 1000; - brakeLevel -= 10 * config->minimumRegen; + range = config->maximumRegen - config->minimumRegen; + brakeLevel = -10 * range * pedalPosition / 1000; + brakeLevel -= 10 * config->minimumRegen; - return brakeLevel; + return brakeLevel; } DeviceId CanBrake::getId() { - return CANBRAKEPEDAL; + return CANBRAKEPEDAL; } /* * Return the device type */ DeviceType CanBrake::getType() { - return (DEVICE_BRAKE); + return (DEVICE_BRAKE); } void CanBrake::loadConfiguration() { - CanBrakeConfiguration *config = (CanBrakeConfiguration *) getConfiguration(); + CanBrakeConfiguration *config = (CanBrakeConfiguration *) getConfiguration(); - if (!config) { // as lowest sub-class make sure we have a config object - config = new CanBrakeConfiguration(); - setConfiguration(config); - } + if (!config) { // as lowest sub-class make sure we have a config object + config = new CanBrakeConfiguration(); + setConfiguration(config); + } - Throttle::loadConfiguration(); // call parent + Throttle::loadConfiguration(); // call parent #ifdef USE_HARD_CODED - if (false) { + if (false) { #else - if (prefsHandler->checksumValid()) { //checksum is good, read in the values stored in EEPROM + if (prefsHandler->checksumValid()) { //checksum is good, read in the values stored in EEPROM #endif - Logger::debug(CANBRAKEPEDAL, (char *)Constants::validChecksum); - prefsHandler->read(EETH_MIN_ONE, &config->minimumLevel1); - prefsHandler->read(EETH_MAX_ONE, &config->maximumLevel1); - prefsHandler->read(EETH_CAR_TYPE, &config->carType); - } else { //checksum invalid. Reinitialize values and store to EEPROM - Logger::warn(CANBRAKEPEDAL, (char *)Constants::invalidChecksum); - config->minimumLevel1 = 2; - config->maximumLevel1 = 255; - config->carType = Volvo_S80_Gas; - saveConfiguration(); - } - Logger::debug(CANBRAKEPEDAL, "T1 MIN: %l MAX: %l Type: %d", config->minimumLevel1, config->maximumLevel1, config->carType); + Logger::debug(CANBRAKEPEDAL, (char *)Constants::validChecksum); + prefsHandler->read(EETH_MIN_ONE, &config->minimumLevel1); + prefsHandler->read(EETH_MAX_ONE, &config->maximumLevel1); + prefsHandler->read(EETH_CAR_TYPE, &config->carType); + } else { //checksum invalid. Reinitialize values and store to EEPROM + Logger::warn(CANBRAKEPEDAL, (char *)Constants::invalidChecksum); + config->minimumLevel1 = 2; + config->maximumLevel1 = 255; + config->carType = Volvo_S80_Gas; + saveConfiguration(); + } + Logger::debug(CANBRAKEPEDAL, "T1 MIN: %l MAX: %l Type: %d", config->minimumLevel1, config->maximumLevel1, config->carType); } /* * Store the current configuration to EEPROM */ void CanBrake::saveConfiguration() { - CanBrakeConfiguration *config = (CanBrakeConfiguration *) getConfiguration(); + CanBrakeConfiguration *config = (CanBrakeConfiguration *) getConfiguration(); - Throttle::saveConfiguration(); // call parent + Throttle::saveConfiguration(); // call parent - prefsHandler->write(EETH_MIN_ONE, config->minimumLevel1); - prefsHandler->write(EETH_MAX_ONE, config->maximumLevel1); - prefsHandler->write(EETH_CAR_TYPE, config->carType); - prefsHandler->saveChecksum(); + prefsHandler->write(EETH_MIN_ONE, config->minimumLevel1); + prefsHandler->write(EETH_MAX_ONE, config->maximumLevel1); + prefsHandler->write(EETH_CAR_TYPE, config->carType); + prefsHandler->saveChecksum(); } diff --git a/CanBrake.h b/CanBrake.h index 819c506..6829fea 100644 --- a/CanBrake.h +++ b/CanBrake.h @@ -37,35 +37,35 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. class CanBrakeConfiguration : public ThrottleConfiguration { public: - uint16_t minimumLevel1, maximumLevel1; // values for when the pedal is at its min and max - uint16_t carType; // the type of car, so we know how to interpret which bytes + uint16_t minimumLevel1, maximumLevel1; // values for when the pedal is at its min and max + uint16_t carType; // the type of car, so we know how to interpret which bytes }; class CanBrake: public Throttle, CanObserver { public: - CanBrake(); - void setup(); - void handleTick(); - void handleCanFrame(CAN_FRAME *frame); - DeviceId getId(); - DeviceType getType(); + CanBrake(); + void setup(); + void handleTick(); + void handleCanFrame(CAN_FRAME *frame); + DeviceId getId(); + DeviceType getType(); - RawSignalData *acquireRawSignal(); - void loadConfiguration(); - void saveConfiguration(); + RawSignalData *acquireRawSignal(); + void loadConfiguration(); + void saveConfiguration(); protected: - bool validateSignal(RawSignalData *); - uint16_t calculatePedalPosition(RawSignalData *); - int16_t mapPedalPosition(int16_t); + bool validateSignal(RawSignalData *); + uint16_t calculatePedalPosition(RawSignalData *); + int16_t mapPedalPosition(int16_t); private: - CAN_FRAME requestFrame; // the request frame sent to the car - RawSignalData rawSignal; // raw signal - uint8_t ticksNoResponse; // number of ticks no response was received - uint32_t responseId; // the CAN id with which the response is sent; - uint32_t responseMask; // the mask for the responseId - bool responseExtended; // if the response is expected as an extended frame + CAN_FRAME requestFrame; // the request frame sent to the car + RawSignalData rawSignal; // raw signal + uint8_t ticksNoResponse; // number of ticks no response was received + uint32_t responseId; // the CAN id with which the response is sent; + uint32_t responseMask; // the mask for the responseId + bool responseExtended; // if the response is expected as an extended frame }; #endif /* CAN_BRAKE_H_ */ diff --git a/CanHandler.cpp b/CanHandler.cpp index 367d45f..ba4ed92 100644 --- a/CanHandler.cpp +++ b/CanHandler.cpp @@ -36,16 +36,16 @@ CanHandler *CanHandler::canHandlerCar = NULL; * Private constructor of the can handler */ CanHandler::CanHandler(CanBusNode canBusNode) { - this->canBusNode = canBusNode; + this->canBusNode = canBusNode; - // assign the correct bus instance to the pointer - if (canBusNode == CAN_BUS_CAR) - bus = &CAN2; - else - bus = &CAN; + // assign the correct bus instance to the pointer + if (canBusNode == CAN_BUS_CAR) + bus = &CAN2; + else + bus = &CAN; - for (int i=0; i < CFG_CAN_NUM_OBSERVERS; i++) - observerData[i].observer = NULL; + for (int i=0; i < CFG_CAN_NUM_OBSERVERS; i++) + observerData[i].observer = NULL; } /* @@ -56,9 +56,9 @@ CanHandler::CanHandler(CanBusNode canBusNode) { */ CanHandler* CanHandler::getInstanceEV() { - if (canHandlerEV == NULL) - canHandlerEV = new CanHandler(CAN_BUS_EV); - return canHandlerEV; + if (canHandlerEV == NULL) + canHandlerEV = new CanHandler(CAN_BUS_EV); + return canHandlerEV; } /* @@ -69,22 +69,22 @@ CanHandler* CanHandler::getInstanceEV() */ CanHandler* CanHandler::getInstanceCar() { - if (canHandlerCar == NULL) - canHandlerCar = new CanHandler(CAN_BUS_CAR); - return canHandlerCar; + if (canHandlerCar == NULL) + canHandlerCar = new CanHandler(CAN_BUS_CAR); + return canHandlerCar; } /* * Initialization of the CAN bus */ void CanHandler::initialize() { - // Initialize the canbus at the specified baudrate - bus->init(canBusNode == CAN_BUS_EV ? CFG_CAN0_SPEED : CFG_CAN1_SPEED); + // Initialize the canbus at the specified baudrate + bus->init(canBusNode == CAN_BUS_EV ? CFG_CAN0_SPEED : CFG_CAN1_SPEED); - //Mailboxes are default set up initialized with one MB for TX and the rest for RX - //That's OK with us so no need to initialize those things there. + //Mailboxes are default set up initialized with one MB for TX and the rest for RX + //That's OK with us so no need to initialize those things there. - Logger::info("CAN%d init ok", (canBusNode == CAN_BUS_EV ? 0 : 1)); + Logger::info("CAN%d init ok", (canBusNode == CAN_BUS_EV ? 0 : 1)); } /* @@ -98,27 +98,27 @@ void CanHandler::initialize() { * \param extended - set if extended frames must be supported */ void CanHandler::attach(CanObserver* observer, uint32_t id, uint32_t mask, bool extended) { - int8_t pos = findFreeObserverData(); - if (pos == -1) { - Logger::error("no free space in CanHandler::observerData, increase its size via CFG_CAN_NUM_OBSERVERS"); - return; - } - - int mailbox = bus->findFreeRXMailbox(); - if (mailbox == -1) { - Logger::error("no free CAN mailbox on bus %d", canBusNode); - return; - } - - observerData[pos].id = id; - observerData[pos].mask = mask; - observerData[pos].extended = extended; - observerData[pos].mailbox = mailbox; - observerData[pos].observer = observer; - - bus->setRXFilter((uint8_t)mailbox, id, mask, extended); - - Logger::debug("attached CanObserver (%X) for id=%X, mask=%X, mailbox=%d", observer, id, mask, mailbox); + int8_t pos = findFreeObserverData(); + if (pos == -1) { + Logger::error("no free space in CanHandler::observerData, increase its size via CFG_CAN_NUM_OBSERVERS"); + return; + } + + int mailbox = bus->findFreeRXMailbox(); + if (mailbox == -1) { + Logger::error("no free CAN mailbox on bus %d", canBusNode); + return; + } + + observerData[pos].id = id; + observerData[pos].mask = mask; + observerData[pos].extended = extended; + observerData[pos].mailbox = mailbox; + observerData[pos].observer = observer; + + bus->setRXFilter((uint8_t)mailbox, id, mask, extended); + + Logger::debug("attached CanObserver (%X) for id=%X, mask=%X, mailbox=%d", observer, id, mask, mailbox); } /* @@ -129,15 +129,15 @@ void CanHandler::attach(CanObserver* observer, uint32_t id, uint32_t mask, bool * \param mask - mask of the observer to detach (dito) */ void CanHandler::detach(CanObserver* observer, uint32_t id, uint32_t mask) { - for (int i = 0; i < CFG_CAN_NUM_OBSERVERS; i++) { - if (observerData[i].observer == observer && - observerData[i].id == id && - observerData[i].mask == mask) { - observerData[i].observer = NULL; - - //TODO: if no more observers on same mailbox, disable its interrupt, reset mailbox - } - } + for (int i = 0; i < CFG_CAN_NUM_OBSERVERS; i++) { + if (observerData[i].observer == observer && + observerData[i].id == id && + observerData[i].mask == mask) { + observerData[i].observer = NULL; + + //TODO: if no more observers on same mailbox, disable its interrupt, reset mailbox + } + } } /* @@ -146,12 +146,12 @@ void CanHandler::detach(CanObserver* observer, uint32_t id, uint32_t mask) { * \param frame - the received can frame to log */ void CanHandler::logFrame(CAN_FRAME& frame) { - if (Logger::isDebug()) { - Logger::debug("CAN: dlc=%X fid=%X id=%X ide=%X rtr=%X data=%X,%X,%X,%X,%X,%X,%X,%X", - frame.length, frame.fid, frame.id, frame.extended, frame.rtr, - frame.data.bytes[0], frame.data.bytes[1], frame.data.bytes[2], frame.data.bytes[3], - frame.data.bytes[4], frame.data.bytes[5], frame.data.bytes[6], frame.data.bytes[7]); - } + if (Logger::isDebug()) { + Logger::debug("CAN: dlc=%X fid=%X id=%X ide=%X rtr=%X data=%X,%X,%X,%X,%X,%X,%X,%X", + frame.length, frame.fid, frame.id, frame.extended, frame.rtr, + frame.data.bytes[0], frame.data.bytes[1], frame.data.bytes[2], frame.data.bytes[3], + frame.data.bytes[4], frame.data.bytes[5], frame.data.bytes[6], frame.data.bytes[7]); + } } @@ -161,11 +161,11 @@ void CanHandler::logFrame(CAN_FRAME& frame) { * \retval array index of the next unused entry in observerData[] */ int8_t CanHandler::findFreeObserverData() { - for (int i = 0; i < CFG_CAN_NUM_OBSERVERS; i++) { - if (observerData[i].observer == NULL) - return i; - } - return -1; + for (int i = 0; i < CFG_CAN_NUM_OBSERVERS; i++) { + if (observerData[i].observer == NULL) + return i; + } + return -1; } /* @@ -174,47 +174,47 @@ int8_t CanHandler::findFreeObserverData() { * \retval the mailbox index of the next unused mailbox */ int8_t CanHandler::findFreeMailbox() { - uint8_t numRxMailboxes = (canBusNode == CAN_BUS_EV ? CFG_CAN0_NUM_RX_MAILBOXES : CFG_CAN1_NUM_RX_MAILBOXES); - for (uint8_t i = 0; i < numRxMailboxes; i++) { - bool used = false; - for (uint8_t j = 0; j < CFG_CAN_NUM_OBSERVERS; j++) { - if (observerData[j].observer != NULL && observerData[j].mailbox == i) - used = true; - } - if (!used) - return i; - } - return -1; + uint8_t numRxMailboxes = (canBusNode == CAN_BUS_EV ? CFG_CAN0_NUM_RX_MAILBOXES : CFG_CAN1_NUM_RX_MAILBOXES); + for (uint8_t i = 0; i < numRxMailboxes; i++) { + bool used = false; + for (uint8_t j = 0; j < CFG_CAN_NUM_OBSERVERS; j++) { + if (observerData[j].observer != NULL && observerData[j].mailbox == i) + used = true; + } + if (!used) + return i; + } + return -1; } /* * If a message is available, read it and forward it to registered observers. */ void CanHandler::process() { - static CAN_FRAME frame; - - if (bus->rx_avail()) { - bus->get_rx_buff(frame); - //logFrame(frame); - - for (int i = 0; i < CFG_CAN_NUM_OBSERVERS; i++) { - if (observerData[i].observer != NULL) { - // Apply mask to frame.id and observer.id. If they match, forward the frame to the observer - if ((frame.id & observerData[i].mask) == (observerData[i].id & observerData[i].mask)) - observerData[i].observer->handleCanFrame(&frame); - } - - if(frame.id==CAN_SWITCH)CANIO(frame); - - } - } + static CAN_FRAME frame; + + if (bus->rx_avail()) { + bus->get_rx_buff(frame); + //logFrame(frame); + + for (int i = 0; i < CFG_CAN_NUM_OBSERVERS; i++) { + if (observerData[i].observer != NULL) { + // Apply mask to frame.id and observer.id. If they match, forward the frame to the observer + if ((frame.id & observerData[i].mask) == (observerData[i].id & observerData[i].mask)) + observerData[i].observer->handleCanFrame(&frame); + } + + if(frame.id==CAN_SWITCH)CANIO(frame); + + } + } } -//Allow the canbus driver to figure out the proper mailbox to use +//Allow the canbus driver to figure out the proper mailbox to use //(whatever happens to be open) or queue it to send (if nothing is open) void CanHandler::sendFrame(CAN_FRAME& frame) { - bus->sendFrame(frame); - // logFrame(frame); + bus->sendFrame(frame); + // logFrame(frame); } /* @@ -222,56 +222,56 @@ void CanHandler::sendFrame(CAN_FRAME& frame) { * by every sub-class. */ void CanObserver::handleCanFrame(CAN_FRAME *frame) { - Logger::error("CanObserver does not implement handleCanFrame(), frame.id=%d", frame->id); + Logger::error("CanObserver does not implement handleCanFrame(), frame.id=%d", frame->id); } void CanHandler::CANIO(CAN_FRAME& frame) { - static CAN_FRAME CANioFrame; - - CANioFrame.id = CAN_OUTPUTS; - CANioFrame.length = 8; - CANioFrame.extended = 0; //standard frame - CANioFrame.rtr = 0; - - for(int i=0;i==8;i++) + static CAN_FRAME CANioFrame; + + CANioFrame.id = CAN_OUTPUTS; + CANioFrame.length = 8; + CANioFrame.extended = 0; //standard frame + CANioFrame.rtr = 0; + + for(int i=0; i==8; i++) { - if(frame.data.bytes[i]==0x88)setOutput(i,true); - if(frame.data.bytes[i]==0xFF)setOutput(i,false); + if(frame.data.bytes[i]==0x88)setOutput(i,true); + if(frame.data.bytes[i]==0xFF)setOutput(i,false); } - - for(int i=0;i==8;i++) + + for(int i=0; i==8; i++) { - if(getOutput(i))CANioFrame.data.bytes[i]=0x88; + if(getOutput(i))CANioFrame.data.bytes[i]=0x88; else CANioFrame.data.bytes[i]=0xFF; } - - sendFrame(CANioFrame); - - - CANioFrame.id = CAN_ANALOG_INPUTS; - int i=0; - uint16_t anaVal; - - for(int j=0;j>6;j+=2) + + sendFrame(CANioFrame); + + + CANioFrame.id = CAN_ANALOG_INPUTS; + int i=0; + uint16_t anaVal; + + for(int j=0; j>6; j+=2) { - anaVal=getAnalog(i++); - CANioFrame.data.bytes[j]=highByte (anaVal); - CANioFrame.data.bytes[j+1]=lowByte(anaVal); + anaVal=getAnalog(i++); + CANioFrame.data.bytes[j]=highByte (anaVal); + CANioFrame.data.bytes[j+1]=lowByte(anaVal); } - - sendFrame(CANioFrame); - CANioFrame.id = CAN_DIGITAL_INPUTS; - CANioFrame.length = 4; - - for(int i=0;i==4;i++) + sendFrame(CANioFrame); + + CANioFrame.id = CAN_DIGITAL_INPUTS; + CANioFrame.length = 4; + + for(int i=0; i==4; i++) { - if (getDigital(i))CANioFrame.data.bytes[i]=0x88; - else CANioFrame.data.bytes[i]=0xff; + if (getDigital(i))CANioFrame.data.bytes[i]=0x88; + else CANioFrame.data.bytes[i]=0xff; } - - sendFrame(CANioFrame); + + sendFrame(CANioFrame); } diff --git a/CanHandler.h b/CanHandler.h index b2b8bb4..2a7b34d 100644 --- a/CanHandler.h +++ b/CanHandler.h @@ -40,45 +40,45 @@ class Device; class CanObserver { public: - virtual void handleCanFrame(CAN_FRAME *frame); + virtual void handleCanFrame(CAN_FRAME *frame); }; class CanHandler { public: - enum CanBusNode { - CAN_BUS_EV, // CAN0 is intended to be connected to the EV bus (controller, charger, etc.) - CAN_BUS_CAR // CAN1 is intended to be connected to the car's high speed bus (the one with the ECU) - }; - - void initialize(); - void attach(CanObserver *observer, uint32_t id, uint32_t mask, bool extended); - void detach(CanObserver *observer, uint32_t id, uint32_t mask); - void process(); - void sendFrame(CAN_FRAME& frame); - void CANIO(CAN_FRAME& frame); - static CanHandler *getInstanceCar(); - static CanHandler *getInstanceEV(); + enum CanBusNode { + CAN_BUS_EV, // CAN0 is intended to be connected to the EV bus (controller, charger, etc.) + CAN_BUS_CAR // CAN1 is intended to be connected to the car's high speed bus (the one with the ECU) + }; + + void initialize(); + void attach(CanObserver *observer, uint32_t id, uint32_t mask, bool extended); + void detach(CanObserver *observer, uint32_t id, uint32_t mask); + void process(); + void sendFrame(CAN_FRAME& frame); + void CANIO(CAN_FRAME& frame); + static CanHandler *getInstanceCar(); + static CanHandler *getInstanceEV(); protected: private: - struct CanObserverData { - uint32_t id; // what id to listen to - uint32_t mask; // the CAN frame mask to listen to - bool extended; // are extended frames expected - uint8_t mailbox; // which mailbox is this observer assigned to - CanObserver *observer; // the observer object (e.g. a device) - }; - static CanHandler *canHandlerEV; // singleton reference to the EV instance (CAN0) - static CanHandler *canHandlerCar; // singleton reference to the car instance (CAN1) - - CanBusNode canBusNode; // indicator to which can bus this instance is assigned to - CANRaw *bus; // the can bus instance which this CanHandler instance is assigned to - CanObserverData observerData[CFG_CAN_NUM_OBSERVERS]; // Can observers - - CanHandler(CanBusNode busNumber); - void logFrame(CAN_FRAME& frame); - int8_t findFreeObserverData(); - int8_t findFreeMailbox(); + struct CanObserverData { + uint32_t id; // what id to listen to + uint32_t mask; // the CAN frame mask to listen to + bool extended; // are extended frames expected + uint8_t mailbox; // which mailbox is this observer assigned to + CanObserver *observer; // the observer object (e.g. a device) + }; + static CanHandler *canHandlerEV; // singleton reference to the EV instance (CAN0) + static CanHandler *canHandlerCar; // singleton reference to the car instance (CAN1) + + CanBusNode canBusNode; // indicator to which can bus this instance is assigned to + CANRaw *bus; // the can bus instance which this CanHandler instance is assigned to + CanObserverData observerData[CFG_CAN_NUM_OBSERVERS]; // Can observers + + CanHandler(CanBusNode busNumber); + void logFrame(CAN_FRAME& frame); + int8_t findFreeObserverData(); + int8_t findFreeMailbox(); }; #endif /* CAN_HANDLER_H_ */ diff --git a/CanPIDListener.cpp b/CanPIDListener.cpp index 50957ee..fc959df 100644 --- a/CanPIDListener.cpp +++ b/CanPIDListener.cpp @@ -2,7 +2,7 @@ * CanPIDListener.cpp * * Listens for PID requests over canbus and responds with the relevant information in the proper format - * + * * Currently this is in a very rough state and shouldn't be trusted - Make configuration work soon * Copyright (c) 2013 Collin Kidder, Michael Neuweiler, Charles Galpin @@ -32,28 +32,28 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. CanPIDListener::CanPIDListener() : Device() { - prefsHandler = new PrefHandler(PIDLISTENER); + prefsHandler = new PrefHandler(PIDLISTENER); - responseId = 0; - responseMask = 0x7ff; - responseExtended = false; + responseId = 0; + responseMask = 0x7ff; + responseExtended = false; } void CanPIDListener::setup() { - //TickHandler::getInstance()->detach(this); + //TickHandler::getInstance()->detach(this); - loadConfiguration(); - Device::setup(); + loadConfiguration(); + Device::setup(); - //TODO: FIXME Quickly coded as hard coded values. This is naughty. - CanHandler::getInstanceEV()->attach(this, 0x7DF, 0x7DF, false); - CanHandler::getInstanceEV()->attach(this, 0x7E0, 0x7E0, false); - //TickHandler::getInstance()->attach(this, CFG_TICK_INTERVAL_CAN_THROTTLE); + //TODO: FIXME Quickly coded as hard coded values. This is naughty. + CanHandler::getInstanceEV()->attach(this, 0x7DF, 0x7DF, false); + CanHandler::getInstanceEV()->attach(this, 0x7E0, 0x7E0, false); + //TickHandler::getInstance()->attach(this, CFG_TICK_INTERVAL_CAN_THROTTLE); } /* * There is no tick handler because this is the only place we do anything is here -* +* SAE standard says that this is the format for SAE requests to us: byte 0 = # of bytes following byte 1 = mode for PID request @@ -82,254 +82,254 @@ void CanPIDListener::setup() { 0x61 = Driver requested torque (A-125) - Percentage 0x62 = Actual Torque delivered (A-125) - Percentage 0x63 = Reference torque for engine - presumably max torque - A*256 + B - Nm - + Mode 3 Returns DTC (diag trouble codes) - Three per frame bits 6-7 = DTC first character (00 = P = Powertrain, 01=C=Chassis, 10=B=Body, 11=U=Network) bits 4-5 = Second char (00 = 0, 01 = 1, 10 = 2, 11 = 3) bits 0-3 = third char (stored as normal nibble) Then next byte has two nibbles for the next 2 characters (fourth char = bits 4-7, fifth = 0-3) - + Mode 9 PIDs 0x0 = Mode 9 pids supported (same scheme as mode 1) 0x9 = How long is ECU name returned by 0x0A? 0xA = ASCII string of ECU name. 20 characters are to be returned, I believe 4 at a time - + * */ void CanPIDListener::handleCanFrame(CAN_FRAME *frame) { - CAN_FRAME outputFrame; - bool ret; - - if ((frame->id == 0x7E0) || (frame->id == 0x7DF)) { - //Do some common setup for our output - we won't pull the trigger unless we need to. - outputFrame.id = 0x7E8; //first ECU replying - TODO: Perhaps allow this to be configured from 0x7E8 - 0x7EF - outputFrame.data.bytes[1] = frame->data.bytes[1] + 0x40; //to show that this is a response - outputFrame.data.bytes[2] = frame->data.bytes[2]; //copy standard PID - outputFrame.data.bytes[0] = 2; - if (frame->data.bytes[1] > 0x50) { - outputFrame.data.bytes[3] = frame->data.bytes[3]; //if using proprietary PIDs then copy second byte too - outputFrame.data.bytes[0] = 3; - } - - ret = false; - - switch (frame->data.bytes[1]) { - case 1: //show current data - ret = processShowData(frame, outputFrame); - break; - case 2: //show freeze frame data - not sure we'll be supporting this - break; - case 3: //show stored diagnostic codes - we can probably map our faults to some existing DTC codes or roll our own - break; - case 4: //clear diagnostic trouble codes - If we get this frame we just clear all codes no questions asked. - break; - case 6: //test results over CANBus (this replaces mode 5 from non-canbus) - I know nothing of this - break; - case 7: //show pending diag codes (current or last driving cycle) - Might just overlap with mode 3 - break; - case 8: //control operation of on-board systems - this sounds really proprietary and dangerous. Maybe ignore this? - break; - case 9: //request vehicle info - We can identify ourselves here but little else - break; - case 0x20: //custom PID codes we made up for GEVCU - break; - } - - //here is where we'd send out response. Right now it sends over canbus but when we support other - //alteratives they'll be sending here too. - if (ret) { - CanHandler::getInstanceEV()->sendFrame(outputFrame); - } - } + CAN_FRAME outputFrame; + bool ret; + + if ((frame->id == 0x7E0) || (frame->id == 0x7DF)) { + //Do some common setup for our output - we won't pull the trigger unless we need to. + outputFrame.id = 0x7E8; //first ECU replying - TODO: Perhaps allow this to be configured from 0x7E8 - 0x7EF + outputFrame.data.bytes[1] = frame->data.bytes[1] + 0x40; //to show that this is a response + outputFrame.data.bytes[2] = frame->data.bytes[2]; //copy standard PID + outputFrame.data.bytes[0] = 2; + if (frame->data.bytes[1] > 0x50) { + outputFrame.data.bytes[3] = frame->data.bytes[3]; //if using proprietary PIDs then copy second byte too + outputFrame.data.bytes[0] = 3; + } + + ret = false; + + switch (frame->data.bytes[1]) { + case 1: //show current data + ret = processShowData(frame, outputFrame); + break; + case 2: //show freeze frame data - not sure we'll be supporting this + break; + case 3: //show stored diagnostic codes - we can probably map our faults to some existing DTC codes or roll our own + break; + case 4: //clear diagnostic trouble codes - If we get this frame we just clear all codes no questions asked. + break; + case 6: //test results over CANBus (this replaces mode 5 from non-canbus) - I know nothing of this + break; + case 7: //show pending diag codes (current or last driving cycle) - Might just overlap with mode 3 + break; + case 8: //control operation of on-board systems - this sounds really proprietary and dangerous. Maybe ignore this? + break; + case 9: //request vehicle info - We can identify ourselves here but little else + break; + case 0x20: //custom PID codes we made up for GEVCU + break; + } + + //here is where we'd send out response. Right now it sends over canbus but when we support other + //alteratives they'll be sending here too. + if (ret) { + CanHandler::getInstanceEV()->sendFrame(outputFrame); + } + } } //Process SAE standard PID requests. Function returns whether it handled the request or not. bool CanPIDListener::processShowData(CAN_FRAME* inFrame, CAN_FRAME& outFrame) { - MotorController* motorController = DeviceManager::getInstance()->getMotorController(); - int temp; - - switch (inFrame->data.bytes[2]) { - case 0: //pids 1-0x20 that we support - bitfield - //returns 4 bytes so immediately indicate that. - outFrame.data.bytes[0] += 4; - outFrame.data.bytes[3] = 0b11011000; //pids 1 - 8 - starting with pid 1 in the MSB and going from there - outFrame.data.bytes[4] = 0b00010000; //pids 9 - 0x10 - outFrame.data.bytes[5] = 0b10000000; //pids 0x11 - 0x18 - outFrame.data.bytes[6] = 0b00010011; //pids 0x19 - 0x20 - return true; - break; - case 1: //Returns 32 bits but we really can only support the first byte which has bit 7 = Malfunction? Bits 0-6 = # of DTCs - outFrame.data.bytes[0] += 4; - outFrame.data.bytes[3] = 0; //TODO: We aren't properly keeping track of faults yet but when we do fix this. - outFrame.data.bytes[3] = 0; //these next three are really related to ICE diagnostics - outFrame.data.bytes[3] = 0; //so ignore them. - outFrame.data.bytes[3] = 0; - return true; - break; - case 2: //Freeze DTC - return false; //don't support freeze framing yet. Might be useful in the future. - break; - case 4: //Calculated engine load (A * 100 / 255) - Percentage - temp = (255 * motorController->getTorqueActual()) / motorController->getTorqueAvailable(); - outFrame.data.bytes[0] += 1; - outFrame.data.bytes[3] = (uint8_t)(temp & 0xFF); - return true; - break; - case 5: //Engine Coolant Temp (A - 40) = Degrees Centigrade - //our code stores temperatures as a signed integer for tenths of a degree so translate - temp = motorController->getTemperatureSystem() / 10; - if (temp < -40) temp = -40; - if (temp > 215) temp = 215; - temp += 40; - outFrame.data.bytes[0] += 1; //returning only one byte - outFrame.data.bytes[3] = (uint8_t)(temp); - return true; - break; - case 0xC: //Engine RPM (A * 256 + B) / 4 - temp = motorController->getSpeedActual() * 4; //we store in RPM while the PID code wants quarter rpms - outFrame.data.bytes[0] += 2; - outFrame.data.bytes[3] = (uint8_t)(temp / 256); - outFrame.data.bytes[4] = (uint8_t)(temp); - return true; - break; - case 0x11: //Throttle position (A * 100 / 255) - Percentage - temp = motorController->getThrottle() / 10; //getThrottle returns in 10ths of a percent - if (temp < 0) temp = 0; //negative throttle can't be shown for OBDII - temp = (255 * temp) / 100; - outFrame.data.bytes[0] += 1; - outFrame.data.bytes[3] = (uint8_t)(temp); - return true; - break; - case 0x1C: //Standard supported (We return 1 = OBDII) - outFrame.data.bytes[0] += 1; - outFrame.data.bytes[3] = 1; - return true; - break; - case 0x1F: //runtime since engine start (A*256 + B) - outFrame.data.bytes[0] += 2; - outFrame.data.bytes[3] = 0; //TODO: Get the actual runtime. - outFrame.data.bytes[4] = 0; - return true; - break; - case 0x20: //pids supported (next 32 pids - formatted just like PID 0) - outFrame.data.bytes[0] += 4; - outFrame.data.bytes[3] = 0b00000000; //pids 0x21 - 0x28 - starting with pid 0x21 in the MSB and going from there - outFrame.data.bytes[4] = 0b00000000; //pids 0x29 - 0x30 - outFrame.data.bytes[5] = 0b00000000; //pids 0x31 - 0x38 - outFrame.data.bytes[6] = 0b00000001; //pids 0x39 - 0x40 - return true; - break; - case 0x21: //Distance traveled with fault light lit (A*256 + B) - In km - outFrame.data.bytes[0] += 2; - outFrame.data.bytes[3] = 0; //TODO: Can we get this information? - outFrame.data.bytes[4] = 0; - return true; - break; - case 0x2F: //Fuel level (A * 100 / 255) - Percentage - outFrame.data.bytes[0] += 1; - outFrame.data.bytes[3] = 0; //TODO: finish BMS interface and get this value - return true; - break; - case 0x40: //PIDs supported, next 32 - outFrame.data.bytes[0] += 4; - outFrame.data.bytes[3] = 0b00000000; //pids 0x41 - 0x48 - starting with pid 0x41 in the MSB and going from there - outFrame.data.bytes[4] = 0b00000000; //pids 0x49 - 0x50 - outFrame.data.bytes[5] = 0b10000000; //pids 0x51 - 0x58 - outFrame.data.bytes[6] = 0b00000001; //pids 0x59 - 0x60 - return true; - break; - case 0x51: //What type of fuel do we use? (We use 8 = electric, presumably.) - outFrame.data.bytes[0] += 1; - outFrame.data.bytes[3] = 8; - return true; - break; - case 0x60: //PIDs supported, next 32 - outFrame.data.bytes[0] += 4; - outFrame.data.bytes[3] = 0b11100000; //pids 0x61 - 0x68 - starting with pid 0x61 in the MSB and going from there - outFrame.data.bytes[4] = 0b00000000; //pids 0x69 - 0x70 - outFrame.data.bytes[5] = 0b00000000; //pids 0x71 - 0x78 - outFrame.data.bytes[6] = 0b00000000; //pids 0x79 - 0x80 - return true; - break; - case 0x61: //Driver requested torque (A-125) - Percentage - temp = (100 * motorController->getTorqueRequested()) / motorController->getTorqueAvailable(); - temp += 125; - outFrame.data.bytes[0] += 1; - outFrame.data.bytes[3] = (uint8_t)temp; - return true; - break; - case 0x62: //Actual Torque delivered (A-125) - Percentage - temp = (100 * motorController->getTorqueActual()) / motorController->getTorqueAvailable(); - temp += 125; - outFrame.data.bytes[0] += 1; - outFrame.data.bytes[3] = (uint8_t)temp; - return true; - break; - case 0x63: //Reference torque for engine - presumably max torque - A*256 + B - Nm - temp = motorController->getTorqueAvailable(); - outFrame.data.bytes[0] += 2; - outFrame.data.bytes[3] = (uint8_t)(temp / 256); - outFrame.data.bytes[4] = (uint8_t)(temp & 0xFF); - return true; - break; - } - return false; + MotorController* motorController = DeviceManager::getInstance()->getMotorController(); + int temp; + + switch (inFrame->data.bytes[2]) { + case 0: //pids 1-0x20 that we support - bitfield + //returns 4 bytes so immediately indicate that. + outFrame.data.bytes[0] += 4; + outFrame.data.bytes[3] = 0b11011000; //pids 1 - 8 - starting with pid 1 in the MSB and going from there + outFrame.data.bytes[4] = 0b00010000; //pids 9 - 0x10 + outFrame.data.bytes[5] = 0b10000000; //pids 0x11 - 0x18 + outFrame.data.bytes[6] = 0b00010011; //pids 0x19 - 0x20 + return true; + break; + case 1: //Returns 32 bits but we really can only support the first byte which has bit 7 = Malfunction? Bits 0-6 = # of DTCs + outFrame.data.bytes[0] += 4; + outFrame.data.bytes[3] = 0; //TODO: We aren't properly keeping track of faults yet but when we do fix this. + outFrame.data.bytes[3] = 0; //these next three are really related to ICE diagnostics + outFrame.data.bytes[3] = 0; //so ignore them. + outFrame.data.bytes[3] = 0; + return true; + break; + case 2: //Freeze DTC + return false; //don't support freeze framing yet. Might be useful in the future. + break; + case 4: //Calculated engine load (A * 100 / 255) - Percentage + temp = (255 * motorController->getTorqueActual()) / motorController->getTorqueAvailable(); + outFrame.data.bytes[0] += 1; + outFrame.data.bytes[3] = (uint8_t)(temp & 0xFF); + return true; + break; + case 5: //Engine Coolant Temp (A - 40) = Degrees Centigrade + //our code stores temperatures as a signed integer for tenths of a degree so translate + temp = motorController->getTemperatureSystem() / 10; + if (temp < -40) temp = -40; + if (temp > 215) temp = 215; + temp += 40; + outFrame.data.bytes[0] += 1; //returning only one byte + outFrame.data.bytes[3] = (uint8_t)(temp); + return true; + break; + case 0xC: //Engine RPM (A * 256 + B) / 4 + temp = motorController->getSpeedActual() * 4; //we store in RPM while the PID code wants quarter rpms + outFrame.data.bytes[0] += 2; + outFrame.data.bytes[3] = (uint8_t)(temp / 256); + outFrame.data.bytes[4] = (uint8_t)(temp); + return true; + break; + case 0x11: //Throttle position (A * 100 / 255) - Percentage + temp = motorController->getThrottle() / 10; //getThrottle returns in 10ths of a percent + if (temp < 0) temp = 0; //negative throttle can't be shown for OBDII + temp = (255 * temp) / 100; + outFrame.data.bytes[0] += 1; + outFrame.data.bytes[3] = (uint8_t)(temp); + return true; + break; + case 0x1C: //Standard supported (We return 1 = OBDII) + outFrame.data.bytes[0] += 1; + outFrame.data.bytes[3] = 1; + return true; + break; + case 0x1F: //runtime since engine start (A*256 + B) + outFrame.data.bytes[0] += 2; + outFrame.data.bytes[3] = 0; //TODO: Get the actual runtime. + outFrame.data.bytes[4] = 0; + return true; + break; + case 0x20: //pids supported (next 32 pids - formatted just like PID 0) + outFrame.data.bytes[0] += 4; + outFrame.data.bytes[3] = 0b00000000; //pids 0x21 - 0x28 - starting with pid 0x21 in the MSB and going from there + outFrame.data.bytes[4] = 0b00000000; //pids 0x29 - 0x30 + outFrame.data.bytes[5] = 0b00000000; //pids 0x31 - 0x38 + outFrame.data.bytes[6] = 0b00000001; //pids 0x39 - 0x40 + return true; + break; + case 0x21: //Distance traveled with fault light lit (A*256 + B) - In km + outFrame.data.bytes[0] += 2; + outFrame.data.bytes[3] = 0; //TODO: Can we get this information? + outFrame.data.bytes[4] = 0; + return true; + break; + case 0x2F: //Fuel level (A * 100 / 255) - Percentage + outFrame.data.bytes[0] += 1; + outFrame.data.bytes[3] = 0; //TODO: finish BMS interface and get this value + return true; + break; + case 0x40: //PIDs supported, next 32 + outFrame.data.bytes[0] += 4; + outFrame.data.bytes[3] = 0b00000000; //pids 0x41 - 0x48 - starting with pid 0x41 in the MSB and going from there + outFrame.data.bytes[4] = 0b00000000; //pids 0x49 - 0x50 + outFrame.data.bytes[5] = 0b10000000; //pids 0x51 - 0x58 + outFrame.data.bytes[6] = 0b00000001; //pids 0x59 - 0x60 + return true; + break; + case 0x51: //What type of fuel do we use? (We use 8 = electric, presumably.) + outFrame.data.bytes[0] += 1; + outFrame.data.bytes[3] = 8; + return true; + break; + case 0x60: //PIDs supported, next 32 + outFrame.data.bytes[0] += 4; + outFrame.data.bytes[3] = 0b11100000; //pids 0x61 - 0x68 - starting with pid 0x61 in the MSB and going from there + outFrame.data.bytes[4] = 0b00000000; //pids 0x69 - 0x70 + outFrame.data.bytes[5] = 0b00000000; //pids 0x71 - 0x78 + outFrame.data.bytes[6] = 0b00000000; //pids 0x79 - 0x80 + return true; + break; + case 0x61: //Driver requested torque (A-125) - Percentage + temp = (100 * motorController->getTorqueRequested()) / motorController->getTorqueAvailable(); + temp += 125; + outFrame.data.bytes[0] += 1; + outFrame.data.bytes[3] = (uint8_t)temp; + return true; + break; + case 0x62: //Actual Torque delivered (A-125) - Percentage + temp = (100 * motorController->getTorqueActual()) / motorController->getTorqueAvailable(); + temp += 125; + outFrame.data.bytes[0] += 1; + outFrame.data.bytes[3] = (uint8_t)temp; + return true; + break; + case 0x63: //Reference torque for engine - presumably max torque - A*256 + B - Nm + temp = motorController->getTorqueAvailable(); + outFrame.data.bytes[0] += 2; + outFrame.data.bytes[3] = (uint8_t)(temp / 256); + outFrame.data.bytes[4] = (uint8_t)(temp & 0xFF); + return true; + break; + } + return false; } bool CanPIDListener::processShowCustomData(CAN_FRAME* inFrame, CAN_FRAME& outFrame) { - int pid = inFrame->data.bytes[2] * 256 + inFrame->data.bytes[3]; - switch (pid) { - } - return false; + int pid = inFrame->data.bytes[2] * 256 + inFrame->data.bytes[3]; + switch (pid) { + } + return false; } DeviceId CanPIDListener::getId() { - return PIDLISTENER; + return PIDLISTENER; } void CanPIDListener::loadConfiguration() { - CanPIDConfiguration *config = (CanPIDConfiguration *) getConfiguration(); + CanPIDConfiguration *config = (CanPIDConfiguration *) getConfiguration(); - if (!config) { // as lowest sub-class make sure we have a config object - config = new CanPIDConfiguration(); - setConfiguration(config); - } + if (!config) { // as lowest sub-class make sure we have a config object + config = new CanPIDConfiguration(); + setConfiguration(config); + } - Device::loadConfiguration(); // call parent + Device::loadConfiguration(); // call parent #ifdef USE_HARD_CODED - if (false) { + if (false) { #else - if (prefsHandler->checksumValid()) { //checksum is good, read in the values stored in EEPROM + if (prefsHandler->checksumValid()) { //checksum is good, read in the values stored in EEPROM #endif - Logger::debug(PIDLISTENER, (char *)Constants::validChecksum); - //prefsHandler->read(EETH_MIN_ONE, &config->minimumLevel1); - //prefsHandler->read(EETH_MAX_ONE, &config->maximumLevel1); - //prefsHandler->read(EETH_CAR_TYPE, &config->carType); - } else { //checksum invalid. Reinitialize values and store to EEPROM - Logger::warn(PIDLISTENER, (char *)Constants::invalidChecksum); - //config->minimumLevel1 = Throttle1MinValue; - //config->maximumLevel1 = Throttle1MaxValue; - //config->carType = Volvo_S80_Gas; - saveConfiguration(); - } - //Logger::debug(CANACCELPEDAL, "T1 MIN: %l MAX: %l Type: %d", config->minimumLevel1, config->maximumLevel1, config->carType); + Logger::debug(PIDLISTENER, (char *)Constants::validChecksum); + //prefsHandler->read(EETH_MIN_ONE, &config->minimumLevel1); + //prefsHandler->read(EETH_MAX_ONE, &config->maximumLevel1); + //prefsHandler->read(EETH_CAR_TYPE, &config->carType); + } else { //checksum invalid. Reinitialize values and store to EEPROM + Logger::warn(PIDLISTENER, (char *)Constants::invalidChecksum); + //config->minimumLevel1 = Throttle1MinValue; + //config->maximumLevel1 = Throttle1MaxValue; + //config->carType = Volvo_S80_Gas; + saveConfiguration(); + } + //Logger::debug(CANACCELPEDAL, "T1 MIN: %l MAX: %l Type: %d", config->minimumLevel1, config->maximumLevel1, config->carType); } /* * Store the current configuration to EEPROM */ void CanPIDListener::saveConfiguration() { - CanPIDConfiguration *config = (CanPIDConfiguration *) getConfiguration(); + CanPIDConfiguration *config = (CanPIDConfiguration *) getConfiguration(); - Device::saveConfiguration(); // call parent + Device::saveConfiguration(); // call parent - //prefsHandler->write(EETH_MIN_ONE, config->minimumLevel1); - //prefsHandler->write(EETH_MAX_ONE, config->maximumLevel1); - //prefsHandler->write(EETH_CAR_TYPE, config->carType); - //prefsHandler->saveChecksum(); + //prefsHandler->write(EETH_MIN_ONE, config->minimumLevel1); + //prefsHandler->write(EETH_MAX_ONE, config->maximumLevel1); + //prefsHandler->write(EETH_CAR_TYPE, config->carType); + //prefsHandler->saveChecksum(); } diff --git a/CanPIDListener.h b/CanPIDListener.h index 3b3f250..e1b74a1 100644 --- a/CanPIDListener.h +++ b/CanPIDListener.h @@ -38,30 +38,30 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. class CanPIDConfiguration : public DeviceConfiguration { public: - uint32_t pidId; //what ID are we listening for? - uint32_t pidMask; - bool useExtended; + uint32_t pidId; //what ID are we listening for? + uint32_t pidMask; + bool useExtended; }; class CanPIDListener: public Device, CanObserver { public: - CanPIDListener(); - void setup(); - void handleTick(); - void handleCanFrame(CAN_FRAME *frame); - DeviceId getId(); + CanPIDListener(); + void setup(); + void handleTick(); + void handleCanFrame(CAN_FRAME *frame); + DeviceId getId(); - void loadConfiguration(); - void saveConfiguration(); + void loadConfiguration(); + void saveConfiguration(); protected: private: - uint32_t responseId; // the CAN id with which the response is sent; - uint32_t responseMask; // the mask for the responseId - bool responseExtended; // if the response is expected as an extended frame - bool processShowData(CAN_FRAME* inFrame, CAN_FRAME& outFrame); - bool processShowCustomData(CAN_FRAME* inFrame, CAN_FRAME& outFrame); + uint32_t responseId; // the CAN id with which the response is sent; + uint32_t responseMask; // the mask for the responseId + bool responseExtended; // if the response is expected as an extended frame + bool processShowData(CAN_FRAME* inFrame, CAN_FRAME& outFrame); + bool processShowCustomData(CAN_FRAME* inFrame, CAN_FRAME& outFrame); }; #endif //CAN_PID_H_ diff --git a/CanThrottle.cpp b/CanThrottle.cpp index 9d76808..826ac2a 100644 --- a/CanThrottle.cpp +++ b/CanThrottle.cpp @@ -27,54 +27,58 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include "CanThrottle.h" CanThrottle::CanThrottle() : Throttle() { - prefsHandler = new PrefHandler(CANACCELPEDAL); - rawSignal.input1 = 0; - rawSignal.input2 = 0; - rawSignal.input3 = 0; - ticksNoResponse = 255; // invalidate input signal until response is received - responseId = 0; - responseMask = 0x7ff; - responseExtended = false; - - commonName = "CANBus accelerator"; + prefsHandler = new PrefHandler(CANACCELPEDAL); + rawSignal.input1 = 0; + rawSignal.input2 = 0; + rawSignal.input3 = 0; + ticksNoResponse = 255; // invalidate input signal until response is received + responseId = 0; + responseMask = 0x7ff; + responseExtended = false; + + commonName = "CANBus accelerator"; } void CanThrottle::setup() { - TickHandler::getInstance()->detach(this); - - Logger::info("add device: CanThrottle (id: %X, %X)", CANACCELPEDAL, this); - - loadConfiguration(); - Throttle::setup(); - - requestFrame.length = 0x08; - requestFrame.rtr = 0x00; - requestFrame.extended = 0x00; - - CanThrottleConfiguration *config = (CanThrottleConfiguration *)getConfiguration(); - switch (config->carType) { - case Volvo_S80_Gas: - // Request: dlc=0x08 fid=0x7e0 id=0x7e0 ide=0x00 rtr=0x00 data=0x03,0x22,0xEE,0xCB,0x00,0x00,0x00,0x00 (vida: [0x00, 0x00, 0x07, 0xe0, 0x22, 0xee, 0xcb]) - // Raw response: dlc=0x08 fid=0x7e8 id=0x7e8 ide=0x00 rtr=0x00 data=0x04,0x62,0xEE,0xCB,0x14,0x00,0x00,0x00 (vida: [0x00, 0x00, 0x07, 0xe8, 0x62, 0xee, 0xcb, 0x14]) - requestFrame.id = 0x7e0; - memcpy(requestFrame.data.bytes, (const uint8_t[]){ 0x03, 0x22, 0xee, 0xcb, 0x00, 0x00, 0x00, 0x00 }, 8); - responseId = 0x7e8; - break; - case Volvo_V50_Diesel: - // Request: dlc=0x08 fid=0xFFFFE id=0x3FFFE ide=0x01 rtr=0x00 data=0xCD,0x11,0xA6,0x00,0x24,0x01,0x00,0x00 ([0x00, 0xf, 0xff, 0xfe, 0xcd, 0x11, 0xa6, 0x00, 0x24, 0x01, 0x00, 0x00]) - // Response: dlc=0x08 fid=0x400021 id=0x21 ide=0x01 rtr=0x00 data=0xCE,0x11,0xE6,0x00,0x24,0x03,0xFD,0x00 (vida: [0x00, 0x40, 0x00, 0x21, 0xce, 0x11, 0xe6, 0x00, 0x24, 0x03, 0xfd, 0x00]) - requestFrame.id = 0x3FFFE; - requestFrame.extended = 0x01; - memcpy(requestFrame.data.bytes, (const uint8_t[]){ 0xce, 0x11, 0xe6, 0x00, 0x24, 0x03, 0xfd, 0x00 }, 8); - responseId = 0x21; - responseExtended = true; - break; - default: - Logger::error(CANACCELPEDAL, "no valid car type defined."); - } - - CanHandler::getInstanceCar()->attach(this, responseId, responseMask, responseExtended); - TickHandler::getInstance()->attach(this, CFG_TICK_INTERVAL_CAN_THROTTLE); + TickHandler::getInstance()->detach(this); + + Logger::info("add device: CanThrottle (id: %X, %X)", CANACCELPEDAL, this); + + loadConfiguration(); + Throttle::setup(); + + requestFrame.length = 0x08; + requestFrame.rtr = 0x00; + requestFrame.extended = 0x00; + + CanThrottleConfiguration *config = (CanThrottleConfiguration *)getConfiguration(); + switch (config->carType) { + case Volvo_S80_Gas: + // Request: dlc=0x08 fid=0x7e0 id=0x7e0 ide=0x00 rtr=0x00 data=0x03,0x22,0xEE,0xCB,0x00,0x00,0x00,0x00 (vida: [0x00, 0x00, 0x07, 0xe0, 0x22, 0xee, 0xcb]) + // Raw response: dlc=0x08 fid=0x7e8 id=0x7e8 ide=0x00 rtr=0x00 data=0x04,0x62,0xEE,0xCB,0x14,0x00,0x00,0x00 (vida: [0x00, 0x00, 0x07, 0xe8, 0x62, 0xee, 0xcb, 0x14]) + requestFrame.id = 0x7e0; + memcpy(requestFrame.data.bytes, (const uint8_t[]) { + 0x03, 0x22, 0xee, 0xcb, 0x00, 0x00, 0x00, 0x00 + }, 8); + responseId = 0x7e8; + break; + case Volvo_V50_Diesel: + // Request: dlc=0x08 fid=0xFFFFE id=0x3FFFE ide=0x01 rtr=0x00 data=0xCD,0x11,0xA6,0x00,0x24,0x01,0x00,0x00 ([0x00, 0xf, 0xff, 0xfe, 0xcd, 0x11, 0xa6, 0x00, 0x24, 0x01, 0x00, 0x00]) + // Response: dlc=0x08 fid=0x400021 id=0x21 ide=0x01 rtr=0x00 data=0xCE,0x11,0xE6,0x00,0x24,0x03,0xFD,0x00 (vida: [0x00, 0x40, 0x00, 0x21, 0xce, 0x11, 0xe6, 0x00, 0x24, 0x03, 0xfd, 0x00]) + requestFrame.id = 0x3FFFE; + requestFrame.extended = 0x01; + memcpy(requestFrame.data.bytes, (const uint8_t[]) { + 0xce, 0x11, 0xe6, 0x00, 0x24, 0x03, 0xfd, 0x00 + }, 8); + responseId = 0x21; + responseExtended = true; + break; + default: + Logger::error(CANACCELPEDAL, "no valid car type defined."); + } + + CanHandler::getInstanceCar()->attach(this, responseId, responseMask, responseExtended); + TickHandler::getInstance()->attach(this, CFG_TICK_INTERVAL_CAN_THROTTLE); } /* @@ -82,12 +86,12 @@ void CanThrottle::setup() { * */ void CanThrottle::handleTick() { - Throttle::handleTick(); // Call parent handleTick + Throttle::handleTick(); // Call parent handleTick - CanHandler::getInstanceCar()->sendFrame(requestFrame); + CanHandler::getInstanceCar()->sendFrame(requestFrame); - if (ticksNoResponse < 255) // make sure it doesn't overflow - ticksNoResponse++; + if (ticksNoResponse < 255) // make sure it doesn't overflow + ticksNoResponse++; } /* @@ -95,105 +99,105 @@ void CanThrottle::handleTick() { * */ void CanThrottle::handleCanFrame(CAN_FRAME *frame) { - CanThrottleConfiguration *config = (CanThrottleConfiguration *)getConfiguration(); - - if (frame->id == responseId) { - switch (config->carType) { - case Volvo_S80_Gas: - rawSignal.input1 = frame->data.bytes[4]; - break; - case Volvo_V50_Diesel: - rawSignal.input1 = (frame->data.bytes[5] + 1) * frame->data.bytes[6]; - break; - } - ticksNoResponse = 0; - } + CanThrottleConfiguration *config = (CanThrottleConfiguration *)getConfiguration(); + + if (frame->id == responseId) { + switch (config->carType) { + case Volvo_S80_Gas: + rawSignal.input1 = frame->data.bytes[4]; + break; + case Volvo_V50_Diesel: + rawSignal.input1 = (frame->data.bytes[5] + 1) * frame->data.bytes[6]; + break; + } + ticksNoResponse = 0; + } } RawSignalData* CanThrottle::acquireRawSignal() { - return &rawSignal; // should have already happened in the background + return &rawSignal; // should have already happened in the background } bool CanThrottle::validateSignal(RawSignalData* rawSignal) { - CanThrottleConfiguration *config = (CanThrottleConfiguration *) getConfiguration(); - - if (ticksNoResponse >= CFG_CANTHROTTLE_MAX_NUM_LOST_MSG) { - if (status == OK) - Logger::error(CANACCELPEDAL, "no response on position request received: %d ", ticksNoResponse); - status = ERR_MISC; - return false; - } - if (rawSignal->input1 > (config->maximumLevel1 + CFG_THROTTLE_TOLERANCE)) { - if (status == OK) - Logger::error(CANACCELPEDAL, (char *)Constants::valueOutOfRange, rawSignal->input1); - status = ERR_HIGH_T1; - return false; - } - if (rawSignal->input1 < (config->minimumLevel1 - CFG_THROTTLE_TOLERANCE)) { - if (status == OK) - Logger::error(CANACCELPEDAL, (char *)Constants::valueOutOfRange, rawSignal->input1); - status = ERR_LOW_T1; - return false; - } - - // all checks passed -> throttle seems to be ok - if (status != OK) - Logger::info(CANACCELPEDAL, (char *)Constants::normalOperation); - status = OK; - return true; + CanThrottleConfiguration *config = (CanThrottleConfiguration *) getConfiguration(); + + if (ticksNoResponse >= CFG_CANTHROTTLE_MAX_NUM_LOST_MSG) { + if (status == OK) + Logger::error(CANACCELPEDAL, "no response on position request received: %d ", ticksNoResponse); + status = ERR_MISC; + return false; + } + if (rawSignal->input1 > (config->maximumLevel1 + CFG_THROTTLE_TOLERANCE)) { + if (status == OK) + Logger::error(CANACCELPEDAL, (char *)Constants::valueOutOfRange, rawSignal->input1); + status = ERR_HIGH_T1; + return false; + } + if (rawSignal->input1 < (config->minimumLevel1 - CFG_THROTTLE_TOLERANCE)) { + if (status == OK) + Logger::error(CANACCELPEDAL, (char *)Constants::valueOutOfRange, rawSignal->input1); + status = ERR_LOW_T1; + return false; + } + + // all checks passed -> throttle seems to be ok + if (status != OK) + Logger::info(CANACCELPEDAL, (char *)Constants::normalOperation); + status = OK; + return true; } uint16_t CanThrottle::calculatePedalPosition(RawSignalData* rawSignal) { - CanThrottleConfiguration *config = (CanThrottleConfiguration *) getConfiguration(); + CanThrottleConfiguration *config = (CanThrottleConfiguration *) getConfiguration(); - return normalizeAndConstrainInput(rawSignal->input1, config->minimumLevel1, config->maximumLevel1); + return normalizeAndConstrainInput(rawSignal->input1, config->minimumLevel1, config->maximumLevel1); } DeviceId CanThrottle::getId() { - return CANACCELPEDAL; + return CANACCELPEDAL; } void CanThrottle::loadConfiguration() { - CanThrottleConfiguration *config = (CanThrottleConfiguration *) getConfiguration(); + CanThrottleConfiguration *config = (CanThrottleConfiguration *) getConfiguration(); - if (!config) { // as lowest sub-class make sure we have a config object - config = new CanThrottleConfiguration(); - setConfiguration(config); - } + if (!config) { // as lowest sub-class make sure we have a config object + config = new CanThrottleConfiguration(); + setConfiguration(config); + } - Throttle::loadConfiguration(); // call parent + Throttle::loadConfiguration(); // call parent #ifdef USE_HARD_CODED - if (false) { + if (false) { #else - if (prefsHandler->checksumValid()) { //checksum is good, read in the values stored in EEPROM + if (prefsHandler->checksumValid()) { //checksum is good, read in the values stored in EEPROM #endif - Logger::debug(CANACCELPEDAL, (char *)Constants::validChecksum); - prefsHandler->read(EETH_MIN_ONE, &config->minimumLevel1); - prefsHandler->read(EETH_MAX_ONE, &config->maximumLevel1); - prefsHandler->read(EETH_CAR_TYPE, &config->carType); - } else { //checksum invalid. Reinitialize values and store to EEPROM - Logger::warn(CANACCELPEDAL, (char *)Constants::invalidChecksum); - config->minimumLevel1 = Throttle1MinValue; - config->maximumLevel1 = Throttle1MaxValue; - config->carType = Volvo_S80_Gas; - saveConfiguration(); - } - Logger::debug(CANACCELPEDAL, "T1 MIN: %l MAX: %l Type: %d", config->minimumLevel1, config->maximumLevel1, config->carType); + Logger::debug(CANACCELPEDAL, (char *)Constants::validChecksum); + prefsHandler->read(EETH_MIN_ONE, &config->minimumLevel1); + prefsHandler->read(EETH_MAX_ONE, &config->maximumLevel1); + prefsHandler->read(EETH_CAR_TYPE, &config->carType); + } else { //checksum invalid. Reinitialize values and store to EEPROM + Logger::warn(CANACCELPEDAL, (char *)Constants::invalidChecksum); + config->minimumLevel1 = Throttle1MinValue; + config->maximumLevel1 = Throttle1MaxValue; + config->carType = Volvo_S80_Gas; + saveConfiguration(); + } + Logger::debug(CANACCELPEDAL, "T1 MIN: %l MAX: %l Type: %d", config->minimumLevel1, config->maximumLevel1, config->carType); } /* * Store the current configuration to EEPROM */ void CanThrottle::saveConfiguration() { - CanThrottleConfiguration *config = (CanThrottleConfiguration *) getConfiguration(); + CanThrottleConfiguration *config = (CanThrottleConfiguration *) getConfiguration(); - Throttle::saveConfiguration(); // call parent + Throttle::saveConfiguration(); // call parent - prefsHandler->write(EETH_MIN_ONE, config->minimumLevel1); - prefsHandler->write(EETH_MAX_ONE, config->maximumLevel1); - prefsHandler->write(EETH_CAR_TYPE, config->carType); - prefsHandler->saveChecksum(); + prefsHandler->write(EETH_MIN_ONE, config->minimumLevel1); + prefsHandler->write(EETH_MAX_ONE, config->maximumLevel1); + prefsHandler->write(EETH_CAR_TYPE, config->carType); + prefsHandler->saveChecksum(); } diff --git a/CanThrottle.h b/CanThrottle.h index 82c7b27..eaac0d7 100644 --- a/CanThrottle.h +++ b/CanThrottle.h @@ -36,40 +36,40 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include "DeviceManager.h" enum CanCarType { - unknowkn = 0x00, - Volvo_S80_Gas = 0x01, - Volvo_V50_Diesel = 0x02 + unknowkn = 0x00, + Volvo_S80_Gas = 0x01, + Volvo_V50_Diesel = 0x02 }; class CanThrottleConfiguration : public ThrottleConfiguration { public: - uint16_t minimumLevel1, maximumLevel1; // values for when the pedal is at its min and max - uint16_t carType; // the type of car, so we know how to interpret which bytes + uint16_t minimumLevel1, maximumLevel1; // values for when the pedal is at its min and max + uint16_t carType; // the type of car, so we know how to interpret which bytes }; class CanThrottle: public Throttle, CanObserver { public: - CanThrottle(); - void setup(); - void handleTick(); - void handleCanFrame(CAN_FRAME *frame); - DeviceId getId(); + CanThrottle(); + void setup(); + void handleTick(); + void handleCanFrame(CAN_FRAME *frame); + DeviceId getId(); - RawSignalData *acquireRawSignal(); - void loadConfiguration(); - void saveConfiguration(); + RawSignalData *acquireRawSignal(); + void loadConfiguration(); + void saveConfiguration(); protected: - bool validateSignal(RawSignalData *); - uint16_t calculatePedalPosition(RawSignalData *); + bool validateSignal(RawSignalData *); + uint16_t calculatePedalPosition(RawSignalData *); private: - CAN_FRAME requestFrame; // the request frame sent to the car - RawSignalData rawSignal; // raw signal - uint8_t ticksNoResponse; // number of ticks no response was received - uint32_t responseId; // the CAN id with which the response is sent; - uint32_t responseMask; // the mask for the responseId - bool responseExtended; // if the response is expected as an extended frame + CAN_FRAME requestFrame; // the request frame sent to the car + RawSignalData rawSignal; // raw signal + uint8_t ticksNoResponse; // number of ticks no response was received + uint32_t responseId; // the CAN id with which the response is sent; + uint32_t responseMask; // the mask for the responseId + bool responseExtended; // if the response is expected as an extended frame }; #endif /* CAN_THROTTLE_H_ */ diff --git a/CodaMotorController.cpp b/CodaMotorController.cpp index 3e77975..069f1e0 100644 --- a/CodaMotorController.cpp +++ b/CodaMotorController.cpp @@ -1,17 +1,17 @@ /* * CodaMotorController.cpp * - * CAN Interface to the Coda flavored UQM Powerphase 100 inverter - + * CAN Interface to the Coda flavored UQM Powerphase 100 inverter - Handles sending of commands and reception of status frames to drive - the inverter and thus motor. Endianess is configurable in the firmware - inside the UQM inverter but default is little endian. This object module * uses little endian format + the inverter and thus motor. Endianess is configurable in the firmware + inside the UQM inverter but default is little endian. This object module * uses little endian format - the least significant byte is the first in order with the MSB following. **************NOTE*************** Ticks are critical for the UQM inverter. A tick value of 10000 in config.h is necessary as the inverter expects a torque command within each 12 millisecond period. Failing to provide it is a bit subtle to catch but quite dramatic. The motor will run at speed for about 5 to 7 minutes and then "cough" losing all torque and then recovering. Five minutes later, this will repeat. Setting to a very fast value of 10000 seems to cure it NOW. - As the software grows and the load on the CPU increases, this could show up again. + As the software grows and the load on the CPU increases, this could show up again. * Copyright (c) 2014 Jack Rickard @@ -38,15 +38,18 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include "CodaMotorController.h" -template inline Print &operator <<(Print &obj, T arg) { obj.print(arg); return obj; } +template inline Print &operator <<(Print &obj, T arg) { + obj.print(arg); + return obj; +} long mss; -extern bool runThrottle; +extern bool runThrottle; const uint8_t swizzleTable[] = { 0xAA, 0x7F, 0xFE, 0x29, 0x52, 0xA4, 0x9D, 0xEF, 0xB, 0x16, 0x2C, 0x58, 0xB0, 0x60, 0xC0, 1 }; - -CodaMotorController::CodaMotorController() : MotorController() + +CodaMotorController::CodaMotorController() : MotorController() { prefsHandler = new PrefHandler(CODAUQM); @@ -55,112 +58,118 @@ CodaMotorController::CodaMotorController() : MotorController() activityCount = 0; sequence=0; commonName = "Coda UQM Powerphase 100 Inverter"; - + } -void CodaMotorController::setup() +void CodaMotorController::setup() { - TickHandler::getInstance()->detach(this); + TickHandler::getInstance()->detach(this); - Logger::info("add device: CODA UQM (id:%X, %X)", CODAUQM, this); + Logger::info("add device: CODA UQM (id:%X, %X)", CODAUQM, this); - loadConfiguration(); + loadConfiguration(); - MotorController::setup(); // run the parent class version of this function + MotorController::setup(); // run the parent class version of this function + + // register ourselves as observer of all 0x20x can frames for UQM + CanHandler::getInstanceEV()->attach(this, 0x200, 0x7f0, false); + + operationState=ENABLE; + selectedGear=DRIVE; + TickHandler::getInstance()->attach(this, CFG_TICK_INTERVAL_MOTOR_CONTROLLER_CODAUQM); - // register ourselves as observer of all 0x20x can frames for UQM - CanHandler::getInstanceEV()->attach(this, 0x200, 0x7f0, false); - - operationState=ENABLE; - selectedGear=DRIVE; - TickHandler::getInstance()->attach(this, CFG_TICK_INTERVAL_MOTOR_CONTROLLER_CODAUQM); - } -void CodaMotorController::handleCanFrame(CAN_FRAME *frame) +void CodaMotorController::handleCanFrame(CAN_FRAME *frame) { - int RotorTemp, invTemp, StatorTemp; - int temp; - online = 1; //if a frame got to here then it passed the filter and must come from UQM - if (!running) //if we're newly running then cancel faults if necessary. - { - faultHandler.cancelOngoingFault(CODAUQM, FAULT_MOTORCTRL_COMM); - } + int RotorTemp, invTemp, StatorTemp; + int temp; + online = 1; //if a frame got to here then it passed the filter and must come from UQM + if (!running) //if we're newly running then cancel faults if necessary. + { + faultHandler.cancelOngoingFault(CODAUQM, FAULT_MOTORCTRL_COMM); + } running=true; - Logger::debug("UQM inverter msg: %X %X %X %X %X %X %X %X %X", frame->id, frame->data.bytes[0], - frame->data.bytes[1],frame->data.bytes[2],frame->data.bytes[3],frame->data.bytes[4], - frame->data.bytes[5],frame->data.bytes[6],frame->data.bytes[7]); - - switch (frame->id) - { - - case 0x209: //Accurate Feedback Message - - torqueActual = ((((frame->data.bytes[1] * 256) + frame->data.bytes[0])-32128)) ; - dcVoltage = (((frame->data.bytes[3] * 256) + frame->data.bytes[2])-32128); - if(dcVoltage<1000){dcVoltage=1000;}//Lowest value we can display on dashboard - dcCurrent = (((frame->data.bytes[5] * 256) + frame->data.bytes[4])-32128); - speedActual = abs((((frame->data.bytes[7] * 256) + frame->data.bytes[6])-32128)/2); - Logger::debug("UQM Actual Torque: %d DC Voltage: %d Amps: %d RPM: %d", torqueActual/10,dcVoltage/10,dcCurrent/10,speedActual); - break; - - case 0x20A: //System Status Message - Logger::debug("UQM inverter 20A System Status Message Received"); - break; - - - case 0x20B: //Emergency Fuel Cutback Message - Logger::debug("UQM inverter 20B Emergency Fuel Cutback Message Received"); - break; - - case 0x20C: //Reserved Message - Logger::debug("UQM inverter 20C Reserved Message Received"); - break; - - case 0x20D: //Limited Torque Percentage Message - Logger::debug("UQM inverter 20D Limited Torque Percentage Message Received"); - break; - - case 0x20E: //Temperature Feedback Message - - invTemp = frame->data.bytes[2]; - RotorTemp = frame->data.bytes[3]; - StatorTemp = frame->data.bytes[4]; - temperatureInverter = (invTemp-40)*10; - if (RotorTemp > StatorTemp) {temperatureMotor = (RotorTemp-40)*10;} - else {temperatureMotor = (StatorTemp-40)*10;} - Logger::debug("UQM 20E Inverter temp: %d Motor temp: %d", temperatureInverter,temperatureMotor); - break; - - case 0x20F: //CAN Watchdog Status Message - Logger::debug("UQM 20F CAN Watchdog status error"); - warning=true; - running=false; - sendCmd2(); //If we get a Watchdog status, we need to respond with Watchdog reset - break; - } + Logger::debug("UQM inverter msg: %X %X %X %X %X %X %X %X %X", frame->id, frame->data.bytes[0], + frame->data.bytes[1],frame->data.bytes[2],frame->data.bytes[3],frame->data.bytes[4], + frame->data.bytes[5],frame->data.bytes[6],frame->data.bytes[7]); + + switch (frame->id) + { + + case 0x209: //Accurate Feedback Message + + torqueActual = ((((frame->data.bytes[1] * 256) + frame->data.bytes[0])-32128)) ; + dcVoltage = (((frame->data.bytes[3] * 256) + frame->data.bytes[2])-32128); + if(dcVoltage<1000) { + dcVoltage=1000; //Lowest value we can display on dashboard + } + dcCurrent = (((frame->data.bytes[5] * 256) + frame->data.bytes[4])-32128); + speedActual = abs((((frame->data.bytes[7] * 256) + frame->data.bytes[6])-32128)/2); + Logger::debug("UQM Actual Torque: %d DC Voltage: %d Amps: %d RPM: %d", torqueActual/10,dcVoltage/10,dcCurrent/10,speedActual); + break; + + case 0x20A: //System Status Message + Logger::debug("UQM inverter 20A System Status Message Received"); + break; + + + case 0x20B: //Emergency Fuel Cutback Message + Logger::debug("UQM inverter 20B Emergency Fuel Cutback Message Received"); + break; + + case 0x20C: //Reserved Message + Logger::debug("UQM inverter 20C Reserved Message Received"); + break; + + case 0x20D: //Limited Torque Percentage Message + Logger::debug("UQM inverter 20D Limited Torque Percentage Message Received"); + break; + + case 0x20E: //Temperature Feedback Message + + invTemp = frame->data.bytes[2]; + RotorTemp = frame->data.bytes[3]; + StatorTemp = frame->data.bytes[4]; + temperatureInverter = (invTemp-40)*10; + if (RotorTemp > StatorTemp) { + temperatureMotor = (RotorTemp-40)*10; + } + else { + temperatureMotor = (StatorTemp-40)*10; + } + Logger::debug("UQM 20E Inverter temp: %d Motor temp: %d", temperatureInverter,temperatureMotor); + break; + + case 0x20F: //CAN Watchdog Status Message + Logger::debug("UQM 20F CAN Watchdog status error"); + warning=true; + running=false; + sendCmd2(); //If we get a Watchdog status, we need to respond with Watchdog reset + break; + } } void CodaMotorController::handleTick() { - - MotorController::handleTick(); //kick the ball up to papa - sendCmd1(); //Send our lone torque command - - if(!online) //This routine checks to see if we have received any frames from the inverter. If so, ONLINE would be true and - { //we set the RUNNING light on. If no frames are received for 2 seconds, we set running OFF. - if (millis()-mss>2000) - { - running=false; // We haven't received any frames for over 2 seconds. Otherwise online would be true. - mss=millis(); //Reset our 2 second timer - } - } - else running=true; - online=false;//This flag will be set to true by received frames - + + MotorController::handleTick(); //kick the ball up to papa + sendCmd1(); //Send our lone torque command + + if(!online) //This routine checks to see if we have received any frames from the inverter. If so, ONLINE would be true and + { //we set the RUNNING light on. If no frames are received for 2 seconds, we set running OFF. + if (millis()-mss>2000) + { + running=false; // We haven't received any frames for over 2 seconds. Otherwise online would be true. + mss=millis(); //Reset our 2 second timer + } + } + else running=true; + online=false;//This flag will be set to true by received frames + } @@ -169,7 +178,7 @@ UQM only HAS a single command CAN bus frame - address 0x204 Everything is stuff Byte 1 - always set to 0 -Byte 2 - Command Byte +Byte 2 - Command Byte Left four bits contain enable disable and forward reverse Bits 7/6 DISABLED =01 Bits 7/6 ENABLE =10 @@ -179,146 +188,152 @@ Byte 2 - Command Byte Right four bits (3 to 0) is a sequence counter that counts 0000 to 0111 and back to 0000 -Byte 3 LSB of Torque command value. +Byte 3 LSB of Torque command value. Byte 4 MSB of Torque command value Offset is 32128 -Byte 5 Security CRC byte. +Byte 5 Security CRC byte. Bytes must be sent IN SEQUENCE and the CRC byte must be appropriate for bytes 2, 3, and 4. Values above 32128 are positive torque. Values below 32128 are negative torque */ -void CodaMotorController::sendCmd1() +void CodaMotorController::sendCmd1() { - CodaMotorControllerConfiguration *config = (CodaMotorControllerConfiguration *)getConfiguration(); - - CAN_FRAME output; - output.length = 5; - output.id = 0x204; - output.extended = 0; //standard frame - output.rtr = 0; - output.data.bytes[0] = 0x00; //First byte is always zero. - - - if(operationState==ENABLE) - { - output.data.bytes[1] = 0x80; //1000 0000 - } - else - { - output.data.bytes[1] = 0x40; //0100 0000 - } - - if(selectedGear==DRIVE) - { - output.data.bytes[1] |= 0x20; //xx10 0000 - } - else - { - output.data.bytes[1] |= 0x10;//xx01 0000 - } - - sequence+=1; //Increment sequence - if (sequence==8){sequence=0;} //If we reach 8, go to zero - output.data.bytes[1] |= sequence; //This should retain left four and add sequence count - //to right four bits. - //Requested throttle is [-1000, 1000] - //Two byte torque request in 0.1NM Can be positive or negative - - torqueCommand=32128; //Set our zero offset value -torque=0 - torqueRequested = ((throttleRequested * config->torqueMax) / 1000); //Calculate torque request from throttle position x maximum torque - if(speedActualspeedMax){torqueCommand += torqueRequested;} //If actual rpm less than max rpm, add torque command to offset - else {torqueCommand+= torqueRequested/2;} //If at RPM limit, cut torque command in half. - output.data.bytes[3] = (torqueCommand & 0xFF00) >> 8; //Stow torque command in bytes 2 and 3. - output.data.bytes[2] = (torqueCommand & 0x00FF); - output.data.bytes[4] = genCodaCRC(output.data.bytes[1], output.data.bytes[2], output.data.bytes[3]); //Calculate security byte - - CanHandler::getInstanceEV()->sendFrame(output); //Mail it. - timestamp(); - - Logger::debug("Torque command: %X %X ControlByte: %X LSB %X MSB: %X CRC: %X %d:%d:%d.%d",output.id, output.data.bytes[0], -output.data.bytes[1],output.data.bytes[2],output.data.bytes[3],output.data.bytes[4], hours, minutes, seconds, milliseconds); - + CodaMotorControllerConfiguration *config = (CodaMotorControllerConfiguration *)getConfiguration(); + + CAN_FRAME output; + output.length = 5; + output.id = 0x204; + output.extended = 0; //standard frame + output.rtr = 0; + output.data.bytes[0] = 0x00; //First byte is always zero. + + + if(operationState==ENABLE) + { + output.data.bytes[1] = 0x80; //1000 0000 + } + else + { + output.data.bytes[1] = 0x40; //0100 0000 + } + + if(selectedGear==DRIVE) + { + output.data.bytes[1] |= 0x20; //xx10 0000 + } + else + { + output.data.bytes[1] |= 0x10;//xx01 0000 + } + + sequence+=1; //Increment sequence + if (sequence==8) { + sequence=0; //If we reach 8, go to zero + } + output.data.bytes[1] |= sequence; //This should retain left four and add sequence count + //to right four bits. + //Requested throttle is [-1000, 1000] + //Two byte torque request in 0.1NM Can be positive or negative + + torqueCommand=32128; //Set our zero offset value -torque=0 + torqueRequested = ((throttleRequested * config->torqueMax) / 1000); //Calculate torque request from throttle position x maximum torque + if(speedActualspeedMax) { + torqueCommand += torqueRequested; //If actual rpm less than max rpm, add torque command to offset + } + else { + torqueCommand+= torqueRequested/2; //If at RPM limit, cut torque command in half. + } + output.data.bytes[3] = (torqueCommand & 0xFF00) >> 8; //Stow torque command in bytes 2 and 3. + output.data.bytes[2] = (torqueCommand & 0x00FF); + output.data.bytes[4] = genCodaCRC(output.data.bytes[1], output.data.bytes[2], output.data.bytes[3]); //Calculate security byte + + CanHandler::getInstanceEV()->sendFrame(output); //Mail it. + timestamp(); + + Logger::debug("Torque command: %X %X ControlByte: %X LSB %X MSB: %X CRC: %X %d:%d:%d.%d",output.id, output.data.bytes[0], + output.data.bytes[1],output.data.bytes[2],output.data.bytes[3],output.data.bytes[4], hours, minutes, seconds, milliseconds); + } void CodaMotorController::sendCmd2() { - CodaMotorControllerConfiguration *config = (CodaMotorControllerConfiguration *)getConfiguration(); - - /*In the CODA CAN bus capture logs, this command, defined in the UQM manual as a - 207 watchdog reset, is sent every 480msec. It also always occurs after the last count of - a sequence ie 57, 67, 97, or A7. But this may just be coincidence. - By the book, this is to be sent in response to a watchdog timeout. - We send this in response to receipt of a 20F Watchdog status. - */ - - CAN_FRAME output; - output.length = 8; - output.id = 0x207; - output.extended = 0; //standard frame - output.data.bytes[0] = 0xa5; //This is simply three given values. The 5A appears to be - output.data.bytes[1] = 0xa5; //the important one. - output.data.bytes[2] = 0x5a; - output.data.bytes[3] = 0x00; - output.data.bytes[4] = 0x00; - output.data.bytes[5] = 0x00; - output.data.bytes[6] = 0x00; - output.data.bytes[7] = 0x00; - - CanHandler::getInstanceEV()->sendFrame(output); - timestamp(); -Logger::debug("Watchdog reset: %X %X %X %d:%d:%d.%d",output.data.bytes[0], output.data.bytes[1], -output.data.bytes[2], hours, minutes, seconds, milliseconds); - - warning=false; + CodaMotorControllerConfiguration *config = (CodaMotorControllerConfiguration *)getConfiguration(); + + /*In the CODA CAN bus capture logs, this command, defined in the UQM manual as a + 207 watchdog reset, is sent every 480msec. It also always occurs after the last count of + a sequence ie 57, 67, 97, or A7. But this may just be coincidence. + By the book, this is to be sent in response to a watchdog timeout. + We send this in response to receipt of a 20F Watchdog status. + */ + + CAN_FRAME output; + output.length = 8; + output.id = 0x207; + output.extended = 0; //standard frame + output.data.bytes[0] = 0xa5; //This is simply three given values. The 5A appears to be + output.data.bytes[1] = 0xa5; //the important one. + output.data.bytes[2] = 0x5a; + output.data.bytes[3] = 0x00; + output.data.bytes[4] = 0x00; + output.data.bytes[5] = 0x00; + output.data.bytes[6] = 0x00; + output.data.bytes[7] = 0x00; + + CanHandler::getInstanceEV()->sendFrame(output); + timestamp(); + Logger::debug("Watchdog reset: %X %X %X %d:%d:%d.%d",output.data.bytes[0], output.data.bytes[1], + output.data.bytes[2], hours, minutes, seconds, milliseconds); + + warning=false; } DeviceId CodaMotorController::getId() { - return (CODAUQM); + return (CODAUQM); } -uint32_t CodaMotorController::getTickInterval() +uint32_t CodaMotorController::getTickInterval() { - return CFG_TICK_INTERVAL_MOTOR_CONTROLLER_CODAUQM; + return CFG_TICK_INTERVAL_MOTOR_CONTROLLER_CODAUQM; } void CodaMotorController::loadConfiguration() { - CodaMotorControllerConfiguration *config = (CodaMotorControllerConfiguration *)getConfiguration(); + CodaMotorControllerConfiguration *config = (CodaMotorControllerConfiguration *)getConfiguration(); - if (!config) { - config = new CodaMotorControllerConfiguration(); - setConfiguration(config); - } + if (!config) { + config = new CodaMotorControllerConfiguration(); + setConfiguration(config); + } - MotorController::loadConfiguration(); // call parent + MotorController::loadConfiguration(); // call parent } void CodaMotorController::saveConfiguration() { - MotorController::saveConfiguration(); + MotorController::saveConfiguration(); } -uint8_t CodaMotorController::genCodaCRC(uint8_t cmd, uint8_t torq_lsb, uint8_t torq_msb) +uint8_t CodaMotorController::genCodaCRC(uint8_t cmd, uint8_t torq_lsb, uint8_t torq_msb) { - int counter; - uint8_t crc; - uint16_t temp_torq = torq_lsb + (256 * torq_msb); - crc = 0x7F; //7F is the answer if bytes 3 and 4 are zero. We build up from there. - - //this can be done a little more efficiently but this is clearer to read - if (((cmd & 0xA0) == 0xA0) || ((cmd & 0x60) == 0x60)) temp_torq += 1; - - //Not sure why this happens except to obfuscate the result - if ((temp_torq % 4) == 3) temp_torq += 4; - - //increment over the bits within the torque command - //and applies a particular XOR for each set bit. - for (counter = 0; counter < 16; counter++) - { - if ((temp_torq & (1 << counter)) == (1 << counter)) crc = (byte)(crc ^ swizzleTable[counter]); - } + int counter; + uint8_t crc; + uint16_t temp_torq = torq_lsb + (256 * torq_msb); + crc = 0x7F; //7F is the answer if bytes 3 and 4 are zero. We build up from there. + + //this can be done a little more efficiently but this is clearer to read + if (((cmd & 0xA0) == 0xA0) || ((cmd & 0x60) == 0x60)) temp_torq += 1; + + //Not sure why this happens except to obfuscate the result + if ((temp_torq % 4) == 3) temp_torq += 4; + + //increment over the bits within the torque command + //and applies a particular XOR for each set bit. + for (counter = 0; counter < 16; counter++) + { + if ((temp_torq & (1 << counter)) == (1 << counter)) crc = (byte)(crc ^ swizzleTable[counter]); + } return (crc); } @@ -326,13 +341,13 @@ uint8_t CodaMotorController::genCodaCRC(uint8_t cmd, uint8_t torq_lsb, uint8_t t void CodaMotorController::timestamp() { - milliseconds = (int) (millis()/1) %1000 ; - seconds = (int) (millis() / 1000) % 60 ; + milliseconds = (int) (millis()/1) %1000 ; + seconds = (int) (millis() / 1000) % 60 ; minutes = (int) ((millis() / (1000*60)) % 60); hours = (int) ((millis() / (1000*60*60)) % 24); - // char buffer[9]; + // char buffer[9]; //sprintf(buffer,"%02d:%02d:%02d.%03d", hours, minutes, seconds, milliseconds); - // Serial< inline Print &operator <<(Print &obj, T arg) { obj.print(arg); return obj; } +template inline Print &operator <<(Print &obj, T arg) { + obj.print(arg); + return obj; +} + - DCDCController::DCDCController() : Device() { prefsHandler = new PrefHandler(DCDC); //prefsHandler->setEnabledStatus(true); - + commonName = "Delphi DC-DC Converter"; - + } -void DCDCController::handleCanFrame(CAN_FRAME *frame) +void DCDCController::handleCanFrame(CAN_FRAME *frame) { - Logger::debug("DCDC msg: %X", frame->id); - Logger::debug("DCDC data: %X%X%X%X%X%X%X%X", frame->data.bytes[0],frame->data.bytes[1],frame->data.bytes[2],frame->data.bytes[3],frame->data.bytes[4],frame->data.bytes[5],frame->data.bytes[6],frame->data.bytes[7]); + Logger::debug("DCDC msg: %X", frame->id); + Logger::debug("DCDC data: %X%X%X%X%X%X%X%X", frame->data.bytes[0],frame->data.bytes[1],frame->data.bytes[2],frame->data.bytes[3],frame->data.bytes[4],frame->data.bytes[5],frame->data.bytes[6],frame->data.bytes[7]); } void DCDCController::setup() { - TickHandler::getInstance()->detach(this); + TickHandler::getInstance()->detach(this); - loadConfiguration(); - Device::setup(); // run the parent class version of this function + loadConfiguration(); + Device::setup(); // run the parent class version of this function - CanHandler::getInstanceCar()->attach(this, 0x1D5, 0x7ff, false); - //Watch for 0x1D5 messages from Delphi converter - TickHandler::getInstance()->attach(this, CFG_TICK_INTERVAL_DCDC); + CanHandler::getInstanceCar()->attach(this, 0x1D5, 0x7ff, false); + //Watch for 0x1D5 messages from Delphi converter + TickHandler::getInstance()->attach(this, CFG_TICK_INTERVAL_DCDC); } void DCDCController::handleTick() { - Device::handleTick(); //kick the ball up to papa + Device::handleTick(); //kick the ball up to papa + + sendCmd(); //Send our Delphi voltage control command - sendCmd(); //Send our Delphi voltage control command - } @@ -87,59 +90,59 @@ To request 14.0 vdc, the message was: void DCDCController::sendCmd() { - DCDCConfiguration *config = (DCDCConfiguration *)getConfiguration(); - - CAN_FRAME output; - output.length = 8; - output.id = 0x1D7; - output.extended = 0; //standard frame - output.rtr = 0; - output.fid = 0; - output.data.bytes[0] = 0x80; - output.data.bytes[1] = 0x8E; - output.data.bytes[2] = 0; - output.data.bytes[3] = 0; - output.data.bytes[4] = 0; - output.data.bytes[5] = 0; - output.data.bytes[6] = 0; - output.data.bytes[7] = 0x00; - - CanHandler::getInstanceCar()->sendFrame(output); - timestamp(); - Logger::debug("Delphi DC-DC cmd: %X %X %X %X %X %X %X %X %X %d:%d:%d.%d",output.id, output.data.bytes[0], - output.data.bytes[1],output.data.bytes[2],output.data.bytes[3],output.data.bytes[4],output.data.bytes[5],output.data.bytes[6],output.data.bytes[7], hours, minutes, seconds, milliseconds); + DCDCConfiguration *config = (DCDCConfiguration *)getConfiguration(); + + CAN_FRAME output; + output.length = 8; + output.id = 0x1D7; + output.extended = 0; //standard frame + output.rtr = 0; + output.fid = 0; + output.data.bytes[0] = 0x80; + output.data.bytes[1] = 0x8E; + output.data.bytes[2] = 0; + output.data.bytes[3] = 0; + output.data.bytes[4] = 0; + output.data.bytes[5] = 0; + output.data.bytes[6] = 0; + output.data.bytes[7] = 0x00; + + CanHandler::getInstanceCar()->sendFrame(output); + timestamp(); + Logger::debug("Delphi DC-DC cmd: %X %X %X %X %X %X %X %X %X %d:%d:%d.%d",output.id, output.data.bytes[0], + output.data.bytes[1],output.data.bytes[2],output.data.bytes[3],output.data.bytes[4],output.data.bytes[5],output.data.bytes[6],output.data.bytes[7], hours, minutes, seconds, milliseconds); } DeviceId DCDCController::getId() { - return (DCDC); + return (DCDC); } uint32_t DCDCController::getTickInterval() { - return CFG_TICK_INTERVAL_DCDC; + return CFG_TICK_INTERVAL_DCDC; } void DCDCController::loadConfiguration() { - DCDCConfiguration *config = (DCDCConfiguration *)getConfiguration(); + DCDCConfiguration *config = (DCDCConfiguration *)getConfiguration(); - if (!config) { - config = new DCDCConfiguration(); - setConfiguration(config); - } + if (!config) { + config = new DCDCConfiguration(); + setConfiguration(config); + } - Device::loadConfiguration(); // call parent + Device::loadConfiguration(); // call parent } void DCDCController::saveConfiguration() { - Device::saveConfiguration(); + Device::saveConfiguration(); } void DCDCController::timestamp() { - milliseconds = (int) (millis()/1) %1000 ; - seconds = (int) (millis() / 1000) % 60 ; + milliseconds = (int) (millis()/1) %1000 ; + seconds = (int) (millis() / 1000) % 60 ; minutes = (int) ((millis() / (1000*60)) % 60); - hours = (int) ((millis() / (1000*60*60)) % 24); + hours = (int) ((millis() / (1000*60*60)) % 24); } diff --git a/DCDCController.h b/DCDCController.h index 53c61bb..76bb2e1 100644 --- a/DCDCController.h +++ b/DCDCController.h @@ -1,7 +1,7 @@ /* * DCDCController.h * - * + * * Copyright (c) 2014 Jack Rickard @@ -45,24 +45,24 @@ class DCDCConfiguration : public DeviceConfiguration { class DCDCController: public Device, CanObserver { public: - virtual void handleTick(); - virtual void handleCanFrame(CAN_FRAME *frame); - virtual void setup(); + virtual void handleTick(); + virtual void handleCanFrame(CAN_FRAME *frame); + virtual void setup(); + + DCDCController(); + void timestamp(); + DeviceId getId(); + uint32_t getTickInterval(); - DCDCController(); - void timestamp(); - DeviceId getId(); - uint32_t getTickInterval(); - - virtual void loadConfiguration(); - virtual void saveConfiguration(); + virtual void loadConfiguration(); + virtual void saveConfiguration(); private: - int milliseconds ; - int seconds; - int minutes; - int hours; - void sendCmd(); + int milliseconds ; + int seconds; + int minutes; + int hours; + void sendCmd(); }; #endif /* DCDC_H_ */ diff --git a/Device.cpp b/Device.cpp index abb29d4..426e0a8 100644 --- a/Device.cpp +++ b/Device.cpp @@ -28,11 +28,11 @@ #include "DeviceManager.h" Device::Device() { - deviceConfiguration = NULL; - prefsHandler = NULL; - //since all derived classes eventually call this base method this will cause every device to auto register itself with the device manager - DeviceManager::getInstance()->addDevice(this); - commonName = "Generic Device"; + deviceConfiguration = NULL; + prefsHandler = NULL; + //since all derived classes eventually call this base method this will cause every device to auto register itself with the device manager + DeviceManager::getInstance()->addDevice(this); + commonName = "Generic Device"; } //Empty functions to handle these callbacks if the derived classes don't @@ -41,35 +41,35 @@ void Device::setup() { } char* Device::getCommonName() { - return commonName; + return commonName; } void Device::handleTick() { } uint32_t Device::getTickInterval() { - return 0; + return 0; } //just bubbles up the value from the preference handler. bool Device::isEnabled() { - return prefsHandler->isEnabled(); + return prefsHandler->isEnabled(); } void Device::handleMessage(uint32_t msgType, void* message) { - switch (msgType) { - case MSG_STARTUP: - this->setup(); - break; - } + switch (msgType) { + case MSG_STARTUP: + this->setup(); + break; + } } DeviceType Device::getType() { - return DEVICE_NONE; + return DEVICE_NONE; } DeviceId Device::getId() { - return INVALID; + return INVALID; } void Device::loadConfiguration() { @@ -79,11 +79,11 @@ void Device::saveConfiguration() { } DeviceConfiguration *Device::getConfiguration() { - return this->deviceConfiguration; + return this->deviceConfiguration; } void Device::setConfiguration(DeviceConfiguration *configuration) { - this->deviceConfiguration = configuration; + this->deviceConfiguration = configuration; } diff --git a/Device.h b/Device.h index 729d469..064455f 100644 --- a/Device.h +++ b/Device.h @@ -49,27 +49,27 @@ class DeviceConfiguration { */ class Device: public TickObserver { public: - Device(); - virtual void setup(); - virtual void handleMessage(uint32_t, void* ); - virtual DeviceType getType(); - virtual DeviceId getId(); - void handleTick(); - bool isEnabled(); - virtual uint32_t getTickInterval(); - char* getCommonName(); + Device(); + virtual void setup(); + virtual void handleMessage(uint32_t, void* ); + virtual DeviceType getType(); + virtual DeviceId getId(); + void handleTick(); + bool isEnabled(); + virtual uint32_t getTickInterval(); + char* getCommonName(); - virtual void loadConfiguration(); - virtual void saveConfiguration(); - DeviceConfiguration *getConfiguration(); - void setConfiguration(DeviceConfiguration *); + virtual void loadConfiguration(); + virtual void saveConfiguration(); + DeviceConfiguration *getConfiguration(); + void setConfiguration(DeviceConfiguration *); protected: - PrefHandler *prefsHandler; - char *commonName; + PrefHandler *prefsHandler; + char *commonName; private: - DeviceConfiguration *deviceConfiguration; // reference to the currently active configuration + DeviceConfiguration *deviceConfiguration; // reference to the currently active configuration }; #endif /* DEVICE_H_ */ diff --git a/DeviceManager.cpp b/DeviceManager.cpp index d61179b..c010b71 100644 --- a/DeviceManager.cpp +++ b/DeviceManager.cpp @@ -40,11 +40,11 @@ DeviceManager *DeviceManager::deviceManager = NULL; DeviceManager::DeviceManager() { - throttle = NULL; - brake = NULL; - motorController = NULL; - for (int i = 0; i < CFG_DEV_MGR_MAX_DEVICES; i++) - devices[i] = NULL; + throttle = NULL; + brake = NULL; + motorController = NULL; + for (int i = 0; i < CFG_DEV_MGR_MAX_DEVICES; i++) + devices[i] = NULL; } /* @@ -55,56 +55,56 @@ DeviceManager::DeviceManager() { * Arduino has power. */ DeviceManager *DeviceManager::getInstance() { - if (deviceManager == NULL) - deviceManager = new DeviceManager(); - return deviceManager; + if (deviceManager == NULL) + deviceManager = new DeviceManager(); + return deviceManager; } /* * Add the specified device to the list of registered devices */ void DeviceManager::addDevice(Device *device) { - if (findDevice(device) == -1) { - int8_t i = findDevice(NULL); - if (i != -1) { - devices[i] = device; - } else { - Logger::error("unable to register device, max number of devices reached."); - } - } - /* - switch (device->getType()) { - case DEVICE_THROTTLE: - throttle = (Throttle *) device; - break; - case DEVICE_BRAKE: - brake = (Throttle *) device; - break; - case DEVICE_MOTORCTRL: - motorController = (MotorController *) device; - break; - } - */ + if (findDevice(device) == -1) { + int8_t i = findDevice(NULL); + if (i != -1) { + devices[i] = device; + } else { + Logger::error("unable to register device, max number of devices reached."); + } + } + /* + switch (device->getType()) { + case DEVICE_THROTTLE: + throttle = (Throttle *) device; + break; + case DEVICE_BRAKE: + brake = (Throttle *) device; + break; + case DEVICE_MOTORCTRL: + motorController = (MotorController *) device; + break; + } + */ } /* * Remove the specified device from the list of registered devices */ void DeviceManager::removeDevice(Device *device) { - int8_t i = findDevice(NULL); - if (i != -1) - devices[i] = NULL; - switch (device->getType()) { - case DEVICE_THROTTLE: - throttle = NULL; - break; - case DEVICE_BRAKE: - brake = NULL; - break; - case DEVICE_MOTORCTRL: - motorController = NULL; - break; - } + int8_t i = findDevice(NULL); + if (i != -1) + devices[i] = NULL; + switch (device->getType()) { + case DEVICE_THROTTLE: + throttle = NULL; + break; + case DEVICE_BRAKE: + brake = NULL; + break; + case DEVICE_MOTORCTRL: + motorController = NULL; + break; + } } /*Add a new tick handler to the specified device. It should @@ -134,106 +134,106 @@ void DeviceManager::removeDevice(Device *device) { */ void DeviceManager::sendMessage(DeviceType devType, DeviceId devId, uint32_t msgType, void* message) { - for (int i = 0; i < CFG_DEV_MGR_MAX_DEVICES; i++) - { - if (devices[i] && devices[i]->isEnabled()) //does this object exist and is it enabled? - { - if (devType == DEVICE_ANY || devType == devices[i]->getType()) - { - if (devId == INVALID || devId == devices[i]->getId()) - { - Logger::debug("Sending msg to device with ID %X", devices[i]->getId()); - devices[i]->handleMessage(msgType, message); - } - } - } - } + for (int i = 0; i < CFG_DEV_MGR_MAX_DEVICES; i++) + { + if (devices[i] && devices[i]->isEnabled()) //does this object exist and is it enabled? + { + if (devType == DEVICE_ANY || devType == devices[i]->getType()) + { + if (devId == INVALID || devId == devices[i]->getId()) + { + Logger::debug("Sending msg to device with ID %X", devices[i]->getId()); + devices[i]->handleMessage(msgType, message); + } + } + } + } } void DeviceManager::setParameter(DeviceType deviceType, DeviceId deviceId, uint32_t msgType, char *key, char *value) { - char *params[] = { key, value }; - sendMessage(deviceType, deviceId, msgType, params); + char *params[] = { key, value }; + sendMessage(deviceType, deviceId, msgType, params); } void DeviceManager::setParameter(DeviceType deviceType, DeviceId deviceId, uint32_t msgType, char *key, uint32_t value) { - char buffer[15]; - sprintf(buffer, "%lu", value); - setParameter(deviceType, deviceId, msgType, key, buffer); + char buffer[15]; + sprintf(buffer, "%lu", value); + setParameter(deviceType, deviceId, msgType, key, buffer); } uint8_t DeviceManager::getNumThrottles() { - return countDeviceType(DEVICE_THROTTLE); + return countDeviceType(DEVICE_THROTTLE); } uint8_t DeviceManager::getNumControllers() { - return countDeviceType(DEVICE_MOTORCTRL); + return countDeviceType(DEVICE_MOTORCTRL); } uint8_t DeviceManager::getNumBMS() { - return countDeviceType(DEVICE_BMS); + return countDeviceType(DEVICE_BMS); } uint8_t DeviceManager::getNumChargers() { - return countDeviceType(DEVICE_CHARGER); + return countDeviceType(DEVICE_CHARGER); } uint8_t DeviceManager::getNumDisplays() { - return countDeviceType(DEVICE_DISPLAY); + return countDeviceType(DEVICE_DISPLAY); } Throttle *DeviceManager::getAccelerator() { - //try to find one if nothing registered. Cache it if we find one - if (!throttle) throttle = (Throttle *)getDeviceByType(DEVICE_THROTTLE); - - //if there is no throttle then instantiate a dummy throttle - //so down range code doesn't puke - if (!throttle) - { - Logger::debug("getAccelerator() called but there is no registered accelerator!"); - return 0; //NULL! - } - return throttle; + //try to find one if nothing registered. Cache it if we find one + if (!throttle) throttle = (Throttle *)getDeviceByType(DEVICE_THROTTLE); + + //if there is no throttle then instantiate a dummy throttle + //so down range code doesn't puke + if (!throttle) + { + Logger::debug("getAccelerator() called but there is no registered accelerator!"); + return 0; //NULL! + } + return throttle; } Throttle *DeviceManager::getBrake() { - if (!brake) brake = (Throttle *)getDeviceByType(DEVICE_BRAKE); + if (!brake) brake = (Throttle *)getDeviceByType(DEVICE_BRAKE); - if (!brake) - { - //Logger::debug("getBrake() called but there is no registered brake!"); - return 0; //NULL! - } - return brake; + if (!brake) + { + //Logger::debug("getBrake() called but there is no registered brake!"); + return 0; //NULL! + } + return brake; } MotorController *DeviceManager::getMotorController() { - if (!motorController) motorController = (MotorController *)getDeviceByType(DEVICE_MOTORCTRL); - - if (!motorController) - { - Logger::debug("getMotorController() called but there is no registered motor controller!"); - return 0; //NULL! - } - return motorController; + if (!motorController) motorController = (MotorController *)getDeviceByType(DEVICE_MOTORCTRL); + + if (!motorController) + { + Logger::debug("getMotorController() called but there is no registered motor controller!"); + return 0; //NULL! + } + return motorController; } /* Allows one to request a reference to a device with the given ID. This lets code specifically request a certain device. Normally this would be a bad idea because it sort of breaks the OOP design philosophy of polymorphism -but sometimes you can't help it. +but sometimes you can't help it. */ Device *DeviceManager::getDeviceByID(DeviceId id) { - for (int i = 0; i < CFG_DEV_MGR_MAX_DEVICES; i++) - { - if (devices[i]) - { - if (devices[i]->getId() == id) return devices[i]; - } - } - Logger::debug("getDeviceByID - No device with ID: %X", (int)id); - return 0; //NULL! + for (int i = 0; i < CFG_DEV_MGR_MAX_DEVICES; i++) + { + if (devices[i]) + { + if (devices[i]->getId() == id) return devices[i]; + } + } + Logger::debug("getDeviceByID - No device with ID: %X", (int)id); + return 0; //NULL! } /* @@ -242,15 +242,15 @@ a given type. */ Device *DeviceManager::getDeviceByType(DeviceType type) { - for (int i = 0; i < CFG_DEV_MGR_MAX_DEVICES; i++) - { - if (devices[i] && devices[i]->isEnabled()) - { - if (devices[i]->getType() == type) return devices[i]; - } - } - Logger::debug("getDeviceByType - No devices of type: %X", (int)type); - return 0; //NULL! + for (int i = 0; i < CFG_DEV_MGR_MAX_DEVICES; i++) + { + if (devices[i] && devices[i]->isEnabled()) + { + if (devices[i]->getType() == type) return devices[i]; + } + } + Logger::debug("getDeviceByType - No devices of type: %X", (int)type); + return 0; //NULL! } /* @@ -258,74 +258,74 @@ Device *DeviceManager::getDeviceByType(DeviceType type) * /retval the position of the device or -1 if not found. */ int8_t DeviceManager::findDevice(Device *device) { - for (int i = 0; i < CFG_DEV_MGR_MAX_DEVICES; i++) { - if (device == devices[i]) - return i; - } - return -1; + for (int i = 0; i < CFG_DEV_MGR_MAX_DEVICES; i++) { + if (device == devices[i]) + return i; + } + return -1; } /* * Count the number of registered devices of a certain type. */ uint8_t DeviceManager::countDeviceType(DeviceType deviceType) { - uint8_t count = 0; - for (int i = 0; i < CFG_DEV_MGR_MAX_DEVICES; i++) { - if (devices[i]->getType() == deviceType) - count++; - } - return count; + uint8_t count = 0; + for (int i = 0; i < CFG_DEV_MGR_MAX_DEVICES; i++) { + if (devices[i]->getType() == deviceType) + count++; + } + return count; } void DeviceManager::printDeviceList() { - Logger::console("Currently enabled devices: (DISABLE= to disable)"); - for (int i = 0; i < CFG_DEV_MGR_MAX_DEVICES; i++) { - if (devices[i] && devices[i]->isEnabled()) { - Logger::console(" %X %s", devices[i]->getId(), devices[i]->getCommonName()); - } - } - - Logger::console("Currently disabled devices: (ENABLE= to enable)"); - for (int i = 0; i < CFG_DEV_MGR_MAX_DEVICES; i++) { - if (devices[i] && !devices[i]->isEnabled()) { - Logger::console(" %X %s", devices[i]->getId(), devices[i]->getCommonName()); - } - } + Logger::console("Currently enabled devices: (DISABLE= to disable)"); + for (int i = 0; i < CFG_DEV_MGR_MAX_DEVICES; i++) { + if (devices[i] && devices[i]->isEnabled()) { + Logger::console(" %X %s", devices[i]->getId(), devices[i]->getCommonName()); + } + } + + Logger::console("Currently disabled devices: (ENABLE= to enable)"); + for (int i = 0; i < CFG_DEV_MGR_MAX_DEVICES; i++) { + if (devices[i] && !devices[i]->isEnabled()) { + Logger::console(" %X %s", devices[i]->getId(), devices[i]->getCommonName()); + } + } } void DeviceManager::updateWifi() { - - sendMessage(DEVICE_WIFI, ICHIP2128, MSG_CONFIG_CHANGE, NULL); //Load all our other parameters first - - char param [2][30]; //A two element array containing id and enable state - char *paramPtr[2] = { ¶m[0][0], ¶m[1][0] }; //A two element array of pointers, pointing to the addresses of row 1 and row 2 of array. - //paramPtr[0] then contains address of param row 0 element 0 - //paramPtr[1] then contains address of param row 1 element 0. - - - for (int i = 0; i < CFG_DEV_MGR_MAX_DEVICES; i++) { //Find all devices that are enabled and load into array - if (devices[i] && devices[i]->isEnabled()) - { - sprintf(paramPtr[0],"x%X",devices[i]->getId()); - sprintf(paramPtr[1],"255"); - // Logger::console(" Device: %s value %s", paramPtr[0], paramPtr[1]); - - sendMessage(DEVICE_WIFI, ICHIP2128, MSG_SET_PARAM, paramPtr); //Send the array to ichip by id (ie 1031) 255 indicates enabled - } - } - - for (int i = 0; i < CFG_DEV_MGR_MAX_DEVICES; i++) { //Find all devices that are NOT enabled and load into array - if (devices[i] && !devices[i]->isEnabled()) - { - sprintf(paramPtr[0],"x%X",devices[i]->getId()); - sprintf(paramPtr[1],"0"); - // Logger::console(" Device: %s value %s", paramPtr[0], paramPtr[1]); - sendMessage(DEVICE_WIFI, ICHIP2128, MSG_SET_PARAM, paramPtr); //Send array to ichip by id (ie 1002) 0 indicates disabled - } - } - - + + sendMessage(DEVICE_WIFI, ICHIP2128, MSG_CONFIG_CHANGE, NULL); //Load all our other parameters first + + char param [2][30]; //A two element array containing id and enable state + char *paramPtr[2] = { ¶m[0][0], ¶m[1][0] }; //A two element array of pointers, pointing to the addresses of row 1 and row 2 of array. + //paramPtr[0] then contains address of param row 0 element 0 + //paramPtr[1] then contains address of param row 1 element 0. + + + for (int i = 0; i < CFG_DEV_MGR_MAX_DEVICES; i++) { //Find all devices that are enabled and load into array + if (devices[i] && devices[i]->isEnabled()) + { + sprintf(paramPtr[0],"x%X",devices[i]->getId()); + sprintf(paramPtr[1],"255"); + // Logger::console(" Device: %s value %s", paramPtr[0], paramPtr[1]); + + sendMessage(DEVICE_WIFI, ICHIP2128, MSG_SET_PARAM, paramPtr); //Send the array to ichip by id (ie 1031) 255 indicates enabled + } + } + + for (int i = 0; i < CFG_DEV_MGR_MAX_DEVICES; i++) { //Find all devices that are NOT enabled and load into array + if (devices[i] && !devices[i]->isEnabled()) + { + sprintf(paramPtr[0],"x%X",devices[i]->getId()); + sprintf(paramPtr[1],"0"); + // Logger::console(" Device: %s value %s", paramPtr[0], paramPtr[1]); + sendMessage(DEVICE_WIFI, ICHIP2128, MSG_SET_PARAM, paramPtr); //Send array to ichip by id (ie 1002) 0 indicates disabled + } + } + + } diff --git a/DeviceManager.h b/DeviceManager.h index 592187f..d7c47b6 100644 --- a/DeviceManager.h +++ b/DeviceManager.h @@ -38,41 +38,41 @@ class MotorController; // cyclic reference between MotorController and DeviceMan class DeviceManager { public: - static DeviceManager *getInstance(); - void addDevice(Device *device); - void removeDevice(Device *device); + static DeviceManager *getInstance(); + void addDevice(Device *device); + void removeDevice(Device *device); // void addTickObserver(TickObserver *observer, uint32_t frequency); // void addCanObserver(CanObserver *observer, uint32_t id, uint32_t mask, bool extended, CanHandler::CanBusNode canBus); - void sendMessage(DeviceType deviceType, DeviceId deviceId, uint32_t msgType, void* message); - void setParameter(DeviceType deviceType, DeviceId deviceId, uint32_t msgType, char *key, char *value); - void setParameter(DeviceType deviceType, DeviceId deviceId, uint32_t msgType, char *key, uint32_t value); - uint8_t getNumThrottles(); - uint8_t getNumControllers(); - uint8_t getNumBMS(); - uint8_t getNumChargers(); - uint8_t getNumDisplays(); - Throttle *getAccelerator(); - Throttle *getBrake(); - MotorController *getMotorController(); - Device *getDeviceByID(DeviceId); - Device *getDeviceByType(DeviceType); - void printDeviceList(); - void updateWifi(); - Device *updateWifiByID(DeviceId); + void sendMessage(DeviceType deviceType, DeviceId deviceId, uint32_t msgType, void* message); + void setParameter(DeviceType deviceType, DeviceId deviceId, uint32_t msgType, char *key, char *value); + void setParameter(DeviceType deviceType, DeviceId deviceId, uint32_t msgType, char *key, uint32_t value); + uint8_t getNumThrottles(); + uint8_t getNumControllers(); + uint8_t getNumBMS(); + uint8_t getNumChargers(); + uint8_t getNumDisplays(); + Throttle *getAccelerator(); + Throttle *getBrake(); + MotorController *getMotorController(); + Device *getDeviceByID(DeviceId); + Device *getDeviceByType(DeviceType); + void printDeviceList(); + void updateWifi(); + Device *updateWifiByID(DeviceId); protected: private: - DeviceManager(); // private constructor - static DeviceManager *deviceManager; + DeviceManager(); // private constructor + static DeviceManager *deviceManager; - Device *devices[CFG_DEV_MGR_MAX_DEVICES]; - Throttle *throttle; - Throttle *brake; - MotorController *motorController; + Device *devices[CFG_DEV_MGR_MAX_DEVICES]; + Throttle *throttle; + Throttle *brake; + MotorController *motorController; - int8_t findDevice(Device *device); - uint8_t countDeviceType(DeviceType deviceType); + int8_t findDevice(Device *device); + uint8_t countDeviceType(DeviceType deviceType); }; #endif diff --git a/DeviceTypes.h b/DeviceTypes.h index b72a103..0104cbb 100644 --- a/DeviceTypes.h +++ b/DeviceTypes.h @@ -28,41 +28,41 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #define DEVICE_TYPES_H_ enum DeviceType { - DEVICE_ANY, - DEVICE_MOTORCTRL, - DEVICE_BMS, - DEVICE_CHARGER, - DEVICE_DISPLAY, - DEVICE_THROTTLE, - DEVICE_BRAKE, - DEVICE_MISC, - DEVICE_WIFI, - DEVICE_NONE + DEVICE_ANY, + DEVICE_MOTORCTRL, + DEVICE_BMS, + DEVICE_CHARGER, + DEVICE_DISPLAY, + DEVICE_THROTTLE, + DEVICE_BRAKE, + DEVICE_MISC, + DEVICE_WIFI, + DEVICE_NONE }; enum DeviceId { //unique device ID for every piece of hardware possible - DMOC645 = 0x1000, - BRUSA_DMC5 = 0x1001, + DMOC645 = 0x1000, + BRUSA_DMC5 = 0x1001, CODAUQM = 0x1002, - BRUSACHARGE = 0x1010, - TCCHCHARGE = 0x1011, - LEAR=0x1012, - THROTTLE = 0x1030, - POTACCELPEDAL = 0x1031, - POTBRAKEPEDAL = 0x1032, - CANACCELPEDAL = 0x1033, - CANBRAKEPEDAL = 0x1034, - EVICTUS = 0x4400, - ICHIP2128 = 0x1040, - DCDC = 0x1050, - THINKBMS = 0x2000, - FAULTSYS = 0x4000, - SYSTEM = 0x5000, - HEARTBEAT = 0x5001, - MEMCACHE = 0x5002, - PIDLISTENER = 0x6000, - ELM327EMU = 0x650, - INVALID = 0xFFFF + BRUSACHARGE = 0x1010, + TCCHCHARGE = 0x1011, + LEAR=0x1012, + THROTTLE = 0x1030, + POTACCELPEDAL = 0x1031, + POTBRAKEPEDAL = 0x1032, + CANACCELPEDAL = 0x1033, + CANBRAKEPEDAL = 0x1034, + EVICTUS = 0x4400, + ICHIP2128 = 0x1040, + DCDC = 0x1050, + THINKBMS = 0x2000, + FAULTSYS = 0x4000, + SYSTEM = 0x5000, + HEARTBEAT = 0x5001, + MEMCACHE = 0x5002, + PIDLISTENER = 0x6000, + ELM327EMU = 0x650, + INVALID = 0xFFFF }; #endif /* DEVICE_TYPES_H_ */ diff --git a/DmocMotorController.cpp b/DmocMotorController.cpp index d83c009..0bb35ca 100644 --- a/DmocMotorController.cpp +++ b/DmocMotorController.cpp @@ -47,37 +47,37 @@ extern bool runThrottle; //TODO: remove use of global variables ! long ms; DmocMotorController::DmocMotorController() : MotorController() { - prefsHandler = new PrefHandler(DMOC645); - step = SPEED_TORQUE; - + prefsHandler = new PrefHandler(DMOC645); + step = SPEED_TORQUE; + selectedGear = NEUTRAL; - operationState = DISABLED; - actualState = DISABLED; - online = 0; - activityCount = 0; + operationState = DISABLED; + actualState = DISABLED; + online = 0; + activityCount = 0; // maxTorque = 2000; - commonName = "DMOC645 Inverter"; + commonName = "DMOC645 Inverter"; } void DmocMotorController::setup() { - TickHandler::getInstance()->detach(this); + TickHandler::getInstance()->detach(this); - Logger::info("add device: DMOC645 (id:%X, %X)", DMOC645, this); + Logger::info("add device: DMOC645 (id:%X, %X)", DMOC645, this); - loadConfiguration(); - MotorController::setup(); // run the parent class version of this function + loadConfiguration(); + MotorController::setup(); // run the parent class version of this function - // register ourselves as observer of 0x23x and 0x65x can frames - CanHandler::getInstanceEV()->attach(this, 0x230, 0x7f0, false); - CanHandler::getInstanceEV()->attach(this, 0x650, 0x7f0, false); + // register ourselves as observer of 0x23x and 0x65x can frames + CanHandler::getInstanceEV()->attach(this, 0x230, 0x7f0, false); + CanHandler::getInstanceEV()->attach(this, 0x650, 0x7f0, false); - running = false; - setPowerMode(modeTorque); - setSelectedGear(NEUTRAL); - setOpState(DISABLED ); - ms=millis(); + running = false; + setPowerMode(modeTorque); + setSelectedGear(NEUTRAL); + setOpState(DISABLED ); + ms=millis(); - TickHandler::getInstance()->attach(this, CFG_TICK_INTERVAL_MOTOR_CONTROLLER_DMOC); + TickHandler::getInstance()->attach(this, CFG_TICK_INTERVAL_MOTOR_CONTROLLER_DMOC); } /* @@ -89,95 +89,95 @@ void DmocMotorController::setup() { */ void DmocMotorController::handleCanFrame(CAN_FRAME *frame) { - int RotorTemp, invTemp, StatorTemp; - int temp; - online = true; //if a frame got to here then it passed the filter and must have been from the DMOC - - Logger::debug("DMOC CAN received: %X %X %X %X %X %X %X %X %X", frame->id,frame->data.bytes[0] ,frame->data.bytes[1],frame->data.bytes[2],frame->data.bytes[3],frame->data.bytes[4],frame->data.bytes[5],frame->data.bytes[6],frame->data.bytes[70]); - - - switch (frame->id) { - case 0x651: //Temperature status - RotorTemp = frame->data.bytes[0]; - invTemp = frame->data.bytes[1]; - StatorTemp = frame->data.bytes[2]; - temperatureInverter = (invTemp-40) *10; - //now pick highest of motor temps and report it - if (RotorTemp > StatorTemp) { - temperatureMotor = (RotorTemp-40) *10; - } - else { - temperatureMotor = (StatorTemp-40) *10; - } - activityCount++; - break; - case 0x23A: //torque report - torqueActual = ((frame->data.bytes[0] * 256) + frame->data.bytes[1]) - 30000; - activityCount++; - break; - - case 0x23B: //speed and current operation status - speedActual = abs(((frame->data.bytes[0] * 256) + frame->data.bytes[1]) - 20000); - temp = (OperationState) (frame->data.bytes[6] >> 4); - //actually, the above is an operation status report which doesn't correspond - //to the state enum so translate here. - switch (temp) { - - case 0: //Initializing - actualState = DISABLED; - faulted=false; - break; - - case 1: //disabled - actualState = DISABLED; - faulted=false; - break; - - case 2: //ready (standby) - actualState = STANDBY; - faulted=false; - ready = true; - break; - - case 3: //enabled - actualState = ENABLE; - faulted=false; - break; - - case 4: //Power Down - actualState = POWERDOWN; - faulted=false; - break; - - case 5: //Fault - actualState = DISABLED; - faulted=true; - break; - - case 6: //Critical Fault - actualState = DISABLED; - faulted=true; - break; - - case 7: //LOS - actualState = DISABLED; - faulted=true; - break; - } - Logger::debug("OpState: %d", temp); - activityCount++; - break; - - //case 0x23E: //electrical status - //gives volts and amps for D and Q but does the firmware really care? - //break; - - case 0x650: //HV bus status - dcVoltage = ((frame->data.bytes[0] * 256) + frame->data.bytes[1]); - dcCurrent = ((frame->data.bytes[2] * 256) + frame->data.bytes[3]) - 5000; //offset is 500A, unit = .1A - activityCount++; - break; - } + int RotorTemp, invTemp, StatorTemp; + int temp; + online = true; //if a frame got to here then it passed the filter and must have been from the DMOC + + Logger::debug("DMOC CAN received: %X %X %X %X %X %X %X %X %X", frame->id,frame->data.bytes[0] ,frame->data.bytes[1],frame->data.bytes[2],frame->data.bytes[3],frame->data.bytes[4],frame->data.bytes[5],frame->data.bytes[6],frame->data.bytes[70]); + + + switch (frame->id) { + case 0x651: //Temperature status + RotorTemp = frame->data.bytes[0]; + invTemp = frame->data.bytes[1]; + StatorTemp = frame->data.bytes[2]; + temperatureInverter = (invTemp-40) *10; + //now pick highest of motor temps and report it + if (RotorTemp > StatorTemp) { + temperatureMotor = (RotorTemp-40) *10; + } + else { + temperatureMotor = (StatorTemp-40) *10; + } + activityCount++; + break; + case 0x23A: //torque report + torqueActual = ((frame->data.bytes[0] * 256) + frame->data.bytes[1]) - 30000; + activityCount++; + break; + + case 0x23B: //speed and current operation status + speedActual = abs(((frame->data.bytes[0] * 256) + frame->data.bytes[1]) - 20000); + temp = (OperationState) (frame->data.bytes[6] >> 4); + //actually, the above is an operation status report which doesn't correspond + //to the state enum so translate here. + switch (temp) { + + case 0: //Initializing + actualState = DISABLED; + faulted=false; + break; + + case 1: //disabled + actualState = DISABLED; + faulted=false; + break; + + case 2: //ready (standby) + actualState = STANDBY; + faulted=false; + ready = true; + break; + + case 3: //enabled + actualState = ENABLE; + faulted=false; + break; + + case 4: //Power Down + actualState = POWERDOWN; + faulted=false; + break; + + case 5: //Fault + actualState = DISABLED; + faulted=true; + break; + + case 6: //Critical Fault + actualState = DISABLED; + faulted=true; + break; + + case 7: //LOS + actualState = DISABLED; + faulted=true; + break; + } + Logger::debug("OpState: %d", temp); + activityCount++; + break; + + //case 0x23E: //electrical status + //gives volts and amps for D and Q but does the firmware really care? + //break; + + case 0x650: //HV bus status + dcVoltage = ((frame->data.bytes[0] * 256) + frame->data.bytes[1]); + dcCurrent = ((frame->data.bytes[2] * 256) + frame->data.bytes[3]) - 5000; //offset is 500A, unit = .1A + activityCount++; + break; + } } /*Do note that the DMOC expects all three command frames and it expect them to happen at least twice a second. So, probably it'd be ok to essentially @@ -185,264 +185,268 @@ void DmocMotorController::handleCanFrame(CAN_FRAME *frame) { */ void DmocMotorController::handleTick() { - MotorController::handleTick(); //kick the ball up to papa + MotorController::handleTick(); //kick the ball up to papa - if (activityCount > 0) + if (activityCount > 0) { - activityCount--; - if (activityCount > 60) activityCount = 60; - if (activityCount > 40) //If we are receiving regular CAN messages from DMOC, this will very quickly get to over 40. We'll limit - // it to 60 so if we lose communications, within 20 ticks we will decrement below this value. - { - Logger::debug("EnableIn=%i and ReverseIn = %i" ,getEnableIn(),getReverseIn()); - if(getEnableIn()<0)setOpState(ENABLE); //If we HAVE an enableinput 0-3, we'll let that handle opstate. Otherwise set it to ENABLE - if(getReverseIn()<0)setSelectedGear(DRIVE); //If we HAVE a reverse input, we'll let that determine forward/reverse. Otherwise set it to DRIVE - } - } - else { - setSelectedGear(NEUTRAL); //We will stay in NEUTRAL until we get at least 40 frames ahead indicating continous communications. - } - - - if(!online) //This routine checks to see if we have received any frames from the inverter. If so, ONLINE would be true and - { //we set the RUNNING light on. If no frames are received for 2 seconds, we set running OFF. - if ((millis()-ms)>2000) - { - running=false; // We haven't received any frames for over 2 seconds. Otherwise online would be true. - ms=millis(); //Reset our 2 second timer - } - } - else running=true; - online=false;//This flag will be set to 1 by received frames. - - - sendCmd1(); //This actually sets our GEAR and our actualstate cycle - sendCmd2(); //This is our torque command - sendCmd3(); - //sendCmd4(); //These appear to be not needed. - //sendCmd5(); //But we'll keep them for future reference - - + activityCount--; + if (activityCount > 60) activityCount = 60; + if (activityCount > 40) //If we are receiving regular CAN messages from DMOC, this will very quickly get to over 40. We'll limit + // it to 60 so if we lose communications, within 20 ticks we will decrement below this value. + { + Logger::debug("EnableIn=%i and ReverseIn = %i" ,getEnableIn(),getReverseIn()); + if(getEnableIn()<0)setOpState(ENABLE); //If we HAVE an enableinput 0-3, we'll let that handle opstate. Otherwise set it to ENABLE + if(getReverseIn()<0)setSelectedGear(DRIVE); //If we HAVE a reverse input, we'll let that determine forward/reverse. Otherwise set it to DRIVE + } + } + else { + setSelectedGear(NEUTRAL); //We will stay in NEUTRAL until we get at least 40 frames ahead indicating continous communications. + } + + + if(!online) //This routine checks to see if we have received any frames from the inverter. If so, ONLINE would be true and + { //we set the RUNNING light on. If no frames are received for 2 seconds, we set running OFF. + if ((millis()-ms)>2000) + { + running=false; // We haven't received any frames for over 2 seconds. Otherwise online would be true. + ms=millis(); //Reset our 2 second timer + } + } + else running=true; + online=false;//This flag will be set to 1 by received frames. + + + sendCmd1(); //This actually sets our GEAR and our actualstate cycle + sendCmd2(); //This is our torque command + sendCmd3(); + //sendCmd4(); //These appear to be not needed. + //sendCmd5(); //But we'll keep them for future reference + + } //Commanded RPM plus state of key and gear selector void DmocMotorController::sendCmd1() { - DmocMotorControllerConfiguration *config = (DmocMotorControllerConfiguration *)getConfiguration(); - CAN_FRAME output; - OperationState newstate; - alive = (alive + 2) & 0x0F; - output.length = 8; - output.id = 0x232; - output.extended = 0; //standard frame - output.rtr = 0; - - if (throttleRequested > 0 && operationState == ENABLE && selectedGear != NEUTRAL && powerMode == modeSpeed) - speedRequested = 20000 + (((long) throttleRequested * (long) config->speedMax) / 1000); - else - speedRequested = 20000; - output.data.bytes[0] = (speedRequested & 0xFF00) >> 8; - output.data.bytes[1] = (speedRequested & 0x00FF); - output.data.bytes[2] = 0; //not used - output.data.bytes[3] = 0; //not used - output.data.bytes[4] = 0; //not used - output.data.bytes[5] = ON; //key state - - //handle proper state transitions - newstate = DISABLED; - if (actualState == DISABLED && (operationState == STANDBY || operationState == ENABLE)) - newstate = STANDBY; - if ((actualState == STANDBY || actualState == ENABLE) && operationState == ENABLE) - newstate = ENABLE; - if (operationState == POWERDOWN) - newstate = POWERDOWN; - - if (actualState == ENABLE) { - output.data.bytes[6] = alive + ((byte) selectedGear << 4) + ((byte) newstate << 6); //use new automatic state system. - } - else { //force neutral gear until the system is enabled. - output.data.bytes[6] = alive + ((byte) NEUTRAL << 4) + ((byte) newstate << 6); //use new automatic state system. - } - - output.data.bytes[7] = calcChecksum(output); - - CanHandler::getInstanceEV()->sendFrame(output); + DmocMotorControllerConfiguration *config = (DmocMotorControllerConfiguration *)getConfiguration(); + CAN_FRAME output; + OperationState newstate; + alive = (alive + 2) & 0x0F; + output.length = 8; + output.id = 0x232; + output.extended = 0; //standard frame + output.rtr = 0; + + if (throttleRequested > 0 && operationState == ENABLE && selectedGear != NEUTRAL && powerMode == modeSpeed) + speedRequested = 20000 + (((long) throttleRequested * (long) config->speedMax) / 1000); + else + speedRequested = 20000; + output.data.bytes[0] = (speedRequested & 0xFF00) >> 8; + output.data.bytes[1] = (speedRequested & 0x00FF); + output.data.bytes[2] = 0; //not used + output.data.bytes[3] = 0; //not used + output.data.bytes[4] = 0; //not used + output.data.bytes[5] = ON; //key state + + //handle proper state transitions + newstate = DISABLED; + if (actualState == DISABLED && (operationState == STANDBY || operationState == ENABLE)) + newstate = STANDBY; + if ((actualState == STANDBY || actualState == ENABLE) && operationState == ENABLE) + newstate = ENABLE; + if (operationState == POWERDOWN) + newstate = POWERDOWN; + + if (actualState == ENABLE) { + output.data.bytes[6] = alive + ((byte) selectedGear << 4) + ((byte) newstate << 6); //use new automatic state system. + } + else { //force neutral gear until the system is enabled. + output.data.bytes[6] = alive + ((byte) NEUTRAL << 4) + ((byte) newstate << 6); //use new automatic state system. + } + + output.data.bytes[7] = calcChecksum(output); + + CanHandler::getInstanceEV()->sendFrame(output); } //Torque limits void DmocMotorController::sendCmd2() { - DmocMotorControllerConfiguration *config = (DmocMotorControllerConfiguration *)getConfiguration(); - CAN_FRAME output; - output.length = 8; - output.id = 0x233; - output.extended = 0; //standard frame - output.rtr = 0; - //30000 is the base point where torque = 0 - //MaxTorque is in tenths like it should be. - //Requested throttle is [-1000, 1000] - //data 0-1 is upper limit, 2-3 is lower limit. They are set to same value to lock torque to this value - //torqueRequested = 30000L + (((long)throttleRequested * (long)MaxTorque) / 1000L); - - torqueCommand = 30000; //set offset for zero torque commanded - - torqueRequested=0; - if (actualState == ENABLE) { //don't even try sending torque commands until the DMOC reports it is ready - if (selectedGear == DRIVE) - torqueRequested = (((long) throttleRequested * (long) config->torqueMax) / 1000L); - if (selectedGear == REVERSE) - torqueRequested = (((long) throttleRequested * -1 *(long) config->torqueMax) / 1000L);//If reversed, regen becomes positive torque and positive pedal becomes regen. Let's reverse this by reversing the sign. In this way, we'll have gradually diminishing positive torque (in reverse, regen) followed by gradually increasing regen (positive torque in reverse.) - } - - if(speedActual < config->speedMax){torqueCommand+=torqueRequested;} //If actual rpm is less than max rpm, add torque to offset - else {torqueCommand += torqueRequested /1.3;} // else torque is halved - output.data.bytes[0] = (torqueCommand & 0xFF00) >> 8; - output.data.bytes[1] = (torqueCommand & 0x00FF); - output.data.bytes[2] = output.data.bytes[0]; - output.data.bytes[3] = output.data.bytes[1]; - - //what the hell is standby torque? Does it keep the transmission spinning for automatics? I don't know. - output.data.bytes[4] = 0x75; //msb standby torque. -3000 offset, 0.1 scale. These bytes give a standby of 0Nm - output.data.bytes[5] = 0x30; //lsb - output.data.bytes[6] = alive; - output.data.bytes[7] = calcChecksum(output); + DmocMotorControllerConfiguration *config = (DmocMotorControllerConfiguration *)getConfiguration(); + CAN_FRAME output; + output.length = 8; + output.id = 0x233; + output.extended = 0; //standard frame + output.rtr = 0; + //30000 is the base point where torque = 0 + //MaxTorque is in tenths like it should be. + //Requested throttle is [-1000, 1000] + //data 0-1 is upper limit, 2-3 is lower limit. They are set to same value to lock torque to this value + //torqueRequested = 30000L + (((long)throttleRequested * (long)MaxTorque) / 1000L); + + torqueCommand = 30000; //set offset for zero torque commanded + + torqueRequested=0; + if (actualState == ENABLE) { //don't even try sending torque commands until the DMOC reports it is ready + if (selectedGear == DRIVE) + torqueRequested = (((long) throttleRequested * (long) config->torqueMax) / 1000L); + if (selectedGear == REVERSE) + torqueRequested = (((long) throttleRequested * -1 *(long) config->torqueMax) / 1000L);//If reversed, regen becomes positive torque and positive pedal becomes regen. Let's reverse this by reversing the sign. In this way, we'll have gradually diminishing positive torque (in reverse, regen) followed by gradually increasing regen (positive torque in reverse.) + } + + if(speedActual < config->speedMax) { + torqueCommand+=torqueRequested; //If actual rpm is less than max rpm, add torque to offset + } + else { + torqueCommand += torqueRequested /1.3; // else torque is halved + } + output.data.bytes[0] = (torqueCommand & 0xFF00) >> 8; + output.data.bytes[1] = (torqueCommand & 0x00FF); + output.data.bytes[2] = output.data.bytes[0]; + output.data.bytes[3] = output.data.bytes[1]; + + //what the hell is standby torque? Does it keep the transmission spinning for automatics? I don't know. + output.data.bytes[4] = 0x75; //msb standby torque. -3000 offset, 0.1 scale. These bytes give a standby of 0Nm + output.data.bytes[5] = 0x30; //lsb + output.data.bytes[6] = alive; + output.data.bytes[7] = calcChecksum(output); //Logger::debug("max torque: %i", maxTorque); - + //Logger::debug("requested torque: %i",(((long) throttleRequested * (long) maxTorque) / 1000L)); - CanHandler::getInstanceEV()->sendFrame(output); - timestamp(); - Logger::debug("Torque command: MSB: %X LSB: %X %X %X %X %X %X CRC: %X %d:%d:%d.%d",output.data.bytes[0], -output.data.bytes[1],output.data.bytes[2],output.data.bytes[3],output.data.bytes[4],output.data.bytes[5],output.data.bytes[6],output.data.bytes[7], hours, minutes, seconds, milliseconds); - + CanHandler::getInstanceEV()->sendFrame(output); + timestamp(); + Logger::debug("Torque command: MSB: %X LSB: %X %X %X %X %X %X CRC: %X %d:%d:%d.%d",output.data.bytes[0], + output.data.bytes[1],output.data.bytes[2],output.data.bytes[3],output.data.bytes[4],output.data.bytes[5],output.data.bytes[6],output.data.bytes[7], hours, minutes, seconds, milliseconds); + } //Power limits plus setting ambient temp and whether to cool power train or go into limp mode void DmocMotorController::sendCmd3() { - CAN_FRAME output; - output.length = 8; - output.id = 0x234; - output.extended = 0; //standard frame - output.rtr = 0; - - int regenCalc = 65000 - (MaxRegenWatts / 4); - int accelCalc = (MaxAccelWatts / 4); - output.data.bytes[0] = ((regenCalc & 0xFF00) >> 8); //msb of regen watt limit - output.data.bytes[1] = (regenCalc & 0xFF); //lsb - output.data.bytes[2] = ((accelCalc & 0xFF00) >> 8); //msb of acceleration limit - output.data.bytes[3] = (accelCalc & 0xFF); //lsb - output.data.bytes[4] = 0; //not used - output.data.bytes[5] = 60; //20 degrees celsius - output.data.bytes[6] = alive; - output.data.bytes[7] = calcChecksum(output); - - CanHandler::getInstanceEV()->sendFrame(output); + CAN_FRAME output; + output.length = 8; + output.id = 0x234; + output.extended = 0; //standard frame + output.rtr = 0; + + int regenCalc = 65000 - (MaxRegenWatts / 4); + int accelCalc = (MaxAccelWatts / 4); + output.data.bytes[0] = ((regenCalc & 0xFF00) >> 8); //msb of regen watt limit + output.data.bytes[1] = (regenCalc & 0xFF); //lsb + output.data.bytes[2] = ((accelCalc & 0xFF00) >> 8); //msb of acceleration limit + output.data.bytes[3] = (accelCalc & 0xFF); //lsb + output.data.bytes[4] = 0; //not used + output.data.bytes[5] = 60; //20 degrees celsius + output.data.bytes[6] = alive; + output.data.bytes[7] = calcChecksum(output); + + CanHandler::getInstanceEV()->sendFrame(output); } //challenge/response frame 1 - Really doesn't contain anything we need I dont think void DmocMotorController::sendCmd4() { - CAN_FRAME output; - output.length = 8; - output.id = 0x235; - output.extended = 0; //standard frame - output.rtr = 0; - output.data.bytes[0] = 37; //i don't know what all these values are - output.data.bytes[1] = 11; //they're just copied from real traffic - output.data.bytes[2] = 0; - output.data.bytes[3] = 0; - output.data.bytes[4] = 6; - output.data.bytes[5] = 1; - output.data.bytes[6] = alive; - output.data.bytes[7] = calcChecksum(output); - - CanHandler::getInstanceEV()->sendFrame(output); + CAN_FRAME output; + output.length = 8; + output.id = 0x235; + output.extended = 0; //standard frame + output.rtr = 0; + output.data.bytes[0] = 37; //i don't know what all these values are + output.data.bytes[1] = 11; //they're just copied from real traffic + output.data.bytes[2] = 0; + output.data.bytes[3] = 0; + output.data.bytes[4] = 6; + output.data.bytes[5] = 1; + output.data.bytes[6] = alive; + output.data.bytes[7] = calcChecksum(output); + + CanHandler::getInstanceEV()->sendFrame(output); } //Another C/R frame but this one also specifies which shifter position we're in void DmocMotorController::sendCmd5() { - CAN_FRAME output; - output.length = 8; - output.id = 0x236; - output.extended = 0; //standard frame - output.rtr = 0; - output.data.bytes[0] = 2; - output.data.bytes[1] = 127; - output.data.bytes[2] = 0; - if (operationState == ENABLE && selectedGear != NEUTRAL) { - output.data.bytes[3] = 52; - output.data.bytes[4] = 26; - output.data.bytes[5] = 59; //drive - } - else { - output.data.bytes[3] = 39; - output.data.bytes[4] = 19; - output.data.bytes[5] = 55; //neutral - } - //--PRND12 - output.data.bytes[6] = alive; - output.data.bytes[7] = calcChecksum(output); - - CanHandler::getInstanceEV()->sendFrame(output); + CAN_FRAME output; + output.length = 8; + output.id = 0x236; + output.extended = 0; //standard frame + output.rtr = 0; + output.data.bytes[0] = 2; + output.data.bytes[1] = 127; + output.data.bytes[2] = 0; + if (operationState == ENABLE && selectedGear != NEUTRAL) { + output.data.bytes[3] = 52; + output.data.bytes[4] = 26; + output.data.bytes[5] = 59; //drive + } + else { + output.data.bytes[3] = 39; + output.data.bytes[4] = 19; + output.data.bytes[5] = 55; //neutral + } + //--PRND12 + output.data.bytes[6] = alive; + output.data.bytes[7] = calcChecksum(output); + + CanHandler::getInstanceEV()->sendFrame(output); } void DmocMotorController::setGear(Gears gear) { - selectedGear = gear; - //if the gear was just set to drive or reverse and the DMOC is not currently in enabled - //op state then ask for it by name - if (selectedGear != NEUTRAL) { - operationState = ENABLE; - } - //should it be set to standby when selecting neutral? I don't know. Doing that prevents regen - //when in neutral and I don't think people will like that. + selectedGear = gear; + //if the gear was just set to drive or reverse and the DMOC is not currently in enabled + //op state then ask for it by name + if (selectedGear != NEUTRAL) { + operationState = ENABLE; + } + //should it be set to standby when selecting neutral? I don't know. Doing that prevents regen + //when in neutral and I don't think people will like that. } //this might look stupid. You might not believe this is real. It is. This is how you //calculate the checksum for the DMOC frames. byte DmocMotorController::calcChecksum(CAN_FRAME thisFrame) { - byte cs; - byte i; - cs = thisFrame.id; - for (i = 0; i < 7; i++) - cs += thisFrame.data.bytes[i]; - i = cs + 3; - cs = ((int) 256 - i); - return cs; + byte cs; + byte i; + cs = thisFrame.id; + for (i = 0; i < 7; i++) + cs += thisFrame.data.bytes[i]; + i = cs + 3; + cs = ((int) 256 - i); + return cs; } DeviceId DmocMotorController::getId() { - return (DMOC645); + return (DMOC645); } -uint32_t DmocMotorController::getTickInterval() +uint32_t DmocMotorController::getTickInterval() { - return CFG_TICK_INTERVAL_MOTOR_CONTROLLER_DMOC; + return CFG_TICK_INTERVAL_MOTOR_CONTROLLER_DMOC; } void DmocMotorController::loadConfiguration() { - DmocMotorControllerConfiguration *config = (DmocMotorControllerConfiguration *)getConfiguration(); + DmocMotorControllerConfiguration *config = (DmocMotorControllerConfiguration *)getConfiguration(); - if (!config) { - config = new DmocMotorControllerConfiguration(); - setConfiguration(config); - } + if (!config) { + config = new DmocMotorControllerConfiguration(); + setConfiguration(config); + } - MotorController::loadConfiguration(); // call parent + MotorController::loadConfiguration(); // call parent } void DmocMotorController::saveConfiguration() { - MotorController::saveConfiguration(); + MotorController::saveConfiguration(); } void DmocMotorController::timestamp() { - milliseconds = (int) (millis()/1) %1000 ; - seconds = (int) (millis() / 1000) % 60 ; + milliseconds = (int) (millis()/1) %1000 ; + seconds = (int) (millis() / 1000) % 60 ; minutes = (int) ((millis() / (1000*60)) % 60); hours = (int) ((millis() / (1000*60*60)) % 24); - // char buffer[9]; + // char buffer[9]; //sprintf(buffer,"%02d:%02d:%02d.%03d", hours, minutes, seconds, milliseconds); - // Serial<> 8) & 0xFF); - Logger::debug(ELM327EMU, "Mode: %i, PID: %i", mode, pidnum); - char out[7]; - char buff[10]; - if (obd2Handler->processRequest(mode, pidnum, NULL, out)) { - if (bHeader) { - retString.concat("7E8"); - out[0] += 2; //not sending only data bits but mode and pid too - for (int i = 0; i <= out[0]; i++) { - sprintf(buff, "%02X", out[i]); - retString.concat(buff); - } - } - else { - mode += 0x40; - sprintf(buff, "%02X", mode); - retString.concat(buff); - sprintf(buff, "%02X", pidnum); - retString.concat(buff); - for (int i = 1; i <= out[0]; i++) { - sprintf(buff, "%02X", out[i+2]); - retString.concat(buff); - } - } - } - } - } + if (!strcmp(cmd, "atz")) { //reset hardware + retString.concat(lineEnding); + retString.concat("ELM327 v1.3a"); + } + else if (!strncmp(cmd, "atsh",4)) { //set header address + //ignore this - just say OK + retString.concat("OK"); + } + else if (!strncmp(cmd, "ate",3)) { //turn echo on/off + //could support echo but I don't see the need, just ignore this + retString.concat("OK"); + } + else if (!strncmp(cmd, "ath",3)) { //turn headers on/off + if (cmd[3] == '1') bHeader = true; + else bHeader = false; + retString.concat("OK"); + } + else if (!strncmp(cmd, "atl",3)) { //turn linefeeds on/off + if (cmd[3] == '1') bLineFeed = true; + else bLineFeed = false; + retString.concat("OK"); + } + else if (!strcmp(cmd, "at@1")) { //send device description + retString.concat("ELM327 Emulator"); + } + else if (!strcmp(cmd, "ati")) { //send chip ID + retString.concat("ELM327 v1.3a"); + } + else if (!strncmp(cmd, "atat",4)) { //set adaptive timing + //don't intend to support adaptive timing at all + retString.concat("OK"); + } + else if (!strncmp(cmd, "atsp",4)) { //set protocol + //theoretically we can ignore this + retString.concat("OK"); + } + else if (!strcmp(cmd, "atdp")) { //show description of protocol + retString.concat("can11/500"); + } + else if (!strcmp(cmd, "atdpn")) { //show protocol number (same as passed to sp) + retString.concat("6"); + } + else if (!strcmp(cmd, "atd")) { //set to defaults + retString.concat("OK"); + } + else if (!strncmp(cmd, "atm", 3)) { //turn memory on/off + retString.concat("OK"); + } + else if (!strcmp(cmd, "atrv")) { //show 12v rail voltage + //TODO: the system should actually have this value so it wouldn't hurt to + //look it up and report the real value. + retString.concat("14.2V"); + } + else { //by default respond to anything not specifically handled by just saying OK and pretending. + retString.concat("OK"); + } + } + else { //if no AT then assume it is a PID request. This takes the form of four bytes which form the alpha hex digit encoding for two bytes + //there should be four or six characters here forming the ascii representation of the PID request. Easiest for now is to turn the ascii into + //a 16 bit number and mask off to get the bytes + if (strlen(cmd) == 4) { + uint32_t valu = strtol((char *) cmd, NULL, 16); //the pid format is always in hex + uint8_t pidnum = (uint8_t)(valu & 0xFF); + uint8_t mode = (uint8_t)((valu >> 8) & 0xFF); + Logger::debug(ELM327EMU, "Mode: %i, PID: %i", mode, pidnum); + char out[7]; + char buff[10]; + if (obd2Handler->processRequest(mode, pidnum, NULL, out)) { + if (bHeader) { + retString.concat("7E8"); + out[0] += 2; //not sending only data bits but mode and pid too + for (int i = 0; i <= out[0]; i++) { + sprintf(buff, "%02X", out[i]); + retString.concat(buff); + } + } + else { + mode += 0x40; + sprintf(buff, "%02X", mode); + retString.concat(buff); + sprintf(buff, "%02X", pidnum); + retString.concat(buff); + for (int i = 1; i <= out[0]; i++) { + sprintf(buff, "%02X", out[i+2]); + retString.concat(buff); + } + } + } + } + } - retString.concat(lineEnding); - retString.concat(">"); //prompt to show we're ready to receive again + retString.concat(lineEnding); + retString.concat(">"); //prompt to show we're ready to receive again - return retString; + return retString; } diff --git a/ELM327Processor.h b/ELM327Processor.h index cbc4110..3bc3c1f 100644 --- a/ELM327Processor.h +++ b/ELM327Processor.h @@ -10,13 +10,13 @@ class ELM327Processor { public: - ELM327Processor(); - String processELMCmd(char *cmd); + ELM327Processor(); + String processELMCmd(char *cmd); private: - OBD2Handler *obd2Handler; - char buffer[30]; // a buffer for various string conversions - bool bLineFeed; - bool bHeader; + OBD2Handler *obd2Handler; + char buffer[30]; // a buffer for various string conversions + bool bLineFeed; + bool bHeader; }; #endif diff --git a/ELM327_Emu.cpp b/ELM327_Emu.cpp index 0c45352..8a8986f 100644 --- a/ELM327_Emu.cpp +++ b/ELM327_Emu.cpp @@ -37,24 +37,24 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * Constructor. Assign serial interface to use for comm with bluetooth adapter we're emulating with */ ELM327Emu::ELM327Emu() { - prefsHandler = new PrefHandler(ELM327EMU); + prefsHandler = new PrefHandler(ELM327EMU); - uint8_t sys_type; - sysPrefs->read(EESYS_SYSTEM_TYPE, &sys_type); - if (sys_type == 3 || sys_type == 4) - serialInterface = &Serial2; - else //older hardware used this instead - serialInterface = &Serial3; + uint8_t sys_type; + sysPrefs->read(EESYS_SYSTEM_TYPE, &sys_type); + if (sys_type == 3 || sys_type == 4) + serialInterface = &Serial2; + else //older hardware used this instead + serialInterface = &Serial3; - commonName = "ELM327 Emulator over Bluetooth"; + commonName = "ELM327 Emulator over Bluetooth"; } /* * Constructor. Pass serial interface to use */ ELM327Emu::ELM327Emu(USARTClass *which) { - prefsHandler = new PrefHandler(ELM327EMU); - serialInterface = which; + prefsHandler = new PrefHandler(ELM327EMU); + serialInterface = which; } @@ -63,29 +63,29 @@ ELM327Emu::ELM327Emu(USARTClass *which) { */ void ELM327Emu::setup() { - Logger::info("add device: ELM327 emulator (id: %X, %X", ELM327EMU, this); + Logger::info("add device: ELM327 emulator (id: %X, %X", ELM327EMU, this); - TickHandler::getInstance()->detach(this); + TickHandler::getInstance()->detach(this); - tickCounter = 0; - ibWritePtr = 0; - serialInterface->begin(9600); + tickCounter = 0; + ibWritePtr = 0; + serialInterface->begin(9600); - elmProc = new ELM327Processor(); + elmProc = new ELM327Processor(); - //this isn't a wifi link but the timer interval can be the same - //because it serves a similar function and has similar timing requirements - TickHandler::getInstance()->attach(this, CFG_TICK_INTERVAL_WIFI); + //this isn't a wifi link but the timer interval can be the same + //because it serves a similar function and has similar timing requirements + TickHandler::getInstance()->attach(this, CFG_TICK_INTERVAL_WIFI); } /* * Send a command to ichip. The "AT+i" part will be added. */ void ELM327Emu::sendCmd(String cmd) { - serialInterface->write("AT"); - serialInterface->print(cmd); - serialInterface->write(13); - loop(); // parse the response + serialInterface->write("AT"); + serialInterface->print(cmd); + serialInterface->write(13); + loop(); // parse the response } /* @@ -99,18 +99,18 @@ void ELM327Emu::handleTick() { * Handle a message sent by the DeviceManager. */ void ELM327Emu::handleMessage(uint32_t messageType, void* message) { - Device::handleMessage(messageType, message); - - switch (messageType) { - case MSG_SET_PARAM: { - break; - } - case MSG_CONFIG_CHANGE: - break; - case MSG_COMMAND: - sendCmd((char *)message); - break; - } + Device::handleMessage(messageType, message); + + switch (messageType) { + case MSG_SET_PARAM: { + break; + } + case MSG_CONFIG_CHANGE: + break; + case MSG_COMMAND: + sendCmd((char *)message); + break; + } } /* @@ -121,25 +121,25 @@ void ELM327Emu::handleMessage(uint32_t messageType, void* message) { */ void ELM327Emu::loop() { - int incoming; - while (serialInterface->available()) { - incoming = serialInterface->read(); - if (incoming != -1) { //and there is no reason it should be -1 - if (incoming == 13 || ibWritePtr > 126) { // on CR or full buffer, process the line - incomingBuffer[ibWritePtr] = 0; //null terminate the string - ibWritePtr = 0; //reset the write pointer - - if (Logger::isDebug()) - Logger::debug(ELM327EMU, incomingBuffer); - processCmd(); - - } else { // add more characters - if (incoming != 10 && incoming != ' ') // don't add a LF character or spaces. Strip them right out - incomingBuffer[ibWritePtr++] = (char)tolower(incoming); //force lowercase to make processing easier - } - } else - return; - } + int incoming; + while (serialInterface->available()) { + incoming = serialInterface->read(); + if (incoming != -1) { //and there is no reason it should be -1 + if (incoming == 13 || ibWritePtr > 126) { // on CR or full buffer, process the line + incomingBuffer[ibWritePtr] = 0; //null terminate the string + ibWritePtr = 0; //reset the write pointer + + if (Logger::isDebug()) + Logger::debug(ELM327EMU, incomingBuffer); + processCmd(); + + } else { // add more characters + if (incoming != 10 && incoming != ' ') // don't add a LF character or spaces. Strip them right out + incomingBuffer[ibWritePtr++] = (char)tolower(incoming); //force lowercase to make processing easier + } + } else + return; + } } /* @@ -147,42 +147,42 @@ void ELM327Emu::loop() { * But, for reference, this cmd processes the command in incomingBuffer */ void ELM327Emu::processCmd() { - String retString = elmProc->processELMCmd(incomingBuffer); - - serialInterface->print(retString); - if (Logger::isDebug()) { - char buff[30]; - retString.toCharArray(buff, 30); - Logger::debug(ELM327EMU, buff); - } - + String retString = elmProc->processELMCmd(incomingBuffer); + + serialInterface->print(retString); + if (Logger::isDebug()) { + char buff[30]; + retString.toCharArray(buff, 30); + Logger::debug(ELM327EMU, buff); + } + } DeviceType ELM327Emu::getType() { - return DEVICE_MISC; + return DEVICE_MISC; } DeviceId ELM327Emu::getId() { - return (ELM327EMU); + return (ELM327EMU); } void ELM327Emu::loadConfiguration() { - ELM327Configuration *config = (ELM327Configuration *)getConfiguration(); + ELM327Configuration *config = (ELM327Configuration *)getConfiguration(); - if (prefsHandler->checksumValid()) { //checksum is good, read in the values stored in EEPROM - Logger::debug(ELM327EMU, "Valid checksum so using stored elm327 emulator config values"); - //TODO: implement processing of config params for WIFI + if (prefsHandler->checksumValid()) { //checksum is good, read in the values stored in EEPROM + Logger::debug(ELM327EMU, "Valid checksum so using stored elm327 emulator config values"); + //TODO: implement processing of config params for WIFI // prefsHandler->read(EESYS_WIFI0_SSID, &config->ssid); - } + } } void ELM327Emu::saveConfiguration() { - ELM327Configuration *config = (ELM327Configuration *) getConfiguration(); + ELM327Configuration *config = (ELM327Configuration *) getConfiguration(); - //TODO: implement processing of config params for WIFI + //TODO: implement processing of config params for WIFI // prefsHandler->write(EESYS_WIFI0_SSID, config->ssid); // prefsHandler->saveChecksum(); } - + diff --git a/ELM327_Emu.h b/ELM327_Emu.h index 8395a29..e9ebfb0 100644 --- a/ELM327_Emu.h +++ b/ELM327_Emu.h @@ -68,31 +68,31 @@ class ELM327Configuration : public DeviceConfiguration { }; class ELM327Emu : public Device { - public: - +public: + ELM327Emu(); ELM327Emu(USARTClass *which); void setup(); //initialization on start up void handleTick(); //periodic processes void handleMessage(uint32_t messageType, void* message); - DeviceType getType(); + DeviceType getType(); DeviceId getId(); void loop(); - void sendCmd(String cmd); + void sendCmd(String cmd); - void loadConfiguration(); - void saveConfiguration(); + void loadConfiguration(); + void saveConfiguration(); - private: +private: USARTClass *serialInterface; //Allows for retargetting which serial port we use - ELM327Processor *elmProc; + ELM327Processor *elmProc; char incomingBuffer[128]; //storage for one incoming line int tickCounter; int ibWritePtr; - int currReply; - char buffer[30]; // a buffer for various string conversions + int currReply; + char buffer[30]; // a buffer for various string conversions - void processCmd(); + void processCmd(); }; #endif diff --git a/EVIC.cpp b/EVIC.cpp index 805e3eb..38e1770 100644 --- a/EVIC.cpp +++ b/EVIC.cpp @@ -3,7 +3,7 @@ * * Class to interface with the Electric Vehicle Interface Controller EVIC by Andromeda Interfaces. This Class * will extract operating data from the GEVCU and send to EVIC via CAN message for display. - * It will also RECEIVE data from a JLD505 pack measurement unit if it is available and use that as a more + * It will also RECEIVE data from a JLD505 pack measurement unit if it is available and use that as a more * accurate source for some data. * Copyright (c) 2015 Jack Rickard @@ -32,17 +32,20 @@ #include "EVIC.h" //This just gives us a different way of printing to serial port by streaming. -template inline Print &operator <<(Print &obj, T arg) { obj.print(arg); return obj; } +template inline Print &operator <<(Print &obj, T arg) { + obj.print(arg); + return obj; +} + - /* - * Constructor. + * Constructor. */ EVIC::EVIC() : Device() { prefsHandler = new PrefHandler(EVICTUS); - + commonName = "Andromeda Interfaces EVIC Display"; } @@ -52,109 +55,121 @@ EVIC::EVIC() : Device() */ void EVIC::setup() { - Logger::info("add device: EVIC (id: %X, %X)", EVICTUS, this); - - TickHandler::getInstance()->detach(this);//Turn off tickhandler - - loadConfiguration(); //Retrieve any persistant variables - - Device::setup(); // run the parent class version of this function - - // register ourselves as observer of all 0x404 and 0x505 can frames from JLD505 - CanHandler::getInstanceCar()->attach(this, 0x404, 0x7ff, false); - CanHandler::getInstanceCar()->attach(this, 0x505, 0x7ff, false); - - MotorController* motorController = DeviceManager::getInstance()->getMotorController(); - nominalVolt=(motorController->nominalVolts); //Get default nominal volts and capacity from motorcontroller - capacity=(motorController->capacity);//If we do NOT have a JLD505, we will use these. - - tickCounter = 0; - testMode=0; - AHf=AH; - SOC=0; - SOCf=0.001; - milliAH=0.00; - DCV=0; - DCA=0; - TEMPM=0; - TEMPI=0; - CellHi=63; - Cello=60; - - elapsedtime=timemark = timemark2=millis(); - rpm=0; //Increment all our test variables each time - - TickHandler::getInstance()->attach(this, CFG_TICK_INTERVAL_EVIC); + Logger::info("add device: EVIC (id: %X, %X)", EVICTUS, this); + + TickHandler::getInstance()->detach(this);//Turn off tickhandler + + loadConfiguration(); //Retrieve any persistant variables + + Device::setup(); // run the parent class version of this function + + // register ourselves as observer of all 0x404 and 0x505 can frames from JLD505 + CanHandler::getInstanceCar()->attach(this, 0x404, 0x7ff, false); + CanHandler::getInstanceCar()->attach(this, 0x505, 0x7ff, false); + + MotorController* motorController = DeviceManager::getInstance()->getMotorController(); + nominalVolt=(motorController->nominalVolts); //Get default nominal volts and capacity from motorcontroller + capacity=(motorController->capacity);//If we do NOT have a JLD505, we will use these. + + tickCounter = 0; + testMode=0; + AHf=AH; + SOC=0; + SOCf=0.001; + milliAH=0.00; + DCV=0; + DCA=0; + TEMPM=0; + TEMPI=0; + CellHi=63; + Cello=60; + + elapsedtime=timemark = timemark2=millis(); + rpm=0; //Increment all our test variables each time + + TickHandler::getInstance()->attach(this, CFG_TICK_INTERVAL_EVIC); } //This method handles particular received CAN frames we have registered for -void EVIC::handleCanFrame(CAN_FRAME *frame) +void EVIC::handleCanFrame(CAN_FRAME *frame) { - - Logger::debug("EVIC received msg: %X %X %X %X %X %X %X %X %X", frame->id, frame->data.bytes[0], - frame->data.bytes[1],frame->data.bytes[2],frame->data.bytes[3],frame->data.bytes[4], - frame->data.bytes[5],frame->data.bytes[6],frame->data.bytes[7]); - - switch (frame->id) - { - - case 0x404: //Battery measurement message - dcVoltage= word(frame->data.bytes[0],frame->data.bytes[1]); - dcVoltage=dcVoltage; - dcCurrent= word(frame->data.bytes[2],frame->data.bytes[3]); - dcCurrent=dcCurrent; - AH= word(frame->data.bytes[4],frame->data.bytes[5]); - capacity=frame->data.bytes[6]; - SOC=frame->data.bytes[7]; - - - Logger::debug("JLD404 DC Voltage: %d Amps: %d AH: %d Capacity: %d SOC: %d", dcVoltage,dcCurrent,AH,capacity,SOC); - timemark=millis(); //We'll use this to indicate how long since we received from a 505. - break; - - case 0x505: //System Status Message - - Power= word(frame->data.bytes[0],frame->data.bytes[1]); - kWh= word(frame->data.bytes[2],frame->data.bytes[3]); - kWh=kWh/10; - celltemp1=frame->data.bytes[4]-40; - celltemp2=frame->data.bytes[5]-40; - celltemp3=frame->data.bytes[6]-40; - celltemp4=frame->data.bytes[7]-40; - - CellHi=Cello=celltemp1; - if(CellHicelltemp2){Cello=celltemp2;} //CellT to hold highest value - if(CellHicelltemp3){Cello=celltemp3;} //CellT to hold highest value - if(CellHicelltemp4){Cello=celltemp4;} //CellT to hold highest value - - - - Logger::debug("JLD505 Message Received Power output: %d kiloWatt-Hours: %d ", Power/10,kWh/10); - timemark=millis(); - break; - } -} - -//This method handles periodic tick calls received from the tasker. - -void EVIC::handleTick() + + Logger::debug("EVIC received msg: %X %X %X %X %X %X %X %X %X", frame->id, frame->data.bytes[0], + frame->data.bytes[1],frame->data.bytes[2],frame->data.bytes[3],frame->data.bytes[4], + frame->data.bytes[5],frame->data.bytes[6],frame->data.bytes[7]); + + switch (frame->id) + { + + case 0x404: //Battery measurement message + dcVoltage= word(frame->data.bytes[0],frame->data.bytes[1]); + dcVoltage=dcVoltage; + dcCurrent= word(frame->data.bytes[2],frame->data.bytes[3]); + dcCurrent=dcCurrent; + AH= word(frame->data.bytes[4],frame->data.bytes[5]); + capacity=frame->data.bytes[6]; + SOC=frame->data.bytes[7]; + + + Logger::debug("JLD404 DC Voltage: %d Amps: %d AH: %d Capacity: %d SOC: %d", dcVoltage,dcCurrent,AH,capacity,SOC); + timemark=millis(); //We'll use this to indicate how long since we received from a 505. + break; + + case 0x505: //System Status Message + + Power= word(frame->data.bytes[0],frame->data.bytes[1]); + kWh= word(frame->data.bytes[2],frame->data.bytes[3]); + kWh=kWh/10; + celltemp1=frame->data.bytes[4]-40; + celltemp2=frame->data.bytes[5]-40; + celltemp3=frame->data.bytes[6]-40; + celltemp4=frame->data.bytes[7]-40; + + CellHi=Cello=celltemp1; + if(CellHicelltemp2) { + Cello=celltemp2; //CellT to hold highest value + } + if(CellHicelltemp3) { + Cello=celltemp3; //CellT to hold highest value + } + if(CellHicelltemp4) { + Cello=celltemp4; //CellT to hold highest value + } + + + + Logger::debug("JLD505 Message Received Power output: %d kiloWatt-Hours: %d ", Power/10,kWh/10); + timemark=millis(); + break; + } +} + +//This method handles periodic tick calls received from the tasker. + +void EVIC::handleTick() { - - if(testMode==0) - { + + if(testMode==0) + { sendCmdCurtis(); sendCmdOrion(); - } + } else - { + { sendTestCmdCurtis(); sendTestCmdOrion(); - } + } } @@ -170,198 +185,200 @@ motor_amps 40 16 0.1 0 -1000 2000 amps signed motor_voltage 56 16 0.1 0 0 1000 volts signed */ -void EVIC::sendTestCmdCurtis() +void EVIC::sendTestCmdCurtis() { - rpm++; //Increment all our test variables each time - DCV++; - DCA++; - TEMPM++; - TEMPI++; - - CAN_FRAME output; - output.length = 8; - output.id = 0x601; - output.extended = 0; //standard frame - output.rtr = 0; - output.fid=0; - output.priority=0; - output.data.bytes[0] = highByte(rpm); - output.data.bytes[1] = lowByte(rpm); - output.data.bytes[2] = TEMPM; - output.data.bytes[3] = TEMPI; - output.data.bytes[4] = highByte(DCA); - output.data.bytes[5] = lowByte(DCA); - output.data.bytes[6] = highByte(DCV); - output.data.bytes[7] = lowByte(DCV); - - CanHandler::getInstanceCar()->sendFrame(output); //Mail it. - - timestamp(); - - Logger::debug("EVIC Message: %X %X %X %X %X %X %X %X %X %d:%d:%d.%d",output.id, output.data.bytes[0], -output.data.bytes[1],output.data.bytes[2],output.data.bytes[3],output.data.bytes[4],output.data.bytes[5],output.data.bytes[6],output.data.bytes[7], hours, minutes, seconds, milliseconds); - -} - -void EVIC::sendTestCmdOrion() + rpm++; //Increment all our test variables each time + DCV++; + DCA++; + TEMPM++; + TEMPI++; + + CAN_FRAME output; + output.length = 8; + output.id = 0x601; + output.extended = 0; //standard frame + output.rtr = 0; + output.fid=0; + output.priority=0; + output.data.bytes[0] = highByte(rpm); + output.data.bytes[1] = lowByte(rpm); + output.data.bytes[2] = TEMPM; + output.data.bytes[3] = TEMPI; + output.data.bytes[4] = highByte(DCA); + output.data.bytes[5] = lowByte(DCA); + output.data.bytes[6] = highByte(DCV); + output.data.bytes[7] = lowByte(DCV); + + CanHandler::getInstanceCar()->sendFrame(output); //Mail it. + + timestamp(); + + Logger::debug("EVIC Message: %X %X %X %X %X %X %X %X %X %d:%d:%d.%d",output.id, output.data.bytes[0], + output.data.bytes[1],output.data.bytes[2],output.data.bytes[3],output.data.bytes[4],output.data.bytes[5],output.data.bytes[6],output.data.bytes[7], hours, minutes, seconds, milliseconds); + +} + +void EVIC::sendTestCmdOrion() { - AH--; - CAN_FRAME output; - output.length = 8; - output.id = 0x150; - output.extended = 0; //standard frame - output.rtr = 0; -output.fid=0; - output.data.bytes[0] = highByte(DCA); - output.data.bytes[1] = lowByte(DCA); - output.data.bytes[2] = highByte(DCV); - output.data.bytes[3] = lowByte(DCV); - output.data.bytes[4] = highByte(AH); - output.data.bytes[5] = lowByte(AH); //Pack capacity in tenths of ampere-hours - output.data.bytes[6] = 0; //Cell temp - output.data.bytes[7] = 0; //Cell temp - - CanHandler::getInstanceCar()->sendFrame(output); //Mail it. - timestamp(); - - Logger::debug("Orion Message1: %X %X %X %X %X %X %X %X %X %d:%d:%d.%d",output.id, output.data.bytes[0], -output.data.bytes[1],output.data.bytes[2],output.data.bytes[3],output.data.bytes[4],output.data.bytes[5],output.data.bytes[6],output.data.bytes[7], hours, minutes, seconds, milliseconds); - - //CAN_FRAME output; - output.length = 8; - output.id = 0x650; - output.extended = 0; //standard frame - output.rtr = 0; - output.fid=0; - output.data.bytes[0] = SOC--; //SOC in percent 0-100 - output.data.bytes[1] = 0; //pack internal resistance MSB - output.data.bytes[2] = 0; //pack internal resistance LSB - output.data.bytes[3] = 100;//pack health 0-100%; - output.data.bytes[4] = lowByte(DCV); - output.data.bytes[5] = highByte(DCV); - output.data.bytes[6] = 0; //pack cycles MSB - output.data.bytes[7] = 0; //pack cycles LSB - + AH--; + CAN_FRAME output; + output.length = 8; + output.id = 0x150; + output.extended = 0; //standard frame + output.rtr = 0; + output.fid=0; + output.data.bytes[0] = highByte(DCA); + output.data.bytes[1] = lowByte(DCA); + output.data.bytes[2] = highByte(DCV); + output.data.bytes[3] = lowByte(DCV); + output.data.bytes[4] = highByte(AH); + output.data.bytes[5] = lowByte(AH); //Pack capacity in tenths of ampere-hours + output.data.bytes[6] = 0; //Cell temp + output.data.bytes[7] = 0; //Cell temp + + CanHandler::getInstanceCar()->sendFrame(output); //Mail it. + timestamp(); + + Logger::debug("Orion Message1: %X %X %X %X %X %X %X %X %X %d:%d:%d.%d",output.id, output.data.bytes[0], + output.data.bytes[1],output.data.bytes[2],output.data.bytes[3],output.data.bytes[4],output.data.bytes[5],output.data.bytes[6],output.data.bytes[7], hours, minutes, seconds, milliseconds); + + //CAN_FRAME output; + output.length = 8; + output.id = 0x650; + output.extended = 0; //standard frame + output.rtr = 0; + output.fid=0; + output.data.bytes[0] = SOC--; //SOC in percent 0-100 + output.data.bytes[1] = 0; //pack internal resistance MSB + output.data.bytes[2] = 0; //pack internal resistance LSB + output.data.bytes[3] = 100;//pack health 0-100%; + output.data.bytes[4] = lowByte(DCV); + output.data.bytes[5] = highByte(DCV); + output.data.bytes[6] = 0; //pack cycles MSB + output.data.bytes[7] = 0; //pack cycles LSB + CanHandler::getInstanceCar()->sendFrame(output); //Mail it. timestamp(); Logger::debug("Orion Message2: %X %X %X %X %X %X %X %X %X %d:%d:%d.%d",output.id, output.data.bytes[0], -output.data.bytes[1],output.data.bytes[2],output.data.bytes[3],output.data.bytes[4],output.data.bytes[5],output.data.bytes[6],output.data.bytes[7], hours, minutes, seconds, milliseconds); - + output.data.bytes[1],output.data.bytes[2],output.data.bytes[3],output.data.bytes[4],output.data.bytes[5],output.data.bytes[6],output.data.bytes[7], hours, minutes, seconds, milliseconds); + } -void EVIC::sendCmdCurtis() +void EVIC::sendCmdCurtis() { - - MotorController* motorController = DeviceManager::getInstance()->getMotorController(); - - if(millis()-timemark>2000) + + MotorController* motorController = DeviceManager::getInstance()->getMotorController(); + + if(millis()-timemark>2000) { dcCurrent=motorController->getDcCurrent(); dcVoltage=motorController->getDcVoltage(); - + } CAN_FRAME output; - output.length = 8; - output.id = 0x601; - output.extended = 0; //standard frame - output.rtr = 0; - output.fid=0; - output.data.bytes[0] = highByte(motorController->getSpeedActual()); - output.data.bytes[1] = lowByte(motorController->getSpeedActual()); - output.data.bytes[2] = (motorController->getTemperatureMotor()/10); - output.data.bytes[3] = (motorController->getTemperatureInverter()/10); - output.data.bytes[4] = highByte(dcCurrent); - output.data.bytes[5] = lowByte(dcCurrent); - output.data.bytes[6] = highByte(dcVoltage); - output.data.bytes[7] = lowByte(dcVoltage); - - CanHandler::getInstanceCar()->sendFrame(output); //Mail it. - timestamp(); - Logger::debug("EVIC Message: %X %X %X %X %X %X %X %X %X %d:%d:%d.%d",output.id, output.data.bytes[0], -output.data.bytes[1],output.data.bytes[2],output.data.bytes[3],output.data.bytes[4],output.data.bytes[5],output.data.bytes[6],output.data.bytes[7], hours, minutes, seconds, milliseconds); - -} - -void EVIC::sendCmdOrion() + output.length = 8; + output.id = 0x601; + output.extended = 0; //standard frame + output.rtr = 0; + output.fid=0; + output.data.bytes[0] = highByte(motorController->getSpeedActual()); + output.data.bytes[1] = lowByte(motorController->getSpeedActual()); + output.data.bytes[2] = (motorController->getTemperatureMotor()/10); + output.data.bytes[3] = (motorController->getTemperatureInverter()/10); + output.data.bytes[4] = highByte(dcCurrent); + output.data.bytes[5] = lowByte(dcCurrent); + output.data.bytes[6] = highByte(dcVoltage); + output.data.bytes[7] = lowByte(dcVoltage); + + CanHandler::getInstanceCar()->sendFrame(output); //Mail it. + timestamp(); + Logger::debug("EVIC Message: %X %X %X %X %X %X %X %X %X %d:%d:%d.%d",output.id, output.data.bytes[0], + output.data.bytes[1],output.data.bytes[2],output.data.bytes[3],output.data.bytes[4],output.data.bytes[5],output.data.bytes[6],output.data.bytes[7], hours, minutes, seconds, milliseconds); + +} + +void EVIC::sendCmdOrion() { - elapsedtime = (millis() - timemark2); + elapsedtime = (millis() - timemark2); timemark2=millis(); - - if(millis()-timemark>2000) // Checks to see how long its been since JLD505 message was received. - //If more than 2 seconds, we'll use MotorController values and calculate what we need. + + if(millis()-timemark>2000) // Checks to see how long its been since JLD505 message was received. + //If more than 2 seconds, we'll use MotorController values and calculate what we need. { - MotorController* motorController = DeviceManager::getInstance()->getMotorController(); - dcCurrent=(motorController->getDcCurrent()); - dcVoltage=(motorController->getDcVoltage()); - - //dcVoltage=3320; //Test value - Logger::debug("DC Voltage: %i Nominal Voltage: %i Capacity: %i",dcVoltage/10,nominalVolt/10,capacity); - - if(!(dcVoltagegetMotorController(); + dcCurrent=(motorController->getDcCurrent()); + dcVoltage=(motorController->getDcVoltage()); + + //dcVoltage=3320; //Test value + Logger::debug("DC Voltage: %i Nominal Voltage: %i Capacity: %i",dcVoltage/10,nominalVolt/10,capacity); + + if(!(dcVoltagesendFrame(output); //Mail it. - timestamp(); -Logger::debug("Orion Message1: %X %X %X %X %X %X %X %X %X %d:%d:%d.%d",output.id, output.data.bytes[0], -output.data.bytes[1],output.data.bytes[2],output.data.bytes[3],output.data.bytes[4],output.data.bytes[5],output.data.bytes[6],output.data.bytes[7], hours, minutes, seconds, milliseconds); - - //Assemble our 650 frame output; - output.length = 8; - output.id = 0x650; - output.extended = 0; //standard frame - output.rtr = 0; - output.fid=0; - - if(SOC>110){SOC=0;} - - output.data.bytes[0] = SOC*2; //SOC in percent 0-100 EVIC expects this as 0-200 with 200=100%. - output.data.bytes[1] = 0; //pack internal resistance MSB - output.data.bytes[2] = 0; //pack internal resistance LSB - output.data.bytes[3] = 100;//pack health 0-100%; - output.data.bytes[4] = highByte(dcVoltage); - output.data.bytes[5] = lowByte(dcVoltage); - output.data.bytes[6] = 0; //pack cycles MSB - output.data.bytes[7] = 0; //pack cycles LSB - + CAN_FRAME output; + output.length = 8; + output.id = 0x150; + output.extended = 0; //standard frame + output.rtr = 0; + output.fid=0; + output.data.bytes[0] = highByte(dcCurrent); //Pack Current in tenths of an ampere. + output.data.bytes[1] = lowByte(dcCurrent); + output.data.bytes[2] = lowByte(dcVoltage); //Pack voltage in whole volts + output.data.bytes[3] = highByte(dcVoltage); + output.data.bytes[4] = highByte(AH); //current ampere-hours in tenths of an ampere-hour + output.data.bytes[5] = lowByte(AH); + output.data.bytes[6] = CellHi; //Cell temp + output.data.bytes[7] = Cello; //Cell temp + + CanHandler::getInstanceCar()->sendFrame(output); //Mail it. + timestamp(); + Logger::debug("Orion Message1: %X %X %X %X %X %X %X %X %X %d:%d:%d.%d",output.id, output.data.bytes[0], + output.data.bytes[1],output.data.bytes[2],output.data.bytes[3],output.data.bytes[4],output.data.bytes[5],output.data.bytes[6],output.data.bytes[7], hours, minutes, seconds, milliseconds); + + //Assemble our 650 frame output; + output.length = 8; + output.id = 0x650; + output.extended = 0; //standard frame + output.rtr = 0; + output.fid=0; + + if(SOC>110) { + SOC=0; + } + + output.data.bytes[0] = SOC*2; //SOC in percent 0-100 EVIC expects this as 0-200 with 200=100%. + output.data.bytes[1] = 0; //pack internal resistance MSB + output.data.bytes[2] = 0; //pack internal resistance LSB + output.data.bytes[3] = 100;//pack health 0-100%; + output.data.bytes[4] = highByte(dcVoltage); + output.data.bytes[5] = lowByte(dcVoltage); + output.data.bytes[6] = 0; //pack cycles MSB + output.data.bytes[7] = 0; //pack cycles LSB + CanHandler::getInstanceCar()->sendFrame(output); //Mail it. timestamp(); Logger::debug("Orion Message2: %X %X %X %X %X %X %X %X %X %d:%d:%d.%d",output.id, output.data.bytes[0], -output.data.bytes[1],output.data.bytes[2],output.data.bytes[3],output.data.bytes[4],output.data.bytes[5],output.data.bytes[6],output.data.bytes[7], hours, minutes, seconds, milliseconds); - + output.data.bytes[1],output.data.bytes[2],output.data.bytes[3],output.data.bytes[4],output.data.bytes[5],output.data.bytes[6],output.data.bytes[7], hours, minutes, seconds, milliseconds); + } @@ -371,9 +388,9 @@ void EVIC::timestamp() seconds = (int) (millis() / 1000) % 60 ; minutes = (int) ((millis() / (1000*60)) % 60); hours = (int) ((millis() / (1000*60*60)) % 24); - // char buffer[9]; + // char buffer[9]; //sprintf(buffer,"%02d:%02d:%02d.%03d", hours, minutes, seconds, milliseconds); - // Serial<checksumValid()) + { //checksum is good, read in the values stored in EEPROM + prefsHandler->read(EESYS_CAPACITY, &capacity); + prefsHandler->read(EESYS_AH, &AH); + + } + else + { + capacity = BatteryCapacity; //Get capacity value from config.h + prefsHandler->write(EESYS_CAPACITY, capacity); //and write it to EEPROM + // prefsHandler->write(EESYS_AH,AH); + prefsHandler->saveChecksum(); + } - if (prefsHandler->checksumValid()) - { //checksum is good, read in the values stored in EEPROM - prefsHandler->read(EESYS_CAPACITY, &capacity); - prefsHandler->read(EESYS_AH, &AH); - - } - else - { - capacity = BatteryCapacity; //Get capacity value from config.h - prefsHandler->write(EESYS_CAPACITY, capacity); //and write it to EEPROM - // prefsHandler->write(EESYS_AH,AH); - prefsHandler->saveChecksum(); - } - } void EVIC::saveConfiguration() { - EVICConfiguration *config = (EVICConfiguration *)getConfiguration(); + EVICConfiguration *config = (EVICConfiguration *)getConfiguration(); - - //Device::saveConfiguration(); //call parent save routine - prefsHandler->write(EESYS_CAPACITY, capacity); //save current values to EEPROM - prefsHandler->write(EESYS_AH, AH); //save current values to EEPROM - prefsHandler->saveChecksum(); - - loadConfiguration(); + //Device::saveConfiguration(); //call parent save routine + + prefsHandler->write(EESYS_CAPACITY, capacity); //save current values to EEPROM + prefsHandler->write(EESYS_AH, AH); //save current values to EEPROM + prefsHandler->saveChecksum(); + + loadConfiguration(); } int16_t EVIC::getdcVoltage() - { - return dcVoltage; - } +{ + return dcVoltage; +} int16_t EVIC::getdcCurrent() - { - return dcCurrent; - } +{ + return dcCurrent; +} uint16_t EVIC::getAH() - { - return AH; - } +{ + return AH; +} uint8_t EVIC::getCapacity() - { - return capacity; - } +{ + return capacity; +} void EVIC::setCapacity(uint8_t capacity) - { - capacity=capacity; - } +{ + capacity=capacity; +} uint8_t EVIC::getSOC() - { - return SOC; - } +{ + return SOC; +} int16_t EVIC::getPower() - { - return Power; - } +{ + return Power; +} int16_t EVIC::getkWh() - { - return kWh; - } +{ + return kWh; +} int16_t EVIC::getTemperatureMotor() - { - return temperatureMotor; - } +{ + return temperatureMotor; +} int16_t EVIC::getTemperatureInverter() - { - return temperatureInverter; - } +{ + return temperatureInverter; +} int16_t EVIC::getRPM() - { - return rpm; - } +{ + return rpm; +} uint8_t EVIC::getCellTemp1() - { - return celltemp1; - } +{ + return celltemp1; +} uint8_t EVIC::getCellTemp2() - { - return celltemp2; - } +{ + return celltemp2; +} uint8_t EVIC::getCellTemp3() - { - return celltemp3; - } +{ + return celltemp3; +} uint8_t EVIC::getCellTemp4() - { - return celltemp4; - } +{ + return celltemp4; +} uint8_t EVIC::getCellHi() - { - return CellHi; - } +{ + return CellHi; +} uint8_t EVIC::getCello() - { - return Cello; - } - +{ + return Cello; +} + diff --git a/EVIC.h b/EVIC.h index e8c0726..7d2f18a 100644 --- a/EVIC.h +++ b/EVIC.h @@ -47,23 +47,23 @@ extern PrefHandler *sysPrefs; class EVICConfiguration: public DeviceConfiguration { public: - //uint8_t capacity; + //uint8_t capacity; }; class EVIC: public Device, CanObserver { - public: - +public: + EVIC(); //EVIC(USARTClass *which); virtual void handleTick(); virtual void handleCanFrame(CAN_FRAME *frame); - + virtual void setup(); //initialization on start up void timestamp(); DeviceType getType(); DeviceId getId(); - + char *getTimeRunning(); void loadConfiguration(); void saveConfiguration(); @@ -84,55 +84,55 @@ class EVIC: public Device, CanObserver { uint8_t getCellTemp4(); uint8_t getCellHi(); uint8_t getCello(); - - unsigned long timemark; - unsigned long timemark2; - int16_t torqueActual; - int16_t speedActual; - int16_t dcVoltage; - int16_t dcCurrent; - uint16_t nominalVolt; - uint16_t AH; - uint8_t capacity; - uint8_t SOC; - int16_t Power; - int16_t kWh; - int16_t temperatureMotor; - int16_t temperatureInverter; - int16_t rpm; - uint8_t celltemp1; - uint8_t celltemp2; - uint8_t celltemp3; - uint8_t celltemp4; - uint8_t CellHi; - uint8_t Cello; - - private: + + unsigned long timemark; + unsigned long timemark2; + int16_t torqueActual; + int16_t speedActual; + int16_t dcVoltage; + int16_t dcCurrent; + uint16_t nominalVolt; + uint16_t AH; + uint8_t capacity; + uint8_t SOC; + int16_t Power; + int16_t kWh; + int16_t temperatureMotor; + int16_t temperatureInverter; + int16_t rpm; + uint8_t celltemp1; + uint8_t celltemp2; + uint8_t celltemp3; + uint8_t celltemp4; + uint8_t CellHi; + uint8_t Cello; + +private: void sendTestCmdCurtis(); - void sendTestCmdOrion(); + void sendTestCmdOrion(); void sendCmdCurtis(); - void sendCmdOrion(); - - double AHf; - double milliAH; - float SOCf; - int milliseconds ; - int seconds; - int minutes; - int hours ; - unsigned long elapsedtime; - int16_t DCV; - int16_t DCA; - int8_t TEMPM; - int8_t TEMPI; - + void sendCmdOrion(); + + double AHf; + double milliAH; + float SOCf; + int milliseconds ; + int seconds; + int minutes; + int hours ; + unsigned long elapsedtime; + int16_t DCV; + int16_t DCA; + int8_t TEMPM; + int8_t TEMPI; + int tickCounter; char buffer[30]; // a buffer for various string conversions uint32_t lastSentTime; boolean weHave505; boolean testMode; - - + + }; #endif diff --git a/FaultCodes.h b/FaultCodes.h index 12f14c3..1e4790c 100644 --- a/FaultCodes.h +++ b/FaultCodes.h @@ -23,7 +23,7 @@ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * + * */ #ifndef FAULTCODES_H_ @@ -44,127 +44,127 @@ codes with hex digits to avoid overlap */ enum FAULTCODE { - FAULT_NONE = 0, - - //The A throttle seems to be stuck low - FAULT_THROTTLE_LOW_A = 0x0F01, //P0F01 - - //The A throttle seems to be stuck high - FAULT_THROTTLE_HIGH_A = 0x0F02, //P0F02 - - //The B throttle seems to be stuck low - FAULT_THROTTLE_LOW_B = 0x0F06, //P0F06 - - //The B throttle seems to be stuck high - FAULT_THROTTLE_HIGH_B = 0x0F07, //P0F07 - - //The C throttle seems to be stuck low - FAULT_THROTTLE_LOW_C = 0x0F0A, //P0F0A - - //The C throttle seems to be stuck high - FAULT_THROTTLE_HIGH_C = 0x0F0B, //P0F0B - - //Throttles A and B do not match - FAULT_THROTTLE_MISMATCH_AB = 0x0F11, //P0F11 - - //Throttles A and C do not match - FAULT_THROTTLE_MISMATCH_AC = 0x0F12, //P0F12 - - //Throttles B and C do not match - FAULT_THROTTLE_MISMATCH_BC = 0x0F13, //P0F13 - - //There was a general fault in the throttle - FAULT_THROTTLE_MISC = 0x0F40, //P0F40 - - //There was a problem communicating with an external throttle module - FAULT_THROTTLE_COMM = 0x0F60, //P0F60 - - //The brake input seems to be stuck low - FAULT_BRAKE_LOW = 0x0B01, //P0B01 - - //The brake input seems to be stuck high - FAULT_BRAKE_HIGH = 0x0B02, //P0B02 - - //There was a problem communicating with an external brake module - FAULT_BRAKE_COMM = 0x0B60, //P0B60 - - //The +12V battery or DC/DC system seems to have excessively high voltage - FAULT_12V_BATT_HIGH = 0x0A01, //P0A01 - - //The +12V battery or DC/DC system seems to have excessively low voltage - FAULT_12V_BATT_LOW = 0x0A02, //P0A02 - - //The HV battery has too high of a voltage - FAULT_HV_BATT_HIGH = 0x0A11, //P0A11 - - //The HV battery has too low of a voltage - FAULT_HV_BATT_LOW = 0x0A12, //P0A12 - - //A request has been made for more current than allowable from the HV battery - FAULT_HV_BATT_OVERCURR = 0x0A30, //P0A30 - - //The HV battery is too cold - FAULT_HV_BATT_UNDERTEMP = 0x0A50, //P0A50 - - //The HV battery is too hot - FAULT_HV_BATT_OVERTEMP = 0x0A51, //P0A51 - - //There is a problem with isolation of HV from the chassis - FAULT_HV_BATT_ISOLATION = 0x0A70, //P0A70 - - //A cell in the HV pack is too high of a voltage - FAULT_HV_CELL_HIGH = 0x0AA1, //P0AA1 - - //A cell in the HV pack is too low of a voltage - FAULT_HV_CELL_LOW = 0x0AA2, //P0AA2 - - //A cell in the HV pack is too cold - FAULT_HV_CELL_UNDERTEMP = 0x0AB0, //P0AB0 - - //A cell in the HV pack is too hot - FAULT_HV_CELL_OVERTEMP = 0x0AB1, //P0AB1 - - //BMS failed to initialize properly - FAULT_BMS_INIT = 0xCC10, //U0C10 - - //There was a problem communicating with the BMS - FAULT_BMS_COMM = 0xCC60, //U0C60 - - //There was a general fault at the BMS - FAULT_BMS_MISC = 0xCC40, //U0C40 - - //The motor is too hot - FAULT_MOTOR_OVERTEMP = 0x0D50, //P0D50 - - //The motor controller is too hot - FAULT_MOTORCTRL_OVERTEMP = 0x0D80, //P0D80 - - //There was a problem communicating with the motor controller - FAULT_MOTORCTRL_COMM = 0x0D60, //P0D60 - - //There was a general fault in the motor controller - FAULT_MOTORCTRL_MISC = 0x0D40, //P0D40 - - //The motor and controller cannot satisfy the torque request - FAULT_MOTORCTRL_INSUFF_TORQUE = 0x0D10, //P0D10 - - //The motor is spinning faster that it should be - FAULT_MOTORCTRL_EXCESSIVE_SPEED = 0x0D20, //P0D20 - - //The motor is providing more torque than it should be (didn't request this much) - FAULT_MOTORCTRL_EXCESSIVE_TORQUE = 0x0D25, //P0D25 - - //It seems that we cannot enable the motor controller though we've tried. - FAULT_MOTORCTRL_CANT_ENABLE = 0x0DA0, //P0DA0 - - //It seems we cannot go into drive even though we asked to go into drive - FAULT_MOTORCTRL_CANT_DRIVE = 0x0DA4, //P0DA4 - - //It seems we cannot go into reverse even though we asked to go into reverse - FAULT_MOTORCTRL_CANT_REVERSE = 0x0DA8, //P0DA8 - - //there was a request for power from the motor but the controller is not in a state to provide power - FAULT_MOTORCTRL_POWERREQ_INV = 0x0DB0 //P0DB0 + FAULT_NONE = 0, + + //The A throttle seems to be stuck low + FAULT_THROTTLE_LOW_A = 0x0F01, //P0F01 + + //The A throttle seems to be stuck high + FAULT_THROTTLE_HIGH_A = 0x0F02, //P0F02 + + //The B throttle seems to be stuck low + FAULT_THROTTLE_LOW_B = 0x0F06, //P0F06 + + //The B throttle seems to be stuck high + FAULT_THROTTLE_HIGH_B = 0x0F07, //P0F07 + + //The C throttle seems to be stuck low + FAULT_THROTTLE_LOW_C = 0x0F0A, //P0F0A + + //The C throttle seems to be stuck high + FAULT_THROTTLE_HIGH_C = 0x0F0B, //P0F0B + + //Throttles A and B do not match + FAULT_THROTTLE_MISMATCH_AB = 0x0F11, //P0F11 + + //Throttles A and C do not match + FAULT_THROTTLE_MISMATCH_AC = 0x0F12, //P0F12 + + //Throttles B and C do not match + FAULT_THROTTLE_MISMATCH_BC = 0x0F13, //P0F13 + + //There was a general fault in the throttle + FAULT_THROTTLE_MISC = 0x0F40, //P0F40 + + //There was a problem communicating with an external throttle module + FAULT_THROTTLE_COMM = 0x0F60, //P0F60 + + //The brake input seems to be stuck low + FAULT_BRAKE_LOW = 0x0B01, //P0B01 + + //The brake input seems to be stuck high + FAULT_BRAKE_HIGH = 0x0B02, //P0B02 + + //There was a problem communicating with an external brake module + FAULT_BRAKE_COMM = 0x0B60, //P0B60 + + //The +12V battery or DC/DC system seems to have excessively high voltage + FAULT_12V_BATT_HIGH = 0x0A01, //P0A01 + + //The +12V battery or DC/DC system seems to have excessively low voltage + FAULT_12V_BATT_LOW = 0x0A02, //P0A02 + + //The HV battery has too high of a voltage + FAULT_HV_BATT_HIGH = 0x0A11, //P0A11 + + //The HV battery has too low of a voltage + FAULT_HV_BATT_LOW = 0x0A12, //P0A12 + + //A request has been made for more current than allowable from the HV battery + FAULT_HV_BATT_OVERCURR = 0x0A30, //P0A30 + + //The HV battery is too cold + FAULT_HV_BATT_UNDERTEMP = 0x0A50, //P0A50 + + //The HV battery is too hot + FAULT_HV_BATT_OVERTEMP = 0x0A51, //P0A51 + + //There is a problem with isolation of HV from the chassis + FAULT_HV_BATT_ISOLATION = 0x0A70, //P0A70 + + //A cell in the HV pack is too high of a voltage + FAULT_HV_CELL_HIGH = 0x0AA1, //P0AA1 + + //A cell in the HV pack is too low of a voltage + FAULT_HV_CELL_LOW = 0x0AA2, //P0AA2 + + //A cell in the HV pack is too cold + FAULT_HV_CELL_UNDERTEMP = 0x0AB0, //P0AB0 + + //A cell in the HV pack is too hot + FAULT_HV_CELL_OVERTEMP = 0x0AB1, //P0AB1 + + //BMS failed to initialize properly + FAULT_BMS_INIT = 0xCC10, //U0C10 + + //There was a problem communicating with the BMS + FAULT_BMS_COMM = 0xCC60, //U0C60 + + //There was a general fault at the BMS + FAULT_BMS_MISC = 0xCC40, //U0C40 + + //The motor is too hot + FAULT_MOTOR_OVERTEMP = 0x0D50, //P0D50 + + //The motor controller is too hot + FAULT_MOTORCTRL_OVERTEMP = 0x0D80, //P0D80 + + //There was a problem communicating with the motor controller + FAULT_MOTORCTRL_COMM = 0x0D60, //P0D60 + + //There was a general fault in the motor controller + FAULT_MOTORCTRL_MISC = 0x0D40, //P0D40 + + //The motor and controller cannot satisfy the torque request + FAULT_MOTORCTRL_INSUFF_TORQUE = 0x0D10, //P0D10 + + //The motor is spinning faster that it should be + FAULT_MOTORCTRL_EXCESSIVE_SPEED = 0x0D20, //P0D20 + + //The motor is providing more torque than it should be (didn't request this much) + FAULT_MOTORCTRL_EXCESSIVE_TORQUE = 0x0D25, //P0D25 + + //It seems that we cannot enable the motor controller though we've tried. + FAULT_MOTORCTRL_CANT_ENABLE = 0x0DA0, //P0DA0 + + //It seems we cannot go into drive even though we asked to go into drive + FAULT_MOTORCTRL_CANT_DRIVE = 0x0DA4, //P0DA4 + + //It seems we cannot go into reverse even though we asked to go into reverse + FAULT_MOTORCTRL_CANT_REVERSE = 0x0DA8, //P0DA8 + + //there was a request for power from the motor but the controller is not in a state to provide power + FAULT_MOTORCTRL_POWERREQ_INV = 0x0DB0 //P0DB0 }; diff --git a/FaultHandler.cpp b/FaultHandler.cpp index c5cf590..164f3e2 100644 --- a/FaultHandler.cpp +++ b/FaultHandler.cpp @@ -22,207 +22,207 @@ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ + */ #include "FaultHandler.h" #include "eeprom_layout.h" - FaultHandler::FaultHandler() - { - } - - void FaultHandler::setup() - { - TickHandler::getInstance()->detach(this); - - Logger::info("Initializing Fault Handler", FAULTSYS, this); - - loadFromEEPROM(); - - //Use the heartbeat interval because it's slow and already exists so we can piggyback on the interrupt - //so as to not create more timers than necessary. - TickHandler::getInstance()->attach(this, CFG_TICK_INTERVAL_HEARTBEAT); - } - - - //Every tick update the global time and save it to EEPROM (delayed saving) - void FaultHandler::handleTick() - { - globalTime = baseTime + (millis() / 100); - memCache->Write(EE_FAULT_LOG + EEFAULT_RUNTIME, globalTime); - } - - uint16_t FaultHandler::raiseFault(uint16_t device, uint16_t code, bool ongoing = false) - { - return 0; //this function is broken. - bool incPtr = false; - globalTime = baseTime + (millis() / 100); - - //first try to see if this fault is already registered as ongoing. If so don't update the time but set ongoing status if necessary - bool found = false; - for (int j = 0; j < CFG_FAULT_HISTORY_SIZE; j++) - { - if (faultList[j].ongoing && faultList[j].device == device && faultList[j].faultCode == code) - { - found = true; - //faultList[j].timeStamp = globalTime; - faultList[j].ongoing = ongoing; - break; //quit searching - } - } - - //nothing ongoing to register a new one - if (!found) - { - faultList[faultWritePointer].timeStamp = globalTime; - faultList[faultWritePointer].ack = false; - faultList[faultWritePointer].device = device; - faultList[faultWritePointer].faultCode = code; - faultList[faultWritePointer].ongoing = ongoing; - incPtr = true; - } - - //write back to EEPROM cache - memCache->Write(EE_FAULT_LOG + EEFAULT_FAULTS_START + sizeof(FAULT) * faultWritePointer, &faultList[faultWritePointer], sizeof(FAULT)); - - if (incPtr) - { - //Cause the memory caching system to immediately write the page but only if incPtr is set (only if this is a new fault) - memCache->InvalidateAddress(EE_FAULT_LOG + EEFAULT_FAULTS_START + sizeof(FAULT)* faultWritePointer); - faultWritePointer = (faultWritePointer + 1) % CFG_FAULT_HISTORY_SIZE; - memCache->Write(EE_FAULT_LOG + EEFAULT_WRITEPTR , faultWritePointer); - //Cause the page to be immediately fully aged so that it is written very soon. - memCache->AgeFullyAddress(EE_FAULT_LOG + EEFAULT_WRITEPTR); - //Also announce fault on the console - Logger::error(FAULTSYS, "Fault %x raised by device %x at uptime %i", code, device, globalTime); - } - } - - void FaultHandler::cancelOngoingFault(uint16_t device, uint16_t code) - { - for (int i = 0; i < CFG_FAULT_HISTORY_SIZE; i++) - { - if (faultList[i].ongoing && faultList[i].device == device && faultList[i].faultCode == code) - { - setFaultOngoing(i, false); - } - } - } - - uint16_t FaultHandler::getFaultCount() - { - int count = 0; - for (int i = 0; i < CFG_FAULT_HISTORY_SIZE; i++) - { - if (faultList[i].ack == false && faultList[i].device != 0xFFFF) - { - count++; - } - } - return count; - } - - //the fault handler isn't a device per se and uses more memory than a device would normally be allocated so - //it does not use PrefHandler - void FaultHandler::loadFromEEPROM() - { - uint8_t validByte; - memCache->Read(EE_FAULT_LOG, &validByte); - if (validByte == 0xB2) //magic byte value for a valid fault cache - { - memCache->Read(EE_FAULT_LOG + EEFAULT_READPTR, &faultReadPointer); - memCache->Read(EE_FAULT_LOG + EEFAULT_WRITEPTR, &faultWritePointer); - memCache->Read(EE_FAULT_LOG + EEFAULT_RUNTIME, &globalTime); - baseTime = globalTime; - for (int i = 0; i < CFG_FAULT_HISTORY_SIZE; i++) - { - memCache->Read(EE_FAULT_LOG + EEFAULT_FAULTS_START + sizeof(FAULT) * i, &faultList[i], sizeof(FAULT)); - } - } - else //reinitialize the fault cache storage - { - validByte = 0xB2; - memCache->Write(EE_FAULT_LOG, validByte); - memCache->Write(EE_FAULT_LOG + EEFAULT_READPTR, (uint16_t)0); - memCache->Write(EE_FAULT_LOG + EEFAULT_WRITEPTR, (uint16_t)0); - globalTime = baseTime = millis() / 100; - memCache->Write(EE_FAULT_LOG + EEFAULT_RUNTIME, globalTime); - - FAULT tempFault; - tempFault.ack = true; - tempFault.device = 0xFFFF; - tempFault.faultCode = 0xFFFF; - tempFault.ongoing = false; - tempFault.timeStamp = 0; - for (int i = 0; i < CFG_FAULT_HISTORY_SIZE; i++) - { - faultList[i] = tempFault; - } - saveToEEPROM(); - } - } - - void FaultHandler::saveToEEPROM() - { - memCache->Write(EE_FAULT_LOG + EEFAULT_READPTR, faultReadPointer); - memCache->Write(EE_FAULT_LOG + EEFAULT_WRITEPTR, faultWritePointer); - memCache->Write(EE_FAULT_LOG + EEFAULT_RUNTIME, globalTime); - for (int i = 0; i < CFG_FAULT_HISTORY_SIZE; i++) - { - memCache->Write(EE_FAULT_LOG + EEFAULT_FAULTS_START + sizeof(FAULT) * i, &faultList[i], sizeof(FAULT)); - } - } - - void FaultHandler::writeFaultToEEPROM(int faultnum) - { - if (faultnum > 0 && faultnum < CFG_FAULT_HISTORY_SIZE) - { - memCache->Write(EE_FAULT_LOG + EEFAULT_FAULTS_START + sizeof(FAULT) * faultnum, &faultList[faultnum], sizeof(FAULT)); - } - } - - bool FaultHandler::getNextFault(FAULT *fault) - { - uint16_t j; - for (int i = 0; i < CFG_FAULT_HISTORY_SIZE; i++) - { - j = (faultReadPointer + i + 1) % CFG_FAULT_HISTORY_SIZE; - if (faultList[j].ack == false) { - fault = &faultList[j]; - faultReadPointer = j; - return true; - } - } - return false; - } - - bool FaultHandler::getFault(uint16_t fault, FAULT *outFault) - { - if (fault > 0 && fault < CFG_FAULT_HISTORY_SIZE) { - outFault = &faultList[fault]; - return true; - } - return false; - } - - uint16_t FaultHandler::setFaultACK(uint16_t fault) - { - if (fault > 0 && fault < CFG_FAULT_HISTORY_SIZE) - { - faultList[fault].ack = 1; - writeFaultToEEPROM(fault); - } - } - - uint16_t FaultHandler::setFaultOngoing(uint16_t fault, bool ongoing) - { - if (fault > 0 && fault < CFG_FAULT_HISTORY_SIZE) - { - faultList[fault].ongoing = ongoing; - writeFaultToEEPROM(fault); - } - } - - FaultHandler faultHandler; +FaultHandler::FaultHandler() +{ +} + +void FaultHandler::setup() +{ + TickHandler::getInstance()->detach(this); + + Logger::info("Initializing Fault Handler", FAULTSYS, this); + + loadFromEEPROM(); + + //Use the heartbeat interval because it's slow and already exists so we can piggyback on the interrupt + //so as to not create more timers than necessary. + TickHandler::getInstance()->attach(this, CFG_TICK_INTERVAL_HEARTBEAT); +} + + +//Every tick update the global time and save it to EEPROM (delayed saving) +void FaultHandler::handleTick() +{ + globalTime = baseTime + (millis() / 100); + memCache->Write(EE_FAULT_LOG + EEFAULT_RUNTIME, globalTime); +} + +uint16_t FaultHandler::raiseFault(uint16_t device, uint16_t code, bool ongoing = false) +{ + return 0; //this function is broken. + bool incPtr = false; + globalTime = baseTime + (millis() / 100); + + //first try to see if this fault is already registered as ongoing. If so don't update the time but set ongoing status if necessary + bool found = false; + for (int j = 0; j < CFG_FAULT_HISTORY_SIZE; j++) + { + if (faultList[j].ongoing && faultList[j].device == device && faultList[j].faultCode == code) + { + found = true; + //faultList[j].timeStamp = globalTime; + faultList[j].ongoing = ongoing; + break; //quit searching + } + } + + //nothing ongoing to register a new one + if (!found) + { + faultList[faultWritePointer].timeStamp = globalTime; + faultList[faultWritePointer].ack = false; + faultList[faultWritePointer].device = device; + faultList[faultWritePointer].faultCode = code; + faultList[faultWritePointer].ongoing = ongoing; + incPtr = true; + } + + //write back to EEPROM cache + memCache->Write(EE_FAULT_LOG + EEFAULT_FAULTS_START + sizeof(FAULT) * faultWritePointer, &faultList[faultWritePointer], sizeof(FAULT)); + + if (incPtr) + { + //Cause the memory caching system to immediately write the page but only if incPtr is set (only if this is a new fault) + memCache->InvalidateAddress(EE_FAULT_LOG + EEFAULT_FAULTS_START + sizeof(FAULT)* faultWritePointer); + faultWritePointer = (faultWritePointer + 1) % CFG_FAULT_HISTORY_SIZE; + memCache->Write(EE_FAULT_LOG + EEFAULT_WRITEPTR , faultWritePointer); + //Cause the page to be immediately fully aged so that it is written very soon. + memCache->AgeFullyAddress(EE_FAULT_LOG + EEFAULT_WRITEPTR); + //Also announce fault on the console + Logger::error(FAULTSYS, "Fault %x raised by device %x at uptime %i", code, device, globalTime); + } +} + +void FaultHandler::cancelOngoingFault(uint16_t device, uint16_t code) +{ + for (int i = 0; i < CFG_FAULT_HISTORY_SIZE; i++) + { + if (faultList[i].ongoing && faultList[i].device == device && faultList[i].faultCode == code) + { + setFaultOngoing(i, false); + } + } +} + +uint16_t FaultHandler::getFaultCount() +{ + int count = 0; + for (int i = 0; i < CFG_FAULT_HISTORY_SIZE; i++) + { + if (faultList[i].ack == false && faultList[i].device != 0xFFFF) + { + count++; + } + } + return count; +} + +//the fault handler isn't a device per se and uses more memory than a device would normally be allocated so +//it does not use PrefHandler +void FaultHandler::loadFromEEPROM() +{ + uint8_t validByte; + memCache->Read(EE_FAULT_LOG, &validByte); + if (validByte == 0xB2) //magic byte value for a valid fault cache + { + memCache->Read(EE_FAULT_LOG + EEFAULT_READPTR, &faultReadPointer); + memCache->Read(EE_FAULT_LOG + EEFAULT_WRITEPTR, &faultWritePointer); + memCache->Read(EE_FAULT_LOG + EEFAULT_RUNTIME, &globalTime); + baseTime = globalTime; + for (int i = 0; i < CFG_FAULT_HISTORY_SIZE; i++) + { + memCache->Read(EE_FAULT_LOG + EEFAULT_FAULTS_START + sizeof(FAULT) * i, &faultList[i], sizeof(FAULT)); + } + } + else //reinitialize the fault cache storage + { + validByte = 0xB2; + memCache->Write(EE_FAULT_LOG, validByte); + memCache->Write(EE_FAULT_LOG + EEFAULT_READPTR, (uint16_t)0); + memCache->Write(EE_FAULT_LOG + EEFAULT_WRITEPTR, (uint16_t)0); + globalTime = baseTime = millis() / 100; + memCache->Write(EE_FAULT_LOG + EEFAULT_RUNTIME, globalTime); + + FAULT tempFault; + tempFault.ack = true; + tempFault.device = 0xFFFF; + tempFault.faultCode = 0xFFFF; + tempFault.ongoing = false; + tempFault.timeStamp = 0; + for (int i = 0; i < CFG_FAULT_HISTORY_SIZE; i++) + { + faultList[i] = tempFault; + } + saveToEEPROM(); + } +} + +void FaultHandler::saveToEEPROM() +{ + memCache->Write(EE_FAULT_LOG + EEFAULT_READPTR, faultReadPointer); + memCache->Write(EE_FAULT_LOG + EEFAULT_WRITEPTR, faultWritePointer); + memCache->Write(EE_FAULT_LOG + EEFAULT_RUNTIME, globalTime); + for (int i = 0; i < CFG_FAULT_HISTORY_SIZE; i++) + { + memCache->Write(EE_FAULT_LOG + EEFAULT_FAULTS_START + sizeof(FAULT) * i, &faultList[i], sizeof(FAULT)); + } +} + +void FaultHandler::writeFaultToEEPROM(int faultnum) +{ + if (faultnum > 0 && faultnum < CFG_FAULT_HISTORY_SIZE) + { + memCache->Write(EE_FAULT_LOG + EEFAULT_FAULTS_START + sizeof(FAULT) * faultnum, &faultList[faultnum], sizeof(FAULT)); + } +} + +bool FaultHandler::getNextFault(FAULT *fault) +{ + uint16_t j; + for (int i = 0; i < CFG_FAULT_HISTORY_SIZE; i++) + { + j = (faultReadPointer + i + 1) % CFG_FAULT_HISTORY_SIZE; + if (faultList[j].ack == false) { + fault = &faultList[j]; + faultReadPointer = j; + return true; + } + } + return false; +} + +bool FaultHandler::getFault(uint16_t fault, FAULT *outFault) +{ + if (fault > 0 && fault < CFG_FAULT_HISTORY_SIZE) { + outFault = &faultList[fault]; + return true; + } + return false; +} + +uint16_t FaultHandler::setFaultACK(uint16_t fault) +{ + if (fault > 0 && fault < CFG_FAULT_HISTORY_SIZE) + { + faultList[fault].ack = 1; + writeFaultToEEPROM(fault); + } +} + +uint16_t FaultHandler::setFaultOngoing(uint16_t fault, bool ongoing) +{ + if (fault > 0 && fault < CFG_FAULT_HISTORY_SIZE) + { + faultList[fault].ongoing = ongoing; + writeFaultToEEPROM(fault); + } +} + +FaultHandler faultHandler; diff --git a/FaultHandler.h b/FaultHandler.h index aa595f5..729a250 100644 --- a/FaultHandler.h +++ b/FaultHandler.h @@ -26,7 +26,7 @@ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ + */ #ifndef FAULT_H_ @@ -43,38 +43,38 @@ extern MemCache *memCache; //structure to use for storing and retrieving faults. //Stores the info a fault record will contain. typedef struct { - uint32_t timeStamp; //number of - uint16_t device; //which device is generating this fault - uint16_t faultCode; //set by the device itself. There is a universal list of codes - uint8_t ack : 1; ////whether this fault has been acknowledged or not 1 = ack'd - uint8_t ongoing : 1; //whether fault still seems to be happening currently 1 = still going on + uint32_t timeStamp; //number of + uint16_t device; //which device is generating this fault + uint16_t faultCode; //set by the device itself. There is a universal list of codes + uint8_t ack : 1; ////whether this fault has been acknowledged or not 1 = ack'd + uint8_t ongoing : 1; //whether fault still seems to be happening currently 1 = still going on } FAULT; //should be 9 bytes because the bottom two are bit fields in a single byte class FaultHandler : public TickObserver { - public: - FaultHandler(); //constructor - uint16_t raiseFault(uint16_t device, uint16_t code, bool ongoing); //raise a new fault. Returns the fault # where this was stored - void cancelOngoingFault(uint16_t device, uint16_t code); //if this fault was registered as ongoing then cancel it (set not ongoing) otherwise do nothing - bool getNextFault(FAULT*); //get the next un-ack'd fault. Will also get first fault if the first call and you forgot to call getFirstFault - bool getFault(uint16_t fault, FAULT*); - uint16_t getFaultCount(); - void handleTick(); - void setup(); - - uint16_t setFaultACK(uint16_t fault); //acknowledge the fault # - returns fault # if successful (0xFFFF otherwise) - uint16_t setFaultOngoing(uint16_t fault, bool ongoing); //set value of ongoing flag - returns fault # on success - - private: - void loadFromEEPROM(); - void saveToEEPROM(); - void writeFaultToEEPROM(int faultnum); - - uint16_t faultWritePointer; //fault # we're up to for writing. Location in EEPROM is start + (fault_ptr * sizeof(FAULT)) - uint16_t faultReadPointer; //fault # we're at when reading. - FAULT faultList[CFG_FAULT_HISTORY_SIZE]; //store up to 50 faults for a long history. 50*9 = 450 bytes of EEPROM - uint32_t globalTime; //how long the unit has been running in total (across all start ups). - uint32_t baseTime; //the time loaded at system start up. millis() / 100 is added to this to get the above time +public: + FaultHandler(); //constructor + uint16_t raiseFault(uint16_t device, uint16_t code, bool ongoing); //raise a new fault. Returns the fault # where this was stored + void cancelOngoingFault(uint16_t device, uint16_t code); //if this fault was registered as ongoing then cancel it (set not ongoing) otherwise do nothing + bool getNextFault(FAULT*); //get the next un-ack'd fault. Will also get first fault if the first call and you forgot to call getFirstFault + bool getFault(uint16_t fault, FAULT*); + uint16_t getFaultCount(); + void handleTick(); + void setup(); + + uint16_t setFaultACK(uint16_t fault); //acknowledge the fault # - returns fault # if successful (0xFFFF otherwise) + uint16_t setFaultOngoing(uint16_t fault, bool ongoing); //set value of ongoing flag - returns fault # on success + +private: + void loadFromEEPROM(); + void saveToEEPROM(); + void writeFaultToEEPROM(int faultnum); + + uint16_t faultWritePointer; //fault # we're up to for writing. Location in EEPROM is start + (fault_ptr * sizeof(FAULT)) + uint16_t faultReadPointer; //fault # we're at when reading. + FAULT faultList[CFG_FAULT_HISTORY_SIZE]; //store up to 50 faults for a long history. 50*9 = 450 bytes of EEPROM + uint32_t globalTime; //how long the unit has been running in total (across all start ups). + uint32_t baseTime; //the time loaded at system start up. millis() / 100 is added to this to get the above time }; extern FaultHandler faultHandler; diff --git a/Heartbeat.cpp b/Heartbeat.cpp index 1d55cf0..68b3f74 100644 --- a/Heartbeat.cpp +++ b/Heartbeat.cpp @@ -27,66 +27,66 @@ #include "Heartbeat.h" Heartbeat::Heartbeat() { - led = false; - throttleDebug = false; + led = false; + throttleDebug = false; } void Heartbeat::setup() { - TickHandler::getInstance()->detach(this); + TickHandler::getInstance()->detach(this); - TickHandler::getInstance()->attach(this, CFG_TICK_INTERVAL_HEARTBEAT); + TickHandler::getInstance()->attach(this, CFG_TICK_INTERVAL_HEARTBEAT); } void Heartbeat::setThrottleDebug(bool debug) { - throttleDebug = debug; + throttleDebug = debug; } bool Heartbeat::getThrottleDebug() { - return throttleDebug; + return throttleDebug; } void Heartbeat::handleTick() { - // Print a dot if no other output has been made since the last tick - if (Logger::getLastLogTime() < lastTickTime) { - SerialUSB.print('.'); - if ((++dotCount % 80) == 0) { - SerialUSB.println(); - } - } - lastTickTime = millis(); - - if (led) { - digitalWrite(BLINK_LED, HIGH); - } else { - digitalWrite(BLINK_LED, LOW); - } - led = !led; - - if (throttleDebug) { - MotorController *motorController = DeviceManager::getInstance()->getMotorController(); - Throttle *accelerator = DeviceManager::getInstance()->getAccelerator(); - Throttle *brake = DeviceManager::getInstance()->getBrake(); - - Logger::console(""); - if (motorController) { - Logger::console("Motor Controller Status: isRunning: %T isFaulted: %T", motorController->isRunning(), motorController->isFaulted()); - } - - Logger::console("AIN0: %d, AIN1: %d, AIN2: %d, AIN3: %d", getAnalog(0), getAnalog(1), getAnalog(2), getAnalog(3)); + // Print a dot if no other output has been made since the last tick + if (Logger::getLastLogTime() < lastTickTime) { + SerialUSB.print('.'); + if ((++dotCount % 80) == 0) { + SerialUSB.println(); + } + } + lastTickTime = millis(); + + if (led) { + digitalWrite(BLINK_LED, HIGH); + } else { + digitalWrite(BLINK_LED, LOW); + } + led = !led; + + if (throttleDebug) { + MotorController *motorController = DeviceManager::getInstance()->getMotorController(); + Throttle *accelerator = DeviceManager::getInstance()->getAccelerator(); + Throttle *brake = DeviceManager::getInstance()->getBrake(); + + Logger::console(""); + if (motorController) { + Logger::console("Motor Controller Status: isRunning: %T isFaulted: %T", motorController->isRunning(), motorController->isFaulted()); + } + + Logger::console("AIN0: %d, AIN1: %d, AIN2: %d, AIN3: %d", getAnalog(0), getAnalog(1), getAnalog(2), getAnalog(3)); Logger::console("DIN0: %d, DIN1: %d, DIN2: %d, DIN3: %d", getDigital(0), getDigital(1), getDigital(2), getDigital(3)); Logger::console("DOUT0: %d, DOUT1: %d, DOUT2: %d, DOUT3: %d,DOUT4: %d, DOUT5: %d, DOUT6: %d, DOUT7: %d", getOutput(0), getOutput(1), getOutput(2), getOutput(3),getOutput(4), getOutput(5), getOutput(6), getOutput(7)); - if (accelerator) { - Logger::console("Throttle Status: isFaulted: %T level: %i", accelerator->isFaulted(), accelerator->getLevel()); - RawSignalData *rawSignal = accelerator->acquireRawSignal(); - Logger::console("Throttle rawSignal1: %d, rawSignal2: %d", rawSignal->input1, rawSignal->input2); - } - if (brake) { - Logger::console("Brake Output: %i", brake->getLevel()); - RawSignalData *rawSignal = brake->acquireRawSignal(); - Logger::console("Brake rawSignal1: %d", rawSignal->input1); - } - } + if (accelerator) { + Logger::console("Throttle Status: isFaulted: %T level: %i", accelerator->isFaulted(), accelerator->getLevel()); + RawSignalData *rawSignal = accelerator->acquireRawSignal(); + Logger::console("Throttle rawSignal1: %d, rawSignal2: %d", rawSignal->input1, rawSignal->input2); + } + if (brake) { + Logger::console("Brake Output: %i", brake->getLevel()); + RawSignalData *rawSignal = brake->acquireRawSignal(); + Logger::console("Brake rawSignal1: %d", rawSignal->input1); + } + } } diff --git a/Heartbeat.h b/Heartbeat.h index d2d21ad..d8cc026 100644 --- a/Heartbeat.h +++ b/Heartbeat.h @@ -34,19 +34,19 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. class Heartbeat: public TickObserver { public: - Heartbeat(); - void setup(); - void handleTick(); - void setThrottleDebug(bool debug); - bool getThrottleDebug(); + Heartbeat(); + void setup(); + void handleTick(); + void setThrottleDebug(bool debug); + bool getThrottleDebug(); protected: private: - bool led; - bool throttleDebug; - int dotCount; - uint32_t lastTickTime; + bool led; + bool throttleDebug; + int dotCount; + uint32_t lastTickTime; }; #endif /* HEARTBEAT_H_ */ diff --git a/Logger.cpp b/Logger.cpp index 7f2c509..5518e60 100644 --- a/Logger.cpp +++ b/Logger.cpp @@ -35,12 +35,12 @@ uint32_t Logger::lastLogTime = 0; * */ void Logger::debug(char *message, ...) { - if (logLevel > Debug) - return; - va_list args; - va_start(args, message); - Logger::log((DeviceId) NULL, Debug, message, args); - va_end(args); + if (logLevel > Debug) + return; + va_list args; + va_start(args, message); + Logger::log((DeviceId) NULL, Debug, message, args); + va_end(args); } /* @@ -48,12 +48,12 @@ void Logger::debug(char *message, ...) { * printf() style, see Logger::log() */ void Logger::debug(DeviceId deviceId, char *message, ...) { - if (logLevel > Debug) - return; - va_list args; - va_start(args, message); - Logger::log(deviceId, Debug, message, args); - va_end(args); + if (logLevel > Debug) + return; + va_list args; + va_start(args, message); + Logger::log(deviceId, Debug, message, args); + va_end(args); } /* @@ -61,12 +61,12 @@ void Logger::debug(DeviceId deviceId, char *message, ...) { * printf() style, see Logger::log() */ void Logger::info(char *message, ...) { - if (logLevel > Info) - return; - va_list args; - va_start(args, message); - Logger::log((DeviceId) NULL, Info, message, args); - va_end(args); + if (logLevel > Info) + return; + va_list args; + va_start(args, message); + Logger::log((DeviceId) NULL, Info, message, args); + va_end(args); } /* @@ -74,12 +74,12 @@ void Logger::info(char *message, ...) { * printf() style, see Logger::log() */ void Logger::info(DeviceId deviceId, char *message, ...) { - if (logLevel > Info) - return; - va_list args; - va_start(args, message); - Logger::log(deviceId, Info, message, args); - va_end(args); + if (logLevel > Info) + return; + va_list args; + va_start(args, message); + Logger::log(deviceId, Info, message, args); + va_end(args); } /* @@ -87,12 +87,12 @@ void Logger::info(DeviceId deviceId, char *message, ...) { * printf() style, see Logger::log() */ void Logger::warn(char *message, ...) { - if (logLevel > Warn) - return; - va_list args; - va_start(args, message); - Logger::log((DeviceId) NULL, Warn, message, args); - va_end(args); + if (logLevel > Warn) + return; + va_list args; + va_start(args, message); + Logger::log((DeviceId) NULL, Warn, message, args); + va_end(args); } /* @@ -100,12 +100,12 @@ void Logger::warn(char *message, ...) { * printf() style, see Logger::log() */ void Logger::warn(DeviceId deviceId, char *message, ...) { - if (logLevel > Warn) - return; - va_list args; - va_start(args, message); - Logger::log(deviceId, Warn, message, args); - va_end(args); + if (logLevel > Warn) + return; + va_list args; + va_start(args, message); + Logger::log(deviceId, Warn, message, args); + va_end(args); } /* @@ -113,12 +113,12 @@ void Logger::warn(DeviceId deviceId, char *message, ...) { * printf() style, see Logger::log() */ void Logger::error(char *message, ...) { - if (logLevel > Error) - return; - va_list args; - va_start(args, message); - Logger::log((DeviceId) NULL, Error, message, args); - va_end(args); + if (logLevel > Error) + return; + va_list args; + va_start(args, message); + Logger::log((DeviceId) NULL, Error, message, args); + va_end(args); } /* @@ -126,12 +126,12 @@ void Logger::error(char *message, ...) { * printf() style, see Logger::log() */ void Logger::error(DeviceId deviceId, char *message, ...) { - if (logLevel > Error) - return; - va_list args; - va_start(args, message); - Logger::log(deviceId, Error, message, args); - va_end(args); + if (logLevel > Error) + return; + va_list args; + va_start(args, message); + Logger::log(deviceId, Error, message, args); + va_end(args); } /* @@ -139,31 +139,31 @@ void Logger::error(DeviceId deviceId, char *message, ...) { * printf() style, see Logger::logMessage() */ void Logger::console(char *message, ...) { - va_list args; - va_start(args, message); - Logger::logMessage(message, args); - va_end(args); + va_list args; + va_start(args, message); + Logger::logMessage(message, args); + va_end(args); } /* * Set the log level. Any output below the specified log level will be omitted. */ void Logger::setLoglevel(LogLevel level) { - logLevel = level; + logLevel = level; } /* * Retrieve the current log level. */ Logger::LogLevel Logger::getLogLevel() { - return logLevel; + return logLevel; } /* * Return a timestamp when the last log entry was made. */ uint32_t Logger::getLastLogTime() { - return lastLogTime; + return lastLogTime; } /* @@ -177,7 +177,7 @@ uint32_t Logger::getLastLogTime() { * } */ boolean Logger::isDebug() { - return logLevel == Debug; + return logLevel == Debug; } /* @@ -199,30 +199,30 @@ boolean Logger::isDebug() { * %T - prints the next parameter as boolean ('true' or 'false') */ void Logger::log(DeviceId deviceId, LogLevel level, char *format, va_list args) { - lastLogTime = millis(); - SerialUSB.print(lastLogTime); - SerialUSB.print(" - "); + lastLogTime = millis(); + SerialUSB.print(lastLogTime); + SerialUSB.print(" - "); - switch (level) { - case Debug: - SerialUSB.print("DEBUG"); - break; - case Info: - SerialUSB.print("INFO"); - break; - case Warn: - SerialUSB.print("WARNING"); - break; - case Error: - SerialUSB.print("ERROR"); - break; - } - SerialUSB.print(": "); + switch (level) { + case Debug: + SerialUSB.print("DEBUG"); + break; + case Info: + SerialUSB.print("INFO"); + break; + case Warn: + SerialUSB.print("WARNING"); + break; + case Error: + SerialUSB.print("ERROR"); + break; + } + SerialUSB.print(": "); - if (deviceId) - printDeviceName(deviceId); + if (deviceId) + printDeviceName(deviceId); - logMessage(format, args); + logMessage(format, args); } /* @@ -244,76 +244,76 @@ void Logger::log(DeviceId deviceId, LogLevel level, char *format, va_list args) * %T - prints the next parameter as boolean ('true' or 'false') */ void Logger::logMessage(char *format, va_list args) { - for (; *format != 0; ++format) { - if (*format == '%') { - ++format; - if (*format == '\0') - break; - if (*format == '%') { - SerialUSB.print(*format); - continue; - } - if (*format == 's') { - register char *s = (char *) va_arg( args, int ); - SerialUSB.print(s); - continue; - } - if (*format == 'd' || *format == 'i') { - SerialUSB.print(va_arg( args, int ), DEC); - continue; - } - if (*format == 'f') { - SerialUSB.print(va_arg( args, double ), 2); - continue; - } - if (*format == 'x') { - SerialUSB.print(va_arg( args, int ), HEX); - continue; - } - if (*format == 'X') { - SerialUSB.print("0x"); - SerialUSB.print(va_arg( args, int ), HEX); - continue; - } - if (*format == 'b') { - SerialUSB.print(va_arg( args, int ), BIN); - continue; - } - if (*format == 'B') { - SerialUSB.print("0b"); - SerialUSB.print(va_arg( args, int ), BIN); - continue; - } - if (*format == 'l') { - SerialUSB.print(va_arg( args, long ), DEC); - continue; - } + for (; *format != 0; ++format) { + if (*format == '%') { + ++format; + if (*format == '\0') + break; + if (*format == '%') { + SerialUSB.print(*format); + continue; + } + if (*format == 's') { + register char *s = (char *) va_arg( args, int ); + SerialUSB.print(s); + continue; + } + if (*format == 'd' || *format == 'i') { + SerialUSB.print(va_arg( args, int ), DEC); + continue; + } + if (*format == 'f') { + SerialUSB.print(va_arg( args, double ), 2); + continue; + } + if (*format == 'x') { + SerialUSB.print(va_arg( args, int ), HEX); + continue; + } + if (*format == 'X') { + SerialUSB.print("0x"); + SerialUSB.print(va_arg( args, int ), HEX); + continue; + } + if (*format == 'b') { + SerialUSB.print(va_arg( args, int ), BIN); + continue; + } + if (*format == 'B') { + SerialUSB.print("0b"); + SerialUSB.print(va_arg( args, int ), BIN); + continue; + } + if (*format == 'l') { + SerialUSB.print(va_arg( args, long ), DEC); + continue; + } - if (*format == 'c') { - SerialUSB.print(va_arg( args, int )); - continue; - } - if (*format == 't') { - if (va_arg( args, int ) == 1) { - SerialUSB.print("T"); - } else { - SerialUSB.print("F"); - } - continue; - } - if (*format == 'T') { - if (va_arg( args, int ) == 1) { - SerialUSB.print(Constants::trueStr); - } else { - SerialUSB.print(Constants::falseStr); - } - continue; - } + if (*format == 'c') { + SerialUSB.print(va_arg( args, int )); + continue; + } + if (*format == 't') { + if (va_arg( args, int ) == 1) { + SerialUSB.print("T"); + } else { + SerialUSB.print("F"); + } + continue; + } + if (*format == 'T') { + if (va_arg( args, int ) == 1) { + SerialUSB.print(Constants::trueStr); + } else { + SerialUSB.print(Constants::falseStr); + } + continue; + } - } - SerialUSB.print(*format); - } - SerialUSB.println(); + } + SerialUSB.print(*format); + } + SerialUSB.println(); } /* @@ -323,51 +323,51 @@ void Logger::logMessage(char *format, va_list args) { * NOTE: Should be kept in synch with the defined devices. */ void Logger::printDeviceName(DeviceId deviceId) { - switch (deviceId) { - case DMOC645: - SerialUSB.print("DMOC645"); - break; - case BRUSA_DMC5: - SerialUSB.print("DMC5"); - break; - case BRUSACHARGE: - SerialUSB.print("NLG5"); - break; - case TCCHCHARGE: - SerialUSB.print("TCCH"); - break; - case THROTTLE: - SerialUSB.print("THROTTLE"); - break; - case POTACCELPEDAL: - SerialUSB.print("POTACCEL"); - break; - case POTBRAKEPEDAL: - SerialUSB.print("POTBRAKE"); - break; - case CANACCELPEDAL: - SerialUSB.print("CANACCEL"); - break; - case CANBRAKEPEDAL: - SerialUSB.print("CANBRAKE"); - break; - case ICHIP2128: - SerialUSB.print("ICHIP"); - break; - case THINKBMS: - SerialUSB.print("THINKBMS"); - break; - case SYSTEM: - SerialUSB.print("SYSTEM"); - break; - case HEARTBEAT: - SerialUSB.print("HEARTBEAT"); - break; - case MEMCACHE: - SerialUSB.print("MEMCACHE"); - break; - } - SerialUSB.print(" - "); + switch (deviceId) { + case DMOC645: + SerialUSB.print("DMOC645"); + break; + case BRUSA_DMC5: + SerialUSB.print("DMC5"); + break; + case BRUSACHARGE: + SerialUSB.print("NLG5"); + break; + case TCCHCHARGE: + SerialUSB.print("TCCH"); + break; + case THROTTLE: + SerialUSB.print("THROTTLE"); + break; + case POTACCELPEDAL: + SerialUSB.print("POTACCEL"); + break; + case POTBRAKEPEDAL: + SerialUSB.print("POTBRAKE"); + break; + case CANACCELPEDAL: + SerialUSB.print("CANACCEL"); + break; + case CANBRAKEPEDAL: + SerialUSB.print("CANBRAKE"); + break; + case ICHIP2128: + SerialUSB.print("ICHIP"); + break; + case THINKBMS: + SerialUSB.print("THINKBMS"); + break; + case SYSTEM: + SerialUSB.print("SYSTEM"); + break; + case HEARTBEAT: + SerialUSB.print("HEARTBEAT"); + break; + case MEMCACHE: + SerialUSB.print("MEMCACHE"); + break; + } + SerialUSB.print(" - "); } diff --git a/Logger.h b/Logger.h index 4ae6686..f569425 100644 --- a/Logger.h +++ b/Logger.h @@ -34,29 +34,29 @@ class Logger { public: - enum LogLevel { - Debug = 0, Info = 1, Warn = 2, Error = 3, Off = 4 - }; - static void debug(char *, ...); - static void debug(DeviceId, char *, ...); - static void info(char *, ...); - static void info(DeviceId, char *, ...); - static void warn(char *, ...); - static void warn(DeviceId, char *, ...); - static void error(char *, ...); - static void error(DeviceId, char *, ...); - static void console(char *, ...); - static void setLoglevel(LogLevel); - static LogLevel getLogLevel(); - static uint32_t getLastLogTime(); - static boolean isDebug(); + enum LogLevel { + Debug = 0, Info = 1, Warn = 2, Error = 3, Off = 4 + }; + static void debug(char *, ...); + static void debug(DeviceId, char *, ...); + static void info(char *, ...); + static void info(DeviceId, char *, ...); + static void warn(char *, ...); + static void warn(DeviceId, char *, ...); + static void error(char *, ...); + static void error(DeviceId, char *, ...); + static void console(char *, ...); + static void setLoglevel(LogLevel); + static LogLevel getLogLevel(); + static uint32_t getLastLogTime(); + static boolean isDebug(); private: - static LogLevel logLevel; - static uint32_t lastLogTime; + static LogLevel logLevel; + static uint32_t lastLogTime; - static void log(DeviceId, LogLevel, char *format, va_list); - static void logMessage(char *format, va_list args); - static void printDeviceName(DeviceId); + static void log(DeviceId, LogLevel, char *format, va_list); + static void logMessage(char *format, va_list args); + static void printDeviceName(DeviceId); }; #endif /* LOGGER_H_ */ diff --git a/MemCache.cpp b/MemCache.cpp index edb2e1d..681d49c 100644 --- a/MemCache.cpp +++ b/MemCache.cpp @@ -31,376 +31,376 @@ MemCache::MemCache() } void MemCache::setup() { - TickHandler::getInstance()->detach(this); - for (U8 c = 0; c < NUM_CACHED_PAGES; c++) { - pages[c].address = 0xFFFFFF; //maximum number. This is way over what our chip will actually support so it signals unused - pages[c].age = 0; - pages[c].dirty = false; - } - //WriteTimer = 0; - - //digital pin 19 is connected to the write protect function of the EEPROM. It is active high so set it low to enable writes - pinMode(19, OUTPUT); - digitalWrite(19, LOW); - TickHandler::getInstance()->attach(this, CFG_TICK_INTERVAL_MEM_CACHE); + TickHandler::getInstance()->detach(this); + for (U8 c = 0; c < NUM_CACHED_PAGES; c++) { + pages[c].address = 0xFFFFFF; //maximum number. This is way over what our chip will actually support so it signals unused + pages[c].age = 0; + pages[c].dirty = false; + } + //WriteTimer = 0; + + //digital pin 19 is connected to the write protect function of the EEPROM. It is active high so set it low to enable writes + pinMode(19, OUTPUT); + digitalWrite(19, LOW); + TickHandler::getInstance()->attach(this, CFG_TICK_INTERVAL_MEM_CACHE); } //Handle aging of dirty pages and flushing of aged out dirty pages void MemCache::handleTick() { - U8 c; - cache_age(); - for (c=0;c> 8; //kick it down to the page we're talking about - c = cache_hit(addr); - if (c != 0xFF) FlushPage(c); + addr = address >> 8; //kick it down to the page we're talking about + c = cache_hit(addr); + if (c != 0xFF) FlushPage(c); } //Like FlushPage but also marks the page invalid (unused) so if another read request comes it it'll have to be re-read from EEPROM void MemCache::InvalidatePage(uint8_t page) { - if (page > NUM_CACHED_PAGES - 1) return; //invalid page, buddy! - if (pages[page].dirty) { - cache_writepage(page); - } - pages[page].dirty = false; - pages[page].address = 0xFFFFFF; - pages[page].age = 0; + if (page > NUM_CACHED_PAGES - 1) return; //invalid page, buddy! + if (pages[page].dirty) { + cache_writepage(page); + } + pages[page].dirty = false; + pages[page].address = 0xFFFFFF; + pages[page].age = 0; } //Mark a given page unused given an address within that page. Will write the page out if it was dirty. void MemCache::InvalidateAddress(uint32_t address) { - uint32_t addr; - uint8_t c; + uint32_t addr; + uint8_t c; - addr = address >> 8; //kick it down to the page we're talking about - c = cache_hit(addr); - if (c != 0xFF) InvalidatePage(c); + addr = address >> 8; //kick it down to the page we're talking about + c = cache_hit(addr); + if (c != 0xFF) InvalidatePage(c); } //Mark all page cache entries unused (go back to clean slate). It will try to write any dirty pages so be prepared to wait. void MemCache::InvalidateAll() { - uint8_t c; - for (c=0;c> 8; //kick it down to the page we're talking about - thisCache = cache_hit(page_addr); + page_addr = address >> 8; //kick it down to the page we're talking about + thisCache = cache_hit(page_addr); - if (thisCache != 0xFF) { //if we did indeed have that page in cache - pages[thisCache].age = MAX_AGE; - } + if (thisCache != 0xFF) { //if we did indeed have that page in cache + pages[thisCache].age = MAX_AGE; + } } //Write data into the memory cache. Takes the place of direct EEPROM writes //There are lots of versions of this boolean MemCache::Write(uint32_t address, uint8_t valu) { - uint32_t addr; - uint8_t c; - - addr = address >> 8; //kick it down to the page we're talking about - c = cache_hit(addr); - if (c == 0xFF) { - c = cache_findpage(); //try to free up a page - if (c != 0xFF) c = cache_readpage(addr); //and populate it with the existing data - } - if (c != 0xFF) { - pages[c].data[(uint16_t)(address & 0x00FF)] = valu; - pages[c].dirty = true; - pages[c].address = addr; //set this in case we actually are setting up a new cache page - return true; - } - return false; + uint32_t addr; + uint8_t c; + + addr = address >> 8; //kick it down to the page we're talking about + c = cache_hit(addr); + if (c == 0xFF) { + c = cache_findpage(); //try to free up a page + if (c != 0xFF) c = cache_readpage(addr); //and populate it with the existing data + } + if (c != 0xFF) { + pages[c].data[(uint16_t)(address & 0x00FF)] = valu; + pages[c].dirty = true; + pages[c].address = addr; //set this in case we actually are setting up a new cache page + return true; + } + return false; } boolean MemCache::Write(uint32_t address, uint16_t valu) { - boolean result; - result = Write(address, &valu, 2); - return result; + boolean result; + result = Write(address, &valu, 2); + return result; } boolean MemCache::Write(uint32_t address, uint32_t valu) { - boolean result; - result = Write(address, &valu, 4); - return result; + boolean result; + result = Write(address, &valu, 4); + return result; } boolean MemCache::Write(uint32_t address, void* data, uint16_t len) { - uint32_t addr; - uint8_t c; - uint16_t count; - - for (count = 0; count < len; count++) { - addr = (address+count) >> 8; //kick it down to the page we're talking about - c = cache_hit(addr); - if (c == 0xFF) { - c = cache_findpage(); //try to find a page that either isn't loaded or isn't dirty - if (c != 0xFF) c = cache_readpage(addr); //and populate it with the existing data - } - if (c != 0xFF) { //could we find a suitable cache page to write to? - pages[c].data[(uint16_t)((address+count) & 0x00FF)] = *(uint8_t *)(data + count); - pages[c].dirty = true; - pages[c].address = addr; //set this in case we actually are setting up a new cache page + uint32_t addr; + uint8_t c; + uint16_t count; + + for (count = 0; count < len; count++) { + addr = (address+count) >> 8; //kick it down to the page we're talking about + c = cache_hit(addr); + if (c == 0xFF) { + c = cache_findpage(); //try to find a page that either isn't loaded or isn't dirty + if (c != 0xFF) c = cache_readpage(addr); //and populate it with the existing data + } + if (c != 0xFF) { //could we find a suitable cache page to write to? + pages[c].data[(uint16_t)((address+count) & 0x00FF)] = *(uint8_t *)(data + count); + pages[c].dirty = true; + pages[c].address = addr; //set this in case we actually are setting up a new cache page + } + else break; } - else break; - } - if (c != 0xFF) return true; //all ok! - return false; + if (c != 0xFF) return true; //all ok! + return false; } boolean MemCache::Read(uint32_t address, uint8_t* valu) { - uint32_t addr; - uint8_t c; - - addr = address >> 8; //kick it down to the page we're talking about - c = cache_hit(addr); - - if (c == 0xFF) { //page isn't cached. Search the cache, potentially dump a page and bring this one in - c = cache_readpage(addr); - } - - if (c != 0xFF) { - *valu = pages[c].data[(uint16_t)(address & 0x00FF)]; - if (!pages[c].dirty) pages[c].age = 0; //reset age since we just used it - return true; //all ok! - } - else { - return false; - } + uint32_t addr; + uint8_t c; + + addr = address >> 8; //kick it down to the page we're talking about + c = cache_hit(addr); + + if (c == 0xFF) { //page isn't cached. Search the cache, potentially dump a page and bring this one in + c = cache_readpage(addr); + } + + if (c != 0xFF) { + *valu = pages[c].data[(uint16_t)(address & 0x00FF)]; + if (!pages[c].dirty) pages[c].age = 0; //reset age since we just used it + return true; //all ok! + } + else { + return false; + } } boolean MemCache::Read(uint32_t address, uint16_t* valu) { - boolean result; - result = Read(address, valu, 2); - return result; + boolean result; + result = Read(address, valu, 2); + return result; } boolean MemCache::Read(uint32_t address, uint32_t* valu) { - boolean result; - result = Read(address, valu, 4); - return result; + boolean result; + result = Read(address, valu, 4); + return result; } boolean MemCache::Read(uint32_t address, void* data, uint16_t len) { - uint32_t addr; - uint8_t c; - uint16_t count; - - for (count = 0; count < len; count++) { - addr = (address + count) >> 8; - c = cache_hit(addr); - if (c == 0xFF) { //page isn't cached. Search the cache, potentially dump a page and bring this one in - c = cache_readpage(addr); - } - if (c != 0xFF) { - *(uint8_t *)(data + count) = pages[c].data[(uint16_t)((address+count) & 0x00FF)]; - if (!pages[c].dirty) pages[c].age = 0; //reset age since we just used it + uint32_t addr; + uint8_t c; + uint16_t count; + + for (count = 0; count < len; count++) { + addr = (address + count) >> 8; + c = cache_hit(addr); + if (c == 0xFF) { //page isn't cached. Search the cache, potentially dump a page and bring this one in + c = cache_readpage(addr); + } + if (c != 0xFF) { + *(uint8_t *)(data + count) = pages[c].data[(uint16_t)((address+count) & 0x00FF)]; + if (!pages[c].dirty) pages[c].age = 0; //reset age since we just used it + } + else break; //bust the for loop if we run into trouble } - else break; //bust the for loop if we run into trouble - } - if (c != 0xFF) return true; //all ok! - return false; + if (c != 0xFF) return true; //all ok! + return false; } boolean MemCache::isWriting() { - //if (WriteTimer) return true; - return false; + //if (WriteTimer) return true; + return false; } uint8_t MemCache::cache_hit(uint32_t address) { - uint8_t c; - for (c = 0; c < NUM_CACHED_PAGES; c++) { - if (pages[c].address == address) { - return c; - } - } - return 0xFF; + uint8_t c; + for (c = 0; c < NUM_CACHED_PAGES; c++) { + if (pages[c].address == address) { + return c; + } + } + return 0xFF; } void MemCache::cache_age() { - uint8_t c; - for (c = 0; c < NUM_CACHED_PAGES; c++) { - if (pages[c].age < MAX_AGE) { - pages[c].age++; + uint8_t c; + for (c = 0; c < NUM_CACHED_PAGES; c++) { + if (pages[c].age < MAX_AGE) { + pages[c].age++; + } } - } } //try to find an empty page or one that can be removed from cache uint8_t MemCache::cache_findpage() { - uint8_t c; - uint8_t old_c, old_v; - for (c=0;c= old_v) { - old_c = c; - old_v = pages[c].age; - } - } - if (old_c == 0xFF) { //no pages were not dirty - try to free one up - FlushSinglePage(); //try to free up a page - //now try to find the free page (if one was freed) + //if we got here then there are no free pages so scan to find the oldest one which isn't dirty + old_c = 0xFF; old_v = 0; - for (c=0;c= old_v) { - old_c = c; - old_v = pages[c].age; - } + for (c=0; c= old_v) { + old_c = c; + old_v = pages[c].age; + } + } + if (old_c == 0xFF) { //no pages were not dirty - try to free one up + FlushSinglePage(); //try to free up a page + //now try to find the free page (if one was freed) + old_v = 0; + for (c=0; c= old_v) { + old_c = c; + old_v = pages[c].age; + } + } + if (old_c == 0xFF) return 0xFF; //if nothing worked then give up } - if (old_c == 0xFF) return 0xFF; //if nothing worked then give up - } - //If we got to this point then we have a page to use - pages[old_c].age = 0; - pages[old_c].dirty = false; - pages[old_c].address = 0xFFFFFF; //mark it unused + //If we got to this point then we have a page to use + pages[old_c].age = 0; + pages[old_c].dirty = false; + pages[old_c].address = 0xFFFFFF; //mark it unused - return old_c; + return old_c; } uint8_t MemCache::cache_readpage(uint32_t addr) { - uint16_t c,d,e; - uint32_t address = addr << 8; - uint8_t buffer[3]; - uint8_t i2c_id; - c = cache_findpage(); + uint16_t c,d,e; + uint32_t address = addr << 8; + uint8_t buffer[3]; + uint8_t i2c_id; + c = cache_findpage(); // Logger::debug("r"); - if (c != 0xFF) { - buffer[0] = ((address & 0xFF00) >> 8); - //buffer[1] = (address & 0x00FF); - buffer[1] = 0; //the pages are 256 bytes so the start of a page is always 00 for the LSB - i2c_id = 0b01010000 + ((address >> 16) & 0x03); //10100 is the chip ID then the two upper bits of the address - Wire.beginTransmission(i2c_id); - Wire.write(buffer, 2); - Wire.endTransmission(false); //do NOT generate stop - //delayMicroseconds(50); //give TWI some time to send and chip some time to get page - Wire.requestFrom(i2c_id, 256); //this will generate stop though. - for (e = 0; e < 256; e++) - { - if(Wire.available()) - { - d = Wire.read(); // receive a byte as character - pages[c].data[e] = d; - } - } - pages[c].address = addr; - pages[c].age = 0; - pages[c].dirty = false; - } - return c; + if (c != 0xFF) { + buffer[0] = ((address & 0xFF00) >> 8); + //buffer[1] = (address & 0x00FF); + buffer[1] = 0; //the pages are 256 bytes so the start of a page is always 00 for the LSB + i2c_id = 0b01010000 + ((address >> 16) & 0x03); //10100 is the chip ID then the two upper bits of the address + Wire.beginTransmission(i2c_id); + Wire.write(buffer, 2); + Wire.endTransmission(false); //do NOT generate stop + //delayMicroseconds(50); //give TWI some time to send and chip some time to get page + Wire.requestFrom(i2c_id, 256); //this will generate stop though. + for (e = 0; e < 256; e++) + { + if(Wire.available()) + { + d = Wire.read(); // receive a byte as character + pages[c].data[e] = d; + } + } + pages[c].address = addr; + pages[c].age = 0; + pages[c].dirty = false; + } + return c; } boolean MemCache::cache_writepage(uint8_t page) { - uint16_t d; - uint32_t addr; - uint8_t buffer[258]; - uint8_t i2c_id; - addr = pages[page].address << 8; - buffer[0] = ((addr & 0xFF00) >> 8); - //buffer[1] = (addr & 0x00FF); - buffer[1] = 0; //pages are 256 bytes so LSB is always 0 for the start of a page - i2c_id = 0b01010000 + ((addr >> 16) & 0x03); //10100 is the chip ID then the two upper bits of the address - for (d = 0; d < 256; d++) { - buffer[d + 2] = pages[page].data[d]; - } - Wire.beginTransmission(i2c_id); - Wire.write(buffer, 258); - Wire.endTransmission(true); - return true; + uint16_t d; + uint32_t addr; + uint8_t buffer[258]; + uint8_t i2c_id; + addr = pages[page].address << 8; + buffer[0] = ((addr & 0xFF00) >> 8); + //buffer[1] = (addr & 0x00FF); + buffer[1] = 0; //pages are 256 bytes so LSB is always 0 for the start of a page + i2c_id = 0b01010000 + ((addr >> 16) & 0x03); //10100 is the chip ID then the two upper bits of the address + for (d = 0; d < 256; d++) { + buffer[d + 2] = pages[page].data[d]; + } + Wire.beginTransmission(i2c_id); + Wire.write(buffer, 258); + Wire.endTransmission(true); + return true; } diff --git a/MemCache.h b/MemCache.h index 545f9c7..a2259e4 100644 --- a/MemCache.h +++ b/MemCache.h @@ -24,7 +24,7 @@ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ + */ #ifndef MEM_CACHE_H_ #define MEM_CACHE_H_ @@ -46,7 +46,7 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // if dirty. For instance, 128 levels * 500 aging period * 10ms (100Hz tick) = 640 seconds // EEPROM handles about 1 million write cycles. So, a flush time of 100 seconds means that // continuous writing would last 100M seconds which is 3.17 years -// Another way to look at it is that 128 aging levels * 40ms tick is 5.12 seconds to flush for +// Another way to look at it is that 128 aging levels * 40ms tick is 5.12 seconds to flush for // each aging period below. Adjust acccordingly. */ #define AGING_PERIOD 60 @@ -54,48 +54,48 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. //Current parameters as of Sept 7 2014 = 128 * 40ms * 60 = 307.2 seconds to flush = about 10 years EEPROM life class MemCache: public TickObserver { - public: - void setup(); - void handleTick(); - void FlushSinglePage(); - void FlushAllPages(); - void FlushPage(uint8_t page); - void FlushAddress(uint32_t address); - void InvalidatePage(uint8_t page); - void InvalidateAddress(uint32_t address); - void InvalidateAll(); - void AgeFullyPage(uint8_t page); - void AgeFullyAddress(uint32_t address); - - boolean Write(uint32_t address, uint8_t valu); - boolean Write(uint32_t address, uint16_t valu); - boolean Write(uint32_t address, uint32_t valu); - boolean Write(uint32_t address, void* data, uint16_t len); - - //It's sort of weird to make the read function take a reference but it allows for overloading - boolean Read(uint32_t address, uint8_t* valu); - boolean Read(uint32_t address, uint16_t* valu); - boolean Read(uint32_t address, uint32_t* valu); - boolean Read(uint32_t address, void* data, uint16_t len); - - MemCache(); - - private: - typedef struct { - uint8_t data[256]; - uint32_t address; //address of start of page - uint8_t age; // - boolean dirty; - } PageCache; - - PageCache pages[NUM_CACHED_PAGES]; - boolean isWriting(); - uint8_t cache_hit(uint32_t address); - void cache_age(); - uint8_t cache_findpage(); - uint8_t cache_readpage(uint32_t addr); - boolean cache_writepage(uint8_t page); - uint8_t agingTimer; +public: + void setup(); + void handleTick(); + void FlushSinglePage(); + void FlushAllPages(); + void FlushPage(uint8_t page); + void FlushAddress(uint32_t address); + void InvalidatePage(uint8_t page); + void InvalidateAddress(uint32_t address); + void InvalidateAll(); + void AgeFullyPage(uint8_t page); + void AgeFullyAddress(uint32_t address); + + boolean Write(uint32_t address, uint8_t valu); + boolean Write(uint32_t address, uint16_t valu); + boolean Write(uint32_t address, uint32_t valu); + boolean Write(uint32_t address, void* data, uint16_t len); + + //It's sort of weird to make the read function take a reference but it allows for overloading + boolean Read(uint32_t address, uint8_t* valu); + boolean Read(uint32_t address, uint16_t* valu); + boolean Read(uint32_t address, uint32_t* valu); + boolean Read(uint32_t address, void* data, uint16_t len); + + MemCache(); + +private: + typedef struct { + uint8_t data[256]; + uint32_t address; //address of start of page + uint8_t age; // + boolean dirty; + } PageCache; + + PageCache pages[NUM_CACHED_PAGES]; + boolean isWriting(); + uint8_t cache_hit(uint32_t address); + void cache_age(); + uint8_t cache_findpage(); + uint8_t cache_readpage(uint32_t addr); + boolean cache_writepage(uint8_t page); + uint8_t agingTimer; }; #endif /* MEM_CACHE_H_ */ diff --git a/MotorController.cpp b/MotorController.cpp index 46d35d6..dfd635e 100644 --- a/MotorController.cpp +++ b/MotorController.cpp @@ -24,610 +24,618 @@ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - + */ + #include "MotorController.h" - + MotorController::MotorController() : Device() { - ready = false; - running = false; - faulted = false; - warning = false; + ready = false; + running = false; + faulted = false; + warning = false; - temperatureMotor = 0; - temperatureInverter = 0; - temperatureSystem = 0; + temperatureMotor = 0; + temperatureInverter = 0; + temperatureSystem = 0; - statusBitfield1 = 0; - statusBitfield2 = 0; - statusBitfield3 = 0; - statusBitfield4 = 0; + statusBitfield1 = 0; + statusBitfield2 = 0; + statusBitfield3 = 0; + statusBitfield4 = 0; - powerMode = modeTorque; - throttleRequested = 0; - speedRequested = 0; - speedActual = 0; - torqueRequested = 0; - torqueActual = 10; - torqueAvailable = 0; - mechanicalPower = 0; + powerMode = modeTorque; + throttleRequested = 0; + speedRequested = 0; + speedActual = 0; + torqueRequested = 0; + torqueActual = 10; + torqueAvailable = 0; + mechanicalPower = 0; - selectedGear = NEUTRAL; - operationState=ENABLE; + selectedGear = NEUTRAL; + operationState=ENABLE; - dcVoltage = 0; - dcCurrent = 0; - acCurrent = 0; - kiloWattHours = 0; - nominalVolts = 0; + dcVoltage = 0; + dcCurrent = 0; + acCurrent = 0; + kiloWattHours = 0; + nominalVolts = 0; - donePrecharge = false; - prelay = false; - coolflag = false; - skipcounter=0; - testenableinput=0; - testreverseinput=0; - premillis=0; + donePrecharge = false; + prelay = false; + coolflag = false; + skipcounter=0; + testenableinput=0; + testreverseinput=0; + premillis=0; } void MotorController::setup() { - - MotorControllerConfiguration *config = (MotorControllerConfiguration *)getConfiguration(); - statusBitfield1 = 0; - statusBitfield2 = 0; - statusBitfield3 = 0; - statusBitfield4 = 0; - prefsHandler->read(EEMC_KILOWATTHRS, &kiloWattHours); //retrieve kilowatt hours from EEPROM - nominalVolts=config->nominalVolt; - capacity=config->capacity; - donePrecharge=false; - premillis=millis(); + + MotorControllerConfiguration *config = (MotorControllerConfiguration *)getConfiguration(); + statusBitfield1 = 0; + statusBitfield2 = 0; + statusBitfield3 = 0; + statusBitfield4 = 0; + prefsHandler->read(EEMC_KILOWATTHRS, &kiloWattHours); //retrieve kilowatt hours from EEPROM + nominalVolts=config->nominalVolt; + capacity=config->capacity; + donePrecharge=false; + premillis=millis(); if(config->prechargeR==12345) - { - torqueActual=2; + { + torqueActual=2; dcCurrent=1501; dcVoltage=3320; - - } + + } Logger::console("PRELAY=%i - Current PreCharge Relay output", config->prechargeRelay); Logger::console("MRELAY=%i - Current Main Contactor Relay output", config->mainContactorRelay); Logger::console("PREDELAY=%i - Precharge delay time", config->prechargeR); - + //show our work Logger::console("PRECHARGING...DOUT0:%d, DOUT1:%d, DOUT2:%d, DOUT3:%d,DOUT4:%d, DOUT5:%d, DOUT6:%d, DOUT7:%d", getOutput(0), getOutput(1), getOutput(2), getOutput(3),getOutput(4), getOutput(5), getOutput(6), getOutput(7)); coolflag=false; - + Device::setup(); - + } void MotorController::handleTick() { - MotorControllerConfiguration *config = (MotorControllerConfiguration *)getConfiguration(); - + MotorControllerConfiguration *config = (MotorControllerConfiguration *)getConfiguration(); + //Set status annunciators - if(ready) statusBitfield1 |=1 << 15;else statusBitfield1 &= ~(1 <<15); - if(running) statusBitfield1 |=1 << 14;else statusBitfield1 &= ~(1 <<14); - if(warning) statusBitfield1 |=1 << 10;else statusBitfield1 &= ~(1 <<10); - if(faulted) statusBitfield1 |=1 << 9;else statusBitfield1 &= ~(1 <<9); - - //Calculate killowatts and kilowatt hours - mechanicalPower=dcVoltage*dcCurrent/10000; //In kilowatts. DC voltage is x10 - if (dcVoltage>nominalVolts && torqueActual>0) {kiloWattHours=1;} //If our voltage is higher than fully charged with no regen, zero our kwh meter - if (milliStamp>millis()) {milliStamp=0;} //In case millis rolls over to zero while running - kiloWattHours+=(millis()-milliStamp)*mechanicalPower;//We assume here that power is at current level since last tick and accrue in kilowattmilliseconds. - milliStamp=millis(); //reset our kwms timer for next check - - - //Throttle check - Throttle *accelerator = DeviceManager::getInstance()->getAccelerator(); - Throttle *brake = DeviceManager::getInstance()->getBrake(); - if (accelerator) - throttleRequested = accelerator->getLevel(); - if (brake && brake->getLevel() < -10 && brake->getLevel() < accelerator->getLevel()) //if the brake has been pressed it overrides the accelerator. - throttleRequested = brake->getLevel(); - //Logger::debug("Throttle: %d", throttleRequested); - - - if (!donePrecharge)checkPrecharge(); - - - if(skipcounter++ > 30) //A very low priority loop for checks that only need to be done once per second. - { - skipcounter=0; //Reset our laptimer - - - //Some test simulations if precharge time is set to 12345 - if(config->prechargeR==12345) - { - dcVoltage--; - if (torqueActual < -500) - { - torqueActual=20; - } - else - { - torqueActual=-650; - } - if (dcCurrent < 0) - { - dcCurrent=120; - } - else - { - dcCurrent=-65; - } - if (temperatureInverter < config->coolOn*10) - { - temperatureInverter=(config->coolOn+2)*10; - } - else - { - temperatureInverter=(config->coolOff-2)*10; - } - - if (throttleRequested < 500) - { - throttleRequested=500; - } - else - { - throttleRequested=0; - } - if(testenableinput) - { - testenableinput=false; - } - else - { - testenableinput=true; - } - - if(testreverseinput) - { - testreverseinput=false; - } - else - { - testreverseinput=true; - } - } - coolingcheck(); - checkBrakeLight(); - checkEnableInput(); - checkReverseInput(); - checkReverseLight(); - - //Store kilowatt hours, but only once in awhile. - prefsHandler->write(EEMC_KILOWATTHRS, kiloWattHours); - prefsHandler->saveChecksum(); - - } + if(ready) statusBitfield1 |=1 << 15; + else statusBitfield1 &= ~(1 <<15); + if(running) statusBitfield1 |=1 << 14; + else statusBitfield1 &= ~(1 <<14); + if(warning) statusBitfield1 |=1 << 10; + else statusBitfield1 &= ~(1 <<10); + if(faulted) statusBitfield1 |=1 << 9; + else statusBitfield1 &= ~(1 <<9); + + //Calculate killowatts and kilowatt hours + mechanicalPower=dcVoltage*dcCurrent/10000; //In kilowatts. DC voltage is x10 + if (dcVoltage>nominalVolts && torqueActual>0) { + kiloWattHours=1; //If our voltage is higher than fully charged with no regen, zero our kwh meter + } + if (milliStamp>millis()) { + milliStamp=0; //In case millis rolls over to zero while running + } + kiloWattHours+=(millis()-milliStamp)*mechanicalPower;//We assume here that power is at current level since last tick and accrue in kilowattmilliseconds. + milliStamp=millis(); //reset our kwms timer for next check + + + //Throttle check + Throttle *accelerator = DeviceManager::getInstance()->getAccelerator(); + Throttle *brake = DeviceManager::getInstance()->getBrake(); + if (accelerator) + throttleRequested = accelerator->getLevel(); + if (brake && brake->getLevel() < -10 && brake->getLevel() < accelerator->getLevel()) //if the brake has been pressed it overrides the accelerator. + throttleRequested = brake->getLevel(); + //Logger::debug("Throttle: %d", throttleRequested); + + + if (!donePrecharge)checkPrecharge(); + + + if(skipcounter++ > 30) //A very low priority loop for checks that only need to be done once per second. + { + skipcounter=0; //Reset our laptimer + + + //Some test simulations if precharge time is set to 12345 + if(config->prechargeR==12345) + { + dcVoltage--; + if (torqueActual < -500) + { + torqueActual=20; + } + else + { + torqueActual=-650; + } + if (dcCurrent < 0) + { + dcCurrent=120; + } + else + { + dcCurrent=-65; + } + if (temperatureInverter < config->coolOn*10) + { + temperatureInverter=(config->coolOn+2)*10; + } + else + { + temperatureInverter=(config->coolOff-2)*10; + } + + if (throttleRequested < 500) + { + throttleRequested=500; + } + else + { + throttleRequested=0; + } + if(testenableinput) + { + testenableinput=false; + } + else + { + testenableinput=true; + } + + if(testreverseinput) + { + testreverseinput=false; + } + else + { + testreverseinput=true; + } + } + coolingcheck(); + checkBrakeLight(); + checkEnableInput(); + checkReverseInput(); + checkReverseLight(); + + //Store kilowatt hours, but only once in awhile. + prefsHandler->write(EEMC_KILOWATTHRS, kiloWattHours); + prefsHandler->saveChecksum(); + + } } void MotorController::checkPrecharge() { - - int prechargetime=getprechargeR(); - int contactor=getmainContactorRelay(); - int relay=getprechargeRelay(); - - if (relay>7 || relay<0 || contactor<0 || contactor>7) //We don't have a contactor and a precharge relay - { - donePrecharge=true; //Let's end this charade. - return; - } - - if ((millis()-premillis)< prechargetime) //Check milliseconds since startup against our entered delay in milliseconds - { - if(!prelay) - { - setOutput(contactor, 0); //Make sure main contactor off - statusBitfield2 &= ~(1 << 17); //clear bitTurn off MAIN CONTACTOR annunciator - statusBitfield1 &= ~(1 << contactor);//clear bitTurn off main contactor output annunciator - setOutput(relay, 1); //ok. Turn on precharge relay - statusBitfield2 |=1 << 19; //set bit to turn on PRECHARGE RELAY annunciator - statusBitfield1 |=1 << relay; //set bit to turn ON precharge OUTPUT annunciator - throttleRequested = 0; //Keep throttle at zero during precharge - prelay=true; - Logger::info("Starting precharge sequence - wait %i milliseconds", prechargetime); - - } - } - else - { - setOutput(contactor, 1); //Main contactor on - statusBitfield2 |=1 << 17; //set bit to turn on MAIN CONTACTOR annunciator - statusBitfield1 |=1 << contactor;//setbit to Turn on main contactor output annunciator - Logger::info("Precharge sequence complete after %i milliseconds", prechargetime); - Logger::info("MAIN CONTACTOR ENABLED...DOUT0:%d, DOUT1:%d, DOUT2:%d, DOUT3:%d,DOUT4:%d, DOUT5:%d, DOUT6:%d, DOUT7:%d", getOutput(0), getOutput(1), getOutput(2), getOutput(3),getOutput(4), getOutput(5), getOutput(6), getOutput(7)); - donePrecharge=true; //Time's up. Let's don't do ANY of this on future ticks. - //Generally, we leave the precharge relay on. This doesn't hurt much in any configuration. But when using two contactors - //one positive with a precharge resistor and one on the negative leg to act as precharge, we need to leave precharge on. - - } + + int prechargetime=getprechargeR(); + int contactor=getmainContactorRelay(); + int relay=getprechargeRelay(); + + if (relay>7 || relay<0 || contactor<0 || contactor>7) //We don't have a contactor and a precharge relay + { + donePrecharge=true; //Let's end this charade. + return; + } + + if ((millis()-premillis)< prechargetime) //Check milliseconds since startup against our entered delay in milliseconds + { + if(!prelay) + { + setOutput(contactor, 0); //Make sure main contactor off + statusBitfield2 &= ~(1 << 17); //clear bitTurn off MAIN CONTACTOR annunciator + statusBitfield1 &= ~(1 << contactor);//clear bitTurn off main contactor output annunciator + setOutput(relay, 1); //ok. Turn on precharge relay + statusBitfield2 |=1 << 19; //set bit to turn on PRECHARGE RELAY annunciator + statusBitfield1 |=1 << relay; //set bit to turn ON precharge OUTPUT annunciator + throttleRequested = 0; //Keep throttle at zero during precharge + prelay=true; + Logger::info("Starting precharge sequence - wait %i milliseconds", prechargetime); + + } + } + else + { + setOutput(contactor, 1); //Main contactor on + statusBitfield2 |=1 << 17; //set bit to turn on MAIN CONTACTOR annunciator + statusBitfield1 |=1 << contactor;//setbit to Turn on main contactor output annunciator + Logger::info("Precharge sequence complete after %i milliseconds", prechargetime); + Logger::info("MAIN CONTACTOR ENABLED...DOUT0:%d, DOUT1:%d, DOUT2:%d, DOUT3:%d,DOUT4:%d, DOUT5:%d, DOUT6:%d, DOUT7:%d", getOutput(0), getOutput(1), getOutput(2), getOutput(3),getOutput(4), getOutput(5), getOutput(6), getOutput(7)); + donePrecharge=true; //Time's up. Let's don't do ANY of this on future ticks. + //Generally, we leave the precharge relay on. This doesn't hurt much in any configuration. But when using two contactors + //one positive with a precharge resistor and one on the negative leg to act as precharge, we need to leave precharge on. + + } } -//This routine is used to set an optional cooling fan output to on if the current temperature +//This routine is used to set an optional cooling fan output to on if the current temperature //exceeds a specified value. Annunciators are set on website to indicate status. void MotorController::coolingcheck() - { - int coolfan=getCoolFan(); - - if(coolfan>=0 and coolfan<8) //We have 8 outputs 0-7 If they entered something else, there is no point in doing this check. - { - if(temperatureInverter/10>getCoolOn()) //If inverter temperature greater than COOLON, we want to turn on the coolingoutput - { - if(!coolflag) - { - coolflag=1; - setOutput(coolfan, 1); //Turn on cooling fan output - statusBitfield1 |=1 << coolfan; //set bit to turn on cooling fan output annunciator - statusBitfield3 |=1 << 9; //Set bit to turn on OVERTEMP annunciator - } - } - - if(temperatureInverter/10=0 and coolfan<8) //We have 8 outputs 0-7 If they entered something else, there is no point in doing this check. + { + if(temperatureInverter/10>getCoolOn()) //If inverter temperature greater than COOLON, we want to turn on the coolingoutput + { + if(!coolflag) + { + coolflag=1; + setOutput(coolfan, 1); //Turn on cooling fan output + statusBitfield1 |=1 << coolfan; //set bit to turn on cooling fan output annunciator + statusBitfield3 |=1 << 9; //Set bit to turn on OVERTEMP annunciator + } + } + + if(temperatureInverter/10=0 && getBrakeLight()<8) //If we have one configured ie NOT 255 but a valid output - { - int brakelight=getBrakeLight(); //Get brakelight output once - - if(getTorqueActual() < -100) //We only want to turn on brake light if we are have regen of more than 10 newton meters - { - setOutput(brakelight, 1); //Turn on brake light output - statusBitfield1 |=1 << brakelight; //set bit to turn on brake light output annunciator - } - else - { - setOutput(brakelight, 0); //Turn off brake light output - statusBitfield1 &= ~(1 << brakelight);//clear bit to turn off brake light output annunciator - } - } + + if(getBrakeLight() >=0 && getBrakeLight()<8) //If we have one configured ie NOT 255 but a valid output + { + int brakelight=getBrakeLight(); //Get brakelight output once + + if(getTorqueActual() < -100) //We only want to turn on brake light if we are have regen of more than 10 newton meters + { + setOutput(brakelight, 1); //Turn on brake light output + statusBitfield1 |=1 << brakelight; //set bit to turn on brake light output annunciator + } + else + { + setOutput(brakelight, 0); //Turn off brake light output + statusBitfield1 &= ~(1 << brakelight);//clear bit to turn off brake light output annunciator + } + } } //If a reverse light output is configured, this will turn it on anytime the gear state is in REVERSE void MotorController::checkReverseLight() { - uint16_t reverseLight=getRevLight(); - if(reverseLight >=0 && reverseLight <8) //255 means none selected. We don't have a reverselight output configured. - { - if(selectedGear==REVERSE) //If the selected gear IS reverse - { - setOutput(reverseLight, true); //Turn on reverse light output - statusBitfield1 |=1 << reverseLight; //set bit to turn on reverse light output annunciator - } - else - { - setOutput(reverseLight, false); //Turn off reverse light output - statusBitfield1 &= ~(1 << reverseLight);//clear bit to turn off reverselight OUTPUT annunciator - } + uint16_t reverseLight=getRevLight(); + if(reverseLight >=0 && reverseLight <8) //255 means none selected. We don't have a reverselight output configured. + { + if(selectedGear==REVERSE) //If the selected gear IS reverse + { + setOutput(reverseLight, true); //Turn on reverse light output + statusBitfield1 |=1 << reverseLight; //set bit to turn on reverse light output annunciator + } + else + { + setOutput(reverseLight, false); //Turn off reverse light output + statusBitfield1 &= ~(1 << reverseLight);//clear bit to turn off reverselight OUTPUT annunciator + } } } //If we have an ENABLE input configured, this will set opstation to ENABLE anytime it is true (12v), DISABLED if not. void MotorController:: checkEnableInput() { - uint16_t enableinput=getEnableIn(); - if(enableinput >= 0 && enableinput<4) //Do we even have an enable input configured ie NOT 255. + uint16_t enableinput=getEnableIn(); + if(enableinput >= 0 && enableinput<4) //Do we even have an enable input configured ie NOT 255. { - if((getDigital(enableinput))||testenableinput) //If it's ON let's set our opstate to ENABLE + if((getDigital(enableinput))||testenableinput) //If it's ON let's set our opstate to ENABLE { - setOpState(ENABLE); - statusBitfield2 |=1 << enableinput; //set bit to turn on ENABLE annunciator - statusBitfield2 |=1 << 18;//set bit to turn on enable input annunciator - } - else + setOpState(ENABLE); + statusBitfield2 |=1 << enableinput; //set bit to turn on ENABLE annunciator + statusBitfield2 |=1 << 18;//set bit to turn on enable input annunciator + } + else { - setOpState(DISABLED);//If it's off, lets set DISABLED. These two could just as easily be reversed - statusBitfield2 &= ~(1 << 18); //clear bit to turn off ENABLE annunciator - statusBitfield2 &= ~(1 << enableinput);//clear bit to turn off enable input annunciator - } + setOpState(DISABLED);//If it's off, lets set DISABLED. These two could just as easily be reversed + statusBitfield2 &= ~(1 << 18); //clear bit to turn off ENABLE annunciator + statusBitfield2 &= ~(1 << enableinput);//clear bit to turn off enable input annunciator + } } } //IF we have a reverse input configured, this will set our selected gear to REVERSE any time the input is true, DRIVE if not void MotorController:: checkReverseInput() { - uint16_t reverseinput=getReverseIn(); - if(reverseinput >= 0 && reverseinput<4) //If we don't have a Reverse Input, do nothing + uint16_t reverseinput=getReverseIn(); + if(reverseinput >= 0 && reverseinput<4) //If we don't have a Reverse Input, do nothing { - if((getDigital(reverseinput))||testreverseinput) - { - setSelectedGear(REVERSE); - statusBitfield2 |=1 << 16; //set bit to turn on REVERSE annunciator - statusBitfield2 |=1 << reverseinput;//setbit to Turn on reverse input annunciator - } - else + if((getDigital(reverseinput))||testreverseinput) + { + setSelectedGear(REVERSE); + statusBitfield2 |=1 << 16; //set bit to turn on REVERSE annunciator + statusBitfield2 |=1 << reverseinput;//setbit to Turn on reverse input annunciator + } + else { - setSelectedGear(DRIVE); //If it's off, lets set to DRIVE. - statusBitfield2 &= ~(1 << 16); //clear bit to turn off REVERSE annunciator - statusBitfield2 &= ~(1 << reverseinput);//clear bit to turn off reverse input annunciator - } + setSelectedGear(DRIVE); //If it's off, lets set to DRIVE. + statusBitfield2 &= ~(1 << 16); //clear bit to turn off REVERSE annunciator + statusBitfield2 &= ~(1 << reverseinput);//clear bit to turn off reverse input annunciator + } } } bool MotorController::isRunning() { - return running; + return running; } bool MotorController::isFaulted() { - return faulted; + return faulted; } bool MotorController::isWarning() { - return warning; + return warning; } DeviceType MotorController::getType() { - return (DEVICE_MOTORCTRL); + return (DEVICE_MOTORCTRL); } void MotorController::setOpState(OperationState op) { - operationState = op; + operationState = op; } MotorController::OperationState MotorController::getOpState() { - return operationState; + return operationState; } MotorController::PowerMode MotorController::getPowerMode() { - return powerMode; + return powerMode; } void MotorController::setPowerMode(PowerMode mode) { - powerMode = mode; + powerMode = mode; } uint32_t MotorController::getStatusBitfield1() { - return statusBitfield1; + return statusBitfield1; } uint32_t MotorController::getStatusBitfield2() { - return statusBitfield2; + return statusBitfield2; } uint32_t MotorController::getStatusBitfield3() { - return statusBitfield3; + return statusBitfield3; } uint32_t MotorController::getStatusBitfield4() { - return statusBitfield4; + return statusBitfield4; } int8_t MotorController::getCoolFan() { - MotorControllerConfiguration *config = (MotorControllerConfiguration *)getConfiguration(); - return config->coolFan; + MotorControllerConfiguration *config = (MotorControllerConfiguration *)getConfiguration(); + return config->coolFan; } int8_t MotorController::getCoolOn() { - MotorControllerConfiguration *config = (MotorControllerConfiguration *)getConfiguration(); - return config->coolOn; + MotorControllerConfiguration *config = (MotorControllerConfiguration *)getConfiguration(); + return config->coolOn; } int8_t MotorController::getCoolOff() { MotorControllerConfiguration *config = (MotorControllerConfiguration *)getConfiguration(); - return config->coolOff; + return config->coolOff; } int8_t MotorController::getBrakeLight() { MotorControllerConfiguration *config = (MotorControllerConfiguration *)getConfiguration(); - return config->brakeLight; + return config->brakeLight; } int8_t MotorController::getRevLight() { MotorControllerConfiguration *config = (MotorControllerConfiguration *)getConfiguration(); - return config->revLight; + return config->revLight; } int8_t MotorController::getEnableIn() { MotorControllerConfiguration *config = (MotorControllerConfiguration *)getConfiguration(); - return config->enableIn; + return config->enableIn; } int8_t MotorController::getReverseIn() { MotorControllerConfiguration *config = (MotorControllerConfiguration *)getConfiguration(); - return config->reverseIn; + return config->reverseIn; } int16_t MotorController::getprechargeR() { MotorControllerConfiguration *config = (MotorControllerConfiguration *)getConfiguration(); - return config->prechargeR; + return config->prechargeR; } int8_t MotorController::getprechargeRelay() { MotorControllerConfiguration *config = (MotorControllerConfiguration *)getConfiguration(); - return config->prechargeRelay; + return config->prechargeRelay; } int8_t MotorController::getmainContactorRelay() { MotorControllerConfiguration *config = (MotorControllerConfiguration *)getConfiguration(); - return config->mainContactorRelay; + return config->mainContactorRelay; } int16_t MotorController::getThrottle() { - return throttleRequested; + return throttleRequested; } int16_t MotorController::getSpeedRequested() { - return speedRequested; + return speedRequested; } int16_t MotorController::getSpeedActual() { - return speedActual; + return speedActual; } int16_t MotorController::getTorqueRequested() { - return torqueRequested; + return torqueRequested; } int16_t MotorController::getTorqueActual() { - return torqueActual; + return torqueActual; } - MotorController::Gears MotorController::getSelectedGear() { - return selectedGear; +MotorController::Gears MotorController::getSelectedGear() { + return selectedGear; } void MotorController::setSelectedGear(Gears gear) { - selectedGear=gear; + selectedGear=gear; } int16_t MotorController::getTorqueAvailable() { - return torqueAvailable; + return torqueAvailable; } uint16_t MotorController::getDcVoltage() { - return dcVoltage; + return dcVoltage; } int16_t MotorController::getDcCurrent() { - return dcCurrent; + return dcCurrent; } uint16_t MotorController::getAcCurrent() { - return acCurrent; + return acCurrent; } int16_t MotorController::getnominalVolt() { - return nominalVolts; + return nominalVolts; } uint32_t MotorController::getKiloWattHours() { - return kiloWattHours; + return kiloWattHours; } int16_t MotorController::getMechanicalPower() { - return mechanicalPower; + return mechanicalPower; } int16_t MotorController::getTemperatureMotor() { - return temperatureMotor; + return temperatureMotor; } int16_t MotorController::getTemperatureInverter() { - return temperatureInverter; + return temperatureInverter; } int16_t MotorController::getTemperatureSystem() { - return temperatureSystem; + return temperatureSystem; } uint32_t MotorController::getTickInterval() { - return CFG_TICK_INTERVAL_MOTOR_CONTROLLER; + return CFG_TICK_INTERVAL_MOTOR_CONTROLLER; } bool MotorController::isReady() { - return false; + return false; } void MotorController::loadConfiguration() { - MotorControllerConfiguration *config = (MotorControllerConfiguration *)getConfiguration(); + MotorControllerConfiguration *config = (MotorControllerConfiguration *)getConfiguration(); - Device::loadConfiguration(); // call parent + Device::loadConfiguration(); // call parent #ifdef USE_HARD_CODED - if (false) { + if (false) { #else - if (prefsHandler->checksumValid()) { //checksum is good, read in the values stored in EEPROM + if (prefsHandler->checksumValid()) { //checksum is good, read in the values stored in EEPROM #endif - prefsHandler->read(EEMC_MAX_RPM, &config->speedMax); - prefsHandler->read(EEMC_MAX_TORQUE, &config->torqueMax); - prefsHandler->read(EEMC_RPM_SLEW_RATE, &config->speedSlewRate); - prefsHandler->read(EEMC_TORQUE_SLEW_RATE, &config->torqueSlewRate); - prefsHandler->read(EEMC_REVERSE_LIMIT, &config->reversePercent); - prefsHandler->read(EEMC_KILOWATTHRS, &config->kilowattHrs); - prefsHandler->read(EEMC_PRECHARGE_R, &config->prechargeR); - prefsHandler->read(EEMC_NOMINAL_V, &config->nominalVolt); - prefsHandler->read(EEMC_PRECHARGE_RELAY, &config->prechargeRelay); - prefsHandler->read(EEMC_CONTACTOR_RELAY, &config->mainContactorRelay); - prefsHandler->read(EEMC_COOL_FAN, &config->coolFan); - prefsHandler->read(EEMC_COOL_ON, &config->coolOn); - prefsHandler->read(EEMC_COOL_OFF, &config->coolOff); - prefsHandler->read(EEMC_BRAKE_LIGHT, &config->brakeLight); - prefsHandler->read(EEMC_REV_LIGHT, &config->revLight); - prefsHandler->read(EEMC_ENABLE_IN, &config->enableIn); - prefsHandler->read(EEMC_REVERSE_IN, &config->reverseIn); - prefsHandler->read(EESYS_CAPACITY, &config->capacity); - - - } - else { //checksum invalid. Reinitialize values and store to EEPROM - config->speedMax = MaxRPMValue; - config->torqueMax = MaxTorqueValue; - config->speedSlewRate = RPMSlewRateValue; - config->torqueSlewRate = TorqueSlewRateValue; - config->reversePercent = ReversePercent; - config->kilowattHrs = KilowattHrs; - config->prechargeR = PrechargeR; - config->nominalVolt = NominalVolt; - config->prechargeRelay = PrechargeRelay; - config->mainContactorRelay = MainContactorRelay; - config->coolFan = CoolFan; - config->coolOn = CoolOn; - config->coolOff = CoolOff; - config->brakeLight = BrakeLight; - config->revLight = RevLight; - config->enableIn = EnableIn; - config->reverseIn = ReverseIn; - - } - //DeviceManager::getInstance()->sendMessage(DEVICE_WIFI, ICHIP2128, MSG_CONFIG_CHANGE, NULL); - - Logger::info("MaxTorque: %i MaxRPM: %i", config->torqueMax, config->speedMax); + prefsHandler->read(EEMC_MAX_RPM, &config->speedMax); + prefsHandler->read(EEMC_MAX_TORQUE, &config->torqueMax); + prefsHandler->read(EEMC_RPM_SLEW_RATE, &config->speedSlewRate); + prefsHandler->read(EEMC_TORQUE_SLEW_RATE, &config->torqueSlewRate); + prefsHandler->read(EEMC_REVERSE_LIMIT, &config->reversePercent); + prefsHandler->read(EEMC_KILOWATTHRS, &config->kilowattHrs); + prefsHandler->read(EEMC_PRECHARGE_R, &config->prechargeR); + prefsHandler->read(EEMC_NOMINAL_V, &config->nominalVolt); + prefsHandler->read(EEMC_PRECHARGE_RELAY, &config->prechargeRelay); + prefsHandler->read(EEMC_CONTACTOR_RELAY, &config->mainContactorRelay); + prefsHandler->read(EEMC_COOL_FAN, &config->coolFan); + prefsHandler->read(EEMC_COOL_ON, &config->coolOn); + prefsHandler->read(EEMC_COOL_OFF, &config->coolOff); + prefsHandler->read(EEMC_BRAKE_LIGHT, &config->brakeLight); + prefsHandler->read(EEMC_REV_LIGHT, &config->revLight); + prefsHandler->read(EEMC_ENABLE_IN, &config->enableIn); + prefsHandler->read(EEMC_REVERSE_IN, &config->reverseIn); + prefsHandler->read(EESYS_CAPACITY, &config->capacity); + + + } + else { //checksum invalid. Reinitialize values and store to EEPROM + config->speedMax = MaxRPMValue; + config->torqueMax = MaxTorqueValue; + config->speedSlewRate = RPMSlewRateValue; + config->torqueSlewRate = TorqueSlewRateValue; + config->reversePercent = ReversePercent; + config->kilowattHrs = KilowattHrs; + config->prechargeR = PrechargeR; + config->nominalVolt = NominalVolt; + config->prechargeRelay = PrechargeRelay; + config->mainContactorRelay = MainContactorRelay; + config->coolFan = CoolFan; + config->coolOn = CoolOn; + config->coolOff = CoolOff; + config->brakeLight = BrakeLight; + config->revLight = RevLight; + config->enableIn = EnableIn; + config->reverseIn = ReverseIn; + + } + //DeviceManager::getInstance()->sendMessage(DEVICE_WIFI, ICHIP2128, MSG_CONFIG_CHANGE, NULL); + + Logger::info("MaxTorque: %i MaxRPM: %i", config->torqueMax, config->speedMax); } void MotorController::saveConfiguration() { - MotorControllerConfiguration *config = (MotorControllerConfiguration *)getConfiguration(); - - Device::saveConfiguration(); // call parent - - prefsHandler->write(EEMC_MAX_RPM, config->speedMax); - prefsHandler->write(EEMC_MAX_TORQUE, config->torqueMax); - prefsHandler->write(EEMC_RPM_SLEW_RATE, config->speedSlewRate); - prefsHandler->write(EEMC_TORQUE_SLEW_RATE, config->torqueSlewRate); - prefsHandler->write(EEMC_REVERSE_LIMIT, config->reversePercent); - prefsHandler->write(EEMC_KILOWATTHRS, config->kilowattHrs); - prefsHandler->write(EEMC_PRECHARGE_R, config->prechargeR); - prefsHandler->write(EEMC_NOMINAL_V, config->nominalVolt); - prefsHandler->write(EEMC_CONTACTOR_RELAY, config->mainContactorRelay); - prefsHandler->write(EEMC_PRECHARGE_RELAY, config->prechargeRelay); - prefsHandler->write(EEMC_COOL_FAN, config->coolFan); - prefsHandler->write(EEMC_COOL_ON, config->coolOn); - prefsHandler->write(EEMC_COOL_OFF, config->coolOff); - prefsHandler->write(EEMC_BRAKE_LIGHT, config->brakeLight); - prefsHandler->write(EEMC_REV_LIGHT, config->revLight); - prefsHandler->write(EEMC_ENABLE_IN, config->enableIn); - prefsHandler->write(EEMC_REVERSE_IN, config->reverseIn); - prefsHandler->write(EESYS_CAPACITY, config->capacity); - - - prefsHandler->saveChecksum(); - loadConfiguration(); + MotorControllerConfiguration *config = (MotorControllerConfiguration *)getConfiguration(); + + Device::saveConfiguration(); // call parent + + prefsHandler->write(EEMC_MAX_RPM, config->speedMax); + prefsHandler->write(EEMC_MAX_TORQUE, config->torqueMax); + prefsHandler->write(EEMC_RPM_SLEW_RATE, config->speedSlewRate); + prefsHandler->write(EEMC_TORQUE_SLEW_RATE, config->torqueSlewRate); + prefsHandler->write(EEMC_REVERSE_LIMIT, config->reversePercent); + prefsHandler->write(EEMC_KILOWATTHRS, config->kilowattHrs); + prefsHandler->write(EEMC_PRECHARGE_R, config->prechargeR); + prefsHandler->write(EEMC_NOMINAL_V, config->nominalVolt); + prefsHandler->write(EEMC_CONTACTOR_RELAY, config->mainContactorRelay); + prefsHandler->write(EEMC_PRECHARGE_RELAY, config->prechargeRelay); + prefsHandler->write(EEMC_COOL_FAN, config->coolFan); + prefsHandler->write(EEMC_COOL_ON, config->coolOn); + prefsHandler->write(EEMC_COOL_OFF, config->coolOff); + prefsHandler->write(EEMC_BRAKE_LIGHT, config->brakeLight); + prefsHandler->write(EEMC_REV_LIGHT, config->revLight); + prefsHandler->write(EEMC_ENABLE_IN, config->enableIn); + prefsHandler->write(EEMC_REVERSE_IN, config->reverseIn); + prefsHandler->write(EESYS_CAPACITY, config->capacity); + + + prefsHandler->saveChecksum(); + loadConfiguration(); } diff --git a/MotorController.h b/MotorController.h index 693ca61..e47d694 100644 --- a/MotorController.h +++ b/MotorController.h @@ -43,94 +43,94 @@ class MotorControllerConfiguration : public DeviceConfiguration { public: - uint16_t speedMax; // in rpm - uint16_t torqueMax; // maximum torque in 0.1 Nm - uint16_t torqueSlewRate; // for torque mode only: slew rate of torque value, 0=disabled, in 0.1Nm/sec - uint16_t speedSlewRate; // for speed mode only: slew rate of speed value, 0=disabled, in rpm/sec - uint8_t reversePercent; - uint16_t kilowattHrs; - uint16_t prechargeR; //resistance of precharge resistor in tenths of ohm - uint16_t nominalVolt; //nominal pack voltage in tenths of a volt - uint8_t prechargeRelay; //# of output to use for this relay or 255 if there is no relay - uint8_t mainContactorRelay; //# of output to use for this relay or 255 if there is no relay - uint8_t coolFan; - uint8_t coolOn; - uint8_t coolOff; - uint8_t brakeLight; - uint8_t revLight; - uint8_t enableIn; - uint8_t reverseIn; - uint8_t capacity; - + uint16_t speedMax; // in rpm + uint16_t torqueMax; // maximum torque in 0.1 Nm + uint16_t torqueSlewRate; // for torque mode only: slew rate of torque value, 0=disabled, in 0.1Nm/sec + uint16_t speedSlewRate; // for speed mode only: slew rate of speed value, 0=disabled, in rpm/sec + uint8_t reversePercent; + uint16_t kilowattHrs; + uint16_t prechargeR; //resistance of precharge resistor in tenths of ohm + uint16_t nominalVolt; //nominal pack voltage in tenths of a volt + uint8_t prechargeRelay; //# of output to use for this relay or 255 if there is no relay + uint8_t mainContactorRelay; //# of output to use for this relay or 255 if there is no relay + uint8_t coolFan; + uint8_t coolOn; + uint8_t coolOff; + uint8_t brakeLight; + uint8_t revLight; + uint8_t enableIn; + uint8_t reverseIn; + uint8_t capacity; + }; class MotorController: public Device { public: - enum Gears { - NEUTRAL = 0, - DRIVE = 1, - REVERSE = 2, - ERROR = 3, - }; - - enum PowerMode { - modeTorque, - modeSpeed - }; - - enum OperationState { - DISABLED = 0, - STANDBY = 1, - ENABLE = 2, - POWERDOWN = 3 - }; + enum Gears { + NEUTRAL = 0, + DRIVE = 1, + REVERSE = 2, + ERROR = 3, + }; + + enum PowerMode { + modeTorque, + modeSpeed + }; + + enum OperationState { + DISABLED = 0, + STANDBY = 1, + ENABLE = 2, + POWERDOWN = 3 + }; MotorController(); - DeviceType getType(); + DeviceType getType(); void setup(); void handleTick(); - uint32_t getTickInterval(); - - void loadConfiguration(); - void saveConfiguration(); - - void coolingcheck(); - void checkBrakeLight(); - void checkReverseLight(); - void checkEnableInput(); - void checkReverseInput(); - void checkPrecharge(); - - void brakecheck(); - bool isReady(); - bool isRunning(); - bool isFaulted(); - bool isWarning(); - -uint32_t getStatusBitfield1(); -uint32_t getStatusBitfield2(); -uint32_t getStatusBitfield3(); -uint32_t getStatusBitfield4(); - -uint32_t statusBitfield1; // bitfield variable for use of the specific implementation -uint32_t statusBitfield2; -uint32_t statusBitfield3; -uint32_t statusBitfield4; -uint32_t kiloWattHours; - - - - - void setPowerMode(PowerMode mode); - PowerMode getPowerMode(); - void setOpState(OperationState op) ; - OperationState getOpState() ; - void setSelectedGear(Gears gear); - Gears getSelectedGear(); - - int16_t getThrottle(); - int8_t getCoolFan(); + uint32_t getTickInterval(); + + void loadConfiguration(); + void saveConfiguration(); + + void coolingcheck(); + void checkBrakeLight(); + void checkReverseLight(); + void checkEnableInput(); + void checkReverseInput(); + void checkPrecharge(); + + void brakecheck(); + bool isReady(); + bool isRunning(); + bool isFaulted(); + bool isWarning(); + + uint32_t getStatusBitfield1(); + uint32_t getStatusBitfield2(); + uint32_t getStatusBitfield3(); + uint32_t getStatusBitfield4(); + + uint32_t statusBitfield1; // bitfield variable for use of the specific implementation + uint32_t statusBitfield2; + uint32_t statusBitfield3; + uint32_t statusBitfield4; + uint32_t kiloWattHours; + + + + + void setPowerMode(PowerMode mode); + PowerMode getPowerMode(); + void setOpState(OperationState op) ; + OperationState getOpState() ; + void setSelectedGear(Gears gear); + Gears getSelectedGear(); + + int16_t getThrottle(); + int8_t getCoolFan(); int8_t getCoolOn(); int8_t getCoolOff(); int8_t getBrakeLight(); @@ -148,63 +148,63 @@ uint32_t kiloWattHours; int16_t getTorqueActual(); int16_t getTorqueAvailable(); int preMillis(); - - uint16_t getDcVoltage(); - int16_t getDcCurrent(); - uint16_t getAcCurrent(); - uint32_t getKiloWattHours(); - int16_t getMechanicalPower(); - int16_t getTemperatureMotor(); - int16_t getTemperatureInverter(); - int16_t getTemperatureSystem(); - - - int milliseconds ; - int seconds; - int minutes; - int hours ; - int premillis; - uint16_t nominalVolts; //nominal pack voltage in 1/10 of a volt - uint8_t capacity; - + + uint16_t getDcVoltage(); + int16_t getDcCurrent(); + uint16_t getAcCurrent(); + uint32_t getKiloWattHours(); + int16_t getMechanicalPower(); + int16_t getTemperatureMotor(); + int16_t getTemperatureInverter(); + int16_t getTemperatureSystem(); + + + int milliseconds ; + int seconds; + int minutes; + int hours ; + int premillis; + uint16_t nominalVolts; //nominal pack voltage in 1/10 of a volt + uint8_t capacity; + protected: - bool ready; // indicates if the controller is ready to enable the power stage - bool running; // indicates if the power stage of the inverter is operative - bool faulted; // indicates a error condition is present in the controller - bool warning; // indicates a warning condition is present in the controller - bool coolflag; - bool testenableinput; - bool testreverseinput; - - - Gears selectedGear; - - PowerMode powerMode; - OperationState operationState; //the op state we want - - int16_t throttleRequested; // -1000 to 1000 (per mille of throttle level) - int16_t speedRequested; // in rpm - int16_t speedActual; // in rpm - int16_t torqueRequested; // in 0.1 Nm - int16_t torqueActual; // in 0.1 Nm - int16_t torqueAvailable; // the maximum available torque in 0.1Nm - - uint16_t dcVoltage; // DC voltage in 0.1 Volts - int16_t dcCurrent; // DC current in 0.1 Amps - uint16_t acCurrent; // AC current in 0.1 Amps - int16_t mechanicalPower; // mechanical power of the motor 0.1 kW - int16_t temperatureMotor; // temperature of motor in 0.1 degree C - int16_t temperatureInverter; // temperature of inverter power stage in 0.1 degree C - int16_t temperatureSystem; // temperature of controller in 0.1 degree C - - - - uint16_t prechargeTime; //time in ms that precharge should last - uint32_t milliStamp; //how long we have precharged so far - bool donePrecharge; //already completed the precharge cycle? - bool prelay; - uint32_t skipcounter; + bool ready; // indicates if the controller is ready to enable the power stage + bool running; // indicates if the power stage of the inverter is operative + bool faulted; // indicates a error condition is present in the controller + bool warning; // indicates a warning condition is present in the controller + bool coolflag; + bool testenableinput; + bool testreverseinput; + + + Gears selectedGear; + + PowerMode powerMode; + OperationState operationState; //the op state we want + + int16_t throttleRequested; // -1000 to 1000 (per mille of throttle level) + int16_t speedRequested; // in rpm + int16_t speedActual; // in rpm + int16_t torqueRequested; // in 0.1 Nm + int16_t torqueActual; // in 0.1 Nm + int16_t torqueAvailable; // the maximum available torque in 0.1Nm + + uint16_t dcVoltage; // DC voltage in 0.1 Volts + int16_t dcCurrent; // DC current in 0.1 Amps + uint16_t acCurrent; // AC current in 0.1 Amps + int16_t mechanicalPower; // mechanical power of the motor 0.1 kW + int16_t temperatureMotor; // temperature of motor in 0.1 degree C + int16_t temperatureInverter; // temperature of inverter power stage in 0.1 degree C + int16_t temperatureSystem; // temperature of controller in 0.1 degree C + + + + uint16_t prechargeTime; //time in ms that precharge should last + uint32_t milliStamp; //how long we have precharged so far + bool donePrecharge; //already completed the precharge cycle? + bool prelay; + uint32_t skipcounter; }; #endif diff --git a/OBD2Handler.cpp b/OBD2Handler.cpp index 8905811..f72147c 100644 --- a/OBD2Handler.cpp +++ b/OBD2Handler.cpp @@ -1,9 +1,9 @@ /* * OBD2Handler.cpp - A simple utility class that can be used to handle OBDII traffic - * of any form. It takes pointers to buffers where upwards of 8 characters reside. + * of any form. It takes pointers to buffers where upwards of 8 characters reside. * Doesn't care about how the traffic came out or how it'll go out. That is handled * in places like CanPIDListener or ELM327Emu - * + * * Copyright (c) 2013 Collin Kidder, Michael Neuweiler, Charles Galpin @@ -34,191 +34,191 @@ OBD2Handler *OBD2Handler::instance = NULL; OBD2Handler::OBD2Handler() { - motorController = (MotorController*) DeviceManager::getInstance()->getMotorController(); - accelPedal = (Throttle*) DeviceManager::getInstance()->getAccelerator(); - brakePedal = (Throttle*) DeviceManager::getInstance()->getBrake(); - BMS = (BatteryManager*) DeviceManager::getInstance()->getDeviceByType(DEVICE_BMS); + motorController = (MotorController*) DeviceManager::getInstance()->getMotorController(); + accelPedal = (Throttle*) DeviceManager::getInstance()->getAccelerator(); + brakePedal = (Throttle*) DeviceManager::getInstance()->getBrake(); + BMS = (BatteryManager*) DeviceManager::getInstance()->getDeviceByType(DEVICE_BMS); } OBD2Handler *OBD2Handler::getInstance() { - if (instance == NULL) - instance = new OBD2Handler(); - return instance; + if (instance == NULL) + instance = new OBD2Handler(); + return instance; } /* -Public method to process OBD2 requests. +Public method to process OBD2 requests. inData is whatever payload the request might need to have sent - it's OK to be NULL if this is a run of the mill PID request with no payload outData should be a preallocated buffer of at least 6 bytes. The format is as follows: outData[0] is the length of the data actually returned - outData[1] is the returned mode (input mode + 0x40) + outData[1] is the returned mode (input mode + 0x40) there after, the rest of the bytes are the data requested. This should be 1-5 bytes */ bool OBD2Handler::processRequest(uint8_t mode, uint8_t pid, char *inData, char *outData) { - bool ret = false; - switch (mode) { - case 1: //show current data - ret = processShowData(pid, inData, outData); - outData[1] = mode + 0x40; - outData[2] = pid; - break; - case 2: //show freeze frame data - not sure we'll be supporting this - break; - case 3: //show stored diagnostic codes - we can probably map our faults to some existing DTC codes or roll our own - break; - case 4: //clear diagnostic trouble codes - If we get this frame we just clear all codes no questions asked. - break; - case 6: //test results over CANBus (this replaces mode 5 from non-canbus) - I know nothing of this - break; - case 7: //show pending diag codes (current or last driving cycle) - Might just overlap with mode 3 - break; - case 8: //control operation of on-board systems - this sounds really proprietary and dangerous. Maybe ignore this? - break; - case 9: //request vehicle info - We can identify ourselves here but little else - break; - case 0x20: //custom PID codes we made up for GEVCU - break; - } - return ret; + bool ret = false; + switch (mode) { + case 1: //show current data + ret = processShowData(pid, inData, outData); + outData[1] = mode + 0x40; + outData[2] = pid; + break; + case 2: //show freeze frame data - not sure we'll be supporting this + break; + case 3: //show stored diagnostic codes - we can probably map our faults to some existing DTC codes or roll our own + break; + case 4: //clear diagnostic trouble codes - If we get this frame we just clear all codes no questions asked. + break; + case 6: //test results over CANBus (this replaces mode 5 from non-canbus) - I know nothing of this + break; + case 7: //show pending diag codes (current or last driving cycle) - Might just overlap with mode 3 + break; + case 8: //control operation of on-board systems - this sounds really proprietary and dangerous. Maybe ignore this? + break; + case 9: //request vehicle info - We can identify ourselves here but little else + break; + case 0x20: //custom PID codes we made up for GEVCU + break; + } + return ret; } //Process SAE standard PID requests. Function returns whether it handled the request or not. bool OBD2Handler::processShowData(uint8_t pid, char *inData, char *outData) { - int temp; - - - switch (pid) { - case 0: //pids 1-0x20 that we support - bitfield - //returns 4 bytes so immediately indicate that. - outData[0] = 4; - outData[3] = 0b11011000; //pids 1 - 8 - starting with pid 1 in the MSB and going from there - outData[4] = 0b00010000; //pids 9 - 0x10 - outData[5] = 0b10000000; //pids 0x11 - 0x18 - outData[6] = 0b00010011; //pids 0x19 - 0x20 - return true; - break; - case 1: //Returns 32 bits but we really can only support the first byte which has bit 7 = Malfunction? Bits 0-6 = # of DTCs - outData[0] = 4; - outData[3] = 0; //TODO: We aren't properly keeping track of faults yet but when we do fix this. - outData[4] = 0; //these next three are really related to ICE diagnostics - outData[5] = 0; //so ignore them. - outData[6] = 0; - return true; - break; - case 2: //Freeze DTC - return false; //don't support freeze framing yet. Might be useful in the future. - break; - case 4: //Calculated engine load (A * 100 / 255) - Percentage - temp = (255 * motorController->getTorqueActual()) / motorController->getTorqueAvailable(); - outData[0] = 1; - outData[3] = (uint8_t)(temp & 0xFF); - return true; - break; - case 5: //Engine Coolant Temp (A - 40) = Degrees Centigrade - //our code stores temperatures as a signed integer for tenths of a degree so translate - temp = motorController->getTemperatureSystem() / 10; - if (temp < -40) temp = -40; - if (temp > 215) temp = 215; - temp += 40; - outData[0] = 1; //returning only one byte - outData[3] = (uint8_t)(temp); - return true; - break; - case 0xC: //Engine RPM (A * 256 + B) / 4 - temp = motorController->getSpeedActual() * 4; //we store in RPM while the PID code wants quarter rpms - outData[0] = 2; - outData[3] = (uint8_t)(temp / 256); - outData[4] = (uint8_t)(temp); - return true; - break; - case 0x11: //Throttle position (A * 100 / 255) - Percentage - temp = motorController->getThrottle() / 10; //getThrottle returns in 10ths of a percent - if (temp < 0) temp = 0; //negative throttle can't be shown for OBDII - temp = (255 * temp) / 100; - outData[0] = 1; - outData[3] = (uint8_t)(temp); - return true; - break; - case 0x1C: //Standard supported (We return 1 = OBDII) - outData[0] = 1; - outData[3] = 1; - return true; - break; - case 0x1F: //runtime since engine start (A*256 + B) - outData[0] = 2; - outData[3] = 0; //TODO: Get the actual runtime. - outData[4] = 0; - return true; - break; - case 0x20: //pids supported (next 32 pids - formatted just like PID 0) - outData[0] = 4; - outData[3] = 0b10000000; //pids 0x21 - 0x28 - starting with pid 0x21 in the MSB and going from there - outData[4] = 0b00000010; //pids 0x29 - 0x30 - outData[5] = 0b00000000; //pids 0x31 - 0x38 - outData[6] = 0b00000001; //pids 0x39 - 0x40 - return true; - break; - case 0x21: //Distance traveled with fault light lit (A*256 + B) - In km - outData[0] = 2; - outData[3] = 0; //TODO: Can we get this information? - outData[4] = 0; - return true; - break; - case 0x2F: //Fuel level (A * 100 / 255) - Percentage - outData[0] = 1; - outData[3] = 0; //TODO: finish BMS interface and get this value - return true; - break; - case 0x40: //PIDs supported, next 32 - outData[0] = 4; - outData[3] = 0b00000000; //pids 0x41 - 0x48 - starting with pid 0x41 in the MSB and going from there - outData[4] = 0b00000000; //pids 0x49 - 0x50 - outData[5] = 0b10000000; //pids 0x51 - 0x58 - outData[6] = 0b00000001; //pids 0x59 - 0x60 - return true; - break; - case 0x51: //What type of fuel do we use? (We use 8 = electric, presumably.) - outData[0] = 1; - outData[3] = 8; - return true; - break; - case 0x60: //PIDs supported, next 32 - outData[0] = 4; - outData[3] = 0b11100000; //pids 0x61 - 0x68 - starting with pid 0x61 in the MSB and going from there - outData[4] = 0b00000000; //pids 0x69 - 0x70 - outData[5] = 0b00000000; //pids 0x71 - 0x78 - outData[6] = 0b00000000; //pids 0x79 - 0x80 - return true; - break; - case 0x61: //Driver requested torque (A-125) - Percentage - temp = (100 * motorController->getTorqueRequested()) / motorController->getTorqueAvailable(); - temp += 125; - outData[0] = 1; - outData[3] = (uint8_t)temp; - return true; - break; - case 0x62: //Actual Torque delivered (A-125) - Percentage - temp = (100 * motorController->getTorqueActual()) / motorController->getTorqueAvailable(); - temp += 125; - outData[0] = 1; - outData[3] = (uint8_t)temp; - return true; - break; - case 0x63: //Reference torque for engine - presumably max torque - A*256 + B - Nm - temp = motorController->getTorqueAvailable(); - outData[0] = 2; - outData[3] = (uint8_t)(temp / 256); - outData[4] = (uint8_t)(temp & 0xFF); - return true; - break; - } - return false; + int temp; + + + switch (pid) { + case 0: //pids 1-0x20 that we support - bitfield + //returns 4 bytes so immediately indicate that. + outData[0] = 4; + outData[3] = 0b11011000; //pids 1 - 8 - starting with pid 1 in the MSB and going from there + outData[4] = 0b00010000; //pids 9 - 0x10 + outData[5] = 0b10000000; //pids 0x11 - 0x18 + outData[6] = 0b00010011; //pids 0x19 - 0x20 + return true; + break; + case 1: //Returns 32 bits but we really can only support the first byte which has bit 7 = Malfunction? Bits 0-6 = # of DTCs + outData[0] = 4; + outData[3] = 0; //TODO: We aren't properly keeping track of faults yet but when we do fix this. + outData[4] = 0; //these next three are really related to ICE diagnostics + outData[5] = 0; //so ignore them. + outData[6] = 0; + return true; + break; + case 2: //Freeze DTC + return false; //don't support freeze framing yet. Might be useful in the future. + break; + case 4: //Calculated engine load (A * 100 / 255) - Percentage + temp = (255 * motorController->getTorqueActual()) / motorController->getTorqueAvailable(); + outData[0] = 1; + outData[3] = (uint8_t)(temp & 0xFF); + return true; + break; + case 5: //Engine Coolant Temp (A - 40) = Degrees Centigrade + //our code stores temperatures as a signed integer for tenths of a degree so translate + temp = motorController->getTemperatureSystem() / 10; + if (temp < -40) temp = -40; + if (temp > 215) temp = 215; + temp += 40; + outData[0] = 1; //returning only one byte + outData[3] = (uint8_t)(temp); + return true; + break; + case 0xC: //Engine RPM (A * 256 + B) / 4 + temp = motorController->getSpeedActual() * 4; //we store in RPM while the PID code wants quarter rpms + outData[0] = 2; + outData[3] = (uint8_t)(temp / 256); + outData[4] = (uint8_t)(temp); + return true; + break; + case 0x11: //Throttle position (A * 100 / 255) - Percentage + temp = motorController->getThrottle() / 10; //getThrottle returns in 10ths of a percent + if (temp < 0) temp = 0; //negative throttle can't be shown for OBDII + temp = (255 * temp) / 100; + outData[0] = 1; + outData[3] = (uint8_t)(temp); + return true; + break; + case 0x1C: //Standard supported (We return 1 = OBDII) + outData[0] = 1; + outData[3] = 1; + return true; + break; + case 0x1F: //runtime since engine start (A*256 + B) + outData[0] = 2; + outData[3] = 0; //TODO: Get the actual runtime. + outData[4] = 0; + return true; + break; + case 0x20: //pids supported (next 32 pids - formatted just like PID 0) + outData[0] = 4; + outData[3] = 0b10000000; //pids 0x21 - 0x28 - starting with pid 0x21 in the MSB and going from there + outData[4] = 0b00000010; //pids 0x29 - 0x30 + outData[5] = 0b00000000; //pids 0x31 - 0x38 + outData[6] = 0b00000001; //pids 0x39 - 0x40 + return true; + break; + case 0x21: //Distance traveled with fault light lit (A*256 + B) - In km + outData[0] = 2; + outData[3] = 0; //TODO: Can we get this information? + outData[4] = 0; + return true; + break; + case 0x2F: //Fuel level (A * 100 / 255) - Percentage + outData[0] = 1; + outData[3] = 0; //TODO: finish BMS interface and get this value + return true; + break; + case 0x40: //PIDs supported, next 32 + outData[0] = 4; + outData[3] = 0b00000000; //pids 0x41 - 0x48 - starting with pid 0x41 in the MSB and going from there + outData[4] = 0b00000000; //pids 0x49 - 0x50 + outData[5] = 0b10000000; //pids 0x51 - 0x58 + outData[6] = 0b00000001; //pids 0x59 - 0x60 + return true; + break; + case 0x51: //What type of fuel do we use? (We use 8 = electric, presumably.) + outData[0] = 1; + outData[3] = 8; + return true; + break; + case 0x60: //PIDs supported, next 32 + outData[0] = 4; + outData[3] = 0b11100000; //pids 0x61 - 0x68 - starting with pid 0x61 in the MSB and going from there + outData[4] = 0b00000000; //pids 0x69 - 0x70 + outData[5] = 0b00000000; //pids 0x71 - 0x78 + outData[6] = 0b00000000; //pids 0x79 - 0x80 + return true; + break; + case 0x61: //Driver requested torque (A-125) - Percentage + temp = (100 * motorController->getTorqueRequested()) / motorController->getTorqueAvailable(); + temp += 125; + outData[0] = 1; + outData[3] = (uint8_t)temp; + return true; + break; + case 0x62: //Actual Torque delivered (A-125) - Percentage + temp = (100 * motorController->getTorqueActual()) / motorController->getTorqueAvailable(); + temp += 125; + outData[0] = 1; + outData[3] = (uint8_t)temp; + return true; + break; + case 0x63: //Reference torque for engine - presumably max torque - A*256 + B - Nm + temp = motorController->getTorqueAvailable(); + outData[0] = 2; + outData[3] = (uint8_t)(temp / 256); + outData[4] = (uint8_t)(temp & 0xFF); + return true; + break; + } + return false; } bool OBD2Handler::processShowCustomData(uint16_t pid, char *inData, char *outData) { - switch (pid) { - } - return false; + switch (pid) { + } + return false; } diff --git a/OBD2Handler.h b/OBD2Handler.h index 2b7b5f3..67e3c53 100644 --- a/OBD2Handler.h +++ b/OBD2Handler.h @@ -39,21 +39,21 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. class OBD2Handler { public: - bool processRequest(uint8_t mode, uint8_t pid, char *inData, char *outData); - static OBD2Handler *getInstance(); + bool processRequest(uint8_t mode, uint8_t pid, char *inData, char *outData); + static OBD2Handler *getInstance(); protected: private: - OBD2Handler(); //it's not right to try to directly instantiate this class - bool processShowData(uint8_t pid, char *inData, char *outData); - bool processShowCustomData(uint16_t pid, char *inData, char *outData); - - static OBD2Handler *instance; - MotorController* motorController; - Throttle* accelPedal; - Throttle* brakePedal; - BatteryManager *BMS; + OBD2Handler(); //it's not right to try to directly instantiate this class + bool processShowData(uint8_t pid, char *inData, char *outData); + bool processShowCustomData(uint16_t pid, char *inData, char *outData); + + static OBD2Handler *instance; + MotorController* motorController; + Throttle* accelPedal; + Throttle* brakePedal; + BatteryManager *BMS; }; #endif diff --git a/PotBrake.cpp b/PotBrake.cpp index 5c5ab31..1f2b7ff 100644 --- a/PotBrake.cpp +++ b/PotBrake.cpp @@ -31,68 +31,68 @@ * Set which ADC channel to use */ PotBrake::PotBrake() : Throttle() { - prefsHandler = new PrefHandler(POTBRAKEPEDAL); - commonName = "Potentiometer (analog) brake"; + prefsHandler = new PrefHandler(POTBRAKEPEDAL); + commonName = "Potentiometer (analog) brake"; } /* * Setup the device. */ void PotBrake::setup() { - TickHandler::getInstance()->detach(this); // unregister from TickHandler first + TickHandler::getInstance()->detach(this); // unregister from TickHandler first - Logger::info("add device: PotBrake (id: %X, %X)", POTBRAKEPEDAL, this); + Logger::info("add device: PotBrake (id: %X, %X)", POTBRAKEPEDAL, this); - Throttle::setup(); //call base class + Throttle::setup(); //call base class - //set digital ports to inputs and pull them up all inputs currently active low - //pinMode(THROTTLE_INPUT_BRAKELIGHT, INPUT_PULLUP); //Brake light switch + //set digital ports to inputs and pull them up all inputs currently active low + //pinMode(THROTTLE_INPUT_BRAKELIGHT, INPUT_PULLUP); //Brake light switch - loadConfiguration(); - TickHandler::getInstance()->attach(this, CFG_TICK_INTERVAL_POT_THROTTLE); + loadConfiguration(); + TickHandler::getInstance()->attach(this, CFG_TICK_INTERVAL_POT_THROTTLE); } /* * Process a timer event. */ void PotBrake::handleTick() { - Throttle::handleTick(); // Call parent which controls the workflow + Throttle::handleTick(); // Call parent which controls the workflow } /* * Retrieve raw input signals from the brake hardware. */ RawSignalData *PotBrake::acquireRawSignal() { - PotBrakeConfiguration *config = (PotBrakeConfiguration *) getConfiguration(); - sys_io_adc_poll(); - rawSignal.input1 = getAnalog(config->AdcPin1); - return &rawSignal; + PotBrakeConfiguration *config = (PotBrakeConfiguration *) getConfiguration(); + sys_io_adc_poll(); + rawSignal.input1 = getAnalog(config->AdcPin1); + return &rawSignal; } /* * Perform sanity check on the ADC input values. */ bool PotBrake::validateSignal(RawSignalData *rawSignal) { - PotBrakeConfiguration *config = (PotBrakeConfiguration *) getConfiguration(); - - if (rawSignal->input1 > (config->maximumLevel1 + CFG_THROTTLE_TOLERANCE)) { - if (status == OK) - Logger::error(POTBRAKEPEDAL, (char *)Constants::valueOutOfRange, rawSignal->input1); - status = ERR_HIGH_T1; - return true; // even if it's too high, let it process and apply full regen ! - } - if (rawSignal->input1 < (config->minimumLevel1 - CFG_THROTTLE_TOLERANCE)) { - if (status == OK) - Logger::error(POTBRAKEPEDAL, (char *)Constants::valueOutOfRange, rawSignal->input1); - status = ERR_LOW_T1; - return false; - } - - // all checks passed -> brake is OK - if (status != OK) - Logger::info(POTBRAKEPEDAL, (char *)Constants::normalOperation); - status = OK; - return true; + PotBrakeConfiguration *config = (PotBrakeConfiguration *) getConfiguration(); + + if (rawSignal->input1 > (config->maximumLevel1 + CFG_THROTTLE_TOLERANCE)) { + if (status == OK) + Logger::error(POTBRAKEPEDAL, (char *)Constants::valueOutOfRange, rawSignal->input1); + status = ERR_HIGH_T1; + return true; // even if it's too high, let it process and apply full regen ! + } + if (rawSignal->input1 < (config->minimumLevel1 - CFG_THROTTLE_TOLERANCE)) { + if (status == OK) + Logger::error(POTBRAKEPEDAL, (char *)Constants::valueOutOfRange, rawSignal->input1); + status = ERR_LOW_T1; + return false; + } + + // all checks passed -> brake is OK + if (status != OK) + Logger::info(POTBRAKEPEDAL, (char *)Constants::normalOperation); + status = OK; + return true; } /* @@ -100,23 +100,23 @@ bool PotBrake::validateSignal(RawSignalData *rawSignal) { * to the specified range and the type of potentiometer. */ uint16_t PotBrake::calculatePedalPosition(RawSignalData *rawSignal) { - PotBrakeConfiguration *config = (PotBrakeConfiguration *) getConfiguration(); - uint16_t calcBrake1, clampedLevel; + PotBrakeConfiguration *config = (PotBrakeConfiguration *) getConfiguration(); + uint16_t calcBrake1, clampedLevel; - if (config->maximumLevel1 == 0) //brake processing disabled if max is 0 - return 0; + if (config->maximumLevel1 == 0) //brake processing disabled if max is 0 + return 0; - clampedLevel = constrain(rawSignal->input1, config->minimumLevel1, config->maximumLevel1); - calcBrake1 = map(clampedLevel, config->minimumLevel1, config->maximumLevel1, (uint16_t) 0, (uint16_t) 1000); + clampedLevel = constrain(rawSignal->input1, config->minimumLevel1, config->maximumLevel1); + calcBrake1 = map(clampedLevel, config->minimumLevel1, config->maximumLevel1, (uint16_t) 0, (uint16_t) 1000); - //This prevents flutter in the ADC readings of the brake from slamming regen on intermittently - // just because the value fluttered a couple of numbers. This makes sure that we're actually - // pushing the pedal. Without this even a small flutter at the brake will send minregen - // out and ignore the accelerator. That'd be unpleasant. - if (calcBrake1 < 15) - calcBrake1 = 0; + //This prevents flutter in the ADC readings of the brake from slamming regen on intermittently + // just because the value fluttered a couple of numbers. This makes sure that we're actually + // pushing the pedal. Without this even a small flutter at the brake will send minregen + // out and ignore the accelerator. That'd be unpleasant. + if (calcBrake1 < 15) + calcBrake1 = 0; - return calcBrake1; + return calcBrake1; } /* @@ -124,29 +124,29 @@ uint16_t PotBrake::calculatePedalPosition(RawSignalData *rawSignal) { * brake based regen. */ int16_t PotBrake::mapPedalPosition(int16_t pedalPosition) { - ThrottleConfiguration *config = (ThrottleConfiguration *) getConfiguration(); - int16_t brakeLevel, range; + ThrottleConfiguration *config = (ThrottleConfiguration *) getConfiguration(); + int16_t brakeLevel, range; - range = config->maximumRegen - config->minimumRegen; - brakeLevel = -10 * range * pedalPosition / 1000; - brakeLevel -= 10 * config->minimumRegen; - //Logger::debug(POTBRAKEPEDAL, "level: %d", level); + range = config->maximumRegen - config->minimumRegen; + brakeLevel = -10 * range * pedalPosition / 1000; + brakeLevel -= 10 * config->minimumRegen; + //Logger::debug(POTBRAKEPEDAL, "level: %d", level); - return brakeLevel; + return brakeLevel; } /* * Return the device ID */ DeviceId PotBrake::getId() { - return (POTBRAKEPEDAL); + return (POTBRAKEPEDAL); } /* * Return the device type */ DeviceType PotBrake::getType() { - return (DEVICE_BRAKE); + return (DEVICE_BRAKE); } /* @@ -155,51 +155,51 @@ DeviceType PotBrake::getType() { * are chosen and the configuration is overwritten in the EEPROM. */ void PotBrake::loadConfiguration() { - PotBrakeConfiguration *config = new PotBrakeConfiguration(); - setConfiguration(config); + PotBrakeConfiguration *config = new PotBrakeConfiguration(); + setConfiguration(config); - // we deliberately do not load config via parent class here ! + // we deliberately do not load config via parent class here ! #ifdef USE_HARD_CODED - if (false) { + if (false) { #else - if (prefsHandler->checksumValid()) { //checksum is good, read in the values stored in EEPROM + if (prefsHandler->checksumValid()) { //checksum is good, read in the values stored in EEPROM #endif - prefsHandler->read(EETH_BRAKE_MIN, &config->minimumLevel1); - prefsHandler->read(EETH_BRAKE_MAX, &config->maximumLevel1); - prefsHandler->read(EETH_MAX_BRAKE_REGEN, &config->maximumRegen); - prefsHandler->read(EETH_MIN_BRAKE_REGEN, &config->minimumRegen); - prefsHandler->read(EETH_ADC_1, &config->AdcPin1); - config->AdcPin1 = 2; - Logger::debug(POTBRAKEPEDAL, "BRAKE MIN: %l MAX: %l", config->minimumLevel1, config->maximumLevel1); - Logger::debug(POTBRAKEPEDAL, "Min: %l MaxRegen: %l", config->minimumRegen, config->maximumRegen); - } else { //checksum invalid. Reinitialize values and store to EEPROM - - //these four values are ADC values - //The next three are tenths of a percent - config->maximumRegen = BrakeMaxRegenValue; //percentage of full power to use for regen at brake pedal transducer - config->minimumRegen = BrakeMinRegenValue; - config->minimumLevel1 = BrakeMinValue; - config->maximumLevel1 = BrakeMaxValue; - config->AdcPin1 = BrakeADC; - saveConfiguration(); - } + prefsHandler->read(EETH_BRAKE_MIN, &config->minimumLevel1); + prefsHandler->read(EETH_BRAKE_MAX, &config->maximumLevel1); + prefsHandler->read(EETH_MAX_BRAKE_REGEN, &config->maximumRegen); + prefsHandler->read(EETH_MIN_BRAKE_REGEN, &config->minimumRegen); + prefsHandler->read(EETH_ADC_1, &config->AdcPin1); + config->AdcPin1 = 2; + Logger::debug(POTBRAKEPEDAL, "BRAKE MIN: %l MAX: %l", config->minimumLevel1, config->maximumLevel1); + Logger::debug(POTBRAKEPEDAL, "Min: %l MaxRegen: %l", config->minimumRegen, config->maximumRegen); + } else { //checksum invalid. Reinitialize values and store to EEPROM + + //these four values are ADC values + //The next three are tenths of a percent + config->maximumRegen = BrakeMaxRegenValue; //percentage of full power to use for regen at brake pedal transducer + config->minimumRegen = BrakeMinRegenValue; + config->minimumLevel1 = BrakeMinValue; + config->maximumLevel1 = BrakeMaxValue; + config->AdcPin1 = BrakeADC; + saveConfiguration(); + } } /* * Store the current configuration to EEPROM */ void PotBrake::saveConfiguration() { - PotBrakeConfiguration *config = (PotBrakeConfiguration *) getConfiguration(); + PotBrakeConfiguration *config = (PotBrakeConfiguration *) getConfiguration(); - // we deliberately do not save config via parent class here ! + // we deliberately do not save config via parent class here ! - prefsHandler->write(EETH_BRAKE_MIN, config->minimumLevel1); - prefsHandler->write(EETH_BRAKE_MAX, config->maximumLevel1); - prefsHandler->write(EETH_MAX_BRAKE_REGEN, config->maximumRegen); - prefsHandler->write(EETH_MIN_BRAKE_REGEN, config->minimumRegen); - prefsHandler->write(EETH_ADC_1, config->AdcPin1); - prefsHandler->saveChecksum(); + prefsHandler->write(EETH_BRAKE_MIN, config->minimumLevel1); + prefsHandler->write(EETH_BRAKE_MAX, config->maximumLevel1); + prefsHandler->write(EETH_MAX_BRAKE_REGEN, config->maximumRegen); + prefsHandler->write(EETH_MIN_BRAKE_REGEN, config->minimumRegen); + prefsHandler->write(EETH_ADC_1, config->AdcPin1); + prefsHandler->saveChecksum(); } diff --git a/PotBrake.h b/PotBrake.h index 15029a7..114bb2e 100644 --- a/PotBrake.h +++ b/PotBrake.h @@ -48,24 +48,24 @@ class PotBrakeConfiguration: public PotThrottleConfiguration { class PotBrake: public Throttle { public: - PotBrake(); - void setup(); - void handleTick(); - DeviceId getId(); - DeviceType getType(); + PotBrake(); + void setup(); + void handleTick(); + DeviceId getId(); + DeviceType getType(); - RawSignalData *acquireRawSignal(); + RawSignalData *acquireRawSignal(); - void loadConfiguration(); - void saveConfiguration(); + void loadConfiguration(); + void saveConfiguration(); protected: - bool validateSignal(RawSignalData *); - uint16_t calculatePedalPosition(RawSignalData *); - int16_t mapPedalPosition(int16_t); + bool validateSignal(RawSignalData *); + uint16_t calculatePedalPosition(RawSignalData *); + int16_t mapPedalPosition(int16_t); private: - RawSignalData rawSignal; + RawSignalData rawSignal; }; #endif /* POT_BRAKE_H_ */ diff --git a/PotThrottle.cpp b/PotThrottle.cpp index 6370e97..5480c02 100644 --- a/PotThrottle.cpp +++ b/PotThrottle.cpp @@ -30,45 +30,45 @@ * Constructor */ PotThrottle::PotThrottle() : Throttle() { - prefsHandler = new PrefHandler(POTACCELPEDAL); - commonName = "Potentiometer (analog) accelerator"; + prefsHandler = new PrefHandler(POTACCELPEDAL); + commonName = "Potentiometer (analog) accelerator"; } /* * Setup the device. */ void PotThrottle::setup() { - TickHandler::getInstance()->detach(this); // unregister from TickHandler first - - Logger::info("add device: PotThrottle (id: %X, %X)", POTACCELPEDAL, this); + TickHandler::getInstance()->detach(this); // unregister from TickHandler first - loadConfiguration(); + Logger::info("add device: PotThrottle (id: %X, %X)", POTACCELPEDAL, this); - Throttle::setup(); //call base class + loadConfiguration(); - //set digital ports to inputs and pull them up all inputs currently active low - //pinMode(THROTTLE_INPUT_BRAKELIGHT, INPUT_PULLUP); //Brake light switch + Throttle::setup(); //call base class - TickHandler::getInstance()->attach(this, CFG_TICK_INTERVAL_POT_THROTTLE); + //set digital ports to inputs and pull them up all inputs currently active low + //pinMode(THROTTLE_INPUT_BRAKELIGHT, INPUT_PULLUP); //Brake light switch + + TickHandler::getInstance()->attach(this, CFG_TICK_INTERVAL_POT_THROTTLE); } /* * Process a timer event. */ void PotThrottle::handleTick() { - Throttle::handleTick(); // Call parent which controls the workflow + Throttle::handleTick(); // Call parent which controls the workflow } /* * Retrieve raw input signals from the throttle hardware. */ RawSignalData *PotThrottle::acquireRawSignal() { - PotThrottleConfiguration *config = (PotThrottleConfiguration *) getConfiguration(); - sys_io_adc_poll(); + PotThrottleConfiguration *config = (PotThrottleConfiguration *) getConfiguration(); + sys_io_adc_poll(); - rawSignal.input1 = getAnalog(config->AdcPin1); - rawSignal.input2 = getAnalog(config->AdcPin2); - return &rawSignal; + rawSignal.input1 = getAnalog(config->AdcPin1); + rawSignal.input2 = getAnalog(config->AdcPin2); + return &rawSignal; } /* @@ -76,108 +76,108 @@ RawSignalData *PotThrottle::acquireRawSignal() { * and the checks are performed on a 0-1000 scale with a percentage tolerance */ bool PotThrottle::validateSignal(RawSignalData *rawSignal) { - PotThrottleConfiguration *config = (PotThrottleConfiguration *) getConfiguration(); - int32_t calcThrottle1, calcThrottle2; - - calcThrottle1 = normalizeInput(rawSignal->input1, config->minimumLevel1, config->maximumLevel1); - if (config->numberPotMeters == 1 && config->throttleSubType == 2) { // inverted - calcThrottle1 = 1000 - calcThrottle1; - } - - - if (calcThrottle1 > (1000 + CFG_THROTTLE_TOLERANCE)) - { - if (status == OK) - Logger::error(POTACCELPEDAL, "ERR_HIGH_T1: throttle 1 value out of range: %l", calcThrottle1); - status = ERR_HIGH_T1; - faultHandler.raiseFault(POTACCELPEDAL, FAULT_THROTTLE_HIGH_A, true); - return false; - } - else - { - faultHandler.cancelOngoingFault(POTACCELPEDAL, FAULT_THROTTLE_HIGH_A); - } - - if (calcThrottle1 < (0 - CFG_THROTTLE_TOLERANCE)) { - if (status == OK) - Logger::error(POTACCELPEDAL, "ERR_LOW_T1: throttle 1 value out of range: %l ", calcThrottle1); - status = ERR_LOW_T1; - faultHandler.raiseFault(POTACCELPEDAL, FAULT_THROTTLE_LOW_A, true); - return false; - } - else - { - faultHandler.cancelOngoingFault(POTACCELPEDAL, FAULT_THROTTLE_LOW_A); - } - - if (config->numberPotMeters > 1) { - calcThrottle2 = normalizeInput(rawSignal->input2, config->minimumLevel2, config->maximumLevel2); - - if (calcThrottle2 > (1000 + CFG_THROTTLE_TOLERANCE)) { - if (status == OK) - Logger::error(POTACCELPEDAL, "ERR_HIGH_T2: throttle 2 value out of range: %l", calcThrottle2); - status = ERR_HIGH_T2; - faultHandler.raiseFault(POTACCELPEDAL, FAULT_THROTTLE_HIGH_B, true); - return false; - } - else - { - faultHandler.cancelOngoingFault(POTACCELPEDAL, FAULT_THROTTLE_HIGH_B); - } - - if (calcThrottle2 < (0 - CFG_THROTTLE_TOLERANCE)) { - if (status == OK) - Logger::error(POTACCELPEDAL, "ERR_LOW_T2: throttle 2 value out of range: %l", calcThrottle2); - status = ERR_LOW_T2; - faultHandler.cancelOngoingFault(POTACCELPEDAL, FAULT_THROTTLE_LOW_B); - return false; - } - else - { - faultHandler.cancelOngoingFault(POTACCELPEDAL, FAULT_THROTTLE_LOW_B); - } - - if (config->throttleSubType == 2) { - // inverted throttle 2 means the sum of the two throttles should be 1000 - if ( abs(1000 - calcThrottle1 - calcThrottle2) > ThrottleMaxErrValue) { - if (status == OK) - Logger::error(POTACCELPEDAL, "Sum of throttle 1 (%l) and throttle 2 (%l) exceeds max variance from 1000 (%l)", - calcThrottle1, calcThrottle2, ThrottleMaxErrValue); - status = ERR_MISMATCH; - faultHandler.raiseFault(POTACCELPEDAL, FAULT_THROTTLE_MISMATCH_AB, true); - return false; - } - else - { - faultHandler.cancelOngoingFault(POTACCELPEDAL, FAULT_THROTTLE_MISMATCH_AB); - } - } else { - if ((calcThrottle1 - ThrottleMaxErrValue) > calcThrottle2) { //then throttle1 is too large compared to 2 - if (status == OK) - Logger::error(POTACCELPEDAL, "throttle 1 too high (%l) compared to 2 (%l)", calcThrottle1, calcThrottle2); - status = ERR_MISMATCH; - faultHandler.raiseFault(POTACCELPEDAL, FAULT_THROTTLE_MISMATCH_AB, true); - return false; - } - else if ((calcThrottle2 - ThrottleMaxErrValue) > calcThrottle1) { //then throttle2 is too large compared to 1 - if (status == OK) - Logger::error(POTACCELPEDAL, "throttle 2 too high (%l) compared to 1 (%l)", calcThrottle2, calcThrottle1); - status = ERR_MISMATCH; - faultHandler.raiseFault(POTACCELPEDAL, FAULT_THROTTLE_MISMATCH_AB, true); - return false; - } - else - { - faultHandler.cancelOngoingFault(POTACCELPEDAL, FAULT_THROTTLE_MISMATCH_AB); - } - } - } - - // all checks passed -> throttle is ok - if (status != OK) - Logger::info(POTACCELPEDAL, (char *)Constants::normalOperation); - status = OK; - return true; + PotThrottleConfiguration *config = (PotThrottleConfiguration *) getConfiguration(); + int32_t calcThrottle1, calcThrottle2; + + calcThrottle1 = normalizeInput(rawSignal->input1, config->minimumLevel1, config->maximumLevel1); + if (config->numberPotMeters == 1 && config->throttleSubType == 2) { // inverted + calcThrottle1 = 1000 - calcThrottle1; + } + + + if (calcThrottle1 > (1000 + CFG_THROTTLE_TOLERANCE)) + { + if (status == OK) + Logger::error(POTACCELPEDAL, "ERR_HIGH_T1: throttle 1 value out of range: %l", calcThrottle1); + status = ERR_HIGH_T1; + faultHandler.raiseFault(POTACCELPEDAL, FAULT_THROTTLE_HIGH_A, true); + return false; + } + else + { + faultHandler.cancelOngoingFault(POTACCELPEDAL, FAULT_THROTTLE_HIGH_A); + } + + if (calcThrottle1 < (0 - CFG_THROTTLE_TOLERANCE)) { + if (status == OK) + Logger::error(POTACCELPEDAL, "ERR_LOW_T1: throttle 1 value out of range: %l ", calcThrottle1); + status = ERR_LOW_T1; + faultHandler.raiseFault(POTACCELPEDAL, FAULT_THROTTLE_LOW_A, true); + return false; + } + else + { + faultHandler.cancelOngoingFault(POTACCELPEDAL, FAULT_THROTTLE_LOW_A); + } + + if (config->numberPotMeters > 1) { + calcThrottle2 = normalizeInput(rawSignal->input2, config->minimumLevel2, config->maximumLevel2); + + if (calcThrottle2 > (1000 + CFG_THROTTLE_TOLERANCE)) { + if (status == OK) + Logger::error(POTACCELPEDAL, "ERR_HIGH_T2: throttle 2 value out of range: %l", calcThrottle2); + status = ERR_HIGH_T2; + faultHandler.raiseFault(POTACCELPEDAL, FAULT_THROTTLE_HIGH_B, true); + return false; + } + else + { + faultHandler.cancelOngoingFault(POTACCELPEDAL, FAULT_THROTTLE_HIGH_B); + } + + if (calcThrottle2 < (0 - CFG_THROTTLE_TOLERANCE)) { + if (status == OK) + Logger::error(POTACCELPEDAL, "ERR_LOW_T2: throttle 2 value out of range: %l", calcThrottle2); + status = ERR_LOW_T2; + faultHandler.cancelOngoingFault(POTACCELPEDAL, FAULT_THROTTLE_LOW_B); + return false; + } + else + { + faultHandler.cancelOngoingFault(POTACCELPEDAL, FAULT_THROTTLE_LOW_B); + } + + if (config->throttleSubType == 2) { + // inverted throttle 2 means the sum of the two throttles should be 1000 + if ( abs(1000 - calcThrottle1 - calcThrottle2) > ThrottleMaxErrValue) { + if (status == OK) + Logger::error(POTACCELPEDAL, "Sum of throttle 1 (%l) and throttle 2 (%l) exceeds max variance from 1000 (%l)", + calcThrottle1, calcThrottle2, ThrottleMaxErrValue); + status = ERR_MISMATCH; + faultHandler.raiseFault(POTACCELPEDAL, FAULT_THROTTLE_MISMATCH_AB, true); + return false; + } + else + { + faultHandler.cancelOngoingFault(POTACCELPEDAL, FAULT_THROTTLE_MISMATCH_AB); + } + } else { + if ((calcThrottle1 - ThrottleMaxErrValue) > calcThrottle2) { //then throttle1 is too large compared to 2 + if (status == OK) + Logger::error(POTACCELPEDAL, "throttle 1 too high (%l) compared to 2 (%l)", calcThrottle1, calcThrottle2); + status = ERR_MISMATCH; + faultHandler.raiseFault(POTACCELPEDAL, FAULT_THROTTLE_MISMATCH_AB, true); + return false; + } + else if ((calcThrottle2 - ThrottleMaxErrValue) > calcThrottle1) { //then throttle2 is too large compared to 1 + if (status == OK) + Logger::error(POTACCELPEDAL, "throttle 2 too high (%l) compared to 1 (%l)", calcThrottle2, calcThrottle1); + status = ERR_MISMATCH; + faultHandler.raiseFault(POTACCELPEDAL, FAULT_THROTTLE_MISMATCH_AB, true); + return false; + } + else + { + faultHandler.cancelOngoingFault(POTACCELPEDAL, FAULT_THROTTLE_MISMATCH_AB); + } + } + } + + // all checks passed -> throttle is ok + if (status != OK) + Logger::info(POTACCELPEDAL, (char *)Constants::normalOperation); + status = OK; + return true; } /* @@ -185,25 +185,25 @@ bool PotThrottle::validateSignal(RawSignalData *rawSignal) { * to the specified range and the type of potentiometer. */ uint16_t PotThrottle::calculatePedalPosition(RawSignalData *rawSignal) { - PotThrottleConfiguration *config = (PotThrottleConfiguration *) getConfiguration(); - uint16_t calcThrottle1, calcThrottle2; - - calcThrottle1 = normalizeInput(rawSignal->input1, config->minimumLevel1, config->maximumLevel1); - - if (config->numberPotMeters > 1) { - calcThrottle2 = normalizeInput(rawSignal->input2, config->minimumLevel2, config->maximumLevel2); - if (config->throttleSubType == 2) // inverted - calcThrottle2 = 1000 - calcThrottle2; - calcThrottle1 = (calcThrottle1 + calcThrottle2) / 2; // now the average of the two - } - return calcThrottle1; + PotThrottleConfiguration *config = (PotThrottleConfiguration *) getConfiguration(); + uint16_t calcThrottle1, calcThrottle2; + + calcThrottle1 = normalizeInput(rawSignal->input1, config->minimumLevel1, config->maximumLevel1); + + if (config->numberPotMeters > 1) { + calcThrottle2 = normalizeInput(rawSignal->input2, config->minimumLevel2, config->maximumLevel2); + if (config->throttleSubType == 2) // inverted + calcThrottle2 = 1000 - calcThrottle2; + calcThrottle1 = (calcThrottle1 + calcThrottle2) / 2; // now the average of the two + } + return calcThrottle1; } /* * Return the device ID */ DeviceId PotThrottle::getId() { - return (POTACCELPEDAL); + return (POTACCELPEDAL); } /* @@ -212,74 +212,74 @@ DeviceId PotThrottle::getId() { * are chosen and the configuration is overwritten in the EEPROM. */ void PotThrottle::loadConfiguration() { - PotThrottleConfiguration *config = (PotThrottleConfiguration *) getConfiguration(); + PotThrottleConfiguration *config = (PotThrottleConfiguration *) getConfiguration(); - if (!config) { // as lowest sub-class make sure we have a config object - config = new PotThrottleConfiguration(); - setConfiguration(config); - } + if (!config) { // as lowest sub-class make sure we have a config object + config = new PotThrottleConfiguration(); + setConfiguration(config); + } - Throttle::loadConfiguration(); // call parent + Throttle::loadConfiguration(); // call parent #ifdef USE_HARD_CODED - if (false) { + if (false) { #else - if (prefsHandler->checksumValid()) { //checksum is good, read in the values stored in EEPROM + if (prefsHandler->checksumValid()) { //checksum is good, read in the values stored in EEPROM #endif - Logger::debug(POTACCELPEDAL, (char *)Constants::validChecksum); - prefsHandler->read(EETH_MIN_ONE, &config->minimumLevel1); - prefsHandler->read(EETH_MAX_ONE, &config->maximumLevel1); - prefsHandler->read(EETH_MIN_TWO, &config->minimumLevel2); - prefsHandler->read(EETH_MAX_TWO, &config->maximumLevel2); - prefsHandler->read(EETH_NUM_THROTTLES, &config->numberPotMeters); - prefsHandler->read(EETH_THROTTLE_TYPE, &config->throttleSubType); - prefsHandler->read(EETH_ADC_1, &config->AdcPin1); - prefsHandler->read(EETH_ADC_2, &config->AdcPin2); - - // ** This is potentially a condition that is only met if you don't have the EEPROM hardware ** - // If preferences have never been set before, numThrottlePots and throttleSubType - // will both be zero. We really should refuse to operate in this condition and force - // calibration, but for now at least allow calibration to work by setting numThrottlePots = 2 - if (config->numberPotMeters == 0 && config->throttleSubType == 0) { - Logger::debug(POTACCELPEDAL, "THROTTLE APPEARS TO NEED CALIBRATION/DETECTION - choose 'z' on the serial console menu"); - config->numberPotMeters = 2; - } - } else { //checksum invalid. Reinitialize values and store to EEPROM - Logger::warn(POTACCELPEDAL, (char *)Constants::invalidChecksum); - - config->minimumLevel1 = Throttle1MinValue; - config->maximumLevel1 = Throttle1MaxValue; - config->minimumLevel2 = Throttle2MinValue; - config->maximumLevel2 = Throttle2MaxValue; - config->numberPotMeters = ThrottleNumPots; - config->throttleSubType = ThrottleSubtype; - config->AdcPin1 = ThrottleADC1; - config->AdcPin2 = ThrottleADC2; - - saveConfiguration(); - } - Logger::debug(POTACCELPEDAL, "# of pots: %d subtype: %d", config->numberPotMeters, config->throttleSubType); - Logger::debug(POTACCELPEDAL, "T1 MIN: %l MAX: %l T2 MIN: %l MAX: %l", config->minimumLevel1, config->maximumLevel1, config->minimumLevel2, - config->maximumLevel2); + Logger::debug(POTACCELPEDAL, (char *)Constants::validChecksum); + prefsHandler->read(EETH_MIN_ONE, &config->minimumLevel1); + prefsHandler->read(EETH_MAX_ONE, &config->maximumLevel1); + prefsHandler->read(EETH_MIN_TWO, &config->minimumLevel2); + prefsHandler->read(EETH_MAX_TWO, &config->maximumLevel2); + prefsHandler->read(EETH_NUM_THROTTLES, &config->numberPotMeters); + prefsHandler->read(EETH_THROTTLE_TYPE, &config->throttleSubType); + prefsHandler->read(EETH_ADC_1, &config->AdcPin1); + prefsHandler->read(EETH_ADC_2, &config->AdcPin2); + + // ** This is potentially a condition that is only met if you don't have the EEPROM hardware ** + // If preferences have never been set before, numThrottlePots and throttleSubType + // will both be zero. We really should refuse to operate in this condition and force + // calibration, but for now at least allow calibration to work by setting numThrottlePots = 2 + if (config->numberPotMeters == 0 && config->throttleSubType == 0) { + Logger::debug(POTACCELPEDAL, "THROTTLE APPEARS TO NEED CALIBRATION/DETECTION - choose 'z' on the serial console menu"); + config->numberPotMeters = 2; + } + } else { //checksum invalid. Reinitialize values and store to EEPROM + Logger::warn(POTACCELPEDAL, (char *)Constants::invalidChecksum); + + config->minimumLevel1 = Throttle1MinValue; + config->maximumLevel1 = Throttle1MaxValue; + config->minimumLevel2 = Throttle2MinValue; + config->maximumLevel2 = Throttle2MaxValue; + config->numberPotMeters = ThrottleNumPots; + config->throttleSubType = ThrottleSubtype; + config->AdcPin1 = ThrottleADC1; + config->AdcPin2 = ThrottleADC2; + + saveConfiguration(); + } + Logger::debug(POTACCELPEDAL, "# of pots: %d subtype: %d", config->numberPotMeters, config->throttleSubType); + Logger::debug(POTACCELPEDAL, "T1 MIN: %l MAX: %l T2 MIN: %l MAX: %l", config->minimumLevel1, config->maximumLevel1, config->minimumLevel2, + config->maximumLevel2); } /* * Store the current configuration to EEPROM */ void PotThrottle::saveConfiguration() { - PotThrottleConfiguration *config = (PotThrottleConfiguration *) getConfiguration(); - - Throttle::saveConfiguration(); // call parent - - prefsHandler->write(EETH_MIN_ONE, config->minimumLevel1); - prefsHandler->write(EETH_MAX_ONE, config->maximumLevel1); - prefsHandler->write(EETH_MIN_TWO, config->minimumLevel2); - prefsHandler->write(EETH_MAX_TWO, config->maximumLevel2); - prefsHandler->write(EETH_NUM_THROTTLES, config->numberPotMeters); - prefsHandler->write(EETH_THROTTLE_TYPE, config->throttleSubType); - prefsHandler->write(EETH_ADC_1, config->AdcPin1); - prefsHandler->write(EETH_ADC_2, config->AdcPin2); - prefsHandler->saveChecksum(); + PotThrottleConfiguration *config = (PotThrottleConfiguration *) getConfiguration(); + + Throttle::saveConfiguration(); // call parent + + prefsHandler->write(EETH_MIN_ONE, config->minimumLevel1); + prefsHandler->write(EETH_MAX_ONE, config->maximumLevel1); + prefsHandler->write(EETH_MIN_TWO, config->minimumLevel2); + prefsHandler->write(EETH_MAX_TWO, config->maximumLevel2); + prefsHandler->write(EETH_NUM_THROTTLES, config->numberPotMeters); + prefsHandler->write(EETH_THROTTLE_TYPE, config->throttleSubType); + prefsHandler->write(EETH_ADC_1, config->AdcPin1); + prefsHandler->write(EETH_ADC_2, config->AdcPin2); + prefsHandler->saveChecksum(); } diff --git a/PotThrottle.h b/PotThrottle.h index c77ccef..671c911 100644 --- a/PotThrottle.h +++ b/PotThrottle.h @@ -44,35 +44,35 @@ */ class PotThrottleConfiguration: public ThrottleConfiguration { public: - /* - * Allows subclasses to have sub types for their pedal type - * 0 - unknown type (prefs will return 0 if never set) - * 1 - standard linear potentiometer (low-high). If 2 pots, both are low-high and the 2nd mirrors the 1st. - * 2 - inverse potentiometer (high-low). If 2 pots, then 1st is low-high and 2nd is high-low) - */ - uint8_t throttleSubType; - uint16_t minimumLevel1, maximumLevel1, minimumLevel2, maximumLevel2; // values for when the pedal is at its min and max for each input - uint8_t numberPotMeters; // the number of potentiometers to be used. Should support three as well since some pedals really do have that many - uint8_t AdcPin1, AdcPin2; //which ADC pins to use for the throttle + /* + * Allows subclasses to have sub types for their pedal type + * 0 - unknown type (prefs will return 0 if never set) + * 1 - standard linear potentiometer (low-high). If 2 pots, both are low-high and the 2nd mirrors the 1st. + * 2 - inverse potentiometer (high-low). If 2 pots, then 1st is low-high and 2nd is high-low) + */ + uint8_t throttleSubType; + uint16_t minimumLevel1, maximumLevel1, minimumLevel2, maximumLevel2; // values for when the pedal is at its min and max for each input + uint8_t numberPotMeters; // the number of potentiometers to be used. Should support three as well since some pedals really do have that many + uint8_t AdcPin1, AdcPin2; //which ADC pins to use for the throttle }; class PotThrottle: public Throttle { public: - PotThrottle(); - void setup(); - void handleTick(); - DeviceId getId(); - RawSignalData *acquireRawSignal(); + PotThrottle(); + void setup(); + void handleTick(); + DeviceId getId(); + RawSignalData *acquireRawSignal(); - void loadConfiguration(); - void saveConfiguration(); + void loadConfiguration(); + void saveConfiguration(); protected: - bool validateSignal(RawSignalData *); - uint16_t calculatePedalPosition(RawSignalData *); + bool validateSignal(RawSignalData *); + uint16_t calculatePedalPosition(RawSignalData *); private: - RawSignalData rawSignal; + RawSignalData rawSignal; }; #endif /* POT_THROTTLE_H_ */ diff --git a/PrefHandler.cpp b/PrefHandler.cpp index 61a304a..b6e4f82 100644 --- a/PrefHandler.cpp +++ b/PrefHandler.cpp @@ -25,194 +25,194 @@ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ + */ #include "PrefHandler.h" PrefHandler::PrefHandler() { - lkg_address = EE_MAIN_OFFSET; //default to normal mode - base_address = 0; + lkg_address = EE_MAIN_OFFSET; //default to normal mode + base_address = 0; } -bool PrefHandler::isEnabled() +bool PrefHandler::isEnabled() { - return enabled; + return enabled; } -void PrefHandler::setEnabledStatus(bool en) +void PrefHandler::setEnabledStatus(bool en) { - uint16_t id; + uint16_t id; - enabled = en; + enabled = en; - if (enabled) { - id |= 0x8000; //set enabled bit - } - else { - id &= 0x7FFF; //clear enabled bit - } + if (enabled) { + id |= 0x8000; //set enabled bit + } + else { + id &= 0x7FFF; //clear enabled bit + } - memCache->Write(EE_DEVICE_TABLE + (2 * position), id); + memCache->Write(EE_DEVICE_TABLE + (2 * position), id); } -void PrefHandler::initDevTable() +void PrefHandler::initDevTable() { - uint16_t id; + uint16_t id; - memCache->Read(EE_DEVICE_TABLE, &id); - if (id == 0xDEAD) return; + memCache->Read(EE_DEVICE_TABLE, &id); + if (id == 0xDEAD) return; - Logger::debug("Initializing EEPROM device table"); + Logger::debug("Initializing EEPROM device table"); - //initialize table with zeros - id = 0; - for (int x = 1; x < 64; x++) { - memCache->Write(EE_DEVICE_TABLE + (2 * x), id); - } + //initialize table with zeros + id = 0; + for (int x = 1; x < 64; x++) { + memCache->Write(EE_DEVICE_TABLE + (2 * x), id); + } - //write out magic entry - id = 0xDEAD; - memCache->Write(EE_DEVICE_TABLE, id); + //write out magic entry + id = 0xDEAD; + memCache->Write(EE_DEVICE_TABLE, id); } //Given a device ID we must search the 64 entry table found in EEPROM to see if the device -//has a spot in EEPROM. If it does not then +//has a spot in EEPROM. If it does not then PrefHandler::PrefHandler(DeviceId id_in) { - uint16_t id; - - enabled = false; - - initDevTable(); - - for (int x = 1; x < 64; x++) { - memCache->Read(EE_DEVICE_TABLE + (2 * x), &id); - if ((id & 0x7FFF) == ((int)id_in)) { - base_address = EE_DEVICES_BASE + (EE_DEVICE_SIZE * x); - lkg_address = EE_MAIN_OFFSET; - if (id & 0x8000) enabled = true; - position = x; - Logger::info("Device ID: %X was found in device table at entry: %i", (int)id_in, x); - return; - } - } - - //if we got here then there was no entry for this device in the table yet. - //try to find an empty spot and place it there. - for (int x = 1; x < 64; x++) { - memCache->Read(EE_DEVICE_TABLE + (2 * x), &id); - if (id == 0) { - base_address = EE_DEVICES_BASE + (EE_DEVICE_SIZE * x); - lkg_address = EE_MAIN_OFFSET; - enabled = false; //default to devices being off until the user says otherwise - id = (int)id_in; - memCache->Write(EE_DEVICE_TABLE + (2*x), id); - position = x; - Logger::info("Device ID: %X was placed into device table at entry: %i", (int)id, x); - return; - } - } - - //we found no matches and could not allocate a space. This is bad. Error out here - base_address = 0xF0F0; - lkg_address = EE_MAIN_OFFSET; - Logger::error("PrefManager - Device Table Full!!!"); + uint16_t id; + + enabled = false; + + initDevTable(); + + for (int x = 1; x < 64; x++) { + memCache->Read(EE_DEVICE_TABLE + (2 * x), &id); + if ((id & 0x7FFF) == ((int)id_in)) { + base_address = EE_DEVICES_BASE + (EE_DEVICE_SIZE * x); + lkg_address = EE_MAIN_OFFSET; + if (id & 0x8000) enabled = true; + position = x; + Logger::info("Device ID: %X was found in device table at entry: %i", (int)id_in, x); + return; + } + } + + //if we got here then there was no entry for this device in the table yet. + //try to find an empty spot and place it there. + for (int x = 1; x < 64; x++) { + memCache->Read(EE_DEVICE_TABLE + (2 * x), &id); + if (id == 0) { + base_address = EE_DEVICES_BASE + (EE_DEVICE_SIZE * x); + lkg_address = EE_MAIN_OFFSET; + enabled = false; //default to devices being off until the user says otherwise + id = (int)id_in; + memCache->Write(EE_DEVICE_TABLE + (2*x), id); + position = x; + Logger::info("Device ID: %X was placed into device table at entry: %i", (int)id, x); + return; + } + } + + //we found no matches and could not allocate a space. This is bad. Error out here + base_address = 0xF0F0; + lkg_address = EE_MAIN_OFFSET; + Logger::error("PrefManager - Device Table Full!!!"); } //A special static function that can be called whenever, wherever to turn a specific device on/off. Does not //attempt to do so at runtime so the user will still have to power cycle to change the device status. //returns true if it could make the change, false if it could not. -bool PrefHandler::setDeviceStatus(uint16_t device, bool enabled) +bool PrefHandler::setDeviceStatus(uint16_t device, bool enabled) { - uint16_t id; - for (int x = 1; x < 64; x++) { - memCache->Read(EE_DEVICE_TABLE + (2 * x), &id); - if ((id & 0x7FFF) == (device & 0x7FFF)) { - Logger::debug("Found a device record to edit"); - if (enabled) { - id |= 0x8000; - } - else { - id &= 0x7FFF; - } - Logger::debug("ID to write: %X", id); - memCache->Write(EE_DEVICE_TABLE + (2 * x), id); - return true; - } - } - return false; + uint16_t id; + for (int x = 1; x < 64; x++) { + memCache->Read(EE_DEVICE_TABLE + (2 * x), &id); + if ((id & 0x7FFF) == (device & 0x7FFF)) { + Logger::debug("Found a device record to edit"); + if (enabled) { + id |= 0x8000; + } + else { + id &= 0x7FFF; + } + Logger::debug("ID to write: %X", id); + memCache->Write(EE_DEVICE_TABLE + (2 * x), id); + return true; + } + } + return false; } PrefHandler::~PrefHandler() { } void PrefHandler::LKG_mode(bool mode) { - if (mode) lkg_address = EE_LKG_OFFSET; - else lkg_address = EE_MAIN_OFFSET; + if (mode) lkg_address = EE_LKG_OFFSET; + else lkg_address = EE_MAIN_OFFSET; } bool PrefHandler::write(uint16_t address, uint8_t val) { - if (address >= EE_DEVICE_SIZE) return false; - return memCache->Write((uint32_t)address + base_address + lkg_address, val); + if (address >= EE_DEVICE_SIZE) return false; + return memCache->Write((uint32_t)address + base_address + lkg_address, val); } bool PrefHandler::write(uint16_t address, uint16_t val) { - if (address >= EE_DEVICE_SIZE) return false; - return memCache->Write((uint32_t)address + base_address + lkg_address, val); + if (address >= EE_DEVICE_SIZE) return false; + return memCache->Write((uint32_t)address + base_address + lkg_address, val); } bool PrefHandler::write(uint16_t address, uint32_t val) { - if (address >= EE_DEVICE_SIZE) return false; - return memCache->Write((uint32_t)address + base_address + lkg_address, val); + if (address >= EE_DEVICE_SIZE) return false; + return memCache->Write((uint32_t)address + base_address + lkg_address, val); } bool PrefHandler::read(uint16_t address, uint8_t *val) { - if (address >= EE_DEVICE_SIZE) return false; - return memCache->Read((uint32_t)address + base_address + lkg_address, val); + if (address >= EE_DEVICE_SIZE) return false; + return memCache->Read((uint32_t)address + base_address + lkg_address, val); } bool PrefHandler::read(uint16_t address, uint16_t *val) { - if (address >= EE_DEVICE_SIZE) return false; - return memCache->Read((uint32_t)address + base_address + lkg_address, val); + if (address >= EE_DEVICE_SIZE) return false; + return memCache->Read((uint32_t)address + base_address + lkg_address, val); } bool PrefHandler::read(uint16_t address, uint32_t *val) { - if (address >= EE_DEVICE_SIZE) return false; - return memCache->Read((uint32_t)address + base_address + lkg_address, val); + if (address >= EE_DEVICE_SIZE) return false; + return memCache->Read((uint32_t)address + base_address + lkg_address, val); } uint8_t PrefHandler::calcChecksum() { - uint16_t counter; - uint8_t accum = 0; - uint8_t temp; - for (counter = 1; counter < EE_DEVICE_SIZE; counter++) { - memCache->Read((uint32_t)counter + base_address + lkg_address, &temp); - accum += temp; - } - return accum; -} + uint16_t counter; + uint8_t accum = 0; + uint8_t temp; + for (counter = 1; counter < EE_DEVICE_SIZE; counter++) { + memCache->Read((uint32_t)counter + base_address + lkg_address, &temp); + accum += temp; + } + return accum; +} //calculate the current checksum and save it to the proper place void PrefHandler::saveChecksum() { - uint8_t csum; - csum = calcChecksum(); - memCache->Write(EE_CHECKSUM + base_address + lkg_address, csum); + uint8_t csum; + csum = calcChecksum(); + memCache->Write(EE_CHECKSUM + base_address + lkg_address, csum); } bool PrefHandler::checksumValid() { - //get checksum from EEPROM and calculate the current checksum to see if they match - uint8_t stored_chk, calc_chk; - - memCache->Read(EE_CHECKSUM + base_address + lkg_address, &stored_chk); - calc_chk = calcChecksum(); - Logger::info("Stored Checksum: %X Calc: %X", stored_chk, calc_chk); - - return (stored_chk == calc_chk); + //get checksum from EEPROM and calculate the current checksum to see if they match + uint8_t stored_chk, calc_chk; + + memCache->Read(EE_CHECKSUM + base_address + lkg_address, &stored_chk); + calc_chk = calcChecksum(); + Logger::info("Stored Checksum: %X Calc: %X", stored_chk, calc_chk); + + return (stored_chk == calc_chk); } void PrefHandler::forceCacheWrite() { - memCache->FlushAllPages(); + memCache->FlushAllPages(); } diff --git a/PrefHandler.h b/PrefHandler.h index f5f16f5..023fd2f 100644 --- a/PrefHandler.h +++ b/PrefHandler.h @@ -45,31 +45,31 @@ extern MemCache *memCache; class PrefHandler { public: - PrefHandler(); - PrefHandler(DeviceId id); - ~PrefHandler(); - void LKG_mode(bool mode); - bool write(uint16_t address, uint8_t val); - bool write(uint16_t address, uint16_t val); - bool write(uint16_t address, uint32_t val); - bool read(uint16_t address, uint8_t *val); - bool read(uint16_t address, uint16_t *val); - bool read(uint16_t address, uint32_t *val); - uint8_t calcChecksum(); - void saveChecksum(); - bool checksumValid(); + PrefHandler(); + PrefHandler(DeviceId id); + ~PrefHandler(); + void LKG_mode(bool mode); + bool write(uint16_t address, uint8_t val); + bool write(uint16_t address, uint16_t val); + bool write(uint16_t address, uint32_t val); + bool read(uint16_t address, uint8_t *val); + bool read(uint16_t address, uint16_t *val); + bool read(uint16_t address, uint32_t *val); + uint8_t calcChecksum(); + void saveChecksum(); + bool checksumValid(); void forceCacheWrite(); - bool isEnabled(); - void setEnabledStatus(bool en); - static bool setDeviceStatus(uint16_t device, bool enabled); + bool isEnabled(); + void setEnabledStatus(bool en); + static bool setDeviceStatus(uint16_t device, bool enabled); private: - uint32_t base_address; //base address for the parent device - uint32_t lkg_address; - bool use_lkg; //use last known good config? - bool enabled; - int position; //position within the device table - void initDevTable(); + uint32_t base_address; //base address for the parent device + uint32_t lkg_address; + bool use_lkg; //use last known good config? + bool enabled; + int position; //position within the device table + void initDevTable(); }; #endif diff --git a/SerialConsole.cpp b/SerialConsole.cpp index 3a311fb..6a85e44 100644 --- a/SerialConsole.cpp +++ b/SerialConsole.cpp @@ -31,216 +31,216 @@ extern PrefHandler *sysPrefs; uint8_t systype; SerialConsole::SerialConsole(MemCache* memCache) : - memCache(memCache), heartbeat(NULL) { - init(); + memCache(memCache), heartbeat(NULL) { + init(); } SerialConsole::SerialConsole(MemCache* memCache, Heartbeat* heartbeat) : - memCache(memCache), heartbeat(heartbeat) { - init(); + memCache(memCache), heartbeat(heartbeat) { + init(); } void SerialConsole::init() { - handlingEvent = false; + handlingEvent = false; - //State variables for serial console - ptrBuffer = 0; - state = STATE_ROOT_MENU; - loopcount=0; - cancel=false; + //State variables for serial console + ptrBuffer = 0; + state = STATE_ROOT_MENU; + loopcount=0; + cancel=false; + + sysPrefs->read(EESYS_SYSTEM_TYPE, &systype); - sysPrefs->read(EESYS_SYSTEM_TYPE, &systype); - } void SerialConsole::loop() { - if(!cancel) + if(!cancel) { - if(loopcount++==350000){ - //DeviceManager::getInstance()->sendMessage(DEVICE_WIFI, ICHIP2128, MSG_CONFIG_CHANGE, NULL); - DeviceManager::getInstance()->updateWifi(); - cancel=true; - } - } - if (handlingEvent == false) { - if (SerialUSB.available()) { - serialEvent(); - } - } + if(loopcount++==350000) { + //DeviceManager::getInstance()->sendMessage(DEVICE_WIFI, ICHIP2128, MSG_CONFIG_CHANGE, NULL); + DeviceManager::getInstance()->updateWifi(); + cancel=true; + } + } + if (handlingEvent == false) { + if (SerialUSB.available()) { + serialEvent(); + } + } } void SerialConsole::printMenu() { - MotorController* motorController = (MotorController*) DeviceManager::getInstance()->getMotorController(); - Throttle *accelerator = DeviceManager::getInstance()->getAccelerator(); - Throttle *brake = DeviceManager::getInstance()->getBrake(); - ICHIPWIFI *wifi = (ICHIPWIFI*) DeviceManager::getInstance()->getDeviceByType(DEVICE_WIFI); - - //Show build # here as well in case people are using the native port and don't get to see the start up messages - SerialUSB.print("Build number: "); - SerialUSB.println(CFG_BUILD_NUM); - if (motorController) { - SerialUSB.println( - "Motor Controller Status: isRunning: " + String(motorController->isRunning()) + " isFaulted: " + String(motorController->isFaulted())); - } - SerialUSB.println("System Menu:"); - SerialUSB.println(); - SerialUSB.println("Enable line endings of some sort (LF, CR, CRLF)"); - SerialUSB.println(); - SerialUSB.println("Short Commands:"); - SerialUSB.println("h = help (displays this message)"); - if (heartbeat != NULL) { - SerialUSB.println("L = show raw analog/digital input/output values (toggle)"); - } - SerialUSB.println("K = set all outputs high"); - SerialUSB.println("J = set all outputs low"); - //SerialUSB.println("U,I = test EEPROM routines"); - SerialUSB.println("E = dump system eeprom values"); - SerialUSB.println("z = detect throttle min/max, num throttles and subtype"); - SerialUSB.println("Z = save throttle values"); - SerialUSB.println("b = detect brake min/max"); - SerialUSB.println("B = save brake values"); - SerialUSB.println("p = enable wifi passthrough (reboot required to resume normal operation)"); - SerialUSB.println("S = show possible device IDs"); - SerialUSB.println("w = GEVCU 4.2 reset wifi to factory defaults, setup GEVCU ad-hoc network"); - SerialUSB.println("W = GEVCU 5.2 reset wifi to factory defaults, setup GEVCU as Access Point"); - SerialUSB.println("s = Scan WiFi for nearby access points"); - SerialUSB.println("A = Autocompensate ADC inputs"); - SerialUSB.println(); - SerialUSB.println("Config Commands (enter command=newvalue). Current values shown in parenthesis:"); + MotorController* motorController = (MotorController*) DeviceManager::getInstance()->getMotorController(); + Throttle *accelerator = DeviceManager::getInstance()->getAccelerator(); + Throttle *brake = DeviceManager::getInstance()->getBrake(); + ICHIPWIFI *wifi = (ICHIPWIFI*) DeviceManager::getInstance()->getDeviceByType(DEVICE_WIFI); + + //Show build # here as well in case people are using the native port and don't get to see the start up messages + SerialUSB.print("Build number: "); + SerialUSB.println(CFG_BUILD_NUM); + if (motorController) { + SerialUSB.println( + "Motor Controller Status: isRunning: " + String(motorController->isRunning()) + " isFaulted: " + String(motorController->isFaulted())); + } + SerialUSB.println("System Menu:"); + SerialUSB.println(); + SerialUSB.println("Enable line endings of some sort (LF, CR, CRLF)"); SerialUSB.println(); + SerialUSB.println("Short Commands:"); + SerialUSB.println("h = help (displays this message)"); + if (heartbeat != NULL) { + SerialUSB.println("L = show raw analog/digital input/output values (toggle)"); + } + SerialUSB.println("K = set all outputs high"); + SerialUSB.println("J = set all outputs low"); + //SerialUSB.println("U,I = test EEPROM routines"); + SerialUSB.println("E = dump system eeprom values"); + SerialUSB.println("z = detect throttle min/max, num throttles and subtype"); + SerialUSB.println("Z = save throttle values"); + SerialUSB.println("b = detect brake min/max"); + SerialUSB.println("B = save brake values"); + SerialUSB.println("p = enable wifi passthrough (reboot required to resume normal operation)"); + SerialUSB.println("S = show possible device IDs"); + SerialUSB.println("w = GEVCU 4.2 reset wifi to factory defaults, setup GEVCU ad-hoc network"); + SerialUSB.println("W = GEVCU 5.2 reset wifi to factory defaults, setup GEVCU as Access Point"); + SerialUSB.println("s = Scan WiFi for nearby access points"); + SerialUSB.println("A = Autocompensate ADC inputs"); + SerialUSB.println(); + SerialUSB.println("Config Commands (enter command=newvalue). Current values shown in parenthesis:"); + SerialUSB.println(); + Logger::console("LOGLEVEL=%i - set log level (0=debug, 1=info, 2=warn, 3=error, 4=off)", Logger::getLogLevel()); + Logger::console("LOGLEVEL=%i - set log level (0=debug, 1=info, 2=warn, 3=error, 4=off)", Logger::getLogLevel()); - Logger::console("LOGLEVEL=%i - set log level (0=debug, 1=info, 2=warn, 3=error, 4=off)", Logger::getLogLevel()); - - sysPrefs->read(EESYS_SYSTEM_TYPE, &systype); - Logger::console("SYSTYPE=%i - Set board revision (Dued=2, GEVCU3=3, GEVCU4-5=4, GEVCU6.2=6)", systype); - - uint16_t val; - sysPrefs->read(EESYS_ADC0_OFFSET, &val); - Logger::console("ADC0OFF=%i - set ADC0 offset", val); - sysPrefs->read(EESYS_ADC0_GAIN, &val); - Logger::console("ADC0GAIN=%i - set ADC0 gain (1024 is 1 gain)", val); - sysPrefs->read(EESYS_ADC1_OFFSET, &val); - Logger::console("ADC1OFF=%i - set ADC1 offset", val); - sysPrefs->read(EESYS_ADC1_GAIN, &val); - Logger::console("ADC1GAIN=%i - set ADC1 gain (1024 is 1 gain)", val); - sysPrefs->read(EESYS_ADC2_OFFSET, &val); - Logger::console("ADC2OFF=%i - set ADC2 offset", val); - sysPrefs->read(EESYS_ADC2_GAIN, &val); - Logger::console("ADC2GAIN=%i - set ADC2 gain (1024 is 1 gain)", val); - sysPrefs->read(EESYS_ADC3_OFFSET, &val); - Logger::console("ADC3OFF=%i - set ADC3 offset", val); - sysPrefs->read(EESYS_ADC3_GAIN, &val); - Logger::console("ADC3GAIN=%i - set ADC3 gain (1024 is 1 gain)", val); - - if (systype > 4) - { - sysPrefs->read(EESYS_ADC_PACKH_OFFSET, &val); - Logger::console("ADCPACKHOFF=%i - set pack high ADC offset", val); - sysPrefs->read(EESYS_ADC_PACKH_GAIN, &val); - Logger::console("ADCPACKHGAIN=%i - set pack high ADC gain (1024 is 1 gain)", val); - sysPrefs->read(EESYS_ADC_PACKL_OFFSET, &val); - Logger::console("ADCPACKLOFF=%i - set pack low ADC offset", val); - sysPrefs->read(EESYS_ADC_PACKL_GAIN, &val); - Logger::console("ADCPACKLGAIN=%i - set pack low ADC gain (1024 is 1 gain)", val); - sysPrefs->read(EESYS_ADC_PACKC_OFFSET, &val); - Logger::console("ADCPACKCOFF=%i - set pack current offset", val); - sysPrefs->read(EESYS_ADC_PACKC_GAIN, &val); - Logger::console("ADCPACKCGAIN=%i - set pack current gain (1024 is 1 gain)", val); - - } - - DeviceManager::getInstance()->printDeviceList(); - - if (motorController && motorController->getConfiguration()) { - MotorControllerConfiguration *config = (MotorControllerConfiguration *) motorController->getConfiguration(); - - SerialUSB.println(); - SerialUSB.println("MOTOR CONTROLS"); - SerialUSB.println(); - Logger::console("TORQ=%i - Set torque upper limit (tenths of a Nm)", config->torqueMax); - Logger::console("RPM=%i - Set maximum RPM", config->speedMax); - Logger::console("REVLIM=%i - How much torque to allow in reverse (Tenths of a percent)", config->reversePercent); - - Logger::console("COOLFAN=%i - Digital output to turn on cooling fan(0-7, 255 for none)", config->coolFan); - Logger::console("COOLON=%i - Inverter temperature C to turn cooling on", config->coolOn); - Logger::console("COOLOFF=%i - Inverter temperature C to turn cooling off", config->coolOff); - Logger::console("BRAKELT = %i - Digital output to turn on brakelight (0-7, 255 for none)", config->brakeLight); - Logger::console("REVLT=%i - Digital output to turn on reverse light (0-7, 255 for none)", config->revLight); - Logger::console("ENABLEIN=%i - Digital input to enable motor controller (0-3, 255 for none)", config->enableIn); - Logger::console("REVIN=%i - Digital input to reverse motor rotation (0-3, 255 for none)", config->reverseIn); - - } - - - if (accelerator && accelerator->getConfiguration()) { - PotThrottleConfiguration *config = (PotThrottleConfiguration *) accelerator->getConfiguration(); - SerialUSB.println(); - SerialUSB.println("THROTTLE CONTROLS"); - SerialUSB.println(); - - Logger::console("TPOT=%i - Number of pots to use (1 or 2)", config->numberPotMeters); - Logger::console("TTYPE=%i - Set throttle subtype (1=std linear, 2=inverse)", config->throttleSubType); - Logger::console("T1ADC=%i - Set throttle 1 ADC pin", config->AdcPin1); - Logger::console("T1MN=%i - Set throttle 1 min value", config->minimumLevel1); - Logger::console("T1MX=%i - Set throttle 1 max value", config->maximumLevel1); - Logger::console("T2ADC=%i - Set throttle 2 ADC pin", config->AdcPin2); - Logger::console("T2MN=%i - Set throttle 2 min value", config->minimumLevel2); - Logger::console("T2MX=%i - Set throttle 2 max value", config->maximumLevel2); - Logger::console("TRGNMAX=%i - Tenths of a percent of pedal where regen is at max", config->positionRegenMaximum); - Logger::console("TRGNMIN=%i - Tenths of a percent of pedal where regen is at min", config->positionRegenMinimum); - Logger::console("TFWD=%i - Tenths of a percent of pedal where forward motion starts", config->positionForwardMotionStart); - Logger::console("TMAP=%i - Tenths of a percent of pedal where 50% throttle will be", config->positionHalfPower); - Logger::console("TMINRN=%i - Percent of full torque to use for min throttle regen", config->minimumRegen); - Logger::console("TMAXRN=%i - Percent of full torque to use for max throttle regen", config->maximumRegen); - Logger::console("TCREEP=%i - Percent of full torque to use for creep (0=disable)", config->creep); - } - - if (brake && brake->getConfiguration()) { - PotThrottleConfiguration *config = (PotThrottleConfiguration *) brake->getConfiguration(); - SerialUSB.println(); - SerialUSB.println("BRAKE CONTROLS"); - SerialUSB.println(); - - Logger::console("B1ADC=%i - Set brake ADC pin", config->AdcPin1); - Logger::console("B1MN=%i - Set brake min value", config->minimumLevel1); - Logger::console("B1MX=%i - Set brake max value", config->maximumLevel1); - Logger::console("BMINR=%i - Percent of full torque for start of brake regen", config->minimumRegen); - Logger::console("BMAXR=%i - Percent of full torque for maximum brake regen", config->maximumRegen); - } - - if (motorController && motorController->getConfiguration()) { - MotorControllerConfiguration *config = (MotorControllerConfiguration *) motorController->getConfiguration(); - SerialUSB.println(); - SerialUSB.println("PRECHARGE CONTROLS"); - SerialUSB.println(); - - Logger::console("PREDELAY=%i - Precharge delay time in milliseconds ", config->prechargeR); - Logger::console("PRELAY=%i - Which output to use for precharge contactor (255 to disable)", config->prechargeRelay); - Logger::console("MRELAY=%i - Which output to use for main contactor (255 to disable)", config->mainContactorRelay); - SerialUSB.println(); - SerialUSB.println("WIRELESS LAN COMMANDS"); - SerialUSB.println(); - Logger::console("WIREACH=anycommand - sends ATi+anycommand to WiReach Module"); - Logger::console("SSID=anyname - sets broadcast ID to anyname"); - Logger::console("IP=192.168.3.10 - sets IP of website to whatever IP is entered"); - Logger::console("PWD=secret - sets website configuration password to entered string"); - Logger::console("CHANNEL=4 - sets website wireless channel - 1 to 11"); - Logger::console("SECURITY=password - sets website wireless connection security for WPA2-AES and password"); - - SerialUSB.println(); - SerialUSB.println("OTHER"); - SerialUSB.println(); - - Logger::console("NOMV=%i - Fully charged pack voltage that automatically resets kWh counter", config->nominalVolt/10); - Logger::console("CAPACITY=%i - capacity of battery pack in ampere-hours", config->capacity); - - Logger::console("kWh=%d - kiloWatt Hours of energy used", config->kilowattHrs/3600000); - Logger::console("OUTPUT=<0-7> - toggles state of specified digital output"); - Logger::console("NUKE=1 - Resets all device settings in EEPROM. You have been warned."); - } - - + sysPrefs->read(EESYS_SYSTEM_TYPE, &systype); + Logger::console("SYSTYPE=%i - Set board revision (Dued=2, GEVCU3=3, GEVCU4-5=4, GEVCU6.2=6)", systype); + + uint16_t val; + sysPrefs->read(EESYS_ADC0_OFFSET, &val); + Logger::console("ADC0OFF=%i - set ADC0 offset", val); + sysPrefs->read(EESYS_ADC0_GAIN, &val); + Logger::console("ADC0GAIN=%i - set ADC0 gain (1024 is 1 gain)", val); + sysPrefs->read(EESYS_ADC1_OFFSET, &val); + Logger::console("ADC1OFF=%i - set ADC1 offset", val); + sysPrefs->read(EESYS_ADC1_GAIN, &val); + Logger::console("ADC1GAIN=%i - set ADC1 gain (1024 is 1 gain)", val); + sysPrefs->read(EESYS_ADC2_OFFSET, &val); + Logger::console("ADC2OFF=%i - set ADC2 offset", val); + sysPrefs->read(EESYS_ADC2_GAIN, &val); + Logger::console("ADC2GAIN=%i - set ADC2 gain (1024 is 1 gain)", val); + sysPrefs->read(EESYS_ADC3_OFFSET, &val); + Logger::console("ADC3OFF=%i - set ADC3 offset", val); + sysPrefs->read(EESYS_ADC3_GAIN, &val); + Logger::console("ADC3GAIN=%i - set ADC3 gain (1024 is 1 gain)", val); + + if (systype > 4) + { + sysPrefs->read(EESYS_ADC_PACKH_OFFSET, &val); + Logger::console("ADCPACKHOFF=%i - set pack high ADC offset", val); + sysPrefs->read(EESYS_ADC_PACKH_GAIN, &val); + Logger::console("ADCPACKHGAIN=%i - set pack high ADC gain (1024 is 1 gain)", val); + sysPrefs->read(EESYS_ADC_PACKL_OFFSET, &val); + Logger::console("ADCPACKLOFF=%i - set pack low ADC offset", val); + sysPrefs->read(EESYS_ADC_PACKL_GAIN, &val); + Logger::console("ADCPACKLGAIN=%i - set pack low ADC gain (1024 is 1 gain)", val); + sysPrefs->read(EESYS_ADC_PACKC_OFFSET, &val); + Logger::console("ADCPACKCOFF=%i - set pack current offset", val); + sysPrefs->read(EESYS_ADC_PACKC_GAIN, &val); + Logger::console("ADCPACKCGAIN=%i - set pack current gain (1024 is 1 gain)", val); + + } + + DeviceManager::getInstance()->printDeviceList(); + + if (motorController && motorController->getConfiguration()) { + MotorControllerConfiguration *config = (MotorControllerConfiguration *) motorController->getConfiguration(); + + SerialUSB.println(); + SerialUSB.println("MOTOR CONTROLS"); + SerialUSB.println(); + Logger::console("TORQ=%i - Set torque upper limit (tenths of a Nm)", config->torqueMax); + Logger::console("RPM=%i - Set maximum RPM", config->speedMax); + Logger::console("REVLIM=%i - How much torque to allow in reverse (Tenths of a percent)", config->reversePercent); + + Logger::console("COOLFAN=%i - Digital output to turn on cooling fan(0-7, 255 for none)", config->coolFan); + Logger::console("COOLON=%i - Inverter temperature C to turn cooling on", config->coolOn); + Logger::console("COOLOFF=%i - Inverter temperature C to turn cooling off", config->coolOff); + Logger::console("BRAKELT = %i - Digital output to turn on brakelight (0-7, 255 for none)", config->brakeLight); + Logger::console("REVLT=%i - Digital output to turn on reverse light (0-7, 255 for none)", config->revLight); + Logger::console("ENABLEIN=%i - Digital input to enable motor controller (0-3, 255 for none)", config->enableIn); + Logger::console("REVIN=%i - Digital input to reverse motor rotation (0-3, 255 for none)", config->reverseIn); + + } + + + if (accelerator && accelerator->getConfiguration()) { + PotThrottleConfiguration *config = (PotThrottleConfiguration *) accelerator->getConfiguration(); + SerialUSB.println(); + SerialUSB.println("THROTTLE CONTROLS"); + SerialUSB.println(); + + Logger::console("TPOT=%i - Number of pots to use (1 or 2)", config->numberPotMeters); + Logger::console("TTYPE=%i - Set throttle subtype (1=std linear, 2=inverse)", config->throttleSubType); + Logger::console("T1ADC=%i - Set throttle 1 ADC pin", config->AdcPin1); + Logger::console("T1MN=%i - Set throttle 1 min value", config->minimumLevel1); + Logger::console("T1MX=%i - Set throttle 1 max value", config->maximumLevel1); + Logger::console("T2ADC=%i - Set throttle 2 ADC pin", config->AdcPin2); + Logger::console("T2MN=%i - Set throttle 2 min value", config->minimumLevel2); + Logger::console("T2MX=%i - Set throttle 2 max value", config->maximumLevel2); + Logger::console("TRGNMAX=%i - Tenths of a percent of pedal where regen is at max", config->positionRegenMaximum); + Logger::console("TRGNMIN=%i - Tenths of a percent of pedal where regen is at min", config->positionRegenMinimum); + Logger::console("TFWD=%i - Tenths of a percent of pedal where forward motion starts", config->positionForwardMotionStart); + Logger::console("TMAP=%i - Tenths of a percent of pedal where 50% throttle will be", config->positionHalfPower); + Logger::console("TMINRN=%i - Percent of full torque to use for min throttle regen", config->minimumRegen); + Logger::console("TMAXRN=%i - Percent of full torque to use for max throttle regen", config->maximumRegen); + Logger::console("TCREEP=%i - Percent of full torque to use for creep (0=disable)", config->creep); + } + + if (brake && brake->getConfiguration()) { + PotThrottleConfiguration *config = (PotThrottleConfiguration *) brake->getConfiguration(); + SerialUSB.println(); + SerialUSB.println("BRAKE CONTROLS"); + SerialUSB.println(); + + Logger::console("B1ADC=%i - Set brake ADC pin", config->AdcPin1); + Logger::console("B1MN=%i - Set brake min value", config->minimumLevel1); + Logger::console("B1MX=%i - Set brake max value", config->maximumLevel1); + Logger::console("BMINR=%i - Percent of full torque for start of brake regen", config->minimumRegen); + Logger::console("BMAXR=%i - Percent of full torque for maximum brake regen", config->maximumRegen); + } + + if (motorController && motorController->getConfiguration()) { + MotorControllerConfiguration *config = (MotorControllerConfiguration *) motorController->getConfiguration(); + SerialUSB.println(); + SerialUSB.println("PRECHARGE CONTROLS"); + SerialUSB.println(); + + Logger::console("PREDELAY=%i - Precharge delay time in milliseconds ", config->prechargeR); + Logger::console("PRELAY=%i - Which output to use for precharge contactor (255 to disable)", config->prechargeRelay); + Logger::console("MRELAY=%i - Which output to use for main contactor (255 to disable)", config->mainContactorRelay); + SerialUSB.println(); + SerialUSB.println("WIRELESS LAN COMMANDS"); + SerialUSB.println(); + Logger::console("WIREACH=anycommand - sends ATi+anycommand to WiReach Module"); + Logger::console("SSID=anyname - sets broadcast ID to anyname"); + Logger::console("IP=192.168.3.10 - sets IP of website to whatever IP is entered"); + Logger::console("PWD=secret - sets website configuration password to entered string"); + Logger::console("CHANNEL=4 - sets website wireless channel - 1 to 11"); + Logger::console("SECURITY=password - sets website wireless connection security for WPA2-AES and password"); + + SerialUSB.println(); + SerialUSB.println("OTHER"); + SerialUSB.println(); + + Logger::console("NOMV=%i - Fully charged pack voltage that automatically resets kWh counter", config->nominalVolt/10); + Logger::console("CAPACITY=%i - capacity of battery pack in ampere-hours", config->capacity); + + Logger::console("kWh=%d - kiloWatt Hours of energy used", config->kilowattHrs/3600000); + Logger::console("OUTPUT=<0-7> - toggles state of specified digital output"); + Logger::console("NUKE=1 - Resets all device settings in EEPROM. You have been warned."); + } + + } /* There is a help menu (press H or h or ?) @@ -250,683 +250,683 @@ void SerialConsole::printMenu() { by sending line ending (LF, CR, or both) */ void SerialConsole::serialEvent() { - int incoming; - incoming = SerialUSB.read(); - if (incoming == -1) { //false alarm.... - return; - } - - if (incoming == 10 || incoming == 13) { //command done. Parse it. - handleConsoleCmd(); - ptrBuffer = 0; //reset line counter once the line has been processed - } else { - cmdBuffer[ptrBuffer++] = (unsigned char) incoming; - if (ptrBuffer > 79) - ptrBuffer = 79; - } + int incoming; + incoming = SerialUSB.read(); + if (incoming == -1) { //false alarm.... + return; + } + + if (incoming == 10 || incoming == 13) { //command done. Parse it. + handleConsoleCmd(); + ptrBuffer = 0; //reset line counter once the line has been processed + } else { + cmdBuffer[ptrBuffer++] = (unsigned char) incoming; + if (ptrBuffer > 79) + ptrBuffer = 79; + } } void SerialConsole::handleConsoleCmd() { - handlingEvent = true; - - if (state == STATE_ROOT_MENU) { - if (ptrBuffer == 1) { //command is a single ascii character - handleShortCmd(); - } else { //if cmd over 1 char then assume (for now) that it is a config line - handleConfigCmd(); - } - } - handlingEvent = false; + handlingEvent = true; + + if (state == STATE_ROOT_MENU) { + if (ptrBuffer == 1) { //command is a single ascii character + handleShortCmd(); + } else { //if cmd over 1 char then assume (for now) that it is a config line + handleConfigCmd(); + } + } + handlingEvent = false; } /*For simplicity the configuration setting code uses four characters for each configuration choice. This makes things easier for comparison purposes. */ void SerialConsole::handleConfigCmd() { - PotThrottleConfiguration *acceleratorConfig = NULL; - PotThrottleConfiguration *brakeConfig = NULL; - MotorControllerConfiguration *motorConfig = NULL; - - Throttle *accelerator = DeviceManager::getInstance()->getAccelerator(); - Throttle *brake = DeviceManager::getInstance()->getBrake(); - MotorController *motorController = DeviceManager::getInstance()->getMotorController(); - int i; - int newValue; - bool updateWifi = true; - - //Logger::debug("Cmd size: %i", ptrBuffer); - if (ptrBuffer < 6) - return; //4 digit command, =, value is at least 6 characters - cmdBuffer[ptrBuffer] = 0; //make sure to null terminate - String cmdString = String(); - unsigned char whichEntry = '0'; - i = 0; - - while (cmdBuffer[i] != '=' && i < ptrBuffer) { - cmdString.concat(String(cmdBuffer[i++])); - } - i++; //skip the = - if (i >= ptrBuffer) - { - Logger::console("Command needs a value..ie TORQ=3000"); - Logger::console(""); - return; //or, we could use this to display the parameter instead of setting - } - - if (accelerator) - acceleratorConfig = (PotThrottleConfiguration *) accelerator->getConfiguration(); - if (brake) - brakeConfig = (PotThrottleConfiguration *) brake->getConfiguration(); - if (motorController) - motorConfig = (MotorControllerConfiguration *) motorController->getConfiguration(); - - // strtol() is able to parse also hex values (e.g. a string "0xCAFE"), useful for enable/disable by device id - newValue = strtol((char *) (cmdBuffer + i), NULL, 0); - - cmdString.toUpperCase(); - if (cmdString == String("TORQ") && motorConfig) { - Logger::console("Setting Torque Limit to %i", newValue); - motorConfig->torqueMax = newValue; - motorController->saveConfiguration(); - } else if (cmdString == String("RPM") && motorConfig) { - Logger::console("Setting RPM Limit to %i", newValue); - motorConfig->speedMax = newValue; - motorController->saveConfiguration(); - } else if (cmdString == String("REVLIM") && motorConfig) { - Logger::console("Setting Reverse Limit to %i", newValue); - motorConfig->reversePercent = newValue; - motorController->saveConfiguration(); - } else if (cmdString == String("TPOT") && acceleratorConfig) { - Logger::console("Setting # of Throttle Pots to %i", newValue); - acceleratorConfig->numberPotMeters = newValue; - accelerator->saveConfiguration(); - } else if (cmdString == String("TTYPE") && acceleratorConfig) { - Logger::console("Setting Throttle Subtype to %i", newValue); - acceleratorConfig->throttleSubType = newValue; - accelerator->saveConfiguration(); - } else if (cmdString == String("T1ADC") && acceleratorConfig) { - Logger::console("Setting Throttle1 ADC pin to %i", newValue); - acceleratorConfig->AdcPin1 = newValue; - accelerator->saveConfiguration(); - } else if (cmdString == String("T1MN") && acceleratorConfig) { - Logger::console("Setting Throttle1 Min to %i", newValue); - acceleratorConfig->minimumLevel1 = newValue; - accelerator->saveConfiguration(); - } else if (cmdString == String("T1MX") && acceleratorConfig) { - Logger::console("Setting Throttle1 Max to %i", newValue); - acceleratorConfig->maximumLevel1 = newValue; - accelerator->saveConfiguration(); - } - else if (cmdString == String("T2ADC") && acceleratorConfig) { - Logger::console("Setting Throttle2 ADC pin to %i", newValue); - acceleratorConfig->AdcPin2 = newValue; - accelerator->saveConfiguration(); - } else if (cmdString == String("T2MN") && acceleratorConfig) { - Logger::console("Setting Throttle2 Min to %i", newValue); - acceleratorConfig->minimumLevel2 = newValue; - accelerator->saveConfiguration(); - } else if (cmdString == String("T2MX") && acceleratorConfig) { - Logger::console("Setting Throttle2 Max to %i", newValue); - acceleratorConfig->maximumLevel2 = newValue; - accelerator->saveConfiguration(); - } else if (cmdString == String("TRGNMAX") && acceleratorConfig) { - Logger::console("Setting Throttle Regen maximum to %i", newValue); - acceleratorConfig->positionRegenMaximum = newValue; - accelerator->saveConfiguration(); - } else if (cmdString == String("TRGNMIN") && acceleratorConfig) { - Logger::console("Setting Throttle Regen minimum to %i", newValue); - acceleratorConfig->positionRegenMinimum = newValue; - accelerator->saveConfiguration(); - } else if (cmdString == String("TFWD") && acceleratorConfig) { - Logger::console("Setting Throttle Forward Start to %i", newValue); - acceleratorConfig->positionForwardMotionStart = newValue; - accelerator->saveConfiguration(); - } else if (cmdString == String("TMAP") && acceleratorConfig) { - Logger::console("Setting Throttle MAP Point to %i", newValue); - acceleratorConfig->positionHalfPower = newValue; - accelerator->saveConfiguration(); - } else if (cmdString == String("TMINRN") && acceleratorConfig) { - Logger::console("Setting Throttle Regen Minimum Strength to %i", newValue); - acceleratorConfig->minimumRegen = newValue; - accelerator->saveConfiguration(); - } else if (cmdString == String("TMAXRN") && acceleratorConfig) { - Logger::console("Setting Throttle Regen Maximum Strength to %i", newValue); - acceleratorConfig->maximumRegen = newValue; - accelerator->saveConfiguration(); - } else if (cmdString == String("TCREEP") && acceleratorConfig) { - Logger::console("Setting Throttle Creep Strength to %i", newValue); - acceleratorConfig->creep = newValue; - accelerator->saveConfiguration(); - } else if (cmdString == String("BMAXR") && brakeConfig) { - Logger::console("Setting Max Brake Regen to %i", newValue); - brakeConfig->maximumRegen = newValue; - brake->saveConfiguration(); - } else if (cmdString == String("BMINR") && brakeConfig) { - Logger::console("Setting Min Brake Regen to %i", newValue); - brakeConfig->minimumRegen = newValue; - brake->saveConfiguration(); - } - else if (cmdString == String("B1ADC") && acceleratorConfig) { - Logger::console("Setting Brake ADC pin to %i", newValue); - brakeConfig->AdcPin1 = newValue; - accelerator->saveConfiguration(); - } else if (cmdString == String("B1MX") && brakeConfig) { - Logger::console("Setting Brake Max to %i", newValue); - brakeConfig->maximumLevel1 = newValue; - brake->saveConfiguration(); - } else if (cmdString == String("B1MN") && brakeConfig) { - Logger::console("Setting Brake Min to %i", newValue); - brakeConfig->minimumLevel1 = newValue; - brake->saveConfiguration(); - } else if (cmdString == String("PREC") && motorConfig) { - Logger::console("Setting Precharge Capacitance to %i", newValue); - motorConfig->kilowattHrs = newValue; - motorController->saveConfiguration(); - } else if (cmdString == String("PREDELAY") && motorConfig) { - Logger::console("Setting Precharge Time Delay to %i milliseconds", newValue); - motorConfig->prechargeR = newValue; - motorController->saveConfiguration(); - } else if (cmdString == String("NOMV") && motorConfig) { - Logger::console("Setting fully charged voltage to %d vdc", newValue); - motorConfig->nominalVolt = newValue * 10; - motorController->saveConfiguration(); - } else if (cmdString == String("BRAKELT") && motorConfig) { - motorConfig->brakeLight = newValue; - motorController->saveConfiguration(); - Logger::console("Brake light output set to DOUT%i.",newValue); - } else if (cmdString == String("REVLT") && motorConfig) { - motorConfig->revLight = newValue; - motorController->saveConfiguration(); - Logger::console("Reverse light output set to DOUT%i.",newValue); - } else if (cmdString == String("ENABLEIN") && motorConfig) { - motorConfig->enableIn = newValue; - motorController->saveConfiguration(); - Logger::console("Motor Enable input set to DIN%i.",newValue); - } else if (cmdString == String("REVIN") && motorConfig) { - motorConfig->reverseIn = newValue; - motorController->saveConfiguration(); - Logger::console("Motor Reverse input set to DIN%i.",newValue); - } else if (cmdString == String("MRELAY") && motorConfig) { - Logger::console("Setting Main Contactor relay output to DOUT%i", newValue); - motorConfig->mainContactorRelay = newValue; - motorController->saveConfiguration(); - } else if (cmdString == String("PRELAY") && motorConfig) { - Logger::console("Setting Precharge Relay output to DOUT%i", newValue); - motorConfig->prechargeRelay = newValue; - motorController->saveConfiguration(); - } else if (cmdString == String("ENABLE")) { - if (PrefHandler::setDeviceStatus(newValue, true)) { - sysPrefs->forceCacheWrite(); //just in case someone takes us literally and power cycles quickly - Logger::console("Successfully enabled device.(%X, %d) Power cycle to activate.", newValue, newValue); - } - else { - Logger::console("Invalid device ID (%X, %d)", newValue, newValue); - } - } else if (cmdString == String("DISABLE")) { - if (PrefHandler::setDeviceStatus(newValue, false)) { - sysPrefs->forceCacheWrite(); //just in case someone takes us literally and power cycles quickly - Logger::console("Successfully disabled device. Power cycle to deactivate."); - } - else { - Logger::console("Invalid device ID (%X, %d)", newValue, newValue); - } - } else if (cmdString == String("SYSTYPE")) { - if (newValue < 7 && newValue > 0) { - sysPrefs->write(EESYS_SYSTEM_TYPE, (uint8_t)(newValue)); - sysPrefs->saveChecksum(); - sysPrefs->forceCacheWrite(); //just in case someone takes us literally and power cycles quickly - Logger::console("System type updated. Power cycle to apply."); - } - else Logger::console("Invalid system type. Please enter a value 1 - 4"); - } else if (cmdString == String("ADC0OFF")) { - if (newValue >= 0 && newValue <= 65535) { - sysPrefs->write(EESYS_ADC0_OFFSET, (uint16_t)(newValue)); - sysPrefs->saveChecksum(); - setup_ADC_params(); //change takes immediate effect - } - else Logger::console("Invalid offset. Enter value from 0 to 65535"); - } else if (cmdString == String("ADC0GAIN")) { - if (newValue >= 0 && newValue <= 65535) { - sysPrefs->write(EESYS_ADC0_GAIN, (uint16_t)(newValue)); - sysPrefs->saveChecksum(); - setup_ADC_params(); //change takes immediate effect - } - else Logger::console("Invalid gain. Enter value from 0 to 65535"); - } else if (cmdString == String("ADC1OFF")) { - if (newValue >= 0 && newValue <= 65535) { - sysPrefs->write(EESYS_ADC1_OFFSET, (uint16_t)(newValue)); - sysPrefs->saveChecksum(); - setup_ADC_params(); //change takes immediate effect - } - else Logger::console("Invalid offset. Enter value from 0 to 65535"); - } else if (cmdString == String("ADC1GAIN")) { - if (newValue >= 0 && newValue <= 65535) { - sysPrefs->write(EESYS_ADC1_GAIN, (uint16_t)(newValue)); - sysPrefs->saveChecksum(); - setup_ADC_params(); //change takes immediate effect - } - else Logger::console("Invalid gain. Enter value from 0 to 65535"); - } else if (cmdString == String("ADC2OFF")) { - if (newValue >= 0 && newValue <= 65535) { - sysPrefs->write(EESYS_ADC2_OFFSET, (uint16_t)(newValue)); - sysPrefs->saveChecksum(); - setup_ADC_params(); //change takes immediate effect - } - else Logger::console("Invalid offset. Enter value from 0 to 65535"); - } else if (cmdString == String("ADC2GAIN")) { - if (newValue >= 0 && newValue <= 65535) { - sysPrefs->write(EESYS_ADC2_GAIN, (uint16_t)(newValue)); - sysPrefs->saveChecksum(); - setup_ADC_params(); //change takes immediate effect - } - else Logger::console("Invalid gain. Enter value from 0 to 65535"); - } else if (cmdString == String("ADC3OFF")) { - if (newValue >= 0 && newValue <= 65535) { - sysPrefs->write(EESYS_ADC3_OFFSET, (uint16_t)(newValue)); - sysPrefs->saveChecksum(); - setup_ADC_params(); //change takes immediate effect - } - else Logger::console("Invalid offset. Enter value from 0 to 65535"); - } else if (cmdString == String("ADC3GAIN")) { - if (newValue >= 0 && newValue <= 65535) { - sysPrefs->write(EESYS_ADC3_GAIN, (uint16_t)(newValue)); - sysPrefs->saveChecksum(); - setup_ADC_params(); //change takes immediate effect - } - else Logger::console("Invalid gain. Enter value from 0 to 65535"); - } else if (cmdString == String("ADCPACKHOFF")) { - if (newValue >= 0 && newValue <= 65535) { - sysPrefs->write(EESYS_ADC_PACKH_OFFSET, (uint16_t)(newValue)); - sysPrefs->saveChecksum(); - setup_ADC_params(); //change takes immediate effect - } - else Logger::console("Invalid offset. Enter value from 0 to 65535"); - } else if (cmdString == String("ADCPACKHGAIN")) { - if (newValue >= 0 && newValue <= 65535) { - sysPrefs->write(EESYS_ADC_PACKH_GAIN, (uint16_t)(newValue)); - sysPrefs->saveChecksum(); - setup_ADC_params(); //change takes immediate effect - } - else Logger::console("Invalid gain. Enter value from 0 to 65535"); - } else if (cmdString == String("ADCPACKLOFF")) { - if (newValue >= 0 && newValue <= 65535) { - sysPrefs->write(EESYS_ADC_PACKL_OFFSET, (uint16_t)(newValue)); - sysPrefs->saveChecksum(); - setup_ADC_params(); //change takes immediate effect - } - else Logger::console("Invalid offset. Enter value from 0 to 65535"); - } else if (cmdString == String("ADCPACKLGAIN")) { - if (newValue >= 0 && newValue <= 65535) { - sysPrefs->write(EESYS_ADC_PACKL_GAIN, (uint16_t)(newValue)); - sysPrefs->saveChecksum(); - setup_ADC_params(); //change takes immediate effect - } - else Logger::console("Invalid gain. Enter value from 0 to 65535"); - } else if (cmdString == String("ADCPACKCOFF")) { - if (newValue >= 0 && newValue <= 65535) { - sysPrefs->write(EESYS_ADC_PACKC_OFFSET, (uint16_t)(newValue)); - sysPrefs->saveChecksum(); - setup_ADC_params(); //change takes immediate effect - } - else Logger::console("Invalid offset. Enter value from 0 to 65535"); - } else if (cmdString == String("ADCPACKCGAIN")) { - if (newValue >= 0 && newValue <= 65535) { - sysPrefs->write(EESYS_ADC_PACKC_GAIN, (uint16_t)(newValue)); - sysPrefs->saveChecksum(); - setup_ADC_params(); //change takes immediate effect - } - else Logger::console("Invalid gain. Enter value from 0 to 65535"); - } else if (cmdString == String("LOGLEVEL")) { - switch (newValue) { - case 0: - Logger::setLoglevel(Logger::Debug); - Logger::console("setting loglevel to 'debug'"); - break; - case 1: - Logger::setLoglevel(Logger::Info); - Logger::console("setting loglevel to 'info'"); - break; - case 2: - Logger::console("setting loglevel to 'warning'"); - Logger::setLoglevel(Logger::Warn); - break; - case 3: - Logger::console("setting loglevel to 'error'"); - Logger::setLoglevel(Logger::Error); - break; - case 4: - Logger::console("setting loglevel to 'off'"); - Logger::setLoglevel(Logger::Off); - break; - } - sysPrefs->write(EESYS_LOG_LEVEL, (uint8_t)newValue); - sysPrefs->saveChecksum(); - - } else if (cmdString == String("WIREACH")) { - DeviceManager::getInstance()->sendMessage(DEVICE_WIFI, ICHIP2128, MSG_COMMAND, (void *)(cmdBuffer + i)); - Logger::info("sent \"AT+i%s\" to WiReach wireless LAN device", (cmdBuffer + i)); - DeviceManager::getInstance()->sendMessage(DEVICE_WIFI, ICHIP2128, MSG_COMMAND, (void *)"DOWN"); - updateWifi = false; - } else if (cmdString == String("SSID")) { - String cmdString = String(); - cmdString.concat("WLSI"); - cmdString.concat('='); - cmdString.concat((char *)(cmdBuffer + i)); - Logger::info("Sent \"%s\" to WiReach wireless LAN device", (cmdString.c_str())); - DeviceManager::getInstance()->sendMessage(DEVICE_WIFI, ICHIP2128, MSG_COMMAND, (void *)cmdString.c_str()); - DeviceManager::getInstance()->sendMessage(DEVICE_WIFI, ICHIP2128, MSG_COMMAND, (void *)"DOWN"); - updateWifi = false; - } else if (cmdString == String("IP")) { - String cmdString = String(); - cmdString.concat("DIP"); - cmdString.concat('='); - cmdString.concat((char *)(cmdBuffer + i)); - Logger::info("Sent \"%s\" to WiReach wireless LAN device", (cmdString.c_str())); - DeviceManager::getInstance()->sendMessage(DEVICE_WIFI, ICHIP2128, MSG_COMMAND, (void *)cmdString.c_str()); - DeviceManager::getInstance()->sendMessage(DEVICE_WIFI, ICHIP2128, MSG_COMMAND, (void *)"DOWN"); - updateWifi = false; - } else if (cmdString == String("CHANNEL")) { - String cmdString = String(); - cmdString.concat("WLCH"); - cmdString.concat('='); - cmdString.concat((char *)(cmdBuffer + i)); - Logger::info("Sent \"%s\" to WiReach wireless LAN device", (cmdString.c_str())); - DeviceManager::getInstance()->sendMessage(DEVICE_WIFI, ICHIP2128, MSG_COMMAND, (void *)cmdString.c_str()); - DeviceManager::getInstance()->sendMessage(DEVICE_WIFI, ICHIP2128, MSG_COMMAND, (void *)"DOWN"); - updateWifi = false; - } else if (cmdString == String("SECURITY")) { - String cmdString = String(); - cmdString.concat("WLPP"); - cmdString.concat('='); - cmdString.concat((char *)(cmdBuffer + i)); - Logger::info("Sent \"%s\" to WiReach wireless LAN device", (cmdString.c_str())); - DeviceManager::getInstance()->sendMessage(DEVICE_WIFI, ICHIP2128, MSG_COMMAND, (void *)cmdString.c_str()); - DeviceManager::getInstance()->sendMessage(DEVICE_WIFI, ICHIP2128, MSG_COMMAND, (void *)"DOWN"); - updateWifi = false; - - } else if (cmdString == String("PWD")) { - String cmdString = String(); - cmdString.concat("WPWD"); - cmdString.concat('='); - cmdString.concat((char *)(cmdBuffer + i)); - Logger::info("Sent \"%s\" to WiReach wireless LAN device", (cmdString.c_str())); - DeviceManager::getInstance()->sendMessage(DEVICE_WIFI, ICHIP2128, MSG_COMMAND, (void *)cmdString.c_str()); - DeviceManager::getInstance()->sendMessage(DEVICE_WIFI, ICHIP2128, MSG_COMMAND, (void *)"DOWN"); - updateWifi = false; - - } else if (cmdString == String("COOLFAN") && motorConfig) { - Logger::console("Cooling fan output updated to: %i", newValue); + PotThrottleConfiguration *acceleratorConfig = NULL; + PotThrottleConfiguration *brakeConfig = NULL; + MotorControllerConfiguration *motorConfig = NULL; + + Throttle *accelerator = DeviceManager::getInstance()->getAccelerator(); + Throttle *brake = DeviceManager::getInstance()->getBrake(); + MotorController *motorController = DeviceManager::getInstance()->getMotorController(); + int i; + int newValue; + bool updateWifi = true; + + //Logger::debug("Cmd size: %i", ptrBuffer); + if (ptrBuffer < 6) + return; //4 digit command, =, value is at least 6 characters + cmdBuffer[ptrBuffer] = 0; //make sure to null terminate + String cmdString = String(); + unsigned char whichEntry = '0'; + i = 0; + + while (cmdBuffer[i] != '=' && i < ptrBuffer) { + cmdString.concat(String(cmdBuffer[i++])); + } + i++; //skip the = + if (i >= ptrBuffer) + { + Logger::console("Command needs a value..ie TORQ=3000"); + Logger::console(""); + return; //or, we could use this to display the parameter instead of setting + } + + if (accelerator) + acceleratorConfig = (PotThrottleConfiguration *) accelerator->getConfiguration(); + if (brake) + brakeConfig = (PotThrottleConfiguration *) brake->getConfiguration(); + if (motorController) + motorConfig = (MotorControllerConfiguration *) motorController->getConfiguration(); + + // strtol() is able to parse also hex values (e.g. a string "0xCAFE"), useful for enable/disable by device id + newValue = strtol((char *) (cmdBuffer + i), NULL, 0); + + cmdString.toUpperCase(); + if (cmdString == String("TORQ") && motorConfig) { + Logger::console("Setting Torque Limit to %i", newValue); + motorConfig->torqueMax = newValue; + motorController->saveConfiguration(); + } else if (cmdString == String("RPM") && motorConfig) { + Logger::console("Setting RPM Limit to %i", newValue); + motorConfig->speedMax = newValue; + motorController->saveConfiguration(); + } else if (cmdString == String("REVLIM") && motorConfig) { + Logger::console("Setting Reverse Limit to %i", newValue); + motorConfig->reversePercent = newValue; + motorController->saveConfiguration(); + } else if (cmdString == String("TPOT") && acceleratorConfig) { + Logger::console("Setting # of Throttle Pots to %i", newValue); + acceleratorConfig->numberPotMeters = newValue; + accelerator->saveConfiguration(); + } else if (cmdString == String("TTYPE") && acceleratorConfig) { + Logger::console("Setting Throttle Subtype to %i", newValue); + acceleratorConfig->throttleSubType = newValue; + accelerator->saveConfiguration(); + } else if (cmdString == String("T1ADC") && acceleratorConfig) { + Logger::console("Setting Throttle1 ADC pin to %i", newValue); + acceleratorConfig->AdcPin1 = newValue; + accelerator->saveConfiguration(); + } else if (cmdString == String("T1MN") && acceleratorConfig) { + Logger::console("Setting Throttle1 Min to %i", newValue); + acceleratorConfig->minimumLevel1 = newValue; + accelerator->saveConfiguration(); + } else if (cmdString == String("T1MX") && acceleratorConfig) { + Logger::console("Setting Throttle1 Max to %i", newValue); + acceleratorConfig->maximumLevel1 = newValue; + accelerator->saveConfiguration(); + } + else if (cmdString == String("T2ADC") && acceleratorConfig) { + Logger::console("Setting Throttle2 ADC pin to %i", newValue); + acceleratorConfig->AdcPin2 = newValue; + accelerator->saveConfiguration(); + } else if (cmdString == String("T2MN") && acceleratorConfig) { + Logger::console("Setting Throttle2 Min to %i", newValue); + acceleratorConfig->minimumLevel2 = newValue; + accelerator->saveConfiguration(); + } else if (cmdString == String("T2MX") && acceleratorConfig) { + Logger::console("Setting Throttle2 Max to %i", newValue); + acceleratorConfig->maximumLevel2 = newValue; + accelerator->saveConfiguration(); + } else if (cmdString == String("TRGNMAX") && acceleratorConfig) { + Logger::console("Setting Throttle Regen maximum to %i", newValue); + acceleratorConfig->positionRegenMaximum = newValue; + accelerator->saveConfiguration(); + } else if (cmdString == String("TRGNMIN") && acceleratorConfig) { + Logger::console("Setting Throttle Regen minimum to %i", newValue); + acceleratorConfig->positionRegenMinimum = newValue; + accelerator->saveConfiguration(); + } else if (cmdString == String("TFWD") && acceleratorConfig) { + Logger::console("Setting Throttle Forward Start to %i", newValue); + acceleratorConfig->positionForwardMotionStart = newValue; + accelerator->saveConfiguration(); + } else if (cmdString == String("TMAP") && acceleratorConfig) { + Logger::console("Setting Throttle MAP Point to %i", newValue); + acceleratorConfig->positionHalfPower = newValue; + accelerator->saveConfiguration(); + } else if (cmdString == String("TMINRN") && acceleratorConfig) { + Logger::console("Setting Throttle Regen Minimum Strength to %i", newValue); + acceleratorConfig->minimumRegen = newValue; + accelerator->saveConfiguration(); + } else if (cmdString == String("TMAXRN") && acceleratorConfig) { + Logger::console("Setting Throttle Regen Maximum Strength to %i", newValue); + acceleratorConfig->maximumRegen = newValue; + accelerator->saveConfiguration(); + } else if (cmdString == String("TCREEP") && acceleratorConfig) { + Logger::console("Setting Throttle Creep Strength to %i", newValue); + acceleratorConfig->creep = newValue; + accelerator->saveConfiguration(); + } else if (cmdString == String("BMAXR") && brakeConfig) { + Logger::console("Setting Max Brake Regen to %i", newValue); + brakeConfig->maximumRegen = newValue; + brake->saveConfiguration(); + } else if (cmdString == String("BMINR") && brakeConfig) { + Logger::console("Setting Min Brake Regen to %i", newValue); + brakeConfig->minimumRegen = newValue; + brake->saveConfiguration(); + } + else if (cmdString == String("B1ADC") && acceleratorConfig) { + Logger::console("Setting Brake ADC pin to %i", newValue); + brakeConfig->AdcPin1 = newValue; + accelerator->saveConfiguration(); + } else if (cmdString == String("B1MX") && brakeConfig) { + Logger::console("Setting Brake Max to %i", newValue); + brakeConfig->maximumLevel1 = newValue; + brake->saveConfiguration(); + } else if (cmdString == String("B1MN") && brakeConfig) { + Logger::console("Setting Brake Min to %i", newValue); + brakeConfig->minimumLevel1 = newValue; + brake->saveConfiguration(); + } else if (cmdString == String("PREC") && motorConfig) { + Logger::console("Setting Precharge Capacitance to %i", newValue); + motorConfig->kilowattHrs = newValue; + motorController->saveConfiguration(); + } else if (cmdString == String("PREDELAY") && motorConfig) { + Logger::console("Setting Precharge Time Delay to %i milliseconds", newValue); + motorConfig->prechargeR = newValue; + motorController->saveConfiguration(); + } else if (cmdString == String("NOMV") && motorConfig) { + Logger::console("Setting fully charged voltage to %d vdc", newValue); + motorConfig->nominalVolt = newValue * 10; + motorController->saveConfiguration(); + } else if (cmdString == String("BRAKELT") && motorConfig) { + motorConfig->brakeLight = newValue; + motorController->saveConfiguration(); + Logger::console("Brake light output set to DOUT%i.",newValue); + } else if (cmdString == String("REVLT") && motorConfig) { + motorConfig->revLight = newValue; + motorController->saveConfiguration(); + Logger::console("Reverse light output set to DOUT%i.",newValue); + } else if (cmdString == String("ENABLEIN") && motorConfig) { + motorConfig->enableIn = newValue; + motorController->saveConfiguration(); + Logger::console("Motor Enable input set to DIN%i.",newValue); + } else if (cmdString == String("REVIN") && motorConfig) { + motorConfig->reverseIn = newValue; + motorController->saveConfiguration(); + Logger::console("Motor Reverse input set to DIN%i.",newValue); + } else if (cmdString == String("MRELAY") && motorConfig) { + Logger::console("Setting Main Contactor relay output to DOUT%i", newValue); + motorConfig->mainContactorRelay = newValue; + motorController->saveConfiguration(); + } else if (cmdString == String("PRELAY") && motorConfig) { + Logger::console("Setting Precharge Relay output to DOUT%i", newValue); + motorConfig->prechargeRelay = newValue; + motorController->saveConfiguration(); + } else if (cmdString == String("ENABLE")) { + if (PrefHandler::setDeviceStatus(newValue, true)) { + sysPrefs->forceCacheWrite(); //just in case someone takes us literally and power cycles quickly + Logger::console("Successfully enabled device.(%X, %d) Power cycle to activate.", newValue, newValue); + } + else { + Logger::console("Invalid device ID (%X, %d)", newValue, newValue); + } + } else if (cmdString == String("DISABLE")) { + if (PrefHandler::setDeviceStatus(newValue, false)) { + sysPrefs->forceCacheWrite(); //just in case someone takes us literally and power cycles quickly + Logger::console("Successfully disabled device. Power cycle to deactivate."); + } + else { + Logger::console("Invalid device ID (%X, %d)", newValue, newValue); + } + } else if (cmdString == String("SYSTYPE")) { + if (newValue < 7 && newValue > 0) { + sysPrefs->write(EESYS_SYSTEM_TYPE, (uint8_t)(newValue)); + sysPrefs->saveChecksum(); + sysPrefs->forceCacheWrite(); //just in case someone takes us literally and power cycles quickly + Logger::console("System type updated. Power cycle to apply."); + } + else Logger::console("Invalid system type. Please enter a value 1 - 4"); + } else if (cmdString == String("ADC0OFF")) { + if (newValue >= 0 && newValue <= 65535) { + sysPrefs->write(EESYS_ADC0_OFFSET, (uint16_t)(newValue)); + sysPrefs->saveChecksum(); + setup_ADC_params(); //change takes immediate effect + } + else Logger::console("Invalid offset. Enter value from 0 to 65535"); + } else if (cmdString == String("ADC0GAIN")) { + if (newValue >= 0 && newValue <= 65535) { + sysPrefs->write(EESYS_ADC0_GAIN, (uint16_t)(newValue)); + sysPrefs->saveChecksum(); + setup_ADC_params(); //change takes immediate effect + } + else Logger::console("Invalid gain. Enter value from 0 to 65535"); + } else if (cmdString == String("ADC1OFF")) { + if (newValue >= 0 && newValue <= 65535) { + sysPrefs->write(EESYS_ADC1_OFFSET, (uint16_t)(newValue)); + sysPrefs->saveChecksum(); + setup_ADC_params(); //change takes immediate effect + } + else Logger::console("Invalid offset. Enter value from 0 to 65535"); + } else if (cmdString == String("ADC1GAIN")) { + if (newValue >= 0 && newValue <= 65535) { + sysPrefs->write(EESYS_ADC1_GAIN, (uint16_t)(newValue)); + sysPrefs->saveChecksum(); + setup_ADC_params(); //change takes immediate effect + } + else Logger::console("Invalid gain. Enter value from 0 to 65535"); + } else if (cmdString == String("ADC2OFF")) { + if (newValue >= 0 && newValue <= 65535) { + sysPrefs->write(EESYS_ADC2_OFFSET, (uint16_t)(newValue)); + sysPrefs->saveChecksum(); + setup_ADC_params(); //change takes immediate effect + } + else Logger::console("Invalid offset. Enter value from 0 to 65535"); + } else if (cmdString == String("ADC2GAIN")) { + if (newValue >= 0 && newValue <= 65535) { + sysPrefs->write(EESYS_ADC2_GAIN, (uint16_t)(newValue)); + sysPrefs->saveChecksum(); + setup_ADC_params(); //change takes immediate effect + } + else Logger::console("Invalid gain. Enter value from 0 to 65535"); + } else if (cmdString == String("ADC3OFF")) { + if (newValue >= 0 && newValue <= 65535) { + sysPrefs->write(EESYS_ADC3_OFFSET, (uint16_t)(newValue)); + sysPrefs->saveChecksum(); + setup_ADC_params(); //change takes immediate effect + } + else Logger::console("Invalid offset. Enter value from 0 to 65535"); + } else if (cmdString == String("ADC3GAIN")) { + if (newValue >= 0 && newValue <= 65535) { + sysPrefs->write(EESYS_ADC3_GAIN, (uint16_t)(newValue)); + sysPrefs->saveChecksum(); + setup_ADC_params(); //change takes immediate effect + } + else Logger::console("Invalid gain. Enter value from 0 to 65535"); + } else if (cmdString == String("ADCPACKHOFF")) { + if (newValue >= 0 && newValue <= 65535) { + sysPrefs->write(EESYS_ADC_PACKH_OFFSET, (uint16_t)(newValue)); + sysPrefs->saveChecksum(); + setup_ADC_params(); //change takes immediate effect + } + else Logger::console("Invalid offset. Enter value from 0 to 65535"); + } else if (cmdString == String("ADCPACKHGAIN")) { + if (newValue >= 0 && newValue <= 65535) { + sysPrefs->write(EESYS_ADC_PACKH_GAIN, (uint16_t)(newValue)); + sysPrefs->saveChecksum(); + setup_ADC_params(); //change takes immediate effect + } + else Logger::console("Invalid gain. Enter value from 0 to 65535"); + } else if (cmdString == String("ADCPACKLOFF")) { + if (newValue >= 0 && newValue <= 65535) { + sysPrefs->write(EESYS_ADC_PACKL_OFFSET, (uint16_t)(newValue)); + sysPrefs->saveChecksum(); + setup_ADC_params(); //change takes immediate effect + } + else Logger::console("Invalid offset. Enter value from 0 to 65535"); + } else if (cmdString == String("ADCPACKLGAIN")) { + if (newValue >= 0 && newValue <= 65535) { + sysPrefs->write(EESYS_ADC_PACKL_GAIN, (uint16_t)(newValue)); + sysPrefs->saveChecksum(); + setup_ADC_params(); //change takes immediate effect + } + else Logger::console("Invalid gain. Enter value from 0 to 65535"); + } else if (cmdString == String("ADCPACKCOFF")) { + if (newValue >= 0 && newValue <= 65535) { + sysPrefs->write(EESYS_ADC_PACKC_OFFSET, (uint16_t)(newValue)); + sysPrefs->saveChecksum(); + setup_ADC_params(); //change takes immediate effect + } + else Logger::console("Invalid offset. Enter value from 0 to 65535"); + } else if (cmdString == String("ADCPACKCGAIN")) { + if (newValue >= 0 && newValue <= 65535) { + sysPrefs->write(EESYS_ADC_PACKC_GAIN, (uint16_t)(newValue)); + sysPrefs->saveChecksum(); + setup_ADC_params(); //change takes immediate effect + } + else Logger::console("Invalid gain. Enter value from 0 to 65535"); + } else if (cmdString == String("LOGLEVEL")) { + switch (newValue) { + case 0: + Logger::setLoglevel(Logger::Debug); + Logger::console("setting loglevel to 'debug'"); + break; + case 1: + Logger::setLoglevel(Logger::Info); + Logger::console("setting loglevel to 'info'"); + break; + case 2: + Logger::console("setting loglevel to 'warning'"); + Logger::setLoglevel(Logger::Warn); + break; + case 3: + Logger::console("setting loglevel to 'error'"); + Logger::setLoglevel(Logger::Error); + break; + case 4: + Logger::console("setting loglevel to 'off'"); + Logger::setLoglevel(Logger::Off); + break; + } + sysPrefs->write(EESYS_LOG_LEVEL, (uint8_t)newValue); + sysPrefs->saveChecksum(); + + } else if (cmdString == String("WIREACH")) { + DeviceManager::getInstance()->sendMessage(DEVICE_WIFI, ICHIP2128, MSG_COMMAND, (void *)(cmdBuffer + i)); + Logger::info("sent \"AT+i%s\" to WiReach wireless LAN device", (cmdBuffer + i)); + DeviceManager::getInstance()->sendMessage(DEVICE_WIFI, ICHIP2128, MSG_COMMAND, (void *)"DOWN"); + updateWifi = false; + } else if (cmdString == String("SSID")) { + String cmdString = String(); + cmdString.concat("WLSI"); + cmdString.concat('='); + cmdString.concat((char *)(cmdBuffer + i)); + Logger::info("Sent \"%s\" to WiReach wireless LAN device", (cmdString.c_str())); + DeviceManager::getInstance()->sendMessage(DEVICE_WIFI, ICHIP2128, MSG_COMMAND, (void *)cmdString.c_str()); + DeviceManager::getInstance()->sendMessage(DEVICE_WIFI, ICHIP2128, MSG_COMMAND, (void *)"DOWN"); + updateWifi = false; + } else if (cmdString == String("IP")) { + String cmdString = String(); + cmdString.concat("DIP"); + cmdString.concat('='); + cmdString.concat((char *)(cmdBuffer + i)); + Logger::info("Sent \"%s\" to WiReach wireless LAN device", (cmdString.c_str())); + DeviceManager::getInstance()->sendMessage(DEVICE_WIFI, ICHIP2128, MSG_COMMAND, (void *)cmdString.c_str()); + DeviceManager::getInstance()->sendMessage(DEVICE_WIFI, ICHIP2128, MSG_COMMAND, (void *)"DOWN"); + updateWifi = false; + } else if (cmdString == String("CHANNEL")) { + String cmdString = String(); + cmdString.concat("WLCH"); + cmdString.concat('='); + cmdString.concat((char *)(cmdBuffer + i)); + Logger::info("Sent \"%s\" to WiReach wireless LAN device", (cmdString.c_str())); + DeviceManager::getInstance()->sendMessage(DEVICE_WIFI, ICHIP2128, MSG_COMMAND, (void *)cmdString.c_str()); + DeviceManager::getInstance()->sendMessage(DEVICE_WIFI, ICHIP2128, MSG_COMMAND, (void *)"DOWN"); + updateWifi = false; + } else if (cmdString == String("SECURITY")) { + String cmdString = String(); + cmdString.concat("WLPP"); + cmdString.concat('='); + cmdString.concat((char *)(cmdBuffer + i)); + Logger::info("Sent \"%s\" to WiReach wireless LAN device", (cmdString.c_str())); + DeviceManager::getInstance()->sendMessage(DEVICE_WIFI, ICHIP2128, MSG_COMMAND, (void *)cmdString.c_str()); + DeviceManager::getInstance()->sendMessage(DEVICE_WIFI, ICHIP2128, MSG_COMMAND, (void *)"DOWN"); + updateWifi = false; + + } else if (cmdString == String("PWD")) { + String cmdString = String(); + cmdString.concat("WPWD"); + cmdString.concat('='); + cmdString.concat((char *)(cmdBuffer + i)); + Logger::info("Sent \"%s\" to WiReach wireless LAN device", (cmdString.c_str())); + DeviceManager::getInstance()->sendMessage(DEVICE_WIFI, ICHIP2128, MSG_COMMAND, (void *)cmdString.c_str()); + DeviceManager::getInstance()->sendMessage(DEVICE_WIFI, ICHIP2128, MSG_COMMAND, (void *)"DOWN"); + updateWifi = false; + + } else if (cmdString == String("COOLFAN") && motorConfig) { + Logger::console("Cooling fan output updated to: %i", newValue); motorConfig->coolFan = newValue; - motorController->saveConfiguration(); - } else if (cmdString == String("COOLON")&& motorConfig) { - if (newValue <= 200 && newValue >= 0) { - Logger::console("Cooling fan ON temperature updated to: %i degrees", newValue); - motorConfig->coolOn = newValue; - motorController->saveConfiguration(); - } - else Logger::console("Invalid cooling ON temperature. Please enter a value 0 - 200F"); - } else if (cmdString == String("COOLOFF")&& motorConfig) { - if (newValue <= 200 && newValue >= 0) { - Logger::console("Cooling fan OFF temperature updated to: %i degrees", newValue); - motorConfig->coolOff = newValue; - motorController->saveConfiguration(); - } - else Logger::console("Invalid cooling OFF temperature. Please enter a value 0 - 200F"); - } else if (cmdString == String("OUTPUT") && newValue<8) { - int outie = getOutput(newValue); - Logger::console("DOUT%d, STATE: %d",newValue, outie); - if(outie) - { - setOutput(newValue,0); - motorController->statusBitfield1 &= ~(1 << newValue);//Clear - } - else - { - setOutput(newValue,1); - motorController->statusBitfield1 |=1 << newValue;//setbit to Turn on annunciator - } - - + motorController->saveConfiguration(); + } else if (cmdString == String("COOLON")&& motorConfig) { + if (newValue <= 200 && newValue >= 0) { + Logger::console("Cooling fan ON temperature updated to: %i degrees", newValue); + motorConfig->coolOn = newValue; + motorController->saveConfiguration(); + } + else Logger::console("Invalid cooling ON temperature. Please enter a value 0 - 200F"); + } else if (cmdString == String("COOLOFF")&& motorConfig) { + if (newValue <= 200 && newValue >= 0) { + Logger::console("Cooling fan OFF temperature updated to: %i degrees", newValue); + motorConfig->coolOff = newValue; + motorController->saveConfiguration(); + } + else Logger::console("Invalid cooling OFF temperature. Please enter a value 0 - 200F"); + } else if (cmdString == String("OUTPUT") && newValue<8) { + int outie = getOutput(newValue); + Logger::console("DOUT%d, STATE: %d",newValue, outie); + if(outie) + { + setOutput(newValue,0); + motorController->statusBitfield1 &= ~(1 << newValue);//Clear + } + else + { + setOutput(newValue,1); + motorController->statusBitfield1 |=1 << newValue;//setbit to Turn on annunciator + } + + Logger::console("DOUT0:%d, DOUT1:%d, DOUT2:%d, DOUT3:%d, DOUT4:%d, DOUT5:%d, DOUT6:%d, DOUT7:%d", getOutput(0), getOutput(1), getOutput(2), getOutput(3), getOutput(4), getOutput(5), getOutput(6), getOutput(7)); - - } else if (cmdString == String("CAPACITY") ) { - motorConfig->capacity = newValue; - motorController->saveConfiguration(); - Logger::console("Battery Pack Capacity set to: %d",motorConfig->capacity); - - } else if (cmdString == String("KWH") ) { - - motorController->kiloWattHours = newValue*3600000; - motorController->saveConfiguration(); - Logger::console("kWh set to: %d",motorController->kiloWattHours); - - - - } else if (cmdString == String("NUKE")) { - if (newValue == 1) - { //write zero to the checksum location of every device in the table. - //Logger::console("Start of EEPROM Nuke"); - uint8_t zeroVal = 0; - for (int j = 0; j < 64; j++) - { - memCache->Write(EE_DEVICES_BASE + (EE_DEVICE_SIZE * j), zeroVal); - memCache->FlushAllPages(); - } - Logger::console("Device settings have been nuked. Reboot to reload default settings"); - } - } else { - Logger::console("Unknown command"); - updateWifi = false; - } - // send updates to ichip wifi - if (updateWifi) - DeviceManager::getInstance()->sendMessage(DEVICE_WIFI, ICHIP2128, MSG_CONFIG_CHANGE, NULL); + + } else if (cmdString == String("CAPACITY") ) { + motorConfig->capacity = newValue; + motorController->saveConfiguration(); + Logger::console("Battery Pack Capacity set to: %d",motorConfig->capacity); + + } else if (cmdString == String("KWH") ) { + + motorController->kiloWattHours = newValue*3600000; + motorController->saveConfiguration(); + Logger::console("kWh set to: %d",motorController->kiloWattHours); + + + + } else if (cmdString == String("NUKE")) { + if (newValue == 1) + { //write zero to the checksum location of every device in the table. + //Logger::console("Start of EEPROM Nuke"); + uint8_t zeroVal = 0; + for (int j = 0; j < 64; j++) + { + memCache->Write(EE_DEVICES_BASE + (EE_DEVICE_SIZE * j), zeroVal); + memCache->FlushAllPages(); + } + Logger::console("Device settings have been nuked. Reboot to reload default settings"); + } + } else { + Logger::console("Unknown command"); + updateWifi = false; + } + // send updates to ichip wifi + if (updateWifi) + DeviceManager::getInstance()->sendMessage(DEVICE_WIFI, ICHIP2128, MSG_CONFIG_CHANGE, NULL); } void SerialConsole::handleShortCmd() { - uint8_t val; - MotorController* motorController = (MotorController*) DeviceManager::getInstance()->getMotorController(); - Throttle *accelerator = DeviceManager::getInstance()->getAccelerator(); - Throttle *brake = DeviceManager::getInstance()->getBrake(); - DeviceManager *deviceManager = DeviceManager::getInstance(); - - switch (cmdBuffer[0]) { - case 'h': - case '?': - case 'H': - printMenu(); - break; - case 'L': - if (heartbeat != NULL) { - heartbeat->setThrottleDebug(!heartbeat->getThrottleDebug()); - if (heartbeat->getThrottleDebug()) { - Logger::console("Output raw throttle"); - } else { - Logger::console("Cease raw throttle output"); - } - } - break; - case 'E': - Logger::console("Reading System EEPROM values"); - for (int i = 0; i < 256; i++) { - memCache->Read(EE_SYSTEM_START + i, &val); - Logger::console("%d: %d", i, val); - } - break; - case 'K': //set all outputs high - for (int tout = 0; tout < NUM_OUTPUT; tout++) setOutput(tout, true); - Logger::console("all outputs: ON"); - break; - case 'J': //set the four outputs low - for (int tout = 0; tout < NUM_OUTPUT; tout++) setOutput(tout, false); - Logger::console("all outputs: OFF"); - break; - case 'z': // detect throttle min/max & other details - if (accelerator) { - ThrottleDetector *detector = new ThrottleDetector(accelerator); - detector->detect(); - } - break; - case 'Z': // save throttle settings - if (accelerator) { - accelerator->saveConfiguration(); - } - break; - case 'b': - if (brake) { - ThrottleDetector *detector = new ThrottleDetector(brake); - detector->detect(); - } - break; - case 'B': - if (brake != NULL) { - brake->saveConfiguration(); - } - break; - case 'p': - Logger::console("PASSTHROUGH MODE - All traffic Serial3 <-> SerialUSB"); - //this never stops so basically everything dies. you will have to reboot. - int inSerialUSB, inSerial3; - while (1 == 1) { - inSerialUSB = SerialUSB.read(); - inSerial3 = Serial3.read(); - if (inSerialUSB > -1) { - Serial3.write((char) inSerialUSB); - } - if (inSerial3 > -1) { - SerialUSB.write((char) inSerial3); - } - } - break; - case 'A': - uint32_t accum; - for (int i = 0; i < 7; i++) - { - accum = 0; - for (int j = 0; j < 400; j++) - { - accum += getRawADC(i); - //normally one shouldn't call watchdog reset in multiple - //places but this is a special case. - watchdogReset(); - delay(7); - } - accum /= 400; - sysPrefs->write(EESYS_ADC0_OFFSET + (4*i), (uint16_t)(accum)); - Logger::console("ADC %i offset is now %i", i, accum); - } - sysPrefs->saveChecksum(); - setup_ADC_params(); //change takes immediate effect - break; - case 'S': - //there is not really any good way (currently) to auto generate this list - //the information just isn't stored anywhere in code. Perhaps we might - //think to change that. Otherwise you must remember to update here or - //nobody will know your device exists. Additionally, these values are - //decoded into decimal from their hex specification in DeviceTypes.h - Logger::console("DMOC645 = %X", DMOC645); - Logger::console("Brusa DMC5 = %X", BRUSA_DMC5); - Logger::console("Brusa Charger = %X", BRUSACHARGE); - Logger::console("TCCH Charger = %X", TCCHCHARGE); - Logger::console("Pot based accelerator = %X", POTACCELPEDAL); - Logger::console("Pot based brake = %X", POTBRAKEPEDAL); - Logger::console("CANBus accelerator = %X", CANACCELPEDAL); - Logger::console("CANBus brake = %X", CANBRAKEPEDAL); - Logger::console("WIFI (iChip2128) = %X", ICHIP2128); - Logger::console("Th!nk City BMS = %X", THINKBMS); - break; - case 's': - Logger::console("Finding and listing all nearby WiFi access points"); - deviceManager->sendMessage(DEVICE_WIFI, ICHIP2128, MSG_COMMAND, (void *)"RP20"); - break; - case 'W': - Logger::console("Resetting wifi to factory defaults and setting up GEVCU5.2 Access Point"); - deviceManager->sendMessage(DEVICE_WIFI, ICHIP2128, MSG_COMMAND, (void *)"FD");//Reset - delay(2000); - deviceManager->sendMessage(DEVICE_WIFI, ICHIP2128, MSG_COMMAND, (void *)"HIF=1"); //Set for RS-232 serial. - delay(1000); - deviceManager->sendMessage(DEVICE_WIFI, ICHIP2128, MSG_COMMAND, (void *)"BDRA");//Auto baud rate selection - delay(1000); - deviceManager->sendMessage(DEVICE_WIFI, ICHIP2128, MSG_COMMAND, (void *)"WLCH=9"); //use whichever channel an AP wants to use - delay(1000); - deviceManager->sendMessage(DEVICE_WIFI, ICHIP2128, MSG_COMMAND, (void *)"WLSI=GEVCU"); //set for GEVCU aS AP. - delay(1000); - - deviceManager->sendMessage(DEVICE_WIFI, ICHIP2128, MSG_COMMAND, (void *)"STAP=1"); //enable IP - delay(1000); - - deviceManager->sendMessage(DEVICE_WIFI, ICHIP2128, MSG_COMMAND, (void *)"DIP=192.168.3.10"); //enable IP - delay(1000); - deviceManager->sendMessage(DEVICE_WIFI, ICHIP2128, MSG_COMMAND, (void *)"DPSZ=8"); //set DHCP server for 8 - delay(1000); - deviceManager->sendMessage(DEVICE_WIFI, ICHIP2128, MSG_COMMAND, (void *)"RPG=secret"); // set the configuration password for /ichip - delay(1000); - deviceManager->sendMessage(DEVICE_WIFI, ICHIP2128, MSG_COMMAND, (void *)"WPWD=secret"); // set the password to update config params - delay(1000); - deviceManager->sendMessage(DEVICE_WIFI, ICHIP2128, MSG_COMMAND, (void *)"AWS=1"); //turn on web server - delay(1000); - deviceManager->sendMessage(DEVICE_WIFI, ICHIP2128, MSG_COMMAND, (void *)"DOWN"); //cause a reset to allow it to come up with the settings - delay(5000); // a 5 second delay is required for the chip to come back up ! Otherwise commands will be lost - - deviceManager->sendMessage(DEVICE_WIFI, ICHIP2128, MSG_CONFIG_CHANGE, NULL); // reload configuration params as they were lost - Logger::console("Wifi 5.2 initialized"); - break; - case 'w': - Logger::console("Resetting wifi to factory defaults and setting up GEVCU4.2 Ad Hoc network"); - resetWiReachMini(); - deviceManager->sendMessage(DEVICE_WIFI, ICHIP2128, MSG_CONFIG_CHANGE, NULL); // reload configuration params as they were lost - break; - - case 'X': - setup(); //this is probably a bad idea. Do not do this while connected to anything you care about - only for debugging in safety! - break; - } + uint8_t val; + MotorController* motorController = (MotorController*) DeviceManager::getInstance()->getMotorController(); + Throttle *accelerator = DeviceManager::getInstance()->getAccelerator(); + Throttle *brake = DeviceManager::getInstance()->getBrake(); + DeviceManager *deviceManager = DeviceManager::getInstance(); + + switch (cmdBuffer[0]) { + case 'h': + case '?': + case 'H': + printMenu(); + break; + case 'L': + if (heartbeat != NULL) { + heartbeat->setThrottleDebug(!heartbeat->getThrottleDebug()); + if (heartbeat->getThrottleDebug()) { + Logger::console("Output raw throttle"); + } else { + Logger::console("Cease raw throttle output"); + } + } + break; + case 'E': + Logger::console("Reading System EEPROM values"); + for (int i = 0; i < 256; i++) { + memCache->Read(EE_SYSTEM_START + i, &val); + Logger::console("%d: %d", i, val); + } + break; + case 'K': //set all outputs high + for (int tout = 0; tout < NUM_OUTPUT; tout++) setOutput(tout, true); + Logger::console("all outputs: ON"); + break; + case 'J': //set the four outputs low + for (int tout = 0; tout < NUM_OUTPUT; tout++) setOutput(tout, false); + Logger::console("all outputs: OFF"); + break; + case 'z': // detect throttle min/max & other details + if (accelerator) { + ThrottleDetector *detector = new ThrottleDetector(accelerator); + detector->detect(); + } + break; + case 'Z': // save throttle settings + if (accelerator) { + accelerator->saveConfiguration(); + } + break; + case 'b': + if (brake) { + ThrottleDetector *detector = new ThrottleDetector(brake); + detector->detect(); + } + break; + case 'B': + if (brake != NULL) { + brake->saveConfiguration(); + } + break; + case 'p': + Logger::console("PASSTHROUGH MODE - All traffic Serial3 <-> SerialUSB"); + //this never stops so basically everything dies. you will have to reboot. + int inSerialUSB, inSerial3; + while (1 == 1) { + inSerialUSB = SerialUSB.read(); + inSerial3 = Serial3.read(); + if (inSerialUSB > -1) { + Serial3.write((char) inSerialUSB); + } + if (inSerial3 > -1) { + SerialUSB.write((char) inSerial3); + } + } + break; + case 'A': + uint32_t accum; + for (int i = 0; i < 7; i++) + { + accum = 0; + for (int j = 0; j < 400; j++) + { + accum += getRawADC(i); + //normally one shouldn't call watchdog reset in multiple + //places but this is a special case. + watchdogReset(); + delay(7); + } + accum /= 400; + sysPrefs->write(EESYS_ADC0_OFFSET + (4*i), (uint16_t)(accum)); + Logger::console("ADC %i offset is now %i", i, accum); + } + sysPrefs->saveChecksum(); + setup_ADC_params(); //change takes immediate effect + break; + case 'S': + //there is not really any good way (currently) to auto generate this list + //the information just isn't stored anywhere in code. Perhaps we might + //think to change that. Otherwise you must remember to update here or + //nobody will know your device exists. Additionally, these values are + //decoded into decimal from their hex specification in DeviceTypes.h + Logger::console("DMOC645 = %X", DMOC645); + Logger::console("Brusa DMC5 = %X", BRUSA_DMC5); + Logger::console("Brusa Charger = %X", BRUSACHARGE); + Logger::console("TCCH Charger = %X", TCCHCHARGE); + Logger::console("Pot based accelerator = %X", POTACCELPEDAL); + Logger::console("Pot based brake = %X", POTBRAKEPEDAL); + Logger::console("CANBus accelerator = %X", CANACCELPEDAL); + Logger::console("CANBus brake = %X", CANBRAKEPEDAL); + Logger::console("WIFI (iChip2128) = %X", ICHIP2128); + Logger::console("Th!nk City BMS = %X", THINKBMS); + break; + case 's': + Logger::console("Finding and listing all nearby WiFi access points"); + deviceManager->sendMessage(DEVICE_WIFI, ICHIP2128, MSG_COMMAND, (void *)"RP20"); + break; + case 'W': + Logger::console("Resetting wifi to factory defaults and setting up GEVCU5.2 Access Point"); + deviceManager->sendMessage(DEVICE_WIFI, ICHIP2128, MSG_COMMAND, (void *)"FD");//Reset + delay(2000); + deviceManager->sendMessage(DEVICE_WIFI, ICHIP2128, MSG_COMMAND, (void *)"HIF=1"); //Set for RS-232 serial. + delay(1000); + deviceManager->sendMessage(DEVICE_WIFI, ICHIP2128, MSG_COMMAND, (void *)"BDRA");//Auto baud rate selection + delay(1000); + deviceManager->sendMessage(DEVICE_WIFI, ICHIP2128, MSG_COMMAND, (void *)"WLCH=9"); //use whichever channel an AP wants to use + delay(1000); + deviceManager->sendMessage(DEVICE_WIFI, ICHIP2128, MSG_COMMAND, (void *)"WLSI=GEVCU"); //set for GEVCU aS AP. + delay(1000); + + deviceManager->sendMessage(DEVICE_WIFI, ICHIP2128, MSG_COMMAND, (void *)"STAP=1"); //enable IP + delay(1000); + + deviceManager->sendMessage(DEVICE_WIFI, ICHIP2128, MSG_COMMAND, (void *)"DIP=192.168.3.10"); //enable IP + delay(1000); + deviceManager->sendMessage(DEVICE_WIFI, ICHIP2128, MSG_COMMAND, (void *)"DPSZ=8"); //set DHCP server for 8 + delay(1000); + deviceManager->sendMessage(DEVICE_WIFI, ICHIP2128, MSG_COMMAND, (void *)"RPG=secret"); // set the configuration password for /ichip + delay(1000); + deviceManager->sendMessage(DEVICE_WIFI, ICHIP2128, MSG_COMMAND, (void *)"WPWD=secret"); // set the password to update config params + delay(1000); + deviceManager->sendMessage(DEVICE_WIFI, ICHIP2128, MSG_COMMAND, (void *)"AWS=1"); //turn on web server + delay(1000); + deviceManager->sendMessage(DEVICE_WIFI, ICHIP2128, MSG_COMMAND, (void *)"DOWN"); //cause a reset to allow it to come up with the settings + delay(5000); // a 5 second delay is required for the chip to come back up ! Otherwise commands will be lost + + deviceManager->sendMessage(DEVICE_WIFI, ICHIP2128, MSG_CONFIG_CHANGE, NULL); // reload configuration params as they were lost + Logger::console("Wifi 5.2 initialized"); + break; + case 'w': + Logger::console("Resetting wifi to factory defaults and setting up GEVCU4.2 Ad Hoc network"); + resetWiReachMini(); + deviceManager->sendMessage(DEVICE_WIFI, ICHIP2128, MSG_CONFIG_CHANGE, NULL); // reload configuration params as they were lost + break; + + case 'X': + setup(); //this is probably a bad idea. Do not do this while connected to anything you care about - only for debugging in safety! + break; + } } void SerialConsole::resetWiReachMini() { - //Serial2.begin(115200); - while (Serial2.available()) { - SerialUSB.write(Serial2.read()); - } - Serial2.println("AT+iFD"); - getResponse(); - Serial2.println("AT+iHIF=1"); - getResponse(); - Serial2.println("AT+iBDRA"); - getResponse(); - Serial2.println("AT+iWLCH=9"); - getResponse(); - Serial2.println("AT+iWLSI=!GEVCU"); - getResponse(); - Serial2.println("AT+iDIP=192.168.3.10"); - getResponse(); - Serial2.println("AT+iDPSZ=8"); - getResponse(); - Serial2.println("AT+iRPG=secret"); - getResponse(); - Serial2.println("AT+iWPWD=secret"); - getResponse(); - Serial2.println("AT+iAWS=1"); - getResponse(); - Serial2.println("AT+iDOWN"); - getResponse(); - getResponse(); - - - - Logger::console("Wifi 4.2 initialized"); + //Serial2.begin(115200); + while (Serial2.available()) { + SerialUSB.write(Serial2.read()); + } + Serial2.println("AT+iFD"); + getResponse(); + Serial2.println("AT+iHIF=1"); + getResponse(); + Serial2.println("AT+iBDRA"); + getResponse(); + Serial2.println("AT+iWLCH=9"); + getResponse(); + Serial2.println("AT+iWLSI=!GEVCU"); + getResponse(); + Serial2.println("AT+iDIP=192.168.3.10"); + getResponse(); + Serial2.println("AT+iDPSZ=8"); + getResponse(); + Serial2.println("AT+iRPG=secret"); + getResponse(); + Serial2.println("AT+iWPWD=secret"); + getResponse(); + Serial2.println("AT+iAWS=1"); + getResponse(); + Serial2.println("AT+iDOWN"); + getResponse(); + getResponse(); + + + + Logger::console("Wifi 4.2 initialized"); } -void SerialConsole::getResponse(){ - - while (Serial2.available()) { - SerialUSB.write(Serial2.read()); - } - SerialUSB.println(); - delay(4000); - +void SerialConsole::getResponse() { + + while (Serial2.available()) { + SerialUSB.write(Serial2.read()); + } + SerialUSB.println(); + delay(4000); + } - + diff --git a/SerialConsole.h b/SerialConsole.h index dc40205..22afd35 100644 --- a/SerialConsole.h +++ b/SerialConsole.h @@ -43,31 +43,31 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. class SerialConsole { public: SerialConsole(MemCache* memCache); - SerialConsole(MemCache* memCache, Heartbeat* heartbeat); - void loop(); - void printMenu(); + SerialConsole(MemCache* memCache, Heartbeat* heartbeat); + void loop(); + void printMenu(); protected: - enum CONSOLE_STATE - { - STATE_ROOT_MENU - }; + enum CONSOLE_STATE + { + STATE_ROOT_MENU + }; private: Heartbeat* heartbeat; MemCache* memCache; bool handlingEvent; - char cmdBuffer[80]; - int ptrBuffer; - int state; - int loopcount; - bool cancel; - - + char cmdBuffer[80]; + int ptrBuffer; + int state; + int loopcount; + bool cancel; + + void init(); void serialEvent(); - void handleConsoleCmd(); - void handleShortCmd(); + void handleConsoleCmd(); + void handleShortCmd(); void handleConfigCmd(); void resetWiReachMini(); void getResponse(); diff --git a/Sys_Messages.h b/Sys_Messages.h index 6b14796..11c6f02 100644 --- a/Sys_Messages.h +++ b/Sys_Messages.h @@ -28,14 +28,14 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. enum SystemMessage { - MSG_STARTUP = 0x3000, - MSG_SOFT_FAULT = 0x3100, - MSG_HARD_FAULT = 0x3150, - MSG_DISABLE = 0x3200, - MSG_ENABLE = 0x3300, - MSG_SET_PARAM = 0x4000, - MSG_CONFIG_CHANGE = 0x4001, - MSG_COMMAND = 0x4002 + MSG_STARTUP = 0x3000, + MSG_SOFT_FAULT = 0x3100, + MSG_HARD_FAULT = 0x3150, + MSG_DISABLE = 0x3200, + MSG_ENABLE = 0x3300, + MSG_SET_PARAM = 0x4000, + MSG_CONFIG_CHANGE = 0x4001, + MSG_COMMAND = 0x4002 }; #endif diff --git a/ThinkBatteryManager.cpp b/ThinkBatteryManager.cpp index 3cc9597..825d945 100644 --- a/ThinkBatteryManager.cpp +++ b/ThinkBatteryManager.cpp @@ -29,166 +29,166 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include "ThinkBatteryManager.h" ThinkBatteryManager::ThinkBatteryManager() : BatteryManager() { - prefsHandler = new PrefHandler(THINKBMS); - allowCharge = false; - allowDischarge = false; - commonName = "Think City BMS"; + prefsHandler = new PrefHandler(THINKBMS); + allowCharge = false; + allowDischarge = false; + commonName = "Think City BMS"; } void ThinkBatteryManager::setup() { - TickHandler::getInstance()->detach(this); + TickHandler::getInstance()->detach(this); - Logger::info("add device: Th!nk City BMS (id: %X, %X)", THINKBMS, this); + Logger::info("add device: Th!nk City BMS (id: %X, %X)", THINKBMS, this); - BatteryManager::setup(); // run the parent class version of this function + BatteryManager::setup(); // run the parent class version of this function - //Relevant BMS messages are 0x300 - 0x30F - CanHandler::getInstanceEV()->attach(this, 0x300, 0x7f0, false); + //Relevant BMS messages are 0x300 - 0x30F + CanHandler::getInstanceEV()->attach(this, 0x300, 0x7f0, false); - TickHandler::getInstance()->attach(this, CFG_TICK_INTERVAL_BMS_THINK); + TickHandler::getInstance()->attach(this, CFG_TICK_INTERVAL_BMS_THINK); } /*For all multibyte integers the format is MSB first, LSB last */ void ThinkBatteryManager::handleCanFrame(CAN_FRAME *frame) { - int temp; - switch (frame->id) { - case 0x300: //Start up message - //we're not really interested in much here except whether init worked. - if ((frame->data.bytes[6] & 1) == 0) //there was an initialization error! - { - faultHandler.raiseFault(THINKBMS, FAULT_BMS_INIT, true); - allowCharge = false; - allowDischarge = false; - } - else - { - faultHandler.cancelOngoingFault(THINKBMS, FAULT_BMS_INIT); - } - break; - case 0x301: //System Data 0 - //first two bytes = current, next two voltage, next two DOD, last two avg. temp - //readings in tenths - packVoltage = (frame->data.bytes[0] * 256 + frame->data.bytes[1]); - packCurrent = (frame->data.bytes[2] * 256 + frame->data.bytes[3]); - break; - case 0x302: //System Data 1 - if ((frame->data.bytes[0] & 1) == 1) //Byte 0 bit 0 = general error - { - faultHandler.raiseFault(THINKBMS, FAULT_BMS_MISC, true); - allowDischarge = false; - allowCharge = false; - } - else - { - faultHandler.cancelOngoingFault(THINKBMS, FAULT_BMS_MISC); - } - if ((frame->data.bytes[2] & 1) == 1) //Byte 2 bit 0 = general isolation error - { - faultHandler.raiseFault(THINKBMS, FAULT_HV_BATT_ISOLATION, true); - allowDischarge = false; - allowCharge = false; - } - else - { - faultHandler.cancelOngoingFault(THINKBMS, FAULT_HV_BATT_ISOLATION); - } - //Min discharge voltage = bytes 4-5 - tenths of a volt - //Max discharge current = bytes 6-7 - tenths of an amp - temp = (S16)(frame->data.bytes[6] * 256 + frame->data.bytes[7]); - if (temp > 0) allowDischarge = true; - break; - case 0x303: //System Data 2 - //bytes 0-1 = max charge voltage (tenths of volt) - //bytes 2-3 = max charge current (tenths of amp) - temp = (S16)(frame->data.bytes[2] * 256 + frame->data.bytes[3]); - if (temp > 0) allowCharge = true; - //byte 4 bit 1 = regen braking OK, bit 2 = Discharging OK - //byte 6 bit 3 = EPO (emergency power off) happened, bit 5 = battery pack fan is on - break; - case 0x304: //System Data 3 - //Byte 2 lower 4 bits = highest error category - //categories: 0 = no faults, 1 = Reserved, 2 = Warning, 3 = Delayed switch off, 4 = immediate switch off - //bytes 4-5 = Pack max temperature (tenths of degree C) - Signed - //byte 6-7 = Pack min temperature (tenths of a degree C) - Signed - lowestCellTemp = (S16)(frame->data.bytes[4] * 256 + frame->data.bytes[5]); - highestCellTemp = (S16)(frame->data.bytes[6] * 256 + frame->data.bytes[7]); - break; - case 0x305: //System Data 4 - //byte 2 bits 0-3 = BMS state - //0 = idle state, 1 = discharge state (contactor closed), 15 = fault state - //byte 2 bit 4 = Internal HV isolation fault - //byte 2 bit 5 = External HV isolation fault - break; - case 0x306: //System Data 5 - //bytes 0-1 = Equiv. internal resistance in milliohms - //not recommended to rely on so probably just ignore it - break; - //technically there is a specification for frames 0x307 - 0x30A but I have never seen these frames - //sent on the canbus system so I doubt that they are used. -/* - case 0x307: //System Data 6 - case 0x308: //System Data 7 - case 0x309: //System Data 8 - case 0x30A: //System Data 9 - //do we care about the serial #? Probably not. - case 0x30E: //Serial # part 1 - case 0x30B: //Serial # part 2 -*/ - } + int temp; + switch (frame->id) { + case 0x300: //Start up message + //we're not really interested in much here except whether init worked. + if ((frame->data.bytes[6] & 1) == 0) //there was an initialization error! + { + faultHandler.raiseFault(THINKBMS, FAULT_BMS_INIT, true); + allowCharge = false; + allowDischarge = false; + } + else + { + faultHandler.cancelOngoingFault(THINKBMS, FAULT_BMS_INIT); + } + break; + case 0x301: //System Data 0 + //first two bytes = current, next two voltage, next two DOD, last two avg. temp + //readings in tenths + packVoltage = (frame->data.bytes[0] * 256 + frame->data.bytes[1]); + packCurrent = (frame->data.bytes[2] * 256 + frame->data.bytes[3]); + break; + case 0x302: //System Data 1 + if ((frame->data.bytes[0] & 1) == 1) //Byte 0 bit 0 = general error + { + faultHandler.raiseFault(THINKBMS, FAULT_BMS_MISC, true); + allowDischarge = false; + allowCharge = false; + } + else + { + faultHandler.cancelOngoingFault(THINKBMS, FAULT_BMS_MISC); + } + if ((frame->data.bytes[2] & 1) == 1) //Byte 2 bit 0 = general isolation error + { + faultHandler.raiseFault(THINKBMS, FAULT_HV_BATT_ISOLATION, true); + allowDischarge = false; + allowCharge = false; + } + else + { + faultHandler.cancelOngoingFault(THINKBMS, FAULT_HV_BATT_ISOLATION); + } + //Min discharge voltage = bytes 4-5 - tenths of a volt + //Max discharge current = bytes 6-7 - tenths of an amp + temp = (S16)(frame->data.bytes[6] * 256 + frame->data.bytes[7]); + if (temp > 0) allowDischarge = true; + break; + case 0x303: //System Data 2 + //bytes 0-1 = max charge voltage (tenths of volt) + //bytes 2-3 = max charge current (tenths of amp) + temp = (S16)(frame->data.bytes[2] * 256 + frame->data.bytes[3]); + if (temp > 0) allowCharge = true; + //byte 4 bit 1 = regen braking OK, bit 2 = Discharging OK + //byte 6 bit 3 = EPO (emergency power off) happened, bit 5 = battery pack fan is on + break; + case 0x304: //System Data 3 + //Byte 2 lower 4 bits = highest error category + //categories: 0 = no faults, 1 = Reserved, 2 = Warning, 3 = Delayed switch off, 4 = immediate switch off + //bytes 4-5 = Pack max temperature (tenths of degree C) - Signed + //byte 6-7 = Pack min temperature (tenths of a degree C) - Signed + lowestCellTemp = (S16)(frame->data.bytes[4] * 256 + frame->data.bytes[5]); + highestCellTemp = (S16)(frame->data.bytes[6] * 256 + frame->data.bytes[7]); + break; + case 0x305: //System Data 4 + //byte 2 bits 0-3 = BMS state + //0 = idle state, 1 = discharge state (contactor closed), 15 = fault state + //byte 2 bit 4 = Internal HV isolation fault + //byte 2 bit 5 = External HV isolation fault + break; + case 0x306: //System Data 5 + //bytes 0-1 = Equiv. internal resistance in milliohms + //not recommended to rely on so probably just ignore it + break; + //technically there is a specification for frames 0x307 - 0x30A but I have never seen these frames + //sent on the canbus system so I doubt that they are used. + /* + case 0x307: //System Data 6 + case 0x308: //System Data 7 + case 0x309: //System Data 8 + case 0x30A: //System Data 9 + //do we care about the serial #? Probably not. + case 0x30E: //Serial # part 1 + case 0x30B: //Serial # part 2 + */ + } } void ThinkBatteryManager::handleTick() { - BatteryManager::handleTick(); //kick the ball up to papa + BatteryManager::handleTick(); //kick the ball up to papa + + sendKeepAlive(); - sendKeepAlive(); - } -//Contactors in pack will close if we sent these two frames with all zeros. -void ThinkBatteryManager::sendKeepAlive() +//Contactors in pack will close if we sent these two frames with all zeros. +void ThinkBatteryManager::sendKeepAlive() { - CAN_FRAME output; - output.length = 3; - output.id = 0x310; - output.extended = 0; //standard frame - output.rtr = 0; - for (int i = 0; i < 8; i++) output.data.bytes[i] = 0; - CanHandler::getInstanceEV()->sendFrame(output); - - output.id = 0x311; - output.length = 2; - CanHandler::getInstanceEV()->sendFrame(output); + CAN_FRAME output; + output.length = 3; + output.id = 0x310; + output.extended = 0; //standard frame + output.rtr = 0; + for (int i = 0; i < 8; i++) output.data.bytes[i] = 0; + CanHandler::getInstanceEV()->sendFrame(output); + + output.id = 0x311; + output.length = 2; + CanHandler::getInstanceEV()->sendFrame(output); } -DeviceId ThinkBatteryManager::getId() +DeviceId ThinkBatteryManager::getId() { - return (THINKBMS); + return (THINKBMS); } -bool ThinkBatteryManager::hasPackVoltage() +bool ThinkBatteryManager::hasPackVoltage() { - return true; + return true; } -bool ThinkBatteryManager::hasPackCurrent() +bool ThinkBatteryManager::hasPackCurrent() { - return true; + return true; } -bool ThinkBatteryManager::hasTemperatures() +bool ThinkBatteryManager::hasTemperatures() { - return true; + return true; } -bool ThinkBatteryManager::isChargeOK() +bool ThinkBatteryManager::isChargeOK() { - return allowCharge; + return allowCharge; } -bool ThinkBatteryManager::isDischargeOK() +bool ThinkBatteryManager::isDischargeOK() { - return allowDischarge; + return allowDischarge; } diff --git a/ThinkBatteryManager.h b/ThinkBatteryManager.h index 3c2c7e4..7a24fc7 100644 --- a/ThinkBatteryManager.h +++ b/ThinkBatteryManager.h @@ -24,8 +24,8 @@ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - + */ + #ifndef THINKBATT_H_ #define THINKBATT_H_ @@ -39,19 +39,19 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. class ThinkBatteryManager : public BatteryManager, CanObserver { public: - ThinkBatteryManager(); - void setup(); - void handleTick(); - void handleCanFrame(CAN_FRAME *frame); - DeviceId getId(); - bool hasPackVoltage(); - bool hasPackCurrent(); - bool hasTemperatures(); - bool isChargeOK(); - bool isDischargeOK(); + ThinkBatteryManager(); + void setup(); + void handleTick(); + void handleCanFrame(CAN_FRAME *frame); + DeviceId getId(); + bool hasPackVoltage(); + bool hasPackCurrent(); + bool hasTemperatures(); + bool isChargeOK(); + bool isDischargeOK(); protected: private: - void sendKeepAlive(); + void sendKeepAlive(); }; #endif diff --git a/Throttle.cpp b/Throttle.cpp index cb9bb71..20acd89 100644 --- a/Throttle.cpp +++ b/Throttle.cpp @@ -31,8 +31,8 @@ * Constructor */ Throttle::Throttle() : Device() { - level = 0; - status = OK; + level = 0; + status = OK; } /* @@ -42,14 +42,14 @@ Throttle::Throttle() : Device() { * Get's called by the sub-class which is triggered by the tick handler */ void Throttle::handleTick() { - Device::handleTick(); - - RawSignalData *rawSignals = acquireRawSignal(); // get raw data from the throttle device - if (validateSignal(rawSignals)) { // validate the raw data - uint16_t position = calculatePedalPosition(rawSignals); // bring the raw data into a range of 0-1000 (without mapping) - level = mapPedalPosition(position); // apply mapping of the 0-1000 range to the user defined settings - } else - level = 0; + Device::handleTick(); + + RawSignalData *rawSignals = acquireRawSignal(); // get raw data from the throttle device + if (validateSignal(rawSignals)) { // validate the raw data + uint16_t position = calculatePedalPosition(rawSignals); // bring the raw data into a range of 0-1000 (without mapping) + level = mapPedalPosition(position); // apply mapping of the 0-1000 range to the user defined settings + } else + level = 0; } /* @@ -80,47 +80,47 @@ void Throttle::handleTick() { * 0 <= positionRegenMaximum <= positionRegenMinimum <= positionForwardMotionStart <= positionHalfPower */ int16_t Throttle::mapPedalPosition(int16_t pedalPosition) { - int16_t throttleLevel, range, value; - ThrottleConfiguration *config = (ThrottleConfiguration *) getConfiguration(); - - throttleLevel = 0; - - if (pedalPosition == 0 && config->creep > 0) { - throttleLevel = 10 * config->creep; - } else if (pedalPosition <= config->positionRegenMinimum) { - if (pedalPosition >= config->positionRegenMaximum) { - range = config->positionRegenMinimum - config->positionRegenMaximum; - value = pedalPosition - config->positionRegenMaximum; - if (range != 0) // prevent div by zero, should result in 0 throttle if min==max - throttleLevel = -10 * config->minimumRegen + (config->maximumRegen - config->minimumRegen) * (100 - value * 100 / range) / -10; - } else { - // no ramping yet below positionRegenMaximum, just drop to 0 + int16_t throttleLevel, range, value; + ThrottleConfiguration *config = (ThrottleConfiguration *) getConfiguration(); + + throttleLevel = 0; + + if (pedalPosition == 0 && config->creep > 0) { + throttleLevel = 10 * config->creep; + } else if (pedalPosition <= config->positionRegenMinimum) { + if (pedalPosition >= config->positionRegenMaximum) { + range = config->positionRegenMinimum - config->positionRegenMaximum; + value = pedalPosition - config->positionRegenMaximum; + if (range != 0) // prevent div by zero, should result in 0 throttle if min==max + throttleLevel = -10 * config->minimumRegen + (config->maximumRegen - config->minimumRegen) * (100 - value * 100 / range) / -10; + } else { + // no ramping yet below positionRegenMaximum, just drop to 0 // range = config->positionRegenMaximum; // value = pedalPosition; // throttleLevel = -10 * config->maximumRegen * value / range; - } - } - - if (pedalPosition >= config->positionForwardMotionStart) { - if (pedalPosition <= config->positionHalfPower) { - range = config->positionHalfPower - config->positionForwardMotionStart; - value = pedalPosition - config->positionForwardMotionStart; - if (range != 0) // prevent div by zero, should result in 0 throttle if half==startFwd - throttleLevel = 500 * value / range; - } else { - range = 1000 - config->positionHalfPower; - value = pedalPosition - config->positionHalfPower; - throttleLevel = 500 + 500 * value / range; - } - } - //Logger::debug("throttle level: %d", throttleLevel); - - //A bit of a kludge. Normally it isn't really possible to ever get to - //100% output. This next line just fudges the numbers a bit to make it - //more likely to get that last bit of power - if (throttleLevel > 979) throttleLevel = 1000; - - return throttleLevel; + } + } + + if (pedalPosition >= config->positionForwardMotionStart) { + if (pedalPosition <= config->positionHalfPower) { + range = config->positionHalfPower - config->positionForwardMotionStart; + value = pedalPosition - config->positionForwardMotionStart; + if (range != 0) // prevent div by zero, should result in 0 throttle if half==startFwd + throttleLevel = 500 * value / range; + } else { + range = 1000 - config->positionHalfPower; + value = pedalPosition - config->positionHalfPower; + throttleLevel = 500 + 500 * value / range; + } + } + //Logger::debug("throttle level: %d", throttleLevel); + + //A bit of a kludge. Normally it isn't really possible to ever get to + //100% output. This next line just fudges the numbers a bit to make it + //more likely to get that last bit of power + if (throttleLevel > 979) throttleLevel = 1000; + + return throttleLevel; } /* @@ -128,108 +128,108 @@ int16_t Throttle::mapPedalPosition(int16_t pedalPosition) { * level linearly to a value from 0 to 1000. */ uint16_t Throttle::normalizeAndConstrainInput(int32_t input, int32_t min, int32_t max) { - return constrain(normalizeInput(input, min, max), (int32_t) 0, (int32_t) 1000); + return constrain(normalizeInput(input, min, max), (int32_t) 0, (int32_t) 1000); } /* * Map the constrained level linearly to a signed value from 0 to 1000. */ int32_t Throttle::normalizeInput(int32_t input, int32_t min, int32_t max) { - return map(input, min, max, (int32_t) 0, (int32_t) 1000); + return map(input, min, max, (int32_t) 0, (int32_t) 1000); } /* * Returns the currently calculated/mapped throttle level (from -1000 to 1000). */ int16_t Throttle::getLevel() { - return level; + return level; } /* * Return the throttle's current status */ Throttle::ThrottleStatus Throttle::getStatus() { - return status; + return status; } /* * Is the throttle faulted? */ bool Throttle::isFaulted() { - return status != OK; + return status != OK; } /* * Return the device type */ DeviceType Throttle::getType() { - return DEVICE_THROTTLE; + return DEVICE_THROTTLE; } RawSignalData* Throttle::acquireRawSignal() { - return NULL; + return NULL; } bool Throttle::validateSignal(RawSignalData*) { - return false; + return false; } uint16_t Throttle::calculatePedalPosition(RawSignalData*) { - return 0; + return 0; } /* * Load the config parameters which are required by all throttles */ void Throttle::loadConfiguration() { - ThrottleConfiguration *config = (ThrottleConfiguration *) getConfiguration(); + ThrottleConfiguration *config = (ThrottleConfiguration *) getConfiguration(); - Device::loadConfiguration(); // call parent + Device::loadConfiguration(); // call parent #ifdef USE_HARD_CODED - if (false) { + if (false) { #else - if (prefsHandler->checksumValid()) { //checksum is good, read in the values stored in EEPROM + if (prefsHandler->checksumValid()) { //checksum is good, read in the values stored in EEPROM #endif - prefsHandler->read(EETH_REGEN_MIN, &config->positionRegenMinimum); - prefsHandler->read(EETH_REGEN_MAX, &config->positionRegenMaximum); - prefsHandler->read(EETH_FWD, &config->positionForwardMotionStart); - prefsHandler->read(EETH_MAP, &config->positionHalfPower); - prefsHandler->read(EETH_CREEP, &config->creep); - prefsHandler->read(EETH_MIN_ACCEL_REGEN, &config->minimumRegen); - prefsHandler->read(EETH_MAX_ACCEL_REGEN, &config->maximumRegen); - } else { //checksum invalid. Reinitialize values, leave storing them to the subclasses - config->positionRegenMinimum = ThrottleRegenMinValue; - config->positionRegenMaximum = ThrottleRegenMaxValue; - config->positionForwardMotionStart = ThrottleFwdValue; - config->positionHalfPower = ThrottleMapValue; - config->creep = ThrottleCreepValue; - config->minimumRegen = ThrottleMinRegenValue; //percentage of minimal power to use when regen starts - config->maximumRegen = ThrottleMaxRegenValue; //percentage of full power to use for regen at throttle - } - Logger::debug(THROTTLE, "RegenMax: %l RegenMin: %l Fwd: %l Map: %l", config->positionRegenMaximum, config->positionRegenMinimum, - config->positionForwardMotionStart, config->positionHalfPower); - Logger::debug(THROTTLE, "MinRegen: %d MaxRegen: %d", config->minimumRegen, config->maximumRegen); + prefsHandler->read(EETH_REGEN_MIN, &config->positionRegenMinimum); + prefsHandler->read(EETH_REGEN_MAX, &config->positionRegenMaximum); + prefsHandler->read(EETH_FWD, &config->positionForwardMotionStart); + prefsHandler->read(EETH_MAP, &config->positionHalfPower); + prefsHandler->read(EETH_CREEP, &config->creep); + prefsHandler->read(EETH_MIN_ACCEL_REGEN, &config->minimumRegen); + prefsHandler->read(EETH_MAX_ACCEL_REGEN, &config->maximumRegen); + } else { //checksum invalid. Reinitialize values, leave storing them to the subclasses + config->positionRegenMinimum = ThrottleRegenMinValue; + config->positionRegenMaximum = ThrottleRegenMaxValue; + config->positionForwardMotionStart = ThrottleFwdValue; + config->positionHalfPower = ThrottleMapValue; + config->creep = ThrottleCreepValue; + config->minimumRegen = ThrottleMinRegenValue; //percentage of minimal power to use when regen starts + config->maximumRegen = ThrottleMaxRegenValue; //percentage of full power to use for regen at throttle + } + Logger::debug(THROTTLE, "RegenMax: %l RegenMin: %l Fwd: %l Map: %l", config->positionRegenMaximum, config->positionRegenMinimum, + config->positionForwardMotionStart, config->positionHalfPower); + Logger::debug(THROTTLE, "MinRegen: %d MaxRegen: %d", config->minimumRegen, config->maximumRegen); } /* * Store the current configuration to EEPROM */ void Throttle::saveConfiguration() { - ThrottleConfiguration *config = (ThrottleConfiguration *) getConfiguration(); + ThrottleConfiguration *config = (ThrottleConfiguration *) getConfiguration(); - Device::saveConfiguration(); // call parent + Device::saveConfiguration(); // call parent - prefsHandler->write(EETH_REGEN_MIN, config->positionRegenMinimum); - prefsHandler->write(EETH_REGEN_MAX, config->positionRegenMaximum); - prefsHandler->write(EETH_FWD, config->positionForwardMotionStart); - prefsHandler->write(EETH_MAP, config->positionHalfPower); - prefsHandler->write(EETH_CREEP, config->creep); - prefsHandler->write(EETH_MIN_ACCEL_REGEN, config->minimumRegen); - prefsHandler->write(EETH_MAX_ACCEL_REGEN, config->maximumRegen); - prefsHandler->saveChecksum(); + prefsHandler->write(EETH_REGEN_MIN, config->positionRegenMinimum); + prefsHandler->write(EETH_REGEN_MAX, config->positionRegenMaximum); + prefsHandler->write(EETH_FWD, config->positionForwardMotionStart); + prefsHandler->write(EETH_MAP, config->positionHalfPower); + prefsHandler->write(EETH_CREEP, config->creep); + prefsHandler->write(EETH_MIN_ACCEL_REGEN, config->minimumRegen); + prefsHandler->write(EETH_MAX_ACCEL_REGEN, config->maximumRegen); + prefsHandler->saveChecksum(); - Logger::console("Throttle configuration saved"); + Logger::console("Throttle configuration saved"); } diff --git a/Throttle.h b/Throttle.h index 57f5d35..fd1fa98 100644 --- a/Throttle.h +++ b/Throttle.h @@ -41,9 +41,9 @@ * E.g. for a three pot pedal, all signals could be used. */ struct RawSignalData { - int32_t input1; // e.g. pot #1 or the signal from a can bus throttle - int32_t input2; // e.g. pot #2 (optional) - int32_t input3; // e.g. pot #3 (optional) + int32_t input1; // e.g. pot #1 or the signal from a can bus throttle + int32_t input2; // e.g. pot #2 (optional) + int32_t input3; // e.g. pot #3 (optional) }; /* @@ -52,11 +52,11 @@ struct RawSignalData { */ class ThrottleConfiguration: public DeviceConfiguration { public: - uint16_t positionRegenMaximum, positionRegenMinimum; // throttle position where regen is highest and lowest - uint16_t positionForwardMotionStart, positionHalfPower; // throttle position where forward motion starts and the mid point of throttle - uint8_t maximumRegen; // percentage of max torque allowable for regen at maximum level - uint8_t minimumRegen; // percentage of max torque allowable for regen at minimum level - uint8_t creep; // percentage of torque used for creep function (imitate creep of automatic transmission, set 0 to disable) + uint16_t positionRegenMaximum, positionRegenMinimum; // throttle position where regen is highest and lowest + uint16_t positionForwardMotionStart, positionHalfPower; // throttle position where forward motion starts and the mid point of throttle + uint8_t maximumRegen; // percentage of max torque allowable for regen at maximum level + uint8_t minimumRegen; // percentage of max torque allowable for regen at minimum level + uint8_t creep; // percentage of torque used for creep function (imitate creep of automatic transmission, set 0 to disable) }; /* @@ -64,37 +64,37 @@ class ThrottleConfiguration: public DeviceConfiguration { */ class Throttle: public Device { public: - enum ThrottleStatus { - OK, - ERR_LOW_T1, - ERR_LOW_T2, - ERR_HIGH_T1, - ERR_HIGH_T2, - ERR_MISMATCH, - ERR_MISC - }; - - Throttle(); - virtual int16_t getLevel(); - void handleTick(); - virtual ThrottleStatus getStatus(); - virtual bool isFaulted(); - virtual DeviceType getType(); - - virtual RawSignalData *acquireRawSignal(); - void loadConfiguration(); - void saveConfiguration(); + enum ThrottleStatus { + OK, + ERR_LOW_T1, + ERR_LOW_T2, + ERR_HIGH_T1, + ERR_HIGH_T2, + ERR_MISMATCH, + ERR_MISC + }; + + Throttle(); + virtual int16_t getLevel(); + void handleTick(); + virtual ThrottleStatus getStatus(); + virtual bool isFaulted(); + virtual DeviceType getType(); + + virtual RawSignalData *acquireRawSignal(); + void loadConfiguration(); + void saveConfiguration(); protected: - ThrottleStatus status; - virtual bool validateSignal(RawSignalData *); - virtual uint16_t calculatePedalPosition(RawSignalData *); - virtual int16_t mapPedalPosition(int16_t); - uint16_t normalizeAndConstrainInput(int32_t, int32_t, int32_t); - int32_t normalizeInput(int32_t, int32_t, int32_t); + ThrottleStatus status; + virtual bool validateSignal(RawSignalData *); + virtual uint16_t calculatePedalPosition(RawSignalData *); + virtual int16_t mapPedalPosition(int16_t); + uint16_t normalizeAndConstrainInput(int32_t, int32_t, int32_t); + int32_t normalizeInput(int32_t, int32_t, int32_t); private: - int16_t level; // the final signed throttle level. [-1000, 1000] in permille of maximum + int16_t level; // the final signed throttle level. [-1000, 1000] in permille of maximum }; #endif diff --git a/ThrottleDetector.cpp b/ThrottleDetector.cpp index b6fdc04..76553b5 100644 --- a/ThrottleDetector.cpp +++ b/ThrottleDetector.cpp @@ -34,12 +34,12 @@ * The constructor takes a pointer to a throttle */ ThrottleDetector::ThrottleDetector(Throttle *throttle) { - this->throttle = throttle; - config = (PotThrottleConfiguration *) throttle->getConfiguration(); - state = DoNothing; - maxThrottleReadingDeviationPercent = 100; // 10% in 0-1000 scale - Logger::debug("ThrottleDetector constructed with throttle %d", throttle); - resetValues(); + this->throttle = throttle; + config = (PotThrottleConfiguration *) throttle->getConfiguration(); + state = DoNothing; + maxThrottleReadingDeviationPercent = 100; // 10% in 0-1000 scale + Logger::debug("ThrottleDetector constructed with throttle %d", throttle); + resetValues(); } /* @@ -53,23 +53,23 @@ ThrottleDetector::~ThrottleDetector() { * method is called so we track the state and resume the operation each call */ void ThrottleDetector::handleTick() { - switch (state) { - case DetectMinWait: - detectMinWait(); - break; - case DetectMinCalibrate: - detectMinCalibrate(); - break; - case DetectMaxWait: - detectMaxWait(); - break; - case DetectMaxCalibrate: - detectMaxCalibrate(); - break; - - case DoNothing: - break; - } + switch (state) { + case DetectMinWait: + detectMinWait(); + break; + case DetectMinCalibrate: + detectMinCalibrate(); + break; + case DetectMaxWait: + detectMaxWait(); + break; + case DetectMaxCalibrate: + detectMaxCalibrate(); + break; + + case DoNothing: + break; + } } /* @@ -77,277 +77,277 @@ void ThrottleDetector::handleTick() { * Step 1. Kick it off */ void ThrottleDetector::detect() { - Logger::console("Throttle detection starting. Do NOT press the pedal until instructed."); + Logger::console("Throttle detection starting. Do NOT press the pedal until instructed."); - resetValues(); + resetValues(); - // reset stats - sampleCount = 0; - linearCount = 0; - inverseCount = 0; - for (int i = 0; i < 200; i++) { - throttle1Values[i] = 0; - throttle2Values[i] = 0; - } + // reset stats + sampleCount = 0; + linearCount = 0; + inverseCount = 0; + for (int i = 0; i < 200; i++) { + throttle1Values[i] = 0; + throttle2Values[i] = 0; + } - // we wait for 2 seconds so kick this off - startTime = millis(); - state = DetectMinWait; + // we wait for 2 seconds so kick this off + startTime = millis(); + state = DetectMinWait; - TickHandler::getInstance()->attach(this, CFG_TICK_INTERVAL_POT_THROTTLE); + TickHandler::getInstance()->attach(this, CFG_TICK_INTERVAL_POT_THROTTLE); } /* * Step 2. Wait for 2 seconds then start taking MIN readings */ void ThrottleDetector::detectMinWait() { - if ((millis() - startTime) >= 2000) { - // take MIN readings for 2 seconds - startTime = millis(); - readThrottleValues(); - state = DetectMinCalibrate; - } + if ((millis() - startTime) >= 2000) { + // take MIN readings for 2 seconds + startTime = millis(); + readThrottleValues(); + state = DetectMinCalibrate; + } } /* * Step 3. Take MIN readings for 2 seconds then start waiting again */ void ThrottleDetector::detectMinCalibrate() { - if ((millis() - startTime) < 2000 || sampleCount < maxSamples / 3) { - readThrottleValues(); - } else { - displayCalibratedValues(true); - - // save rest minimums - throttle1MinRest = throttle1Min; - throttle1MaxRest = throttle1Max; - throttle2MinRest = throttle2Min; - throttle2MaxRest = throttle2Max; - - Logger::console("\nSmoothly depress the pedal to full acceleration"); - Logger::console("and hold the pedal until complete"); - - // wait for 5 seconds so they can react and then still get some readings - startTime = millis(); - state = DetectMaxWait; - } + if ((millis() - startTime) < 2000 || sampleCount < maxSamples / 3) { + readThrottleValues(); + } else { + displayCalibratedValues(true); + + // save rest minimums + throttle1MinRest = throttle1Min; + throttle1MaxRest = throttle1Max; + throttle2MinRest = throttle2Min; + throttle2MaxRest = throttle2Max; + + Logger::console("\nSmoothly depress the pedal to full acceleration"); + Logger::console("and hold the pedal until complete"); + + // wait for 5 seconds so they can react and then still get some readings + startTime = millis(); + state = DetectMaxWait; + } } /* * Step 4. Wait for 5 seconds then start taking MAX readings */ void ThrottleDetector::detectMaxWait() { - if ((millis() - startTime) >= 5000 || sampleCount >= maxSamples * 2 / 3) { - - // take MAX readings for 2 seconds - resetValues(); - startTime = millis(); - readThrottleValues(); - state = DetectMaxCalibrate; - } else { - readThrottleValues(); - } + if ((millis() - startTime) >= 5000 || sampleCount >= maxSamples * 2 / 3) { + + // take MAX readings for 2 seconds + resetValues(); + startTime = millis(); + readThrottleValues(); + state = DetectMaxCalibrate; + } else { + readThrottleValues(); + } } /* * Step 5. Take MAX readings for 3 seconds then show results */ void ThrottleDetector::detectMaxCalibrate() { - if ((millis() - startTime) < 2000 && sampleCount < maxSamples) { - readThrottleValues(); - } else { - displayCalibratedValues(false); - - // take some stats before normalizing min/max - int throttle1MinFluctuation = abs(throttle1MaxRest-throttle1MinRest); - int throttle2MinFluctuation = abs(throttle2MaxRest-throttle2MinRest); - int throttle1MaxFluctuation = abs(throttle1Max-throttle1Min); - int throttle2MaxFluctuation = abs(throttle2Max-throttle2Min); - - // Determine throttle type based off min/max - if (throttle1MinRest > throttle1Min+maxThrottleReadingDeviationPercent) { // high to low pot - throttle1HighLow = true; - } - - if (throttle2MinRest > throttle2Min+maxThrottleReadingDeviationPercent) { // high to low pot - throttle2HighLow = true; - } - - // restore the true min - throttle1Min = throttle1MinRest; - - if ((throttle1HighLow && !throttle2HighLow) || (throttle2HighLow && !throttle1HighLow)) { - throttle2Inverse = true; - } - - // Detect grounded pin (always zero) or floating values which indicate no potentiometer provided - if ((throttle2MinRest == 0 && throttle2MaxRest == 0 && throttle2Min == INT16_MAX && throttle2Max == 0) - || (abs(throttle2MaxRest-throttle2Max) < maxThrottleReadingDeviationPercent - && abs(throttle2MinRest-throttle2Min) < maxThrottleReadingDeviationPercent)) { - potentiometerCount = 1; - } else { - potentiometerCount = 2; - } - - // restore the true min/max for T2 - if ( throttle2Inverse ) { - throttle2Max = throttle2MaxRest; - } else { - throttle2Min = throttle2MinRest; - } - - Logger::debug("Inverse: %s, throttle2Min: %d, throttle2Max: %d", (throttle2Inverse?"true":"false"), throttle2Min, throttle2Max); - - // fluctuation percentages - make sure not to divide by zero - if (!(throttle1Max == throttle1Min)) - { - throttle1MinFluctuationPercent = throttle1MinFluctuation * 100 / abs(throttle1Max - throttle1Min); - throttle1MaxFluctuationPercent = throttle1MaxFluctuation * 100 / abs(throttle1Max - throttle1Min); - } - else - { - throttle1MinFluctuationPercent = 0; - throttle1MaxFluctuationPercent = 0; - } - if (!(throttle2Max == throttle2Min)) - { - throttle2MinFluctuationPercent = throttle2MinFluctuation * 100 / abs(throttle2Max - throttle2Min); - throttle2MaxFluctuationPercent = throttle2MaxFluctuation * 100 / abs(throttle2Max - throttle2Min); - } - else - { - throttle2MinFluctuationPercent = 0; - throttle2MaxFluctuationPercent = 0; - } - - // Determine throttle subtype by examining the data sampled - for (int i = 0; i < sampleCount; i++) { - // normalize the values to a 0-1000 scale using the found min/max - uint16_t value1 = normalize(throttle1Values[i], throttle1Min, throttle1Max, 0, 1000); - uint16_t value2 = normalize(throttle2Values[i], throttle2Min, throttle2Max, 0, 1000); - - // see if they match known subtypes - linearCount += checkLinear(value1, value2); - inverseCount += checkInverse(value1, value2); - - //Logger::debug("T1: %d, T2: %d = NT1: %d, NT2: %d, L: %d, I: %d", throttle1Values[i], throttle2Values[i], value1, value2, linearCount, inverseCount); - } - - throttleSubType = 0; - if (potentiometerCount > 1) { - // For dual pots, we trust the detection of >75% - if ((linearCount * 100) / sampleCount > 75) { - throttleSubType = 1; - } else if ((inverseCount * 100) / sampleCount > 75) { - throttleSubType = 2; - } - } else { - // For single pots we use the high/low - if (throttle1HighLow) { - throttleSubType = 2; - } else { - throttleSubType = 1; - } - } - - char *type = "UNKNOWN"; - if (throttleSubType == 1) { - type = "Linear"; - } else if (throttleSubType == 2) { - type = "Inverse"; - } - - if ( Logger::isDebug()) { - Logger::console("\n----- RAW values ----"); - for (int i = 0; i < sampleCount; i++) { - Logger::console("T1: %d, T2: %d", throttle1Values[i], throttle2Values[i]); - } - } - - Logger::console("\n======================================="); - Logger::console("Detection complete"); - Logger::console("Num samples taken: %d", sampleCount); - Logger::console("Num potentiometers found: %d", potentiometerCount); - Logger::console("T1: %d to %d %s", (throttle1HighLow ? throttle1Max : throttle1Min), (throttle1HighLow ? throttle1Min : throttle1Max), - (throttle1HighLow ? "HIGH-LOW" : "LOW-HIGH")); - Logger::console("T1: rest fluctuation %d%%, full throttle fluctuation %d%%", throttle1MinFluctuationPercent, throttle1MaxFluctuationPercent); - - if (potentiometerCount > 1) { - Logger::console("T2: %d to %d %s %s", (throttle2HighLow ? throttle2Max : throttle2Min), (throttle2HighLow ? throttle2Min : throttle2Max), - (throttle2HighLow ? "HIGH-LOW" : "LOW-HIGH"), (throttle2Inverse ? " (Inverse of T1)" : "")); - Logger::console("T2: rest fluctuation %d%%, full throttle fluctuation %d%%", throttle2MinFluctuationPercent, throttle2MaxFluctuationPercent); - Logger::console("Num linear throttle matches: %d", linearCount); - Logger::console("Num inverse throttle matches: %d", inverseCount); - } - - Logger::console("Throttle type: %s", type); - Logger::console("========================================"); - - // update the throttle's configuration (without storing it yet) - config->minimumLevel1 = throttle1Min; - config->maximumLevel1 = throttle1Max; - config->numberPotMeters = potentiometerCount; - if (config->numberPotMeters > 1) { - config->minimumLevel2 = throttle2Min; - config->maximumLevel2 = throttle2Max; - } else { - config->minimumLevel2 = 0; - config->maximumLevel2 = 0; - } - config->throttleSubType = throttleSubType; - - // Done! - state = DoNothing; - TickHandler::getInstance()->detach(this); - - // send updates to ichip wifi - DeviceManager::getInstance()->sendMessage(DEVICE_WIFI, ICHIP2128, MSG_CONFIG_CHANGE, NULL); - } + if ((millis() - startTime) < 2000 && sampleCount < maxSamples) { + readThrottleValues(); + } else { + displayCalibratedValues(false); + + // take some stats before normalizing min/max + int throttle1MinFluctuation = abs(throttle1MaxRest-throttle1MinRest); + int throttle2MinFluctuation = abs(throttle2MaxRest-throttle2MinRest); + int throttle1MaxFluctuation = abs(throttle1Max-throttle1Min); + int throttle2MaxFluctuation = abs(throttle2Max-throttle2Min); + + // Determine throttle type based off min/max + if (throttle1MinRest > throttle1Min+maxThrottleReadingDeviationPercent) { // high to low pot + throttle1HighLow = true; + } + + if (throttle2MinRest > throttle2Min+maxThrottleReadingDeviationPercent) { // high to low pot + throttle2HighLow = true; + } + + // restore the true min + throttle1Min = throttle1MinRest; + + if ((throttle1HighLow && !throttle2HighLow) || (throttle2HighLow && !throttle1HighLow)) { + throttle2Inverse = true; + } + + // Detect grounded pin (always zero) or floating values which indicate no potentiometer provided + if ((throttle2MinRest == 0 && throttle2MaxRest == 0 && throttle2Min == INT16_MAX && throttle2Max == 0) + || (abs(throttle2MaxRest-throttle2Max) < maxThrottleReadingDeviationPercent + && abs(throttle2MinRest-throttle2Min) < maxThrottleReadingDeviationPercent)) { + potentiometerCount = 1; + } else { + potentiometerCount = 2; + } + + // restore the true min/max for T2 + if ( throttle2Inverse ) { + throttle2Max = throttle2MaxRest; + } else { + throttle2Min = throttle2MinRest; + } + + Logger::debug("Inverse: %s, throttle2Min: %d, throttle2Max: %d", (throttle2Inverse?"true":"false"), throttle2Min, throttle2Max); + + // fluctuation percentages - make sure not to divide by zero + if (!(throttle1Max == throttle1Min)) + { + throttle1MinFluctuationPercent = throttle1MinFluctuation * 100 / abs(throttle1Max - throttle1Min); + throttle1MaxFluctuationPercent = throttle1MaxFluctuation * 100 / abs(throttle1Max - throttle1Min); + } + else + { + throttle1MinFluctuationPercent = 0; + throttle1MaxFluctuationPercent = 0; + } + if (!(throttle2Max == throttle2Min)) + { + throttle2MinFluctuationPercent = throttle2MinFluctuation * 100 / abs(throttle2Max - throttle2Min); + throttle2MaxFluctuationPercent = throttle2MaxFluctuation * 100 / abs(throttle2Max - throttle2Min); + } + else + { + throttle2MinFluctuationPercent = 0; + throttle2MaxFluctuationPercent = 0; + } + + // Determine throttle subtype by examining the data sampled + for (int i = 0; i < sampleCount; i++) { + // normalize the values to a 0-1000 scale using the found min/max + uint16_t value1 = normalize(throttle1Values[i], throttle1Min, throttle1Max, 0, 1000); + uint16_t value2 = normalize(throttle2Values[i], throttle2Min, throttle2Max, 0, 1000); + + // see if they match known subtypes + linearCount += checkLinear(value1, value2); + inverseCount += checkInverse(value1, value2); + + //Logger::debug("T1: %d, T2: %d = NT1: %d, NT2: %d, L: %d, I: %d", throttle1Values[i], throttle2Values[i], value1, value2, linearCount, inverseCount); + } + + throttleSubType = 0; + if (potentiometerCount > 1) { + // For dual pots, we trust the detection of >75% + if ((linearCount * 100) / sampleCount > 75) { + throttleSubType = 1; + } else if ((inverseCount * 100) / sampleCount > 75) { + throttleSubType = 2; + } + } else { + // For single pots we use the high/low + if (throttle1HighLow) { + throttleSubType = 2; + } else { + throttleSubType = 1; + } + } + + char *type = "UNKNOWN"; + if (throttleSubType == 1) { + type = "Linear"; + } else if (throttleSubType == 2) { + type = "Inverse"; + } + + if ( Logger::isDebug()) { + Logger::console("\n----- RAW values ----"); + for (int i = 0; i < sampleCount; i++) { + Logger::console("T1: %d, T2: %d", throttle1Values[i], throttle2Values[i]); + } + } + + Logger::console("\n======================================="); + Logger::console("Detection complete"); + Logger::console("Num samples taken: %d", sampleCount); + Logger::console("Num potentiometers found: %d", potentiometerCount); + Logger::console("T1: %d to %d %s", (throttle1HighLow ? throttle1Max : throttle1Min), (throttle1HighLow ? throttle1Min : throttle1Max), + (throttle1HighLow ? "HIGH-LOW" : "LOW-HIGH")); + Logger::console("T1: rest fluctuation %d%%, full throttle fluctuation %d%%", throttle1MinFluctuationPercent, throttle1MaxFluctuationPercent); + + if (potentiometerCount > 1) { + Logger::console("T2: %d to %d %s %s", (throttle2HighLow ? throttle2Max : throttle2Min), (throttle2HighLow ? throttle2Min : throttle2Max), + (throttle2HighLow ? "HIGH-LOW" : "LOW-HIGH"), (throttle2Inverse ? " (Inverse of T1)" : "")); + Logger::console("T2: rest fluctuation %d%%, full throttle fluctuation %d%%", throttle2MinFluctuationPercent, throttle2MaxFluctuationPercent); + Logger::console("Num linear throttle matches: %d", linearCount); + Logger::console("Num inverse throttle matches: %d", inverseCount); + } + + Logger::console("Throttle type: %s", type); + Logger::console("========================================"); + + // update the throttle's configuration (without storing it yet) + config->minimumLevel1 = throttle1Min; + config->maximumLevel1 = throttle1Max; + config->numberPotMeters = potentiometerCount; + if (config->numberPotMeters > 1) { + config->minimumLevel2 = throttle2Min; + config->maximumLevel2 = throttle2Max; + } else { + config->minimumLevel2 = 0; + config->maximumLevel2 = 0; + } + config->throttleSubType = throttleSubType; + + // Done! + state = DoNothing; + TickHandler::getInstance()->detach(this); + + // send updates to ichip wifi + DeviceManager::getInstance()->sendMessage(DEVICE_WIFI, ICHIP2128, MSG_CONFIG_CHANGE, NULL); + } } /* * Reset/initialize some values */ void ThrottleDetector::resetValues() { - throttle1Min = INT16_MAX; - throttle1Max = 0; - throttle2Min = INT16_MAX; - throttle2Max = 0; - - potentiometerCount = 1; - throttle1HighLow = false; - throttle2HighLow = false; - throttle2Inverse = false; + throttle1Min = INT16_MAX; + throttle1Max = 0; + throttle2Min = INT16_MAX; + throttle2Max = 0; + + potentiometerCount = 1; + throttle1HighLow = false; + throttle2HighLow = false; + throttle2Inverse = false; } /* * Reads values from the throttles. */ void ThrottleDetector::readThrottleValues() { - RawSignalData *rawSignal = throttle->acquireRawSignal(); - throttle1Values[sampleCount] = rawSignal->input1; - throttle2Values[sampleCount] = rawSignal->input2; - sampleCount++; - - // record the minimum sensor value - if (rawSignal->input1 < throttle1Min) { - throttle1Min = rawSignal->input1; - } - - // record the maximum sensor value - if (rawSignal->input1 > throttle1Max) { - throttle1Max = rawSignal->input1; - } - - // record the minimum sensor value - if (rawSignal->input2 < throttle2Min) { - throttle2Min = rawSignal->input2; - } - - // record the maximum sensor value - if (rawSignal->input2 > throttle2Max) { - throttle2Max = rawSignal->input2; - } + RawSignalData *rawSignal = throttle->acquireRawSignal(); + throttle1Values[sampleCount] = rawSignal->input1; + throttle2Values[sampleCount] = rawSignal->input2; + sampleCount++; + + // record the minimum sensor value + if (rawSignal->input1 < throttle1Min) { + throttle1Min = rawSignal->input1; + } + + // record the maximum sensor value + if (rawSignal->input1 > throttle1Max) { + throttle1Max = rawSignal->input1; + } + + // record the minimum sensor value + if (rawSignal->input2 < throttle2Min) { + throttle2Min = rawSignal->input2; + } + + // record the maximum sensor value + if (rawSignal->input2 > throttle2Max) { + throttle2Max = rawSignal->input2; + } } /* @@ -356,10 +356,10 @@ void ThrottleDetector::readThrottleValues() { * Assumes the values are already mapped to a 0-1000 scale */ int ThrottleDetector::checkLinear(uint16_t throttle1Value, uint16_t throttle2Value) { - if ( abs(throttle1Value-throttle2Value) < maxThrottleReadingDeviationPercent) - return 1; + if ( abs(throttle1Value-throttle2Value) < maxThrottleReadingDeviationPercent) + return 1; - return 0; + return 0; } /* @@ -368,25 +368,25 @@ int ThrottleDetector::checkLinear(uint16_t throttle1Value, uint16_t throttle2Val * Assumes the values are already mapped to a 0-1000 scale */ int ThrottleDetector::checkInverse(uint16_t throttle1Value, uint16_t throttle2Value) { - if (abs(1000 - (throttle1Value+throttle2Value)) < maxThrottleReadingDeviationPercent) - return 1; + if (abs(1000 - (throttle1Value+throttle2Value)) < maxThrottleReadingDeviationPercent) + return 1; - return 0; + return 0; } void ThrottleDetector::displayCalibratedValues(bool minPedal) { - Logger::console("\nAt %s T1: %d to %d", (minPedal ? "MIN" : "MAX"), throttle1Min, throttle1Max); - //if (potentiometerCount > 1) - Logger::console(" T2: %d to %d", throttle2Min, throttle2Max); - Logger::console(""); + Logger::console("\nAt %s T1: %d to %d", (minPedal ? "MIN" : "MAX"), throttle1Min, throttle1Max); + //if (potentiometerCount > 1) + Logger::console(" T2: %d to %d", throttle2Min, throttle2Max); + Logger::console(""); } /** * Map and constrain the value to the given range */ uint16_t ThrottleDetector::normalize(uint16_t sensorValue, uint16_t sensorMin, uint16_t sensorMax, uint16_t constrainMin, uint16_t constrainMax) { - int value = map(sensorValue, sensorMin, sensorMax, constrainMin, constrainMax); - return constrain(value, constrainMin, constrainMax); + int value = map(sensorValue, sensorMin, sensorMax, constrainMin, constrainMax); + return constrain(value, constrainMin, constrainMax); } diff --git a/ThrottleDetector.h b/ThrottleDetector.h index 647989f..42dce35 100644 --- a/ThrottleDetector.h +++ b/ThrottleDetector.h @@ -40,60 +40,60 @@ class Throttle; class ThrottleDetector : public TickObserver { public: - ThrottleDetector(Throttle *throttle); - ~ThrottleDetector(); - void handleTick(); - void detect(); + ThrottleDetector(Throttle *throttle); + ~ThrottleDetector(); + void handleTick(); + void detect(); private: - enum DetectionState { - DoNothing, - DetectMinWait, - DetectMinCalibrate, - DetectMaxWait, - DetectMaxCalibrate - }; - - void detectMinWait(); - void detectMinCalibrate(); - void detectMaxWait(); - void detectMaxCalibrate(); - void displayCalibratedValues(bool minPedal); - void resetValues(); - void readThrottleValues(); - int checkLinear(uint16_t, uint16_t); - int checkInverse(uint16_t, uint16_t); - uint16_t normalize(uint16_t sensorValue, uint16_t sensorMin, uint16_t sensorMax, uint16_t constrainMin, uint16_t constrainMax); - - Throttle *throttle; - PotThrottleConfiguration *config; - DetectionState state; - unsigned long startTime; - int potentiometerCount; // the number of potentiometers detected - uint16_t throttle1Min; // the minimum value of throttle1 - uint16_t throttle1Max; // the maximum value of throttle1 - uint16_t throttle2Min; // the minimum value of throttle2 - uint16_t throttle2Max; // the maximum value of throttle2 - uint8_t throttleSubType; // the throttle sub type - bool throttle1HighLow; // true if throttle1 ranges from highest to lowest value as the pedal is pressed - bool throttle2HighLow; // true if throttle2 ranges from highest to lowest value as the pedal is pressed - bool throttle2Inverse; // true if throttle2 values are the opposite of the throttle1 values. - int throttle1MinRest; // minimum sensor value at rest - int throttle1MaxRest; // minimum sensor value at rest - int throttle2MinRest; // minimum sensor value at rest - int throttle2MaxRest; // maximum sensor value at rest - int throttle1MinFluctuationPercent; - int throttle1MaxFluctuationPercent; - int throttle2MinFluctuationPercent; - int throttle2MaxFluctuationPercent; - int maxThrottleReadingDeviationPercent; - // stats/counters when sampling - static const int maxSamples = 300; - int sampleCount; - int linearCount; - int inverseCount; - uint16_t throttle1Values[maxSamples]; - uint16_t throttle2Values[maxSamples]; + enum DetectionState { + DoNothing, + DetectMinWait, + DetectMinCalibrate, + DetectMaxWait, + DetectMaxCalibrate + }; + + void detectMinWait(); + void detectMinCalibrate(); + void detectMaxWait(); + void detectMaxCalibrate(); + void displayCalibratedValues(bool minPedal); + void resetValues(); + void readThrottleValues(); + int checkLinear(uint16_t, uint16_t); + int checkInverse(uint16_t, uint16_t); + uint16_t normalize(uint16_t sensorValue, uint16_t sensorMin, uint16_t sensorMax, uint16_t constrainMin, uint16_t constrainMax); + + Throttle *throttle; + PotThrottleConfiguration *config; + DetectionState state; + unsigned long startTime; + int potentiometerCount; // the number of potentiometers detected + uint16_t throttle1Min; // the minimum value of throttle1 + uint16_t throttle1Max; // the maximum value of throttle1 + uint16_t throttle2Min; // the minimum value of throttle2 + uint16_t throttle2Max; // the maximum value of throttle2 + uint8_t throttleSubType; // the throttle sub type + bool throttle1HighLow; // true if throttle1 ranges from highest to lowest value as the pedal is pressed + bool throttle2HighLow; // true if throttle2 ranges from highest to lowest value as the pedal is pressed + bool throttle2Inverse; // true if throttle2 values are the opposite of the throttle1 values. + int throttle1MinRest; // minimum sensor value at rest + int throttle1MaxRest; // minimum sensor value at rest + int throttle2MinRest; // minimum sensor value at rest + int throttle2MaxRest; // maximum sensor value at rest + int throttle1MinFluctuationPercent; + int throttle1MaxFluctuationPercent; + int throttle2MinFluctuationPercent; + int throttle2MaxFluctuationPercent; + int maxThrottleReadingDeviationPercent; + // stats/counters when sampling + static const int maxSamples = 300; + int sampleCount; + int linearCount; + int inverseCount; + uint16_t throttle1Values[maxSamples]; + uint16_t throttle2Values[maxSamples]; }; diff --git a/TickHandler.cpp b/TickHandler.cpp index 2e3de3f..56ddad4 100644 --- a/TickHandler.cpp +++ b/TickHandler.cpp @@ -36,14 +36,14 @@ TickHandler *TickHandler::tickHandler = NULL; TickHandler::TickHandler() { - for (int i = 0; i < NUM_TIMERS; i++) { - timerEntry[i].interval = 0; - for (int j = 0; j < CFG_TIMER_NUM_OBSERVERS; j++) { - timerEntry[i].observer[j] = NULL; - } - } + for (int i = 0; i < NUM_TIMERS; i++) { + timerEntry[i].interval = 0; + for (int j = 0; j < CFG_TIMER_NUM_OBSERVERS; j++) { + timerEntry[i].observer[j] = NULL; + } + } #ifdef CFG_TIMER_USE_QUEUING - bufferHead = bufferTail = 0; + bufferHead = bufferTail = 0; #endif } @@ -51,10 +51,10 @@ TickHandler::TickHandler() { * Get a singleton instance of the TickHandler */ TickHandler *TickHandler::getInstance() { - if (tickHandler == NULL) { - tickHandler = new TickHandler(); - } - return tickHandler; + if (tickHandler == NULL) { + tickHandler = new TickHandler(); + } + return tickHandler; } /** @@ -67,89 +67,89 @@ TickHandler *TickHandler::getInstance() { * well, the timer is configured and (re)started. */ void TickHandler::attach(TickObserver* observer, uint32_t interval) { - int timer = findTimer(interval); - if (timer == -1) { - timer = findTimer(0); // no timer with given tick interval exist -> look for unused (interval == 0) - if (timer == -1) { - Logger::error("No free timer available for interval=%d", interval); - return; - } - timerEntry[timer].interval = interval; - } - - int observerIndex = findObserver(timer, 0); - if (observerIndex == -1) { - Logger::error("No free observer slot for timer %d with interval %d", timer, timerEntry[timer].interval); - return; - } - timerEntry[timer].observer[observerIndex] = observer; - Logger::debug("attached TickObserver (%X) as number %d to timer %d, %dus interval", observer, observerIndex, timer, interval); - - switch (timer) { // restarting a timer which would already be running is no problem (see DueTimer.cpp) - case 0: - Timer0.setPeriod(interval).attachInterrupt(timer0Interrupt).start(); - break; - case 1: - Timer1.setPeriod(interval).attachInterrupt(timer1Interrupt).start(); - break; - case 2: - Timer2.setPeriod(interval).attachInterrupt(timer2Interrupt).start(); - break; - case 3: - Timer3.setPeriod(interval).attachInterrupt(timer3Interrupt).start(); - break; - case 4: - Timer4.setPeriod(interval).attachInterrupt(timer4Interrupt).start(); - break; - case 5: - Timer5.setPeriod(interval).attachInterrupt(timer5Interrupt).start(); - break; - case 6: - Timer6.setPeriod(interval).attachInterrupt(timer6Interrupt).start(); - break; - case 7: - Timer7.setPeriod(interval).attachInterrupt(timer7Interrupt).start(); - break; - case 8: - Timer8.setPeriod(interval).attachInterrupt(timer8Interrupt).start(); - break; - } + int timer = findTimer(interval); + if (timer == -1) { + timer = findTimer(0); // no timer with given tick interval exist -> look for unused (interval == 0) + if (timer == -1) { + Logger::error("No free timer available for interval=%d", interval); + return; + } + timerEntry[timer].interval = interval; + } + + int observerIndex = findObserver(timer, 0); + if (observerIndex == -1) { + Logger::error("No free observer slot for timer %d with interval %d", timer, timerEntry[timer].interval); + return; + } + timerEntry[timer].observer[observerIndex] = observer; + Logger::debug("attached TickObserver (%X) as number %d to timer %d, %dus interval", observer, observerIndex, timer, interval); + + switch (timer) { // restarting a timer which would already be running is no problem (see DueTimer.cpp) + case 0: + Timer0.setPeriod(interval).attachInterrupt(timer0Interrupt).start(); + break; + case 1: + Timer1.setPeriod(interval).attachInterrupt(timer1Interrupt).start(); + break; + case 2: + Timer2.setPeriod(interval).attachInterrupt(timer2Interrupt).start(); + break; + case 3: + Timer3.setPeriod(interval).attachInterrupt(timer3Interrupt).start(); + break; + case 4: + Timer4.setPeriod(interval).attachInterrupt(timer4Interrupt).start(); + break; + case 5: + Timer5.setPeriod(interval).attachInterrupt(timer5Interrupt).start(); + break; + case 6: + Timer6.setPeriod(interval).attachInterrupt(timer6Interrupt).start(); + break; + case 7: + Timer7.setPeriod(interval).attachInterrupt(timer7Interrupt).start(); + break; + case 8: + Timer8.setPeriod(interval).attachInterrupt(timer8Interrupt).start(); + break; + } } /** * Remove an observer from all timers where it was registered. */ void TickHandler::detach(TickObserver* observer) { - for (int timer = 0; timer < NUM_TIMERS; timer++) { - for (int observerIndex = 0; observerIndex < CFG_TIMER_NUM_OBSERVERS; observerIndex++) { - if (timerEntry[timer].observer[observerIndex] == observer) { - Logger::debug("removing TickObserver (%X) as number %d from timer %d", observer, observerIndex, timer); - timerEntry[timer].observer[observerIndex] = NULL; - } - } - } + for (int timer = 0; timer < NUM_TIMERS; timer++) { + for (int observerIndex = 0; observerIndex < CFG_TIMER_NUM_OBSERVERS; observerIndex++) { + if (timerEntry[timer].observer[observerIndex] == observer) { + Logger::debug("removing TickObserver (%X) as number %d from timer %d", observer, observerIndex, timer); + timerEntry[timer].observer[observerIndex] = NULL; + } + } + } } /** * Find a timer with a specified interval. */ int TickHandler::findTimer(long interval) { - for (int i = 0; i < NUM_TIMERS; i++) { - if (timerEntry[i].interval == interval) - return i; - } - return -1; + for (int i = 0; i < NUM_TIMERS; i++) { + if (timerEntry[i].interval == interval) + return i; + } + return -1; } /* * Find a TickObserver in the list of a specific timer. */ int TickHandler::findObserver(int timer, TickObserver *observer) { - for (int i = 0; i < CFG_TIMER_NUM_OBSERVERS; i++) { - if (timerEntry[timer].observer[i] == observer) - return i; - } - return -1; + for (int i = 0; i < CFG_TIMER_NUM_OBSERVERS; i++) { + if (timerEntry[timer].observer[i] == observer) + return i; + } + return -1; } #ifdef CFG_TIMER_USE_QUEUING @@ -157,15 +157,15 @@ int TickHandler::findObserver(int timer, TickObserver *observer) { * Check if a tick is available, forward it to registered observers. */ void TickHandler::process() { - while (bufferHead != bufferTail) { - tickBuffer[bufferTail]->handleTick(); - bufferTail = (bufferTail + 1) % CFG_TIMER_BUFFER_SIZE; - //Logger::debug("process, bufferHead=%d bufferTail=%d", bufferHead, bufferTail); - } + while (bufferHead != bufferTail) { + tickBuffer[bufferTail]->handleTick(); + bufferTail = (bufferTail + 1) % CFG_TIMER_BUFFER_SIZE; + //Logger::debug("process, bufferHead=%d bufferTail=%d", bufferHead, bufferTail); + } } void TickHandler::cleanBuffer() { - bufferHead = bufferTail = 0; + bufferHead = bufferTail = 0; } #endif //CFG_TIMER_USE_QUEUING @@ -175,72 +175,72 @@ void TickHandler::cleanBuffer() { * All the registered TickObservers of the timer are called. */ void TickHandler::handleInterrupt(int timerNumber) { - for (int i = 0; i < CFG_TIMER_NUM_OBSERVERS; i++) { - if (timerEntry[timerNumber].observer[i] != NULL) { + for (int i = 0; i < CFG_TIMER_NUM_OBSERVERS; i++) { + if (timerEntry[timerNumber].observer[i] != NULL) { #ifdef CFG_TIMER_USE_QUEUING - tickBuffer[bufferHead] = timerEntry[timerNumber].observer[i]; - bufferHead = (bufferHead + 1) % CFG_TIMER_BUFFER_SIZE; + tickBuffer[bufferHead] = timerEntry[timerNumber].observer[i]; + bufferHead = (bufferHead + 1) % CFG_TIMER_BUFFER_SIZE; //Logger::debug("bufferHead=%d, bufferTail=%d, observer=%d", bufferHead, bufferTail, timerEntry[timerNumber].observer[i]); #else - timerEntry[timerNumber].observer[i]->handleTick(); + timerEntry[timerNumber].observer[i]->handleTick(); #endif //CFG_TIMER_USE_QUEUING - } - } + } + } } /* * Interrupt function for Timer0 */ void timer0Interrupt() { - TickHandler::getInstance()->handleInterrupt(0); + TickHandler::getInstance()->handleInterrupt(0); } /* * Interrupt function for Timer1 */ void timer1Interrupt() { - TickHandler::getInstance()->handleInterrupt(1); + TickHandler::getInstance()->handleInterrupt(1); } /* * Interrupt function for Timer2 */ void timer2Interrupt() { - TickHandler::getInstance()->handleInterrupt(2); + TickHandler::getInstance()->handleInterrupt(2); } /* * Interrupt function for Timer3 */ void timer3Interrupt() { - TickHandler::getInstance()->handleInterrupt(3); + TickHandler::getInstance()->handleInterrupt(3); } /* * Interrupt function for Timer4 */ void timer4Interrupt() { - TickHandler::getInstance()->handleInterrupt(4); + TickHandler::getInstance()->handleInterrupt(4); } /* * Interrupt function for Timer5 */ void timer5Interrupt() { - TickHandler::getInstance()->handleInterrupt(5); + TickHandler::getInstance()->handleInterrupt(5); } /* * Interrupt function for Timer6 */ void timer6Interrupt() { - TickHandler::getInstance()->handleInterrupt(6); + TickHandler::getInstance()->handleInterrupt(6); } /* * Interrupt function for Timer7 */ void timer7Interrupt() { - TickHandler::getInstance()->handleInterrupt(7); + TickHandler::getInstance()->handleInterrupt(7); } /* * Interrupt function for Timer8 */ void timer8Interrupt() { - TickHandler::getInstance()->handleInterrupt(8); + TickHandler::getInstance()->handleInterrupt(8); } /* @@ -248,7 +248,7 @@ void timer8Interrupt() { * by every sub-class. */ void TickObserver::handleTick() { - Logger::error("TickObserver does not implement handleTick()"); + Logger::error("TickObserver does not implement handleTick()"); } diff --git a/TickHandler.h b/TickHandler.h index cbf8507..e6c19ff 100644 --- a/TickHandler.h +++ b/TickHandler.h @@ -38,38 +38,38 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. class TickObserver { public: - virtual void handleTick(); + virtual void handleTick(); }; class TickHandler { public: - static TickHandler *getInstance(); - void attach(TickObserver *observer, uint32_t interval); - void detach(TickObserver *observer); - void handleInterrupt(int timerNumber); // must be public when from the non-class functions + static TickHandler *getInstance(); + void attach(TickObserver *observer, uint32_t interval); + void detach(TickObserver *observer); + void handleInterrupt(int timerNumber); // must be public when from the non-class functions #ifdef CFG_TIMER_USE_QUEUING - void cleanBuffer(); - void process(); + void cleanBuffer(); + void process(); #endif protected: private: - struct TimerEntry { - long interval; // interval of timer - TickObserver *observer[CFG_TIMER_NUM_OBSERVERS]; // array of pointers to observers with this interval - }; - TimerEntry timerEntry[NUM_TIMERS]; // array of timer entries (9 as there are 9 timers) - static TickHandler *tickHandler; + struct TimerEntry { + long interval; // interval of timer + TickObserver *observer[CFG_TIMER_NUM_OBSERVERS]; // array of pointers to observers with this interval + }; + TimerEntry timerEntry[NUM_TIMERS]; // array of timer entries (9 as there are 9 timers) + static TickHandler *tickHandler; #ifdef CFG_TIMER_USE_QUEUING - TickObserver *tickBuffer[CFG_TIMER_BUFFER_SIZE]; - volatile uint16_t bufferHead, bufferTail; + TickObserver *tickBuffer[CFG_TIMER_BUFFER_SIZE]; + volatile uint16_t bufferHead, bufferTail; #endif - TickHandler(); - int findTimer(long interval); - int findObserver(int timerNumber, TickObserver *observer); + TickHandler(); + int findTimer(long interval); + int findObserver(int timerNumber, TickObserver *observer); }; void timer0Interrupt(); diff --git a/constants.h b/constants.h index df5263c..da45cbb 100644 --- a/constants.h +++ b/constants.h @@ -31,77 +31,77 @@ #define CONSTANTS_H_ namespace Constants { - // misc - static const char* trueStr = "true"; - static const char* falseStr = "false"; - static const char* notAvailable = "n/a"; - static const char* ichipCommandPrefix = "AT+i"; - static const char* ichipErrorString = "I/ERROR"; +// misc +static const char* trueStr = "true"; +static const char* falseStr = "false"; +static const char* notAvailable = "n/a"; +static const char* ichipCommandPrefix = "AT+i"; +static const char* ichipErrorString = "I/ERROR"; - // configuration +// configuration - static const char* numThrottlePots = "numThrottlePots"; - static const char* throttleSubType = "throttleSubType"; - static const char* throttleMin1 = "throttleMin1"; - static const char* throttleMin2 = "throttleMin2"; - static const char* throttleMax1 = "throttleMax1"; - static const char* throttleMax2 = "throttleMax2"; - static const char* throttleRegenMax = "throttleRegenMax"; - static const char* throttleRegenMin = "throttleRegenMin"; - static const char* throttleFwd = "throttleFwd"; - static const char* throttleMap = "throttleMap"; - static const char* throttleMinRegen = "throttleMinRegen"; - static const char* throttleMaxRegen = "throttleMaxRegen"; - static const char* throttleCreep = "throttleCreep"; - static const char* brakeMin = "brakeMin"; - static const char* brakeMax = "brakeMax"; - static const char* brakeMinRegen = "brakeMinRegen"; - static const char* brakeMaxRegen = "brakeMaxRegen"; - static const char* brakeLight = "brakeLight"; - static const char* revLight = "revLight"; - static const char* enableIn = "enableIn"; - static const char* reverseIn = "reverseIn"; - - static const char* speedMax = "speedMax"; - static const char* torqueMax = "torqueMax"; - static const char* logLevel = "logLevel"; +static const char* numThrottlePots = "numThrottlePots"; +static const char* throttleSubType = "throttleSubType"; +static const char* throttleMin1 = "throttleMin1"; +static const char* throttleMin2 = "throttleMin2"; +static const char* throttleMax1 = "throttleMax1"; +static const char* throttleMax2 = "throttleMax2"; +static const char* throttleRegenMax = "throttleRegenMax"; +static const char* throttleRegenMin = "throttleRegenMin"; +static const char* throttleFwd = "throttleFwd"; +static const char* throttleMap = "throttleMap"; +static const char* throttleMinRegen = "throttleMinRegen"; +static const char* throttleMaxRegen = "throttleMaxRegen"; +static const char* throttleCreep = "throttleCreep"; +static const char* brakeMin = "brakeMin"; +static const char* brakeMax = "brakeMax"; +static const char* brakeMinRegen = "brakeMinRegen"; +static const char* brakeMaxRegen = "brakeMaxRegen"; +static const char* brakeLight = "brakeLight"; +static const char* revLight = "revLight"; +static const char* enableIn = "enableIn"; +static const char* reverseIn = "reverseIn"; - // status - static const char* timeRunning = "timeRunning"; - static const char* torqueRequested = "torqueRequested"; - static const char* torqueActual = "torqueActual"; - static const char* throttle = "throttle"; - static const char* brake = "brake"; - static const char* motorMode = "motorMode"; - static const char* speedRequested = "speedRequested"; - static const char* speedActual = "speedActual"; - static const char* dcVoltage = "dcVoltage"; - static const char* nominalVolt = "nominalVolt"; - static const char* dcCurrent = "dcCurrent"; - static const char* acCurrent = "acCurrent"; - static const char* kiloWattHours = "kiloWattHours"; - static const char* bitfield1 = "bitfield1"; - static const char* bitfield2 = "bitfield2"; - static const char* bitfield3 = "bitfield3"; - static const char* bitfield4 = "bitfield4"; - static const char* running = "running"; - static const char* faulted = "faulted"; - static const char* warning = "warning"; - static const char* gear = "gear"; - static const char* tempMotor = "tempMotor"; - static const char* tempInverter = "tempInverter"; - static const char* tempSystem = "tempSystem"; - static const char* mechPower = "mechPower"; - static const char* prechargeR = "prechargeR"; - static const char* prechargeRelay = "prechargeRelay"; - static const char* mainContactorRelay = "mainContactorRelay"; - static const char* coolFan = "coolFan"; - static const char* coolOn = "coolOn"; - static const char* coolOff = "coolOff"; - static const char* validChecksum = "Valid checksum, using stored config values"; - static const char* invalidChecksum = "Invalid checksum, using hard coded config values"; - static const char* valueOutOfRange = "value out of range: %l"; - static const char* normalOperation = "normal operation restored"; +static const char* speedMax = "speedMax"; +static const char* torqueMax = "torqueMax"; +static const char* logLevel = "logLevel"; + +// status +static const char* timeRunning = "timeRunning"; +static const char* torqueRequested = "torqueRequested"; +static const char* torqueActual = "torqueActual"; +static const char* throttle = "throttle"; +static const char* brake = "brake"; +static const char* motorMode = "motorMode"; +static const char* speedRequested = "speedRequested"; +static const char* speedActual = "speedActual"; +static const char* dcVoltage = "dcVoltage"; +static const char* nominalVolt = "nominalVolt"; +static const char* dcCurrent = "dcCurrent"; +static const char* acCurrent = "acCurrent"; +static const char* kiloWattHours = "kiloWattHours"; +static const char* bitfield1 = "bitfield1"; +static const char* bitfield2 = "bitfield2"; +static const char* bitfield3 = "bitfield3"; +static const char* bitfield4 = "bitfield4"; +static const char* running = "running"; +static const char* faulted = "faulted"; +static const char* warning = "warning"; +static const char* gear = "gear"; +static const char* tempMotor = "tempMotor"; +static const char* tempInverter = "tempInverter"; +static const char* tempSystem = "tempSystem"; +static const char* mechPower = "mechPower"; +static const char* prechargeR = "prechargeR"; +static const char* prechargeRelay = "prechargeRelay"; +static const char* mainContactorRelay = "mainContactorRelay"; +static const char* coolFan = "coolFan"; +static const char* coolOn = "coolOn"; +static const char* coolOff = "coolOff"; +static const char* validChecksum = "Valid checksum, using stored config values"; +static const char* invalidChecksum = "Invalid checksum, using hard coded config values"; +static const char* valueOutOfRange = "value out of range: %l"; +static const char* normalOperation = "normal operation restored"; } #endif /* CONSTANTS_H_ */ diff --git a/eeprom_layout.h b/eeprom_layout.h index e549111..dd6c8b6 100644 --- a/eeprom_layout.h +++ b/eeprom_layout.h @@ -2,9 +2,9 @@ * eeprom_layout.h * *EEPROM Map. There is support for up to 6 devices: A motor controller, display, charger, BMS, Throttle, and a misc device (EPAS, WOC, etc) -* +* *There is a 256KB eeprom chip which stores these settings. The 4K is allocated to primary storage and 4K is allocated to a "known good" -* storage location. This leaves most of EEPROM free for something else, probably logging. +* storage location. This leaves most of EEPROM free for something else, probably logging. Copyright (c) 2013 Collin Kidder, Michael Neuweiler, Charles Galpin @@ -138,7 +138,7 @@ the end of the stardard data. The below numbers are offsets from the device's ee #define EESYS_TWI_BAUD 106 //2 bytes - Baud for TWI in 1000's just like CAN bauds. So 100k baud is set as 100 #define EESYS_TICK_RATE 108 //2 bytes - # of system ticks per second. Can range the full 16 bit value [1, 65536] which yields ms rate of [15us, 1000ms] -//We store the current system time from the RTC in EEPROM every so often. +//We store the current system time from the RTC in EEPROM every so often. //RTC is not battery backed up on the Due so a power failure will reset it. //These storage spaces let the firmware reload the last knowm time to bootstrap itself //as much as possible. The hope is that we'll be able to get access to internet eventually @@ -148,7 +148,7 @@ the end of the stardard data. The below numbers are offsets from the device's ee //Technically there are two different canbus systems in use. The MCP2515 has 2 masks and 5 filters. The Arduino DUE //Has 8 masks and 8 filters potentially (not really, you do need transmit boxes too). So, the most masks and filters -//we could ever set is 7 (using one mb as transmit) so support accordingly. +//we could ever set is 7 (using one mb as transmit) so support accordingly. #define EESYS_CAN_RX_COUNT 199 //1 byte - how many mailboxes to use for RX on the Due. On the Macchina it is always 5. #define EESYS_CAN_MASK0 200 //4 bytes - first canbus mask - bit 31 sets whether it is extended or not (set = extended) @@ -168,7 +168,7 @@ the end of the stardard data. The below numbers are offsets from the device's ee #define EESYS_CAPACITY 256 // 1 byte - battery pack capacity in AH #define EESYS_AH 257 // 2 bytes - current cumulative ampere hours -//Allow for a few defined WIFI SSIDs that the GEVCU will try to automatically connect to. +//Allow for a few defined WIFI SSIDs that the GEVCU will try to automatically connect to. #define EESYS_WIFI0_SSID 300 //32 bytes - the SSID to create or use (prefixed with ! if create ad-hoc) #define EESYS_WIFI0_CHAN 332 //1 byte - the wifi channel (1 - 11) to use #define EESYS_WIFI0_DHCP 333 //1 byte - DHCP mode, 0 = off, 1 = server, 2 = client diff --git a/ichip_2128.cpp b/ichip_2128.cpp index fed521b..63a8fc0 100644 --- a/ichip_2128.cpp +++ b/ichip_2128.cpp @@ -32,24 +32,24 @@ * Constructor. Assign serial interface to use for ichip communication */ ICHIPWIFI::ICHIPWIFI() { - prefsHandler = new PrefHandler(ICHIP2128); + prefsHandler = new PrefHandler(ICHIP2128); - uint8_t sys_type; - sysPrefs->read(EESYS_SYSTEM_TYPE, &sys_type); - if (sys_type == 3 || sys_type == 4) - serialInterface = &Serial2; - else //older hardware used this instead - serialInterface = &Serial3; + uint8_t sys_type; + sysPrefs->read(EESYS_SYSTEM_TYPE, &sys_type); + if (sys_type == 3 || sys_type == 4) + serialInterface = &Serial2; + else //older hardware used this instead + serialInterface = &Serial3; - commonName = "WIFI (iChip2128)"; + commonName = "WIFI (iChip2128)"; } /* * Constructor. Pass serial interface to use for ichip communication */ ICHIPWIFI::ICHIPWIFI(USARTClass *which) { - prefsHandler = new PrefHandler(ICHIP2128); - serialInterface = which; + prefsHandler = new PrefHandler(ICHIP2128); + serialInterface = which; } /* @@ -57,51 +57,51 @@ ICHIPWIFI::ICHIPWIFI(USARTClass *which) { */ void ICHIPWIFI::setup() { - Logger::info("add device: iChip 2128 WiFi (id: %X, %X)", ICHIP2128, this); + Logger::info("add device: iChip 2128 WiFi (id: %X, %X)", ICHIP2128, this); - TickHandler::getInstance()->detach(this); + TickHandler::getInstance()->detach(this); - //MSEL pin - pinMode(18, OUTPUT); - digitalWrite(18, HIGH); + //MSEL pin + pinMode(18, OUTPUT); + digitalWrite(18, HIGH); - //RESET pin - pinMode(42, OUTPUT); - digitalWrite(42, HIGH); + //RESET pin + pinMode(42, OUTPUT); + digitalWrite(42, HIGH); - tickCounter = 0; - ibWritePtr = 0; - psWritePtr = 0; - psReadPtr = 0; - listeningSocket = 0; + tickCounter = 0; + ibWritePtr = 0; + psWritePtr = 0; + psReadPtr = 0; + listeningSocket = 0; - lastSentTime = millis(); - lastSentState = IDLE; - lastSentCmd = String(""); + lastSentTime = millis(); + lastSentState = IDLE; + lastSentCmd = String(""); - activeSockets[0] = -1; - activeSockets[1] = -1; - activeSockets[2] = -1; - activeSockets[3] = -1; + activeSockets[0] = -1; + activeSockets[1] = -1; + activeSockets[2] = -1; + activeSockets[3] = -1; - state = IDLE; + state = IDLE; - didParamLoad = false; - didTCPListener = false; + didParamLoad = false; + didTCPListener = false; - serialInterface->begin(115200); + serialInterface->begin(115200); - paramCache.brakeNotAvailable = true; + paramCache.brakeNotAvailable = true; - elmProc = new ELM327Processor(); + elmProc = new ELM327Processor(); - TickHandler::getInstance()->attach(this, CFG_TICK_INTERVAL_WIFI); + TickHandler::getInstance()->attach(this, CFG_TICK_INTERVAL_WIFI); } //A version of sendCmd that defaults to SET_PARAM which is what most of the code used to assume. void ICHIPWIFI::sendCmd(String cmd) { - sendCmd(cmd, SET_PARAM); + sendCmd(cmd, SET_PARAM); } /* @@ -109,38 +109,38 @@ void ICHIPWIFI::sendCmd(String cmd) { * If the comm channel is busy it buffers the command */ void ICHIPWIFI::sendCmd(String cmd, ICHIP_COMM_STATE cmdstate) { - if (state != IDLE) { //if the comm is tied up then buffer this parameter for sending later - sendingBuffer[psWritePtr].cmd = cmd; - sendingBuffer[psWritePtr].state = cmdstate; - psWritePtr = (psWritePtr + 1) & 63; - if (Logger::isDebug()) { - String temp = "Buffer cmd: " + cmd; - Logger::debug(ICHIP2128, (char *)temp.c_str()); - } - } - else { //otherwise, go ahead and blast away - serialInterface->write(Constants::ichipCommandPrefix); - serialInterface->print(cmd); - serialInterface->write(13); - state = cmdstate; - lastSentTime = millis(); - lastSentCmd = String(cmd); - lastSentState = cmdstate; - - if (Logger::isDebug()) { - String temp = "Send to ichip cmd: " + cmd; - Logger::debug(ICHIP2128, (char *)temp.c_str()); - } - } + if (state != IDLE) { //if the comm is tied up then buffer this parameter for sending later + sendingBuffer[psWritePtr].cmd = cmd; + sendingBuffer[psWritePtr].state = cmdstate; + psWritePtr = (psWritePtr + 1) & 63; + if (Logger::isDebug()) { + String temp = "Buffer cmd: " + cmd; + Logger::debug(ICHIP2128, (char *)temp.c_str()); + } + } + else { //otherwise, go ahead and blast away + serialInterface->write(Constants::ichipCommandPrefix); + serialInterface->print(cmd); + serialInterface->write(13); + state = cmdstate; + lastSentTime = millis(); + lastSentCmd = String(cmd); + lastSentState = cmdstate; + + if (Logger::isDebug()) { + String temp = "Send to ichip cmd: " + cmd; + Logger::debug(ICHIP2128, (char *)temp.c_str()); + } + } } void ICHIPWIFI::sendToSocket(int socket, String data) { - char buff[6]; - sprintf(buff, "%03i", socket); - String temp = "SSND%%:" + String(buff); - sprintf(buff, ",%i:", data.length()); - temp = temp + String(buff) + data; - sendCmd(temp, SEND_SOCKET); + char buff[6]; + sprintf(buff, "%03i", socket); + String temp = "SSND%%:" + String(buff); + sprintf(buff, ",%i:", data.length()); + temp = temp + String(buff) + data; + sendCmd(temp, SEND_SOCKET); } /* @@ -149,273 +149,273 @@ void ICHIPWIFI::sendToSocket(int socket, String data) { */ //TODO: See the processing function below for a more detailed explanation - can't send so many setParam commands in a row void ICHIPWIFI::handleTick() { - MotorController* motorController = DeviceManager::getInstance()->getMotorController(); - Throttle *accelerator = DeviceManager::getInstance()->getAccelerator(); - Throttle *brake = DeviceManager::getInstance()->getBrake(); - static int pollListening = 0; - static int pollSocket = 0; - uint32_t ms = millis(); - char buff[6]; - uint8_t brklt; - tickCounter++; - - if (ms < 1000) return; //wait 10 seconds for things to settle before doing a thing - - // Do a delayed parameter load once about a second after startup - if (!didParamLoad && ms > 5000) { - loadParameters(); - Logger::console("Wifi Parameters loaded..."); - paramCache.bitfield1 = motorController->getStatusBitfield1(); - setParam(Constants::bitfield1, paramCache.bitfield1); - paramCache.bitfield2 = motorController->getStatusBitfield2(); - setParam(Constants::bitfield2, paramCache.bitfield2); - // DeviceManager::getInstance()->updateWifiByID(BRUSA_DMC5); - - didParamLoad = true; - } - - //At 2 seconds start up a listening socket for OBDII - if (!didTCPListener && ms > 12000) { - sendCmd("LTCP:2000,4", START_TCP_LISTENER); - didTCPListener = true; - } - - if (listeningSocket > 9) { - pollListening++; - if (pollListening > 8) { - pollListening = 0; - char buff[5]; - sprintf(buff, "%u", listeningSocket); - String temp = "LSST:" + String(buff); - sendCmd(temp, GET_ACTIVE_SOCKETS); - } - } - - //read any information waiting on active sockets - for (int c = 0; c < 4; c++) - if (activeSockets[c] != -1) { - sprintf(buff, "%03i", activeSockets[c]); - String temp = "SRCV:" + String(buff) + ",80"; - sendCmd(temp, GET_SOCKET); - } - - //TODO:Testing line below. Remove it. - //return; - - - // make small slices so the main loop is not blocked for too long - if (tickCounter == 1) { - if (motorController) { - //Logger::console("Wifi tick counter 1..."); - - paramCache.timeRunning = ms; - setParam(Constants::timeRunning, getTimeRunning()); - - if ( paramCache.torqueRequested != motorController->getTorqueRequested() ) { - paramCache.torqueRequested = motorController->getTorqueRequested(); - setParam(Constants::torqueRequested, paramCache.torqueRequested / 10.0f, 1); - } - if ( paramCache.torqueActual != motorController->getTorqueActual() ) { - paramCache.torqueActual = motorController->getTorqueActual(); - setParam(Constants::torqueActual, paramCache.torqueActual / 10.0f, 1); - } - } - if (accelerator) { + MotorController* motorController = DeviceManager::getInstance()->getMotorController(); + Throttle *accelerator = DeviceManager::getInstance()->getAccelerator(); + Throttle *brake = DeviceManager::getInstance()->getBrake(); + static int pollListening = 0; + static int pollSocket = 0; + uint32_t ms = millis(); + char buff[6]; + uint8_t brklt; + tickCounter++; + + if (ms < 1000) return; //wait 10 seconds for things to settle before doing a thing + + // Do a delayed parameter load once about a second after startup + if (!didParamLoad && ms > 5000) { + loadParameters(); + Logger::console("Wifi Parameters loaded..."); + paramCache.bitfield1 = motorController->getStatusBitfield1(); + setParam(Constants::bitfield1, paramCache.bitfield1); + paramCache.bitfield2 = motorController->getStatusBitfield2(); + setParam(Constants::bitfield2, paramCache.bitfield2); + // DeviceManager::getInstance()->updateWifiByID(BRUSA_DMC5); + + didParamLoad = true; + } + + //At 2 seconds start up a listening socket for OBDII + if (!didTCPListener && ms > 12000) { + sendCmd("LTCP:2000,4", START_TCP_LISTENER); + didTCPListener = true; + } + + if (listeningSocket > 9) { + pollListening++; + if (pollListening > 8) { + pollListening = 0; + char buff[5]; + sprintf(buff, "%u", listeningSocket); + String temp = "LSST:" + String(buff); + sendCmd(temp, GET_ACTIVE_SOCKETS); + } + } + + //read any information waiting on active sockets + for (int c = 0; c < 4; c++) + if (activeSockets[c] != -1) { + sprintf(buff, "%03i", activeSockets[c]); + String temp = "SRCV:" + String(buff) + ",80"; + sendCmd(temp, GET_SOCKET); + } + + //TODO:Testing line below. Remove it. + //return; + + + // make small slices so the main loop is not blocked for too long + if (tickCounter == 1) { + if (motorController) { + //Logger::console("Wifi tick counter 1..."); + + paramCache.timeRunning = ms; + setParam(Constants::timeRunning, getTimeRunning()); + + if ( paramCache.torqueRequested != motorController->getTorqueRequested() ) { + paramCache.torqueRequested = motorController->getTorqueRequested(); + setParam(Constants::torqueRequested, paramCache.torqueRequested / 10.0f, 1); + } + if ( paramCache.torqueActual != motorController->getTorqueActual() ) { + paramCache.torqueActual = motorController->getTorqueActual(); + setParam(Constants::torqueActual, paramCache.torqueActual / 10.0f, 1); + } + } + if (accelerator) { RawSignalData *rawSignal = accelerator->acquireRawSignal(); - if ( paramCache.throttle != rawSignal->input1) { - paramCache.throttle = rawSignal->input1; + if ( paramCache.throttle != rawSignal->input1) { + paramCache.throttle = rawSignal->input1; setParam(Constants::throttle, paramCache.throttle); - - /*if ( paramCache.throttle != accelerator->getLevel() ) { - paramCache.throttle = accelerator->getLevel(); - if (paramCache.throttle<-600){paramCache.throttle=-600;} - setParam(Constants::throttle, paramCache.throttle / 10.0f, 1);*/ - } - } - if (brake) { + + /*if ( paramCache.throttle != accelerator->getLevel() ) { + paramCache.throttle = accelerator->getLevel(); + if (paramCache.throttle<-600){paramCache.throttle=-600;} + setParam(Constants::throttle, paramCache.throttle / 10.0f, 1);*/ + } + } + if (brake) { RawSignalData *rawSignal = brake->acquireRawSignal(); - if ( paramCache.brake != rawSignal->input1) { - paramCache.brake = rawSignal->input1; - paramCache.brakeNotAvailable = false; - setParam(Constants::brake, paramCache.brake); - - /*if ( paramCache.brake != brake->getLevel() ) { - paramCache.brake = brake->getLevel(); - paramCache.brakeNotAvailable = false; - setParam(Constants::brake, paramCache.brake / 10.0f, 1);*/ - } - } else { - if ( paramCache.brakeNotAvailable == true ) { - paramCache.brakeNotAvailable = false; // no need to keep sending this - setParam(Constants::brake, Constants::notAvailable); - } - } - } else if (tickCounter == 2) { - if (motorController) { - //Logger::console("Wifi tick counter 2..."); - if ( paramCache.speedRequested != motorController->getSpeedRequested() ) { - paramCache.speedRequested = motorController->getSpeedRequested(); - setParam(Constants::speedRequested, paramCache.speedRequested); - } - if ( paramCache.speedActual != motorController->getSpeedActual() ) { - paramCache.speedActual = motorController->getSpeedActual(); - if (paramCache.speedActual<0) paramCache.speedActual=0; - if (paramCache.speedActual>10000) paramCache.speedActual=10000; - setParam(Constants::speedActual, paramCache.speedActual); - } - if ( paramCache.dcVoltage != motorController->getDcVoltage() ) { - paramCache.dcVoltage = motorController->getDcVoltage(); - if(paramCache.dcVoltage<1000) paramCache.dcVoltage=1000; //Limits of the gage display - if(paramCache.dcVoltage>4500) paramCache.dcVoltage=4500; - - setParam(Constants::dcVoltage, paramCache.dcVoltage / 10.0f, 1); - } - if ( paramCache.dcCurrent != motorController->getDcCurrent() ) { - paramCache.dcCurrent = motorController->getDcCurrent(); - setParam(Constants::dcCurrent, paramCache.dcCurrent / 10.0f, 1); - } - if ( paramCache.prechargeR != motorController->getprechargeR() ) { - paramCache.prechargeR = motorController->getprechargeR(); - setParam(Constants::prechargeR, (uint16_t)paramCache.prechargeR); - } + if ( paramCache.brake != rawSignal->input1) { + paramCache.brake = rawSignal->input1; + paramCache.brakeNotAvailable = false; + setParam(Constants::brake, paramCache.brake); + + /*if ( paramCache.brake != brake->getLevel() ) { + paramCache.brake = brake->getLevel(); + paramCache.brakeNotAvailable = false; + setParam(Constants::brake, paramCache.brake / 10.0f, 1);*/ + } + } else { + if ( paramCache.brakeNotAvailable == true ) { + paramCache.brakeNotAvailable = false; // no need to keep sending this + setParam(Constants::brake, Constants::notAvailable); + } + } + } else if (tickCounter == 2) { + if (motorController) { + //Logger::console("Wifi tick counter 2..."); + if ( paramCache.speedRequested != motorController->getSpeedRequested() ) { + paramCache.speedRequested = motorController->getSpeedRequested(); + setParam(Constants::speedRequested, paramCache.speedRequested); + } + if ( paramCache.speedActual != motorController->getSpeedActual() ) { + paramCache.speedActual = motorController->getSpeedActual(); + if (paramCache.speedActual<0) paramCache.speedActual=0; + if (paramCache.speedActual>10000) paramCache.speedActual=10000; + setParam(Constants::speedActual, paramCache.speedActual); + } + if ( paramCache.dcVoltage != motorController->getDcVoltage() ) { + paramCache.dcVoltage = motorController->getDcVoltage(); + if(paramCache.dcVoltage<1000) paramCache.dcVoltage=1000; //Limits of the gage display + if(paramCache.dcVoltage>4500) paramCache.dcVoltage=4500; + + setParam(Constants::dcVoltage, paramCache.dcVoltage / 10.0f, 1); + } + if ( paramCache.dcCurrent != motorController->getDcCurrent() ) { + paramCache.dcCurrent = motorController->getDcCurrent(); + setParam(Constants::dcCurrent, paramCache.dcCurrent / 10.0f, 1); + } + if ( paramCache.prechargeR != motorController->getprechargeR() ) { + paramCache.prechargeR = motorController->getprechargeR(); + setParam(Constants::prechargeR, (uint16_t)paramCache.prechargeR); + } if ( paramCache.prechargeRelay != motorController->getprechargeRelay() ) { - paramCache.prechargeRelay = motorController->getprechargeRelay(); - setParam(Constants::prechargeRelay, (uint8_t) paramCache.prechargeRelay); - //Logger::console("Precharge Relay %i", paramCache.prechargeRelay); - //Logger::console("motorController:prechargeRelay:%d, paramCache.prechargeRelay:%d, Constants:prechargeRelay:%s", motorController->getprechargeRelay(),paramCache.prechargeRelay, Constants::prechargeRelay); - } + paramCache.prechargeRelay = motorController->getprechargeRelay(); + setParam(Constants::prechargeRelay, (uint8_t) paramCache.prechargeRelay); + //Logger::console("Precharge Relay %i", paramCache.prechargeRelay); + //Logger::console("motorController:prechargeRelay:%d, paramCache.prechargeRelay:%d, Constants:prechargeRelay:%s", motorController->getprechargeRelay(),paramCache.prechargeRelay, Constants::prechargeRelay); + } if ( paramCache.mainContactorRelay != motorController->getmainContactorRelay() ) { - paramCache.mainContactorRelay = motorController->getmainContactorRelay(); - setParam(Constants::mainContactorRelay, (uint8_t) paramCache.mainContactorRelay); - } - //DeviceManager::getInstance()->updateWifi(); - } - } else if (tickCounter == 3) { - if (motorController) { - //Logger::console("Wifi tick counter 2..."); - if ( paramCache.acCurrent != motorController->getAcCurrent() ) { - paramCache.acCurrent = motorController->getAcCurrent(); - setParam(Constants::acCurrent, paramCache.acCurrent / 10.0f, 1); - } - - //if ( paramCache.kiloWattHours != motorController->getkiloWattHours()/3600000 ) { - paramCache.kiloWattHours = motorController->getKiloWattHours()/3600000; - if(paramCache.kiloWattHours<0)paramCache.kiloWattHours = 0; - if(paramCache.kiloWattHours>300)paramCache.kiloWattHours = 300; - setParam(Constants::kiloWattHours, paramCache.kiloWattHours / 10.0f, 1); - //} - - if ( paramCache.nominalVolt != motorController->getnominalVolt()/10 ){ - paramCache.nominalVolt = motorController->getnominalVolt()/10; - setParam(Constants::nominalVolt, paramCache.nominalVolt); - } - - if ( paramCache.bitfield1 != motorController->getStatusBitfield1() ) { - paramCache.bitfield1 = motorController->getStatusBitfield1(); - setParam(Constants::bitfield1, paramCache.bitfield1); - } - if ( paramCache.bitfield2 != motorController->getStatusBitfield2() ) { - paramCache.bitfield2 = motorController->getStatusBitfield2(); - setParam(Constants::bitfield2, paramCache.bitfield2); - } - if ( paramCache.bitfield3 != motorController->getStatusBitfield3() ) { - paramCache.bitfield3 = motorController->getStatusBitfield3(); - setParam(Constants::bitfield3, paramCache.bitfield3); - } - if ( paramCache.bitfield4 != motorController->getStatusBitfield4() ) { - paramCache.bitfield4 = motorController->getStatusBitfield4(); - setParam(Constants::bitfield4, paramCache.bitfield4); - } - - } - } else if (tickCounter == 4) { - if (motorController) { - // Logger::console("Wifi tick counter 4..."); - if ( paramCache.running != motorController->isRunning() ) { - paramCache.running = motorController->isRunning(); - setParam(Constants::running, (paramCache.running ? Constants::trueStr : Constants::falseStr)); - } - if ( paramCache.faulted != motorController->isFaulted() ) { - paramCache.faulted = motorController->isFaulted(); - setParam(Constants::faulted, (paramCache.faulted ? Constants::trueStr : Constants::falseStr)); - } - if ( paramCache.warning != motorController->isWarning() ) { - paramCache.warning = motorController->isWarning(); - setParam(Constants::warning, (paramCache.warning ? Constants::trueStr : Constants::falseStr)); - } - if ( paramCache.gear != motorController->getSelectedGear() ) { - paramCache.gear = motorController->getSelectedGear(); - setParam(Constants::gear, (uint16_t)paramCache.gear); - } - - if ( paramCache.coolFan != motorController->getCoolFan() ) { - paramCache.coolFan = motorController->getCoolFan(); - setParam(Constants::coolFan, (uint8_t) paramCache.coolFan); - } + paramCache.mainContactorRelay = motorController->getmainContactorRelay(); + setParam(Constants::mainContactorRelay, (uint8_t) paramCache.mainContactorRelay); + } + //DeviceManager::getInstance()->updateWifi(); + } + } else if (tickCounter == 3) { + if (motorController) { + //Logger::console("Wifi tick counter 2..."); + if ( paramCache.acCurrent != motorController->getAcCurrent() ) { + paramCache.acCurrent = motorController->getAcCurrent(); + setParam(Constants::acCurrent, paramCache.acCurrent / 10.0f, 1); + } + + //if ( paramCache.kiloWattHours != motorController->getkiloWattHours()/3600000 ) { + paramCache.kiloWattHours = motorController->getKiloWattHours()/3600000; + if(paramCache.kiloWattHours<0)paramCache.kiloWattHours = 0; + if(paramCache.kiloWattHours>300)paramCache.kiloWattHours = 300; + setParam(Constants::kiloWattHours, paramCache.kiloWattHours / 10.0f, 1); + //} + + if ( paramCache.nominalVolt != motorController->getnominalVolt()/10 ) { + paramCache.nominalVolt = motorController->getnominalVolt()/10; + setParam(Constants::nominalVolt, paramCache.nominalVolt); + } + + if ( paramCache.bitfield1 != motorController->getStatusBitfield1() ) { + paramCache.bitfield1 = motorController->getStatusBitfield1(); + setParam(Constants::bitfield1, paramCache.bitfield1); + } + if ( paramCache.bitfield2 != motorController->getStatusBitfield2() ) { + paramCache.bitfield2 = motorController->getStatusBitfield2(); + setParam(Constants::bitfield2, paramCache.bitfield2); + } + if ( paramCache.bitfield3 != motorController->getStatusBitfield3() ) { + paramCache.bitfield3 = motorController->getStatusBitfield3(); + setParam(Constants::bitfield3, paramCache.bitfield3); + } + if ( paramCache.bitfield4 != motorController->getStatusBitfield4() ) { + paramCache.bitfield4 = motorController->getStatusBitfield4(); + setParam(Constants::bitfield4, paramCache.bitfield4); + } + + } + } else if (tickCounter == 4) { + if (motorController) { + // Logger::console("Wifi tick counter 4..."); + if ( paramCache.running != motorController->isRunning() ) { + paramCache.running = motorController->isRunning(); + setParam(Constants::running, (paramCache.running ? Constants::trueStr : Constants::falseStr)); + } + if ( paramCache.faulted != motorController->isFaulted() ) { + paramCache.faulted = motorController->isFaulted(); + setParam(Constants::faulted, (paramCache.faulted ? Constants::trueStr : Constants::falseStr)); + } + if ( paramCache.warning != motorController->isWarning() ) { + paramCache.warning = motorController->isWarning(); + setParam(Constants::warning, (paramCache.warning ? Constants::trueStr : Constants::falseStr)); + } + if ( paramCache.gear != motorController->getSelectedGear() ) { + paramCache.gear = motorController->getSelectedGear(); + setParam(Constants::gear, (uint16_t)paramCache.gear); + } + + if ( paramCache.coolFan != motorController->getCoolFan() ) { + paramCache.coolFan = motorController->getCoolFan(); + setParam(Constants::coolFan, (uint8_t) paramCache.coolFan); + } if ( paramCache.coolOn != motorController->getCoolOn() ) { - paramCache.coolOn = motorController->getCoolOn(); - setParam(Constants::coolOn, (uint8_t) paramCache.coolOn); - } + paramCache.coolOn = motorController->getCoolOn(); + setParam(Constants::coolOn, (uint8_t) paramCache.coolOn); + } if ( paramCache.coolOff != motorController->getCoolOff() ) { - paramCache.coolOff = motorController->getCoolOff(); - setParam(Constants::coolOff, (uint8_t) paramCache.coolOff); - } - - if ( paramCache.brakeLight != motorController->getBrakeLight() ) { - paramCache.brakeLight = motorController->getBrakeLight(); - setParam(Constants::brakeLight, (uint8_t) paramCache.brakeLight); - } - - if ( paramCache.revLight != motorController->getRevLight() ) { - paramCache.revLight = motorController->getRevLight(); - setParam(Constants::revLight, (uint8_t) paramCache.revLight); - } - - if ( paramCache.enableIn != motorController->getEnableIn() ) { - paramCache.enableIn = motorController->getEnableIn(); - setParam(Constants::enableIn, (uint8_t) paramCache.enableIn); - } - if ( paramCache.reverseIn != motorController->getReverseIn() ) { - paramCache.reverseIn = motorController->getReverseIn(); - setParam(Constants::reverseIn, (uint8_t) paramCache.reverseIn); - } - - } - } else if (tickCounter > 4) { - if (motorController) { - // Logger::console("Wifi tick counter 5..."); - if ( paramCache.tempMotor != motorController->getTemperatureMotor() ) { - paramCache.tempMotor = motorController->getTemperatureMotor(); - setParam(Constants::tempMotor, paramCache.tempMotor / 10.0f, 1); - } - if ( paramCache.tempInverter != motorController->getTemperatureInverter() ) { - paramCache.tempInverter = motorController->getTemperatureInverter(); - setParam(Constants::tempInverter, paramCache.tempInverter / 10.0f, 1); - } - if ( paramCache.tempSystem != motorController->getTemperatureSystem() ) { - paramCache.tempSystem = motorController->getTemperatureSystem(); - setParam(Constants::tempSystem, paramCache.tempSystem / 10.0f, 1); - } - - if (paramCache.powerMode != motorController->getPowerMode() ) { - paramCache.powerMode = motorController->getPowerMode(); - setParam(Constants::motorMode, (uint8_t)paramCache.powerMode); - } - - //if ( paramCache.mechPower != motorController->getMechanicalPower() ) { - paramCache.mechPower = motorController->getMechanicalPower(); - if (paramCache.mechPower<-250)paramCache.mechPower=-250; - if (paramCache.mechPower>1500)paramCache.mechPower=1500; - setParam(Constants::mechPower, paramCache.mechPower / 10.0f, 1); - //} - } - tickCounter = 0; - getNextParam(); - } + paramCache.coolOff = motorController->getCoolOff(); + setParam(Constants::coolOff, (uint8_t) paramCache.coolOff); + } + + if ( paramCache.brakeLight != motorController->getBrakeLight() ) { + paramCache.brakeLight = motorController->getBrakeLight(); + setParam(Constants::brakeLight, (uint8_t) paramCache.brakeLight); + } + + if ( paramCache.revLight != motorController->getRevLight() ) { + paramCache.revLight = motorController->getRevLight(); + setParam(Constants::revLight, (uint8_t) paramCache.revLight); + } + + if ( paramCache.enableIn != motorController->getEnableIn() ) { + paramCache.enableIn = motorController->getEnableIn(); + setParam(Constants::enableIn, (uint8_t) paramCache.enableIn); + } + if ( paramCache.reverseIn != motorController->getReverseIn() ) { + paramCache.reverseIn = motorController->getReverseIn(); + setParam(Constants::reverseIn, (uint8_t) paramCache.reverseIn); + } + + } + } else if (tickCounter > 4) { + if (motorController) { + // Logger::console("Wifi tick counter 5..."); + if ( paramCache.tempMotor != motorController->getTemperatureMotor() ) { + paramCache.tempMotor = motorController->getTemperatureMotor(); + setParam(Constants::tempMotor, paramCache.tempMotor / 10.0f, 1); + } + if ( paramCache.tempInverter != motorController->getTemperatureInverter() ) { + paramCache.tempInverter = motorController->getTemperatureInverter(); + setParam(Constants::tempInverter, paramCache.tempInverter / 10.0f, 1); + } + if ( paramCache.tempSystem != motorController->getTemperatureSystem() ) { + paramCache.tempSystem = motorController->getTemperatureSystem(); + setParam(Constants::tempSystem, paramCache.tempSystem / 10.0f, 1); + } + + if (paramCache.powerMode != motorController->getPowerMode() ) { + paramCache.powerMode = motorController->getPowerMode(); + setParam(Constants::motorMode, (uint8_t)paramCache.powerMode); + } + + //if ( paramCache.mechPower != motorController->getMechanicalPower() ) { + paramCache.mechPower = motorController->getMechanicalPower(); + if (paramCache.mechPower<-250)paramCache.mechPower=-250; + if (paramCache.mechPower>1500)paramCache.mechPower=1500; + setParam(Constants::mechPower, paramCache.mechPower / 10.0f, 1); + //} + } + tickCounter = 0; + getNextParam(); + } } /* @@ -424,44 +424,44 @@ void ICHIPWIFI::handleTick() { Of course, the sprintf is only good to 99 hours so that's a bit less time. */ char *ICHIPWIFI::getTimeRunning() { - uint32_t ms = millis(); - int seconds = (int) (ms / 1000) % 60; - int minutes = (int) ((ms / (1000 * 60)) % 60); - int hours = (int) ((ms / (1000 * 3600)) % 24); - sprintf(buffer, "%02d:%02d:%02d", hours, minutes, seconds); - return buffer; + uint32_t ms = millis(); + int seconds = (int) (ms / 1000) % 60; + int minutes = (int) ((ms / (1000 * 60)) % 60); + int hours = (int) ((ms / (1000 * 3600)) % 24); + sprintf(buffer, "%02d:%02d:%02d", hours, minutes, seconds); + return buffer; } /* * Handle a message sent by the DeviceManager. - * Currently MSG_SET_PARAM is supported. The message should be a two element char pointer array + * Currently MSG_SET_PARAM is supported. The message should be a two element char pointer array * containing the addresses of a two element char array. char *paramPtr[2] = { ¶m[0][0], ¶m[1][0] }; * Element 0 of the base array (char param [2][20]; )should contain the name of the parameter to be changed - * Element 1 of the base array should contain the new value to be set. + * Element 1 of the base array should contain the new value to be set. + * + * sendMessage(DEVICE_WIFI, ICHIP2128, MSG_SET_PARAM, paramPtr); * - * sendMessage(DEVICE_WIFI, ICHIP2128, MSG_SET_PARAM, paramPtr); - * */ void ICHIPWIFI::handleMessage(uint32_t messageType, void* message) { - Device::handleMessage(messageType, message); //Only matters if message is MSG_STARTUP - - switch (messageType) { - - case MSG_SET_PARAM:{ //Sets a single parameter to a single value - char **params = (char **)message; //recast message as a two element array (params) - // Logger::console("Received Device: %s value %s",params[0], params[1]); - setParam((char *)params[0], (char *)params[1]); - break; - } - case MSG_CONFIG_CHANGE:{ //Loads all parameters to web site - loadParameters(); - break; - } - case MSG_COMMAND: //Sends a message to the WiReach module in the form of AT+imessage - sendCmd((char *)message); - break; - } - + Device::handleMessage(messageType, message); //Only matters if message is MSG_STARTUP + + switch (messageType) { + + case MSG_SET_PARAM: { //Sets a single parameter to a single value + char **params = (char **)message; //recast message as a two element array (params) + // Logger::console("Received Device: %s value %s",params[0], params[1]); + setParam((char *)params[0], (char *)params[1]); + break; + } + case MSG_CONFIG_CHANGE: { //Loads all parameters to web site + loadParameters(); + break; + } + case MSG_COMMAND: //Sends a message to the WiReach module in the form of AT+imessage + sendCmd((char *)message); + break; + } + } /* @@ -469,189 +469,189 @@ void ICHIPWIFI::handleMessage(uint32_t messageType, void* message) { * The result will be processed in loop() -> processParameterChange() */ void ICHIPWIFI::getNextParam() { - sendCmd("WNXT", GET_PARAM); //send command to get next changed parameter + sendCmd("WNXT", GET_PARAM); //send command to get next changed parameter } /* * Try to retrieve the value of the given parameter. */ void ICHIPWIFI::getParamById(String paramName) { - sendCmd(paramName + "?", GET_PARAM); + sendCmd(paramName + "?", GET_PARAM); } /* * Set a parameter to the given string value */ void ICHIPWIFI::setParam(String paramName, String value) { - sendCmd(paramName + "=\"" + value + "\"", SET_PARAM); + sendCmd(paramName + "=\"" + value + "\"", SET_PARAM); } /* * Set a parameter to the given int32 value */ void ICHIPWIFI::setParam(String paramName, int32_t value) { - sprintf(buffer, "%l", value); - setParam(paramName, buffer); + sprintf(buffer, "%l", value); + setParam(paramName, buffer); } /* * Set a parameter to the given uint32 value */ void ICHIPWIFI::setParam(String paramName, uint32_t value) { - sprintf(buffer, "%lu", value); - setParam(paramName, buffer); + sprintf(buffer, "%lu", value); + setParam(paramName, buffer); } /* * Set a parameter to the given sint16 value */ void ICHIPWIFI::setParam(String paramName, int16_t value) { - sprintf(buffer, "%d", value); - setParam(paramName, buffer); + sprintf(buffer, "%d", value); + setParam(paramName, buffer); } /* * Set a parameter to the given uint16 value */ void ICHIPWIFI::setParam(String paramName, uint16_t value) { - sprintf(buffer, "%d", value); - setParam(paramName, buffer); + sprintf(buffer, "%d", value); + setParam(paramName, buffer); } /* * Set a parameter to the given uint8 value */ void ICHIPWIFI::setParam(String paramName, uint8_t value) { - sprintf(buffer, "%d", value); - setParam(paramName, buffer); + sprintf(buffer, "%d", value); + setParam(paramName, buffer); } /* * Set a parameter to the given float value */ void ICHIPWIFI::setParam(String paramName, float value, int precision) { - char format[10]; - sprintf(format, "%%.%df", precision); - sprintf(buffer, format, value); - setParam(paramName, buffer); + char format[10]; + sprintf(format, "%%.%df", precision); + sprintf(buffer, format, value); + setParam(paramName, buffer); } /* * Called in the main loop (hopefully) in order to process serial input waiting for us * from the wifi module. It should always terminate its answers with 13 so buffer * until we get 13 (CR) and then process it. - * + * */ void ICHIPWIFI::loop() { - int incoming; - char buff[6]; - while (serialInterface->available()) { - incoming = serialInterface->read(); - if (incoming != -1) { //and there is no reason it should be -1 - if (incoming == 13 || ibWritePtr > 126) { // on CR or full buffer, process the line - incomingBuffer[ibWritePtr] = 0; //null terminate the string - ibWritePtr = 0; //reset the write pointer - //what we do with the input depends on what state the ICHIP comm was set to. - if (Logger::isDebug()) { - sprintf(buff, "%u", state); - String temp = "In Data, state: " + String(buff); - Logger::debug(ICHIP2128, (char *)temp.c_str()); - temp = "Data from ichip: " + String(incomingBuffer); - Logger::debug(ICHIP2128, (char *)temp.c_str()); - - } - - //The ichip echoes our commands back at us. The safer option might be to verify that the command - //we think we're about to process is really proper by validating the echo here. But, for now - //just ignore echoes. - if (strncmp(incomingBuffer, Constants::ichipCommandPrefix, 4) != 0) { - switch (state) { - case GET_PARAM: //reply from an attempt to read changed parameters from ichip - if (strchr(incomingBuffer, '=')) - processParameterChange(incomingBuffer); - break; - case SET_PARAM: //reply from sending parameters to the ichip - break; - case START_TCP_LISTENER: //reply from turning on a listening socket - //reply hopefully has the listening socket #. - if (strcmp(incomingBuffer, Constants::ichipErrorString)) { - listeningSocket = atoi(&incomingBuffer[2]); - if (listeningSocket < 10) listeningSocket = 0; - if (listeningSocket > 11) listeningSocket = 0; - if (Logger::isDebug()) { - sprintf(buff, "%u", listeningSocket); - Logger::debug(ICHIP2128, buff); - } - } - break; - case GET_ACTIVE_SOCKETS: //reply from asking for active connections - if (strcmp(incomingBuffer, Constants::ichipErrorString)) { - activeSockets[0] = atoi(strtok(&incomingBuffer[3], ",")); - activeSockets[1] = atoi(strtok(NULL, ",")); - activeSockets[2] = atoi(strtok(NULL, ",")); - activeSockets[3] = atoi(strtok(NULL, ",")); - if (Logger::isDebug()) { - sprintf(buff, "%i", activeSockets[0]); - Logger::debug(ICHIP2128, buff); - sprintf(buff, "%i", activeSockets[1]); - Logger::debug(ICHIP2128, buff); - sprintf(buff, "%i", activeSockets[2]); - Logger::debug(ICHIP2128, buff); - sprintf(buff, "%i", activeSockets[3]); - Logger::debug(ICHIP2128, buff); - } - } - break; - case POLL_SOCKET: //reply from asking about state of socket and how much data it has - - break; - case SEND_SOCKET: //reply from sending data over a socket - break; - case GET_SOCKET: //reply requesting the data pending on a socket - //reply is I/:data - int dLen; - //do not do anything if the socket read returned an error. - if (strstr(incomingBuffer, "ERROR") == NULL) { - if (strcmp(incomingBuffer, Constants::ichipErrorString)) { - dLen = atoi( strtok(&incomingBuffer[2], ":") ); - String datastr = strtok(0, ":"); //get the rest of the string - datastr.toLowerCase(); - String ret = elmProc->processELMCmd((char *)datastr.c_str()); - sendToSocket(0, ret); //TODO: need to actually track which socket requested this data - } - } - break; - case IDLE: //not sure whether to leave this info or go to debug. The ichip shouldn't be sending things in idle state - default: - //Logger::info(ICHIP2128, incomingBuffer); - break; - - } - - //if we got an I/ reply then the command is done sending data. So, see if there is a buffered cmd to send. - if (strstr(incomingBuffer, "I/") != NULL) { - state = IDLE; - if (psReadPtr != psWritePtr) { //if there is a parameter to send then do it - String temp = "Sending buffered cmd: " + sendingBuffer[psReadPtr].cmd; - if (Logger::isDebug()) Logger::debug(ICHIP2128, (char *)temp.c_str()); - sendCmd(sendingBuffer[psReadPtr].cmd, sendingBuffer[psReadPtr].state); - psReadPtr = (psReadPtr + 1) & 63; - } - } - } - } else { // add more characters - if (incoming != 10) // don't add a LF character - incomingBuffer[ibWritePtr++] = (char) incoming; - } - } - else return; - } - - if (millis() > lastSentTime + 1000) { //if the last sent command hasn't gotten a reply in 1 second - state = IDLE; //something went wrong so reset state - //sendCmd(lastSentCmd, lastSentState); //try to resend it - //The sendCmd call resets lastSentTime so this will at most be called every second until the iChip interface decides to cooperate. - } + int incoming; + char buff[6]; + while (serialInterface->available()) { + incoming = serialInterface->read(); + if (incoming != -1) { //and there is no reason it should be -1 + if (incoming == 13 || ibWritePtr > 126) { // on CR or full buffer, process the line + incomingBuffer[ibWritePtr] = 0; //null terminate the string + ibWritePtr = 0; //reset the write pointer + //what we do with the input depends on what state the ICHIP comm was set to. + if (Logger::isDebug()) { + sprintf(buff, "%u", state); + String temp = "In Data, state: " + String(buff); + Logger::debug(ICHIP2128, (char *)temp.c_str()); + temp = "Data from ichip: " + String(incomingBuffer); + Logger::debug(ICHIP2128, (char *)temp.c_str()); + + } + + //The ichip echoes our commands back at us. The safer option might be to verify that the command + //we think we're about to process is really proper by validating the echo here. But, for now + //just ignore echoes. + if (strncmp(incomingBuffer, Constants::ichipCommandPrefix, 4) != 0) { + switch (state) { + case GET_PARAM: //reply from an attempt to read changed parameters from ichip + if (strchr(incomingBuffer, '=')) + processParameterChange(incomingBuffer); + break; + case SET_PARAM: //reply from sending parameters to the ichip + break; + case START_TCP_LISTENER: //reply from turning on a listening socket + //reply hopefully has the listening socket #. + if (strcmp(incomingBuffer, Constants::ichipErrorString)) { + listeningSocket = atoi(&incomingBuffer[2]); + if (listeningSocket < 10) listeningSocket = 0; + if (listeningSocket > 11) listeningSocket = 0; + if (Logger::isDebug()) { + sprintf(buff, "%u", listeningSocket); + Logger::debug(ICHIP2128, buff); + } + } + break; + case GET_ACTIVE_SOCKETS: //reply from asking for active connections + if (strcmp(incomingBuffer, Constants::ichipErrorString)) { + activeSockets[0] = atoi(strtok(&incomingBuffer[3], ",")); + activeSockets[1] = atoi(strtok(NULL, ",")); + activeSockets[2] = atoi(strtok(NULL, ",")); + activeSockets[3] = atoi(strtok(NULL, ",")); + if (Logger::isDebug()) { + sprintf(buff, "%i", activeSockets[0]); + Logger::debug(ICHIP2128, buff); + sprintf(buff, "%i", activeSockets[1]); + Logger::debug(ICHIP2128, buff); + sprintf(buff, "%i", activeSockets[2]); + Logger::debug(ICHIP2128, buff); + sprintf(buff, "%i", activeSockets[3]); + Logger::debug(ICHIP2128, buff); + } + } + break; + case POLL_SOCKET: //reply from asking about state of socket and how much data it has + + break; + case SEND_SOCKET: //reply from sending data over a socket + break; + case GET_SOCKET: //reply requesting the data pending on a socket + //reply is I/:data + int dLen; + //do not do anything if the socket read returned an error. + if (strstr(incomingBuffer, "ERROR") == NULL) { + if (strcmp(incomingBuffer, Constants::ichipErrorString)) { + dLen = atoi( strtok(&incomingBuffer[2], ":") ); + String datastr = strtok(0, ":"); //get the rest of the string + datastr.toLowerCase(); + String ret = elmProc->processELMCmd((char *)datastr.c_str()); + sendToSocket(0, ret); //TODO: need to actually track which socket requested this data + } + } + break; + case IDLE: //not sure whether to leave this info or go to debug. The ichip shouldn't be sending things in idle state + default: + //Logger::info(ICHIP2128, incomingBuffer); + break; + + } + + //if we got an I/ reply then the command is done sending data. So, see if there is a buffered cmd to send. + if (strstr(incomingBuffer, "I/") != NULL) { + state = IDLE; + if (psReadPtr != psWritePtr) { //if there is a parameter to send then do it + String temp = "Sending buffered cmd: " + sendingBuffer[psReadPtr].cmd; + if (Logger::isDebug()) Logger::debug(ICHIP2128, (char *)temp.c_str()); + sendCmd(sendingBuffer[psReadPtr].cmd, sendingBuffer[psReadPtr].state); + psReadPtr = (psReadPtr + 1) & 63; + } + } + } + } else { // add more characters + if (incoming != 10) // don't add a LF character + incomingBuffer[ibWritePtr++] = (char) incoming; + } + } + else return; + } + + if (millis() > lastSentTime + 1000) { //if the last sent command hasn't gotten a reply in 1 second + state = IDLE; //something went wrong so reset state + //sendCmd(lastSentCmd, lastSentState); //try to resend it + //The sendCmd call resets lastSentTime so this will at most be called every second until the iChip interface decides to cooperate. + } } /* @@ -660,216 +660,284 @@ void ICHIPWIFI::loop() { * by looking for the '=' sign and the leading/trailing '"' have to be ignored. */ void ICHIPWIFI::processParameterChange(char *key) { - PotThrottleConfiguration *acceleratorConfig = NULL; - PotThrottleConfiguration *brakeConfig = NULL; - MotorControllerConfiguration *motorConfig = NULL; - bool parameterFound = true; - - char *value = strchr(key, '='); - if (!value) - return; - - Throttle *accelerator = DeviceManager::getInstance()->getAccelerator(); - Throttle *brake = DeviceManager::getInstance()->getBrake(); - MotorController *motorController = DeviceManager::getInstance()->getMotorController(); - - if (accelerator) - acceleratorConfig = (PotThrottleConfiguration *)accelerator->getConfiguration(); - if (brake) - brakeConfig = (PotThrottleConfiguration *)brake->getConfiguration(); - if(motorController) - motorConfig = (MotorControllerConfiguration *)motorController->getConfiguration(); - - value[0] = 0; // replace the '=' sign with a 0 - value++; - if (value[0] == '"') - value++; // if the value starts with a '"', advance one character - if (value[strlen(value) - 1] == '"') - value[strlen(value) - 1] = 0; // if the value ends with a '"' character, replace it with 0 - - if (!strcmp(key, Constants::numThrottlePots) && acceleratorConfig) { - acceleratorConfig->numberPotMeters = atol(value); - accelerator->saveConfiguration(); - } else if (!strcmp(key, Constants::throttleSubType) && acceleratorConfig) { - acceleratorConfig->throttleSubType = atol(value); - accelerator->saveConfiguration(); - } else if (!strcmp(key, Constants::throttleMin1) && acceleratorConfig) { - acceleratorConfig->minimumLevel1 = atol(value); - accelerator->saveConfiguration(); - } else if (!strcmp(key, Constants::throttleMin2) && acceleratorConfig) { - acceleratorConfig->minimumLevel2 = atol(value); - accelerator->saveConfiguration(); - } else if (!strcmp(key, Constants::throttleMax1) && acceleratorConfig) { - acceleratorConfig->maximumLevel1 = atol(value); - accelerator->saveConfiguration(); - } else if (!strcmp(key, Constants::throttleMax2) && acceleratorConfig) { - acceleratorConfig->maximumLevel2 = atol(value); - accelerator->saveConfiguration(); - } else if (!strcmp(key, Constants::throttleRegenMax) && acceleratorConfig) { - acceleratorConfig->positionRegenMaximum = atol(value) * 10; - } else if (!strcmp(key, Constants::throttleRegenMin) && acceleratorConfig) { - acceleratorConfig->positionRegenMinimum = atol(value) * 10; - accelerator->saveConfiguration(); - } else if (!strcmp(key, Constants::throttleFwd) && acceleratorConfig) { - acceleratorConfig->positionForwardMotionStart = atol(value) * 10; - accelerator->saveConfiguration(); - } else if (!strcmp(key, Constants::throttleMap) && acceleratorConfig) { - acceleratorConfig->positionHalfPower = atol(value) * 10; - accelerator->saveConfiguration(); - } else if (!strcmp(key, Constants::throttleMinRegen) && acceleratorConfig) { - acceleratorConfig->minimumRegen = atol(value); - accelerator->saveConfiguration(); - } else if (!strcmp(key, Constants::throttleMaxRegen) && acceleratorConfig) { - acceleratorConfig->maximumRegen = atol(value); - accelerator->saveConfiguration(); - } else if (!strcmp(key, Constants::throttleCreep) && acceleratorConfig) { - acceleratorConfig->creep = atol(value); - accelerator->saveConfiguration(); - } else if (!strcmp(key, Constants::brakeMin) && brakeConfig) { - brakeConfig->minimumLevel1 = atol(value); - brake->saveConfiguration(); - } else if (!strcmp(key, Constants::brakeMax) && brakeConfig) { - brakeConfig->maximumLevel1 = atol(value); - brake->saveConfiguration(); - } else if (!strcmp(key, Constants::brakeMinRegen) && brakeConfig) { - brakeConfig->minimumRegen = atol(value); - brake->saveConfiguration(); - } else if (!strcmp(key, Constants::brakeMaxRegen) && brakeConfig) { - brakeConfig->maximumRegen = atol(value); - brake->saveConfiguration(); - } else if (!strcmp(key, Constants::speedMax) && motorConfig) { - motorConfig->speedMax = atol(value); - motorController->saveConfiguration(); - } else if (!strcmp(key, Constants::torqueMax) && motorConfig) { - motorConfig->torqueMax = atol(value) * 10; - motorController->saveConfiguration(); + PotThrottleConfiguration *acceleratorConfig = NULL; + PotThrottleConfiguration *brakeConfig = NULL; + MotorControllerConfiguration *motorConfig = NULL; + bool parameterFound = true; + + char *value = strchr(key, '='); + if (!value) + return; + + Throttle *accelerator = DeviceManager::getInstance()->getAccelerator(); + Throttle *brake = DeviceManager::getInstance()->getBrake(); + MotorController *motorController = DeviceManager::getInstance()->getMotorController(); + + if (accelerator) + acceleratorConfig = (PotThrottleConfiguration *)accelerator->getConfiguration(); + if (brake) + brakeConfig = (PotThrottleConfiguration *)brake->getConfiguration(); + if(motorController) + motorConfig = (MotorControllerConfiguration *)motorController->getConfiguration(); + + value[0] = 0; // replace the '=' sign with a 0 + value++; + if (value[0] == '"') + value++; // if the value starts with a '"', advance one character + if (value[strlen(value) - 1] == '"') + value[strlen(value) - 1] = 0; // if the value ends with a '"' character, replace it with 0 + + if (!strcmp(key, Constants::numThrottlePots) && acceleratorConfig) { + acceleratorConfig->numberPotMeters = atol(value); + accelerator->saveConfiguration(); + } else if (!strcmp(key, Constants::throttleSubType) && acceleratorConfig) { + acceleratorConfig->throttleSubType = atol(value); + accelerator->saveConfiguration(); + } else if (!strcmp(key, Constants::throttleMin1) && acceleratorConfig) { + acceleratorConfig->minimumLevel1 = atol(value); + accelerator->saveConfiguration(); + } else if (!strcmp(key, Constants::throttleMin2) && acceleratorConfig) { + acceleratorConfig->minimumLevel2 = atol(value); + accelerator->saveConfiguration(); + } else if (!strcmp(key, Constants::throttleMax1) && acceleratorConfig) { + acceleratorConfig->maximumLevel1 = atol(value); + accelerator->saveConfiguration(); + } else if (!strcmp(key, Constants::throttleMax2) && acceleratorConfig) { + acceleratorConfig->maximumLevel2 = atol(value); + accelerator->saveConfiguration(); + } else if (!strcmp(key, Constants::throttleRegenMax) && acceleratorConfig) { + acceleratorConfig->positionRegenMaximum = atol(value) * 10; + } else if (!strcmp(key, Constants::throttleRegenMin) && acceleratorConfig) { + acceleratorConfig->positionRegenMinimum = atol(value) * 10; + accelerator->saveConfiguration(); + } else if (!strcmp(key, Constants::throttleFwd) && acceleratorConfig) { + acceleratorConfig->positionForwardMotionStart = atol(value) * 10; + accelerator->saveConfiguration(); + } else if (!strcmp(key, Constants::throttleMap) && acceleratorConfig) { + acceleratorConfig->positionHalfPower = atol(value) * 10; + accelerator->saveConfiguration(); + } else if (!strcmp(key, Constants::throttleMinRegen) && acceleratorConfig) { + acceleratorConfig->minimumRegen = atol(value); + accelerator->saveConfiguration(); + } else if (!strcmp(key, Constants::throttleMaxRegen) && acceleratorConfig) { + acceleratorConfig->maximumRegen = atol(value); + accelerator->saveConfiguration(); + } else if (!strcmp(key, Constants::throttleCreep) && acceleratorConfig) { + acceleratorConfig->creep = atol(value); + accelerator->saveConfiguration(); + } else if (!strcmp(key, Constants::brakeMin) && brakeConfig) { + brakeConfig->minimumLevel1 = atol(value); + brake->saveConfiguration(); + } else if (!strcmp(key, Constants::brakeMax) && brakeConfig) { + brakeConfig->maximumLevel1 = atol(value); + brake->saveConfiguration(); + } else if (!strcmp(key, Constants::brakeMinRegen) && brakeConfig) { + brakeConfig->minimumRegen = atol(value); + brake->saveConfiguration(); + } else if (!strcmp(key, Constants::brakeMaxRegen) && brakeConfig) { + brakeConfig->maximumRegen = atol(value); + brake->saveConfiguration(); + } else if (!strcmp(key, Constants::speedMax) && motorConfig) { + motorConfig->speedMax = atol(value); + motorController->saveConfiguration(); + } else if (!strcmp(key, Constants::torqueMax) && motorConfig) { + motorConfig->torqueMax = atol(value) * 10; + motorController->saveConfiguration(); } else if (!strcmp(key, Constants::coolFan) && motorConfig) { - motorConfig->coolFan = atol(value); - motorController->saveConfiguration(); - } else if (!strcmp(key, Constants::coolOn) && motorConfig) { - motorConfig->coolOn = (atol(value)); - motorController->saveConfiguration(); - } else if (!strcmp(key, Constants::coolOff) && motorConfig) { - motorConfig->coolOff = (atol(value)); - motorController->saveConfiguration(); - } else if (!strcmp(key, Constants::prechargeR) && motorConfig) { - motorConfig->prechargeR = atol(value); - motorController->saveConfiguration(); - } else if (!strcmp(key, Constants::prechargeRelay) && motorConfig) { - motorConfig->prechargeRelay = atol(value); - motorController->saveConfiguration(); - } else if (!strcmp(key, Constants::nominalVolt) && motorConfig) { - motorConfig->nominalVolt = (atol(value))*10; - motorController->saveConfiguration(); - - } else if (!strcmp(key, Constants::mainContactorRelay) && motorConfig) { - motorConfig->mainContactorRelay = atol(value); - motorController->saveConfiguration(); - } else if (!strcmp(key, Constants::brakeLight) && motorConfig) { - motorConfig->brakeLight = atol(value); - motorController->saveConfiguration(); - } else if (!strcmp(key, Constants::revLight) && motorConfig) { - motorConfig->revLight = atol(value); - motorController->saveConfiguration(); - } else if (!strcmp(key, Constants::enableIn) && motorConfig) { - motorConfig->enableIn = atol(value); - motorController->saveConfiguration(); - } else if (!strcmp(key, Constants::reverseIn) && motorConfig) { - motorConfig->reverseIn = atol(value); - motorController->saveConfiguration(); - /* } else if (!strcmp(key, Constants::motorMode) && motorConfig) { - motorConfig->motorMode = (MotorController::PowerMode)atoi(value); - motorController->saveConfiguration(); - */ - - - - } else if (!strcmp(key, "x1000")){ - if (255==atol(value)){sysPrefs->setDeviceStatus(strtol(key+1, 0, 16),true);} - else {sysPrefs->setDeviceStatus(strtol(key+1, 0, 16), false);} - //sysPrefs->forceCacheWrite(); - } else if (!strcmp(key, "x1001")){ - if (255==atol(value)){sysPrefs->setDeviceStatus(strtol(key+1, 0, 16),true);} - else {sysPrefs->setDeviceStatus(strtol(key+1, 0, 16), false);} - //sysPrefs->forceCacheWrite(); - } else if (!strcmp(key, "x1002")){ - if (255==atol(value)){sysPrefs->setDeviceStatus(strtol(key+1, 0, 16),true);} - else {sysPrefs->setDeviceStatus(strtol(key+1, 0, 16), false);} - // sysPrefs->forceCacheWrite(); - } else if (!strcmp(key, "x1031")){ - if (255==atol(value)){sysPrefs->setDeviceStatus(strtol(key+1, 0, 16), true);} - else {sysPrefs->setDeviceStatus(strtol(key+1, 0, 16), false);} - //sysPrefs->forceCacheWrite(); - } else if (!strcmp(key, "x1032")){ - if (255==atol(value)){sysPrefs->setDeviceStatus(strtol(key+1, 0, 16), true);} - else {sysPrefs->setDeviceStatus(strtol(key+1, 0, 16), false);} - //sysPrefs->forceCacheWrite(); - } else if (!strcmp(key, "x1033")){ - if (255==atol(value)){sysPrefs->setDeviceStatus(strtol(key+1, 0, 16), true);} - else {sysPrefs->setDeviceStatus(strtol(key+1, 0, 16), false);} - //sysPrefs->forceCacheWrite(); - } else if (!strcmp(key, "x1034")){ - if (255==atol(value)){sysPrefs->setDeviceStatus(strtol(key+1, 0, 16), true);} - else {sysPrefs->setDeviceStatus(strtol(key+1, 0, 16), false);} - // sysPrefs->forceCacheWrite(); - } else if (!strcmp(key, "x1010")){ - if (255==atol(value)){sysPrefs->setDeviceStatus(strtol(key+1, 0, 16), true);} - else {sysPrefs->setDeviceStatus(strtol(key+1, 0, 16), false);} - // sysPrefs->forceCacheWrite(); - } else if (!strcmp(key, "x1011")){ - if (255==atol(value)){sysPrefs->setDeviceStatus(strtol(key+1, 0, 16), true);} - else {sysPrefs->setDeviceStatus(strtol(key+1, 0, 16), false);} - //sysPrefs->forceCacheWrite(); - } else if (!strcmp(key, "x1012")){ - if (255==atol(value)){sysPrefs->setDeviceStatus(strtol(key+1, 0, 16), true);} - else {sysPrefs->setDeviceStatus(strtol(key+1, 0, 16), false);} - //sysPrefs->forceCacheWrite(); - } else if (!strcmp(key, "x1020")){ - if (255==atol(value)){sysPrefs->setDeviceStatus(strtol(key+1, 0, 16), true);} - else {sysPrefs->setDeviceStatus(strtol(key+1, 0, 16), false);} - sysPrefs->forceCacheWrite(); - } else if (!strcmp(key, "x1040")){ - if (255==atol(value)){sysPrefs->setDeviceStatus(strtol(key+1, 0, 16), true);} - else {sysPrefs->setDeviceStatus(strtol(key+1, 0, 16), false);} - // sysPrefs->forceCacheWrite(); - } else if (!strcmp(key, "x1050")){ - if (255==atol(value)){sysPrefs->setDeviceStatus(strtol(key+1, 0, 16), true);} - else {sysPrefs->setDeviceStatus(strtol(key+1, 0, 16), false);} - // sysPrefs->forceCacheWrite(); - } else if (!strcmp(key, "x2000")){ - if (255==atol(value)){sysPrefs->setDeviceStatus(strtol(key+1, 0, 16), true);} - else {sysPrefs->setDeviceStatus(strtol(key+1, 0, 16), false);} - sysPrefs->forceCacheWrite(); - } else if (!strcmp(key, "x4400")){ - if (255==atol(value)){sysPrefs->setDeviceStatus(strtol(key+1, 0, 16), true);} - else {sysPrefs->setDeviceStatus(strtol(key+1, 0, 16), false);} - // sysPrefs->forceCacheWrite(); - sysPrefs->forceCacheWrite(); - } else if (!strcmp(key, "x6000")){ - if (255==atol(value)){sysPrefs->setDeviceStatus(strtol(key+1, 0, 16), true);} - else {sysPrefs->setDeviceStatus(strtol(key+1, 0, 16), false);} - // sysPrefs->forceCacheWrite(); - } else if (!strcmp(key, "x650")){ - if (255==atol(value)){sysPrefs->setDeviceStatus(strtol(key+1, 0, 16), true);} - else {sysPrefs->setDeviceStatus(strtol(key+1, 0, 16), false);} - // sysPrefs->forceCacheWrite(); - - } else if (!strcmp(key, Constants::logLevel)) { - extern PrefHandler *sysPrefs; - uint8_t loglevel = atoi(value); - Logger::setLoglevel((Logger::LogLevel)loglevel); - sysPrefs->write(EESYS_LOG_LEVEL, loglevel); - } else { - parameterFound = false; - } - if (parameterFound) { - Logger::info(ICHIP2128, "parameter change: %s", key); - getNextParam(); // try to get another one immediately - } + motorConfig->coolFan = atol(value); + motorController->saveConfiguration(); + } else if (!strcmp(key, Constants::coolOn) && motorConfig) { + motorConfig->coolOn = (atol(value)); + motorController->saveConfiguration(); + } else if (!strcmp(key, Constants::coolOff) && motorConfig) { + motorConfig->coolOff = (atol(value)); + motorController->saveConfiguration(); + } else if (!strcmp(key, Constants::prechargeR) && motorConfig) { + motorConfig->prechargeR = atol(value); + motorController->saveConfiguration(); + } else if (!strcmp(key, Constants::prechargeRelay) && motorConfig) { + motorConfig->prechargeRelay = atol(value); + motorController->saveConfiguration(); + } else if (!strcmp(key, Constants::nominalVolt) && motorConfig) { + motorConfig->nominalVolt = (atol(value))*10; + motorController->saveConfiguration(); + + } else if (!strcmp(key, Constants::mainContactorRelay) && motorConfig) { + motorConfig->mainContactorRelay = atol(value); + motorController->saveConfiguration(); + } else if (!strcmp(key, Constants::brakeLight) && motorConfig) { + motorConfig->brakeLight = atol(value); + motorController->saveConfiguration(); + } else if (!strcmp(key, Constants::revLight) && motorConfig) { + motorConfig->revLight = atol(value); + motorController->saveConfiguration(); + } else if (!strcmp(key, Constants::enableIn) && motorConfig) { + motorConfig->enableIn = atol(value); + motorController->saveConfiguration(); + } else if (!strcmp(key, Constants::reverseIn) && motorConfig) { + motorConfig->reverseIn = atol(value); + motorController->saveConfiguration(); + /* } else if (!strcmp(key, Constants::motorMode) && motorConfig) { + motorConfig->motorMode = (MotorController::PowerMode)atoi(value); + motorController->saveConfiguration(); + */ + + + + } else if (!strcmp(key, "x1000")) { + if (255==atol(value)) { + sysPrefs->setDeviceStatus(strtol(key+1, 0, 16),true); + } else { - sysPrefs->forceCacheWrite(); - DeviceManager::getInstance()->updateWifi(); - } + sysPrefs->setDeviceStatus(strtol(key+1, 0, 16), false); + } + //sysPrefs->forceCacheWrite(); + } else if (!strcmp(key, "x1001")) { + if (255==atol(value)) { + sysPrefs->setDeviceStatus(strtol(key+1, 0, 16),true); + } + else { + sysPrefs->setDeviceStatus(strtol(key+1, 0, 16), false); + } + //sysPrefs->forceCacheWrite(); + } else if (!strcmp(key, "x1002")) { + if (255==atol(value)) { + sysPrefs->setDeviceStatus(strtol(key+1, 0, 16),true); + } + else { + sysPrefs->setDeviceStatus(strtol(key+1, 0, 16), false); + } + // sysPrefs->forceCacheWrite(); + } else if (!strcmp(key, "x1031")) { + if (255==atol(value)) { + sysPrefs->setDeviceStatus(strtol(key+1, 0, 16), true); + } + else { + sysPrefs->setDeviceStatus(strtol(key+1, 0, 16), false); + } + //sysPrefs->forceCacheWrite(); + } else if (!strcmp(key, "x1032")) { + if (255==atol(value)) { + sysPrefs->setDeviceStatus(strtol(key+1, 0, 16), true); + } + else { + sysPrefs->setDeviceStatus(strtol(key+1, 0, 16), false); + } + //sysPrefs->forceCacheWrite(); + } else if (!strcmp(key, "x1033")) { + if (255==atol(value)) { + sysPrefs->setDeviceStatus(strtol(key+1, 0, 16), true); + } + else { + sysPrefs->setDeviceStatus(strtol(key+1, 0, 16), false); + } + //sysPrefs->forceCacheWrite(); + } else if (!strcmp(key, "x1034")) { + if (255==atol(value)) { + sysPrefs->setDeviceStatus(strtol(key+1, 0, 16), true); + } + else { + sysPrefs->setDeviceStatus(strtol(key+1, 0, 16), false); + } + // sysPrefs->forceCacheWrite(); + } else if (!strcmp(key, "x1010")) { + if (255==atol(value)) { + sysPrefs->setDeviceStatus(strtol(key+1, 0, 16), true); + } + else { + sysPrefs->setDeviceStatus(strtol(key+1, 0, 16), false); + } + // sysPrefs->forceCacheWrite(); + } else if (!strcmp(key, "x1011")) { + if (255==atol(value)) { + sysPrefs->setDeviceStatus(strtol(key+1, 0, 16), true); + } + else { + sysPrefs->setDeviceStatus(strtol(key+1, 0, 16), false); + } + //sysPrefs->forceCacheWrite(); + } else if (!strcmp(key, "x1012")) { + if (255==atol(value)) { + sysPrefs->setDeviceStatus(strtol(key+1, 0, 16), true); + } + else { + sysPrefs->setDeviceStatus(strtol(key+1, 0, 16), false); + } + //sysPrefs->forceCacheWrite(); + } else if (!strcmp(key, "x1020")) { + if (255==atol(value)) { + sysPrefs->setDeviceStatus(strtol(key+1, 0, 16), true); + } + else { + sysPrefs->setDeviceStatus(strtol(key+1, 0, 16), false); + } + sysPrefs->forceCacheWrite(); + } else if (!strcmp(key, "x1040")) { + if (255==atol(value)) { + sysPrefs->setDeviceStatus(strtol(key+1, 0, 16), true); + } + else { + sysPrefs->setDeviceStatus(strtol(key+1, 0, 16), false); + } + // sysPrefs->forceCacheWrite(); + } else if (!strcmp(key, "x1050")) { + if (255==atol(value)) { + sysPrefs->setDeviceStatus(strtol(key+1, 0, 16), true); + } + else { + sysPrefs->setDeviceStatus(strtol(key+1, 0, 16), false); + } + // sysPrefs->forceCacheWrite(); + } else if (!strcmp(key, "x2000")) { + if (255==atol(value)) { + sysPrefs->setDeviceStatus(strtol(key+1, 0, 16), true); + } + else { + sysPrefs->setDeviceStatus(strtol(key+1, 0, 16), false); + } + sysPrefs->forceCacheWrite(); + } else if (!strcmp(key, "x4400")) { + if (255==atol(value)) { + sysPrefs->setDeviceStatus(strtol(key+1, 0, 16), true); + } + else { + sysPrefs->setDeviceStatus(strtol(key+1, 0, 16), false); + } + // sysPrefs->forceCacheWrite(); + sysPrefs->forceCacheWrite(); + } else if (!strcmp(key, "x6000")) { + if (255==atol(value)) { + sysPrefs->setDeviceStatus(strtol(key+1, 0, 16), true); + } + else { + sysPrefs->setDeviceStatus(strtol(key+1, 0, 16), false); + } + // sysPrefs->forceCacheWrite(); + } else if (!strcmp(key, "x650")) { + if (255==atol(value)) { + sysPrefs->setDeviceStatus(strtol(key+1, 0, 16), true); + } + else { + sysPrefs->setDeviceStatus(strtol(key+1, 0, 16), false); + } + // sysPrefs->forceCacheWrite(); + + } else if (!strcmp(key, Constants::logLevel)) { + extern PrefHandler *sysPrefs; + uint8_t loglevel = atoi(value); + Logger::setLoglevel((Logger::LogLevel)loglevel); + sysPrefs->write(EESYS_LOG_LEVEL, loglevel); + } else { + parameterFound = false; + } + if (parameterFound) { + Logger::info(ICHIP2128, "parameter change: %s", key); + getNextParam(); // try to get another one immediately + } + else { + sysPrefs->forceCacheWrite(); + DeviceManager::getInstance()->updateWifi(); + } } /* @@ -877,88 +945,88 @@ void ICHIPWIFI::processParameterChange(char *key) { * This is required to initially set-up the ichip */ void ICHIPWIFI::loadParameters() { - MotorController *motorController = DeviceManager::getInstance()->getMotorController(); - Throttle *accelerator = DeviceManager::getInstance()->getAccelerator(); - Throttle *brake = DeviceManager::getInstance()->getBrake(); - PotThrottleConfiguration *acceleratorConfig = NULL; - PotThrottleConfiguration *brakeConfig = NULL; - MotorControllerConfiguration *motorConfig = NULL; - - Logger::info("loading config params to ichip/wifi"); - - //DeviceManager::getInstance()->updateWifi(); - - if (accelerator) - acceleratorConfig = (PotThrottleConfiguration *)accelerator->getConfiguration(); - if (brake) - brakeConfig = (PotThrottleConfiguration *)brake->getConfiguration(); - if (motorController) - motorConfig = (MotorControllerConfiguration *)motorController->getConfiguration(); - - if (acceleratorConfig) { - setParam(Constants::numThrottlePots, acceleratorConfig->numberPotMeters); - setParam(Constants::throttleSubType, acceleratorConfig->throttleSubType); - setParam(Constants::throttleMin1, acceleratorConfig->minimumLevel1); - setParam(Constants::throttleMin2, acceleratorConfig->minimumLevel2); - setParam(Constants::throttleMax1, acceleratorConfig->maximumLevel1); - setParam(Constants::throttleMax2, acceleratorConfig->maximumLevel2); - setParam(Constants::throttleRegenMax, (uint16_t)(acceleratorConfig->positionRegenMaximum / 10)); - setParam(Constants::throttleRegenMin, (uint16_t)(acceleratorConfig->positionRegenMinimum / 10)); - setParam(Constants::throttleFwd, (uint16_t)(acceleratorConfig->positionForwardMotionStart / 10)); - setParam(Constants::throttleMap, (uint16_t)(acceleratorConfig->positionHalfPower / 10)); - setParam(Constants::throttleMinRegen, acceleratorConfig->minimumRegen); - setParam(Constants::throttleMaxRegen, acceleratorConfig->maximumRegen); - setParam(Constants::throttleCreep, acceleratorConfig->creep); - } - if (brakeConfig) { - setParam(Constants::brakeMin, brakeConfig->minimumLevel1); - setParam(Constants::brakeMax, brakeConfig->maximumLevel1); - setParam(Constants::brakeMinRegen, brakeConfig->minimumRegen); - setParam(Constants::brakeMaxRegen, brakeConfig->maximumRegen); - } - if (motorConfig) { - setParam(Constants::speedMax, motorConfig->speedMax); - setParam(Constants::coolFan, motorConfig->coolFan); - setParam(Constants::coolOn, motorConfig->coolOn); - setParam(Constants::coolOff, motorConfig->coolOff); - setParam(Constants::brakeLight, motorConfig->brakeLight); - setParam(Constants::revLight, motorConfig->revLight); - setParam(Constants::enableIn, motorConfig->enableIn); - setParam(Constants::reverseIn, motorConfig->reverseIn); - setParam(Constants::prechargeR, motorConfig->prechargeR); - setParam(Constants::prechargeRelay, motorConfig->prechargeRelay); - setParam(Constants::mainContactorRelay, motorConfig->mainContactorRelay); - uint16_t nmvlt = motorConfig->nominalVolt/10; - setParam(Constants::nominalVolt, nmvlt); - setParam(Constants::torqueMax, (uint16_t)(motorConfig->torqueMax / 10)); // skip the tenth's - } - setParam(Constants::logLevel, (uint8_t)Logger::getLogLevel()); - - + MotorController *motorController = DeviceManager::getInstance()->getMotorController(); + Throttle *accelerator = DeviceManager::getInstance()->getAccelerator(); + Throttle *brake = DeviceManager::getInstance()->getBrake(); + PotThrottleConfiguration *acceleratorConfig = NULL; + PotThrottleConfiguration *brakeConfig = NULL; + MotorControllerConfiguration *motorConfig = NULL; + + Logger::info("loading config params to ichip/wifi"); + + //DeviceManager::getInstance()->updateWifi(); + + if (accelerator) + acceleratorConfig = (PotThrottleConfiguration *)accelerator->getConfiguration(); + if (brake) + brakeConfig = (PotThrottleConfiguration *)brake->getConfiguration(); + if (motorController) + motorConfig = (MotorControllerConfiguration *)motorController->getConfiguration(); + + if (acceleratorConfig) { + setParam(Constants::numThrottlePots, acceleratorConfig->numberPotMeters); + setParam(Constants::throttleSubType, acceleratorConfig->throttleSubType); + setParam(Constants::throttleMin1, acceleratorConfig->minimumLevel1); + setParam(Constants::throttleMin2, acceleratorConfig->minimumLevel2); + setParam(Constants::throttleMax1, acceleratorConfig->maximumLevel1); + setParam(Constants::throttleMax2, acceleratorConfig->maximumLevel2); + setParam(Constants::throttleRegenMax, (uint16_t)(acceleratorConfig->positionRegenMaximum / 10)); + setParam(Constants::throttleRegenMin, (uint16_t)(acceleratorConfig->positionRegenMinimum / 10)); + setParam(Constants::throttleFwd, (uint16_t)(acceleratorConfig->positionForwardMotionStart / 10)); + setParam(Constants::throttleMap, (uint16_t)(acceleratorConfig->positionHalfPower / 10)); + setParam(Constants::throttleMinRegen, acceleratorConfig->minimumRegen); + setParam(Constants::throttleMaxRegen, acceleratorConfig->maximumRegen); + setParam(Constants::throttleCreep, acceleratorConfig->creep); + } + if (brakeConfig) { + setParam(Constants::brakeMin, brakeConfig->minimumLevel1); + setParam(Constants::brakeMax, brakeConfig->maximumLevel1); + setParam(Constants::brakeMinRegen, brakeConfig->minimumRegen); + setParam(Constants::brakeMaxRegen, brakeConfig->maximumRegen); + } + if (motorConfig) { + setParam(Constants::speedMax, motorConfig->speedMax); + setParam(Constants::coolFan, motorConfig->coolFan); + setParam(Constants::coolOn, motorConfig->coolOn); + setParam(Constants::coolOff, motorConfig->coolOff); + setParam(Constants::brakeLight, motorConfig->brakeLight); + setParam(Constants::revLight, motorConfig->revLight); + setParam(Constants::enableIn, motorConfig->enableIn); + setParam(Constants::reverseIn, motorConfig->reverseIn); + setParam(Constants::prechargeR, motorConfig->prechargeR); + setParam(Constants::prechargeRelay, motorConfig->prechargeRelay); + setParam(Constants::mainContactorRelay, motorConfig->mainContactorRelay); + uint16_t nmvlt = motorConfig->nominalVolt/10; + setParam(Constants::nominalVolt, nmvlt); + setParam(Constants::torqueMax, (uint16_t)(motorConfig->torqueMax / 10)); // skip the tenth's + } + setParam(Constants::logLevel, (uint8_t)Logger::getLogLevel()); + + } DeviceType ICHIPWIFI::getType() { - return DEVICE_WIFI; + return DEVICE_WIFI; } DeviceId ICHIPWIFI::getId() { - return (ICHIP2128); + return (ICHIP2128); } void ICHIPWIFI::loadConfiguration() { - WifiConfiguration *config = (WifiConfiguration *)getConfiguration(); + WifiConfiguration *config = (WifiConfiguration *)getConfiguration(); - if (prefsHandler->checksumValid()) { //checksum is good, read in the values stored in EEPROM - Logger::debug(ICHIP2128, "Valid checksum so using stored wifi config values"); - //TODO: implement processing of config params for WIFI + if (prefsHandler->checksumValid()) { //checksum is good, read in the values stored in EEPROM + Logger::debug(ICHIP2128, "Valid checksum so using stored wifi config values"); + //TODO: implement processing of config params for WIFI // prefsHandler->read(EESYS_WIFI0_SSID, &config->ssid); - } + } } void ICHIPWIFI::saveConfiguration() { - WifiConfiguration *config = (WifiConfiguration *) getConfiguration(); + WifiConfiguration *config = (WifiConfiguration *) getConfiguration(); - //TODO: implement processing of config params for WIFI + //TODO: implement processing of config params for WIFI // prefsHandler->write(EESYS_WIFI0_SSID, config->ssid); // prefsHandler->saveChecksum(); } diff --git a/ichip_2128.h b/ichip_2128.h index 739724c..1ec61c7 100644 --- a/ichip_2128.h +++ b/ichip_2128.h @@ -12,7 +12,7 @@ * If none of those networks can be found then the device will automatically try to form an * adhoc network with the 4th entry which is dedicated to that purpose. * All commands to the wifi start with "AT+i" and end with CR (ascii 13) - * + * * Commands: * RP11 - get list of access points in range * RP7 - Status report (bit 10 if remote has changed a param) @@ -42,13 +42,13 @@ * WSIx - x=0-9 = set SSIDs to associate with * WPPx - x=0-9 WPA pass phrases * WKYx - x=0-9 WEP keys - * WSTx - x=0-9 security type = (0=none, 1=wep64, 2=WEP128,3=WPA/TKIP 4=WPA2 - * - * + * WSTx - x=0-9 security type = (0=none, 1=wep64, 2=WEP128,3=WPA/TKIP 4=WPA2 + * + * * Web Parameters getting/setting - * = set + * = set * ? get - * + * Copyright (c) 2013 Collin Kidder, Michael Neuweiler, Charles Galpin @@ -102,32 +102,32 @@ class WifiConfiguration : public DeviceConfiguration { * Cache of param values to avoid sending an update unless changed */ struct ParamCache { - uint32_t timeRunning; - int16_t torqueRequested; - int16_t torqueActual; - int16_t throttle; - int16_t brake; - bool brakeNotAvailable; - int16_t speedRequested; - int16_t speedActual; - MotorController::PowerMode powerMode; - int16_t dcVoltage; - int16_t dcCurrent; - int16_t acCurrent; - int16_t nominalVolt; - int16_t kiloWattHours; - uint32_t bitfield1; - uint32_t bitfield2; - uint32_t bitfield3; - uint32_t bitfield4; - bool running; - bool faulted; - bool warning; - MotorController::Gears gear; - int16_t tempMotor; - int16_t tempInverter; - int16_t tempSystem; - int16_t mechPower; + uint32_t timeRunning; + int16_t torqueRequested; + int16_t torqueActual; + int16_t throttle; + int16_t brake; + bool brakeNotAvailable; + int16_t speedRequested; + int16_t speedActual; + MotorController::PowerMode powerMode; + int16_t dcVoltage; + int16_t dcCurrent; + int16_t acCurrent; + int16_t nominalVolt; + int16_t kiloWattHours; + uint32_t bitfield1; + uint32_t bitfield2; + uint32_t bitfield3; + uint32_t bitfield4; + bool running; + bool faulted; + bool warning; + MotorController::Gears gear; + int16_t tempMotor; + int16_t tempInverter; + int16_t tempSystem; + int16_t mechPower; int16_t prechargeR; int8_t prechargeRelay; int8_t mainContactorRelay; @@ -141,49 +141,49 @@ struct ParamCache { }; struct SendBuff { - String cmd; - ICHIP_COMM_STATE state; + String cmd; + ICHIP_COMM_STATE state; }; class ICHIPWIFI : public Device { - public: - +public: + ICHIPWIFI(); ICHIPWIFI(USARTClass *which); void setup(); //initialization on start up void handleTick(); //periodic processes void handleMessage(uint32_t messageType, void* message); - DeviceType getType(); + DeviceType getType(); DeviceId getId(); void loop(); char *getTimeRunning(); - - void loadConfiguration(); - void saveConfiguration(); - void loadParameters(); - - private: - ELM327Processor *elmProc; + void loadConfiguration(); + void saveConfiguration(); + void loadParameters(); + + +private: + ELM327Processor *elmProc; USARTClass* serialInterface; //Allows for retargetting which serial port we use char incomingBuffer[128]; //storage for one incoming line int ibWritePtr; //write position into above buffer - SendBuff sendingBuffer[64]; - int psWritePtr; - int psReadPtr; - int tickCounter; - int currReply; - char buffer[30]; // a buffer for various string conversions - ParamCache paramCache; - ICHIP_COMM_STATE state; - bool didParamLoad; - bool didTCPListener; - int listeningSocket; - int activeSockets[4]; //support for four sockets. Lowest byte is socket #, next byte is size of data waiting in that socket - uint32_t lastSentTime; - String lastSentCmd; - ICHIP_COMM_STATE lastSentState; + SendBuff sendingBuffer[64]; + int psWritePtr; + int psReadPtr; + int tickCounter; + int currReply; + char buffer[30]; // a buffer for various string conversions + ParamCache paramCache; + ICHIP_COMM_STATE state; + bool didParamLoad; + bool didTCPListener; + int listeningSocket; + int activeSockets[4]; //support for four sockets. Lowest byte is socket #, next byte is size of data waiting in that socket + uint32_t lastSentTime; + String lastSentCmd; + ICHIP_COMM_STATE lastSentState; void getNextParam(); //get next changed parameter void getParamById(String paramName); //try to retrieve the value of the given parameter @@ -195,11 +195,11 @@ class ICHIPWIFI : public Device { void setParam(String paramName, uint8_t value); void setParam(String paramName, float value, int precision); void sendCmd(String cmd); - void sendCmd(String cmd, ICHIP_COMM_STATE cmdstate); - void sendToSocket(int socket, String data); + void sendCmd(String cmd, ICHIP_COMM_STATE cmdstate); + void sendToSocket(int socket, String data); void processParameterChange(char *response); - + }; #endif diff --git a/sys_io.cpp b/sys_io.cpp index 20fefcf..424fd61 100644 --- a/sys_io.cpp +++ b/sys_io.cpp @@ -28,7 +28,7 @@ some portions based on code credited as: Arduino Due ADC->DMA->USB 1MSPS by stimmer -*/ +*/ #include "sys_io.h" @@ -47,7 +47,7 @@ uint8_t sys_type; int NumADCSamples; -//the ADC values fluctuate a lot so smoothing is required. +//the ADC values fluctuate a lot so smoothing is required. uint16_t adc_buffer[NUM_ANALOG][64]; uint8_t adc_pointer[NUM_ANALOG]; //pointer to next position to use @@ -68,129 +68,194 @@ With this assumption in place it is possible to initialize all possible digital */ void sys_boot_setup() { - for (int i = 2; i < 10; i++) { //possible digital outs are 2 - 9 - pinMode(out[i], OUTPUT); - digitalWrite(out[i], LOW); - } + for (int i = 2; i < 10; i++) { //possible digital outs are 2 - 9 + pinMode(out[i], OUTPUT); + digitalWrite(out[i], LOW); + } } //forces the digital I/O ports to a safe state. This is called very early in initialization. void sys_early_setup() { - int i; - - //the first order of business is to figure out what hardware we are running on and fill in - //the pin tables. - - uint8_t rawadc; - sysPrefs->read(EESYS_RAWADC, &rawadc); - if (rawadc != 0) { - useRawADC = true; - Logger::info("Using raw ADC mode"); - } - else useRawADC = false; - - NumADCSamples = 64; - - sysPrefs->read(EESYS_SYSTEM_TYPE, &sys_type); - if (sys_type == 2) { - Logger::info("Running on GEVCU2/DUED hardware."); - dig[0]=9; dig[1]=11; dig[2]=12; dig[3]=13; - adc[0][0] = 1; adc[0][1] = 0; - adc[1][0] = 3; adc[1][1] = 2; - adc[2][0] = 5; adc[2][1] = 4; - adc[3][0] = 7; adc[3][1] = 6; - out[0] = 52; out[1] = 22; out[2] = 48; out[3] = 32; - out[4] = 255; out[5] = 255; out[6] = 255; out[7] = 255; - NumADCSamples = 32; - } else if (sys_type == 3) { - Logger::info("Running on GEVCU3 hardware"); - dig[0]=48; dig[1]=49; dig[2]=50; dig[3]=51; - adc[0][0] = 3; adc[0][1] = 255; - adc[1][0] = 2; adc[1][1] = 255; - adc[2][0] = 1; adc[2][1] = 255; - adc[3][0] = 0; adc[3][1] = 255; - out[0] = 9; out[1] = 8; out[2] = 7; out[3] = 6; - out[4] = 255; out[5] = 255; out[6] = 255; out[7] = 255; - useRawADC = true; //this board does require raw adc so force it. - } else if (sys_type == 4) { - Logger::info("Running on GEVCU 4.x hardware"); - dig[0]=48; dig[1]=49; dig[2]=50; dig[3]=51; - adc[0][0] = 3; adc[0][1] = 255; - adc[1][0] = 2; adc[1][1] = 255; - adc[2][0] = 1; adc[2][1] = 255; - adc[3][0] = 0; adc[3][1] = 255; - out[0] = 4; out[1] = 5; out[2] = 6; out[3] = 7; - out[4] = 2; out[5] = 3; out[6] = 8; out[7] = 9; - useRawADC = true; //this board does require raw adc so force it. - } else if (sys_type == 6) { - Logger::info("Running on GEVCU 6.2 hardware"); - dig[0]=48; dig[1]=49; dig[2]=50; dig[3]=51; - adc[0][0] = 255; adc[0][1] = 255; //doesn't use SAM3X analog - adc[1][0] = 255; adc[1][1] = 255; - adc[2][0] = 255; adc[2][1] = 255; - adc[3][0] = 255; adc[3][1] = 255; - out[0] = 4; out[1] = 5; out[2] = 6; out[3] = 7; - out[4] = 2; out[5] = 3; out[6] = 8; out[7] = 9; - useRawADC = false; - useSPIADC = true; - pinMode(26, OUTPUT); //Chip Select for first ADC chip - pinMode(28, OUTPUT); //Chip select for second ADC chip - pinMode(30, OUTPUT); //chip select for third ADC chip - digitalWrite(26, HIGH); - digitalWrite(28, HIGH); - digitalWrite(30, HIGH); - SPI.begin(); - pinMode(32, INPUT); //Data Ready indicator - - SPI.begin(); //sets up with default 4Mhz, MSB first - } else { - Logger::info("Running on legacy hardware?"); - dig[0]=11; dig[1]=9; dig[2]=13; dig[3]=12; - adc[0][0] = 1; adc[0][1] = 0; - adc[1][0] = 2; adc[1][1] = 3; - adc[2][0] = 4; adc[2][1] = 5; - adc[3][0] = 7; adc[3][1] = 6; - out[0] = 52; out[1] = 22; out[2] = 48; out[3] = 32; - out[4] = 255; out[5] = 255; out[6] = 255; out[7] = 255; - NumADCSamples = 32; - } - - for (i = 0; i < NUM_DIGITAL; i++) pinMode(dig[i], INPUT); - for (i = 0; i < NUM_OUTPUT; i++) { - if (out[i] != 255) { - pinMode(out[i], OUTPUT); - digitalWrite(out[i], LOW); - } - } + int i; + + //the first order of business is to figure out what hardware we are running on and fill in + //the pin tables. + + uint8_t rawadc; + sysPrefs->read(EESYS_RAWADC, &rawadc); + if (rawadc != 0) { + useRawADC = true; + Logger::info("Using raw ADC mode"); + } + else useRawADC = false; + + NumADCSamples = 64; + + sysPrefs->read(EESYS_SYSTEM_TYPE, &sys_type); + if (sys_type == 2) { + Logger::info("Running on GEVCU2/DUED hardware."); + dig[0]=9; + dig[1]=11; + dig[2]=12; + dig[3]=13; + adc[0][0] = 1; + adc[0][1] = 0; + adc[1][0] = 3; + adc[1][1] = 2; + adc[2][0] = 5; + adc[2][1] = 4; + adc[3][0] = 7; + adc[3][1] = 6; + out[0] = 52; + out[1] = 22; + out[2] = 48; + out[3] = 32; + out[4] = 255; + out[5] = 255; + out[6] = 255; + out[7] = 255; + NumADCSamples = 32; + } else if (sys_type == 3) { + Logger::info("Running on GEVCU3 hardware"); + dig[0]=48; + dig[1]=49; + dig[2]=50; + dig[3]=51; + adc[0][0] = 3; + adc[0][1] = 255; + adc[1][0] = 2; + adc[1][1] = 255; + adc[2][0] = 1; + adc[2][1] = 255; + adc[3][0] = 0; + adc[3][1] = 255; + out[0] = 9; + out[1] = 8; + out[2] = 7; + out[3] = 6; + out[4] = 255; + out[5] = 255; + out[6] = 255; + out[7] = 255; + useRawADC = true; //this board does require raw adc so force it. + } else if (sys_type == 4) { + Logger::info("Running on GEVCU 4.x hardware"); + dig[0]=48; + dig[1]=49; + dig[2]=50; + dig[3]=51; + adc[0][0] = 3; + adc[0][1] = 255; + adc[1][0] = 2; + adc[1][1] = 255; + adc[2][0] = 1; + adc[2][1] = 255; + adc[3][0] = 0; + adc[3][1] = 255; + out[0] = 4; + out[1] = 5; + out[2] = 6; + out[3] = 7; + out[4] = 2; + out[5] = 3; + out[6] = 8; + out[7] = 9; + useRawADC = true; //this board does require raw adc so force it. + } else if (sys_type == 6) { + Logger::info("Running on GEVCU 6.2 hardware"); + dig[0]=48; + dig[1]=49; + dig[2]=50; + dig[3]=51; + adc[0][0] = 255; + adc[0][1] = 255; //doesn't use SAM3X analog + adc[1][0] = 255; + adc[1][1] = 255; + adc[2][0] = 255; + adc[2][1] = 255; + adc[3][0] = 255; + adc[3][1] = 255; + out[0] = 4; + out[1] = 5; + out[2] = 6; + out[3] = 7; + out[4] = 2; + out[5] = 3; + out[6] = 8; + out[7] = 9; + useRawADC = false; + useSPIADC = true; + pinMode(26, OUTPUT); //Chip Select for first ADC chip + pinMode(28, OUTPUT); //Chip select for second ADC chip + pinMode(30, OUTPUT); //chip select for third ADC chip + digitalWrite(26, HIGH); + digitalWrite(28, HIGH); + digitalWrite(30, HIGH); + SPI.begin(); + pinMode(32, INPUT); //Data Ready indicator + + SPI.begin(); //sets up with default 4Mhz, MSB first + } else { + Logger::info("Running on legacy hardware?"); + dig[0]=11; + dig[1]=9; + dig[2]=13; + dig[3]=12; + adc[0][0] = 1; + adc[0][1] = 0; + adc[1][0] = 2; + adc[1][1] = 3; + adc[2][0] = 4; + adc[2][1] = 5; + adc[3][0] = 7; + adc[3][1] = 6; + out[0] = 52; + out[1] = 22; + out[2] = 48; + out[3] = 32; + out[4] = 255; + out[5] = 255; + out[6] = 255; + out[7] = 255; + NumADCSamples = 32; + } + + for (i = 0; i < NUM_DIGITAL; i++) pinMode(dig[i], INPUT); + for (i = 0; i < NUM_OUTPUT; i++) { + if (out[i] != 255) { + pinMode(out[i], OUTPUT); + digitalWrite(out[i], LOW); + } + } } void setup_ADC_params() -{ - int i; - //requires the value to be contiguous in memory - for (i = 0; i < 7; i++) { - sysPrefs->read(EESYS_ADC0_GAIN + 4*i, &adc_comp[i].gain); - sysPrefs->read(EESYS_ADC0_OFFSET + 4*i, &adc_comp[i].offset); - Logger::debug("ADC:%d GAIN: %d Offset: %d", i, adc_comp[i].gain, adc_comp[i].offset); - if (i < NUM_ANALOG) { - for (int j = 0; j < NumADCSamples; j++) adc_buffer[i][j] = 0; - adc_pointer[i] = 0; - adc_values[i] = 0; - adc_out_vals[i] = 0; - } - } +{ + int i; + //requires the value to be contiguous in memory + for (i = 0; i < 7; i++) { + sysPrefs->read(EESYS_ADC0_GAIN + 4*i, &adc_comp[i].gain); + sysPrefs->read(EESYS_ADC0_OFFSET + 4*i, &adc_comp[i].offset); + Logger::debug("ADC:%d GAIN: %d Offset: %d", i, adc_comp[i].gain, adc_comp[i].offset); + if (i < NUM_ANALOG) { + for (int j = 0; j < NumADCSamples; j++) adc_buffer[i][j] = 0; + adc_pointer[i] = 0; + adc_values[i] = 0; + adc_out_vals[i] = 0; + } + } } /* Initialize DMA driven ADC and read in gain/offset for each channel */ void setup_sys_io() { - int i; + int i; -setup_ADC_params(); - - if (useSPIADC) setupSPIADC(); + setup_ADC_params(); + + if (useSPIADC) setupSPIADC(); else setupFastADC(); } @@ -199,93 +264,93 @@ Some of the boards are differential and thus require subtracting one ADC from an handles that case. It also applies gain and offset */ uint16_t getDiffADC(uint8_t which) { - uint32_t low, high; - - low = adc_values[adc[which][0]]; - high = adc_values[adc[which][1]]; - - if (low < high) { - - //first remove the bias to bring us back to where it rests at zero input volts - - if (low >= adc_comp[which].offset) low -= adc_comp[which].offset; - else low = 0; - if (high >= adc_comp[which].offset) high -= adc_comp[which].offset; - else high = 0; - - //gain multiplier is 1024 for 1 to 1 gain, less for lower gain, more for higher. - low *= adc_comp[which].gain; - low = low >> 10; //divide by 1024 again to correct for gain multiplier - high *= adc_comp[which].gain; - high = high >> 10; - - //Lastly, the input scheme is basically differential so we have to subtract - //low from high to get the actual value - high = high - low; - } - else high = 0; - - if (high > 4096) high = 0; //if it somehow got wrapped anyway then set it back to zero - - return high; + uint32_t low, high; + + low = adc_values[adc[which][0]]; + high = adc_values[adc[which][1]]; + + if (low < high) { + + //first remove the bias to bring us back to where it rests at zero input volts + + if (low >= adc_comp[which].offset) low -= adc_comp[which].offset; + else low = 0; + if (high >= adc_comp[which].offset) high -= adc_comp[which].offset; + else high = 0; + + //gain multiplier is 1024 for 1 to 1 gain, less for lower gain, more for higher. + low *= adc_comp[which].gain; + low = low >> 10; //divide by 1024 again to correct for gain multiplier + high *= adc_comp[which].gain; + high = high >> 10; + + //Lastly, the input scheme is basically differential so we have to subtract + //low from high to get the actual value + high = high - low; + } + else high = 0; + + if (high > 4096) high = 0; //if it somehow got wrapped anyway then set it back to zero + + return high; } /* Exactly like the previous function but for non-differential boards (all the non-prototype boards are non-differential) */ uint16_t getRawADC(uint8_t which) { - uint32_t val; + uint32_t val; -if (sys_type < 6) -{ - val = adc_values[adc[which][0]]; - - //first remove the bias to bring us back to where it rests at zero input volts - - if (val >= adc_comp[which].offset) val -= adc_comp[which].offset; - else val = 0; - - //gain multiplier is 1024 for 1 to 1 gain, less for lower gain, more for higher. - val *= adc_comp[which].gain; - val = val >> 10; //divide by 1024 again to correct for gain multiplier - - if (val > 4096) val = 0; //if it somehow got wrapped anyway then set it back to zero -} -else -{ - int32_t valu; - //first 4 analog readings must match old methods - if (which < 2) - { - valu = getSPIADCReading(CS1, (which & 1) + 1); - } - else if (which < 4) valu = getSPIADCReading(CS2, (which & 1) + 1); - //the next three are new though. 4 = current sensor, 5 = pack high (ref to mid), 6 = pack low (ref to mid) - else if (which == 4) valu = getSPIADCReading(CS1, 0); - else if (which == 5) valu = getSPIADCReading(CS3, 1); - else if (which == 6) valu = getSPIADCReading(CS3, 2); - val = valu >> 8; //cut reading down to 16 bit value -} - return val; + if (sys_type < 6) + { + val = adc_values[adc[which][0]]; + + //first remove the bias to bring us back to where it rests at zero input volts + + if (val >= adc_comp[which].offset) val -= adc_comp[which].offset; + else val = 0; + + //gain multiplier is 1024 for 1 to 1 gain, less for lower gain, more for higher. + val *= adc_comp[which].gain; + val = val >> 10; //divide by 1024 again to correct for gain multiplier + + if (val > 4096) val = 0; //if it somehow got wrapped anyway then set it back to zero + } + else + { + int32_t valu; + //first 4 analog readings must match old methods + if (which < 2) + { + valu = getSPIADCReading(CS1, (which & 1) + 1); + } + else if (which < 4) valu = getSPIADCReading(CS2, (which & 1) + 1); + //the next three are new though. 4 = current sensor, 5 = pack high (ref to mid), 6 = pack low (ref to mid) + else if (which == 4) valu = getSPIADCReading(CS1, 0); + else if (which == 5) valu = getSPIADCReading(CS3, 1); + else if (which == 6) valu = getSPIADCReading(CS3, 2); + val = valu >> 8; //cut reading down to 16 bit value + } + return val; } /* Adds a new ADC reading to the buffer for a channel. The buffer is NumADCSamples large (either 32 or 64) and rolling */ void addNewADCVal(uint8_t which, uint16_t val) { - adc_buffer[which][adc_pointer[which]] = val; - adc_pointer[which] = (adc_pointer[which] + 1) % NumADCSamples; + adc_buffer[which][adc_pointer[which]] = val; + adc_pointer[which] = (adc_pointer[which] + 1) % NumADCSamples; } /* Take the arithmetic average of the readings in the buffer for each channel. This smooths out the ADC readings */ uint16_t getADCAvg(uint8_t which) { - uint32_t sum; - sum = 0; - for (int j = 0; j < NumADCSamples; j++) sum += adc_buffer[which][j]; - sum = sum / NumADCSamples; - return ((uint16_t)sum); + uint32_t sum; + sum = 0; + for (int j = 0; j < NumADCSamples; j++) sum += adc_buffer[which][j]; + sum = sum / NumADCSamples; + return ((uint16_t)sum); } /* @@ -303,22 +368,22 @@ uint16_t getAnalog(uint8_t which) { if (which >= 7 && sys_type == 6) which = 0; if (!useSPIADC) return adc_out_vals[which]; else - { - int32_t valu; - //first 4 analog readings must match old methods - if (which < 2) - { - valu = getSPIADCReading(CS1, (which & 1) + 1); - } - else if (which < 4) valu = getSPIADCReading(CS2, (which & 1) + 1); - //the next three are new though. 4 = current sensor, 5 = pack high (ref to mid), 6 = pack low (ref to mid) - else if (which == 4) valu = getSPIADCReading(CS1, 0); - else if (which == 5) valu = getSPIADCReading(CS3, 1); - else if (which == 6) valu = getSPIADCReading(CS3, 2); - valu >>= 8; - valu -= adc_comp[which].offset; - valu = (valu * adc_comp[which].gain) / 1024; - return valu; + { + int32_t valu; + //first 4 analog readings must match old methods + if (which < 2) + { + valu = getSPIADCReading(CS1, (which & 1) + 1); + } + else if (which < 4) valu = getSPIADCReading(CS2, (which & 1) + 1); + //the next three are new though. 4 = current sensor, 5 = pack high (ref to mid), 6 = pack low (ref to mid) + else if (which == 4) valu = getSPIADCReading(CS1, 0); + else if (which == 5) valu = getSPIADCReading(CS3, 1); + else if (which == 6) valu = getSPIADCReading(CS3, 2); + valu >>= 8; + valu -= adc_comp[which].offset; + valu = (valu * adc_comp[which].gain) / 1024; + return valu; } } @@ -326,72 +391,72 @@ uint16_t getAnalog(uint8_t which) { //the new pack voltage and current functions however, being new, don't have legacy problems so they're 24 bit ADC. int32_t getCurrentReading() { - int32_t valu; - valu = getSPIADCReading(CS1, 0); - valu -= (adc_comp[6].offset * 256); - valu = valu >> 3; - valu = (valu * adc_comp[6].gain) / 128; - return valu; + int32_t valu; + valu = getSPIADCReading(CS1, 0); + valu -= (adc_comp[6].offset * 256); + valu = valu >> 3; + valu = (valu * adc_comp[6].gain) / 128; + return valu; } int32_t getPackHighReading() { - int32_t valu; - valu = getSPIADCReading(CS3, 1); - valu -= (adc_comp[4].offset * 256); - valu = valu >> 3; - valu = (valu * adc_comp[4].gain) / 128; - return valu; + int32_t valu; + valu = getSPIADCReading(CS3, 1); + valu -= (adc_comp[4].offset * 256); + valu = valu >> 3; + valu = (valu * adc_comp[4].gain) / 128; + return valu; } int32_t getPackLowReading() { - int32_t valu; - valu = getSPIADCReading(CS3, 2); - valu -= (adc_comp[5].offset * 256); - valu = valu >> 3; - valu = (valu * adc_comp[5].gain) / 128; - return valu; + int32_t valu; + valu = getSPIADCReading(CS3, 2); + valu -= (adc_comp[5].offset * 256); + valu = valu >> 3; + valu = (valu * adc_comp[5].gain) / 128; + return valu; } //get value of one of the 4 digital inputs boolean getDigital(uint8_t which) { - if (which >= NUM_DIGITAL) which = 0; - return !(digitalRead(dig[which])); + if (which >= NUM_DIGITAL) which = 0; + return !(digitalRead(dig[which])); } //set output high or not void setOutput(uint8_t which, boolean active) { - if (which >= NUM_OUTPUT) return; - if (out[which] == 255) return; - if (active) - digitalWrite(out[which], HIGH); - else digitalWrite(out[which], LOW); + if (which >= NUM_OUTPUT) return; + if (out[which] == 255) return; + if (active) + digitalWrite(out[which], HIGH); + else digitalWrite(out[which], LOW); } //get current value of output state (high?) boolean getOutput(uint8_t which) { - if (which >= NUM_OUTPUT) return false; - if (out[which] == 255) return false; - return digitalRead(out[which]); + if (which >= NUM_OUTPUT) return false; + if (out[which] == 255) return false; + return digitalRead(out[which]); } /* When the ADC reads in the programmed # of readings it will do two things: 1. It loads the next buffer and buffer size into current buffer and size 2. It sends this interrupt -This interrupt then loads the "next" fields with the proper values. This is +This interrupt then loads the "next" fields with the proper values. This is done with a four position buffer. In this way the ADC is constantly sampling and this happens virtually for free. It all happens in the background with minimal CPU overhead. */ -void ADC_Handler(){ // move DMA pointers to next buffer - int f=ADC->ADC_ISR; - if (f & (1<<27)){ //receive counter end of buffer - bufn=(bufn+1)&3; - ADC->ADC_RNPR=(uint32_t)adc_buf[bufn]; - ADC->ADC_RNCR=256; - } +void ADC_Handler() { // move DMA pointers to next buffer + int f=ADC->ADC_ISR; + if (f & (1<<27)) { //receive counter end of buffer + bufn=(bufn+1)&3; + ADC->ADC_RNPR=(uint32_t)adc_buf[bufn]; + ADC->ADC_RNCR=256; + } } bool setupSPIADC() @@ -408,22 +473,22 @@ bool setupSPIADC() Logger::info("Trying to wait ADC1 as ready"); for (int i = 0; i < 10; i++) { - SPI.beginTransaction(spi_settings); - digitalWrite(CS1, LOW); //select first ADC chip - SPI.transfer(ADE7913_READ | ADE7913_STATUS0); - result = SPI.transfer(0); - digitalWrite(CS1, HIGH); - SPI.endTransaction(); - if (result & 1) //not ready yet - { - delay(6); - //SerialUSB.println(result); - } - else - { - chip1OK = true; - break; - } + SPI.beginTransaction(spi_settings); + digitalWrite(CS1, LOW); //select first ADC chip + SPI.transfer(ADE7913_READ | ADE7913_STATUS0); + result = SPI.transfer(0); + digitalWrite(CS1, HIGH); + SPI.endTransaction(); + if (result & 1) //not ready yet + { + delay(6); + //SerialUSB.println(result); + } + else + { + chip1OK = true; + break; + } } //SerialUSB.println(); @@ -443,42 +508,42 @@ bool setupSPIADC() delay(110); for (int i = 0; i < 10; i++) { - SPI.beginTransaction(spi_settings); - digitalWrite(CS2, LOW); //select second ADC chip - SPI.transfer(ADE7913_READ | ADE7913_STATUS0); - result = SPI.transfer(0); - digitalWrite(CS2, HIGH); - SPI.endTransaction(); - if (result & 1) //not ready yet - { - delay(6); - } - else - { - chip2OK = true; - //break; - } - SPI.beginTransaction(spi_settings); - digitalWrite(CS3, LOW); //select third ADC chip - SPI.transfer(ADE7913_READ | ADE7913_STATUS0); - result = SPI.transfer(0); - digitalWrite(CS3, HIGH); - SPI.endTransaction(); - if (result & 1) //not ready yet - { - delay(6); - } - else - { - chip3OK = true; - //break; - } - if (chip2OK && chip3OK) break; + SPI.beginTransaction(spi_settings); + digitalWrite(CS2, LOW); //select second ADC chip + SPI.transfer(ADE7913_READ | ADE7913_STATUS0); + result = SPI.transfer(0); + digitalWrite(CS2, HIGH); + SPI.endTransaction(); + if (result & 1) //not ready yet + { + delay(6); + } + else + { + chip2OK = true; + //break; + } + SPI.beginTransaction(spi_settings); + digitalWrite(CS3, LOW); //select third ADC chip + SPI.transfer(ADE7913_READ | ADE7913_STATUS0); + result = SPI.transfer(0); + digitalWrite(CS3, HIGH); + SPI.endTransaction(); + if (result & 1) //not ready yet + { + delay(6); + } + else + { + chip3OK = true; + //break; + } + if (chip2OK && chip3OK) break; } if (!chip2OK || !chip3OK) return false; - SPI.beginTransaction(spi_settings); + SPI.beginTransaction(spi_settings); digitalWrite(CS2, LOW); SPI.transfer(ADE7913_WRITE | ADE7913_CONFIG); SPI.transfer(3 << 4 | 1 << 7); //Set ADC_FREQ to 1khz and lower bandwidth to 2khz @@ -490,22 +555,22 @@ bool setupSPIADC() SPI.transfer(3 << 4 | 1 << 7); //Set ADC_FREQ to 1khz and lower bandwidth to 2khz digitalWrite(CS3, HIGH); SPI.endTransaction(); - + Logger::info("ADC chips 2 and 3 have been successfully started!"); - + return true; } int32_t getSPIADCReading(int CS, int sensor) -{ - int32_t result; +{ + int32_t result; int32_t byt; - Logger::debug("SPI Read CS: %i Sensor: %i", CS, sensor); + Logger::debug("SPI Read CS: %i Sensor: %i", CS, sensor); SPI.beginTransaction(spi_settings); - digitalWrite(CS, LOW); + digitalWrite(CS, LOW); if (sensor == 0) SPI.transfer(ADE7913_READ | ADE7913_AMP_READING); if (sensor == 1) SPI.transfer(ADE7913_READ | ADE7913_ADC1_READING); - if (sensor == 2) SPI.transfer(ADE7913_READ | ADE7913_ADC2_READING); + if (sensor == 2) SPI.transfer(ADE7913_READ | ADE7913_ADC2_READING); byt = SPI.transfer(0); result = (byt << 16); byt = SPI.transfer(0); @@ -525,44 +590,44 @@ Testing to find a good batch of settings for how fast to do ADC readings. The re 1. In the adc_init call it is possible to use something other than ADC_FREQ_MAX to slow down the ADC clock 2. ADC_MR has a clock divisor, start up time, settling time, tracking time, and transfer time. These can be adjusted */ -void setupFastADC(){ - pmc_enable_periph_clk(ID_ADC); - adc_init(ADC, SystemCoreClock, ADC_FREQ_MAX, ADC_STARTUP_FAST); //just about to change a bunch of these parameters with the next command - - /* - The MCLK is 12MHz on our boards. The ADC can only run 1MHz so the prescaler must be at least 12x. - The ADC should take Tracking+Transfer for each read when it is set to switch channels with each read - - Example: - 5+7 = 12 clocks per read 1M / 12 = 83333 reads per second. For newer boards there are 4 channels interleaved - so, for each channel, the readings are 48uS apart. 64 of these readings are averaged together for a total of 3ms - worth of ADC in each average. This is then averaged with the current value in the ADC buffer that is used for output. - - If, for instance, someone wanted to average over 6ms instead then the prescaler could be set to 24x instead. - */ - ADC->ADC_MR = (1 << 7) //free running - + (5 << 8) //12x MCLK divider ((This value + 1) * 2) = divisor - + (1 << 16) //8 periods start up time (0=0clks, 1=8clks, 2=16clks, 3=24, 4=64, 5=80, 6=96, etc) - + (1 << 20) //settling time (0=3clks, 1=5clks, 2=9clks, 3=17clks) - + (4 << 24) //tracking time (Value + 1) clocks - + (2 << 28);//transfer time ((Value * 2) + 3) clocks - - if (useRawADC) - ADC->ADC_CHER=0xF0; //enable A0-A3 - else ADC->ADC_CHER=0xFF; //enable A0-A7 - - NVIC_EnableIRQ(ADC_IRQn); - ADC->ADC_IDR=~(1<<27); //dont disable the ADC interrupt for rx end - ADC->ADC_IER=1<<27; //do enable it - ADC->ADC_RPR=(uint32_t)adc_buf[0]; // DMA buffer - ADC->ADC_RCR=256; //# of samples to take - ADC->ADC_RNPR=(uint32_t)adc_buf[1]; // next DMA buffer - ADC->ADC_RNCR=256; //# of samples to take - bufn=obufn=0; - ADC->ADC_PTCR=1; //enable dma mode - ADC->ADC_CR=2; //start conversions - - Logger::debug("Fast ADC Mode Enabled"); +void setupFastADC() { + pmc_enable_periph_clk(ID_ADC); + adc_init(ADC, SystemCoreClock, ADC_FREQ_MAX, ADC_STARTUP_FAST); //just about to change a bunch of these parameters with the next command + + /* + The MCLK is 12MHz on our boards. The ADC can only run 1MHz so the prescaler must be at least 12x. + The ADC should take Tracking+Transfer for each read when it is set to switch channels with each read + + Example: + 5+7 = 12 clocks per read 1M / 12 = 83333 reads per second. For newer boards there are 4 channels interleaved + so, for each channel, the readings are 48uS apart. 64 of these readings are averaged together for a total of 3ms + worth of ADC in each average. This is then averaged with the current value in the ADC buffer that is used for output. + + If, for instance, someone wanted to average over 6ms instead then the prescaler could be set to 24x instead. + */ + ADC->ADC_MR = (1 << 7) //free running + + (5 << 8) //12x MCLK divider ((This value + 1) * 2) = divisor + + (1 << 16) //8 periods start up time (0=0clks, 1=8clks, 2=16clks, 3=24, 4=64, 5=80, 6=96, etc) + + (1 << 20) //settling time (0=3clks, 1=5clks, 2=9clks, 3=17clks) + + (4 << 24) //tracking time (Value + 1) clocks + + (2 << 28);//transfer time ((Value * 2) + 3) clocks + + if (useRawADC) + ADC->ADC_CHER=0xF0; //enable A0-A3 + else ADC->ADC_CHER=0xFF; //enable A0-A7 + + NVIC_EnableIRQ(ADC_IRQn); + ADC->ADC_IDR=~(1<<27); //dont disable the ADC interrupt for rx end + ADC->ADC_IER=1<<27; //do enable it + ADC->ADC_RPR=(uint32_t)adc_buf[0]; // DMA buffer + ADC->ADC_RCR=256; //# of samples to take + ADC->ADC_RNPR=(uint32_t)adc_buf[1]; // next DMA buffer + ADC->ADC_RNCR=256; //# of samples to take + bufn=obufn=0; + ADC->ADC_PTCR=1; //enable dma mode + ADC->ADC_CR=2; //start conversions + + Logger::debug("Fast ADC Mode Enabled"); } //polls for the end of an adc conversion event. Then processe buffer to extract the averaged @@ -570,62 +635,62 @@ void setupFastADC(){ //which serves as a super fast place for other code to retrieve ADC values // This is only used when RAWADC is not defined void sys_io_adc_poll() { - if (sys_type > 4) return; - if (obufn != bufn) { - uint32_t tempbuff[8] = {0,0,0,0,0,0,0,0}; //make sure its zero'd - - //the eight or four enabled adcs are interleaved in the buffer - //this is a somewhat unrolled for loop with no incrementer. it's odd but it works - if (useRawADC) { - for (int i = 0; i < 256;) { - tempbuff[3] += adc_buf[obufn][i++]; - tempbuff[2] += adc_buf[obufn][i++]; - tempbuff[1] += adc_buf[obufn][i++]; - tempbuff[0] += adc_buf[obufn][i++]; - } - } - else { - for (int i = 0; i < 256;) { - tempbuff[7] += adc_buf[obufn][i++]; - tempbuff[6] += adc_buf[obufn][i++]; - tempbuff[5] += adc_buf[obufn][i++]; - tempbuff[4] += adc_buf[obufn][i++]; - tempbuff[3] += adc_buf[obufn][i++]; - tempbuff[2] += adc_buf[obufn][i++]; - tempbuff[1] += adc_buf[obufn][i++]; - tempbuff[0] += adc_buf[obufn][i++]; - } - } - - //for (int i = 0; i < 256;i++) Logger::debug("%i - %i", i, adc_buf[obufn][i]); - - //now, all of the ADC values are summed over 32/64 readings. So, divide by 32/64 (shift by 5/6) to get the average - //then add that to the old value we had stored and divide by two to average those. Lots of averaging going on. - if (useRawADC) { - for (int j = 0; j < 4; j++) { - adc_values[j] += (tempbuff[j] >> 6); - adc_values[j] = adc_values[j] >> 1; - } - } - else { - for (int j = 0; j < 8; j++) { - adc_values[j] += (tempbuff[j] >> 5); - adc_values[j] = adc_values[j] >> 1; - //Logger::debug("A%i: %i", j, adc_values[j]); - } - } - - for (int i = 0; i < NUM_ANALOG; i++) { - int val; - if (useRawADC) val = getRawADC(i); - else val = getDiffADC(i); + if (sys_type > 4) return; + if (obufn != bufn) { + uint32_t tempbuff[8] = {0,0,0,0,0,0,0,0}; //make sure its zero'd + + //the eight or four enabled adcs are interleaved in the buffer + //this is a somewhat unrolled for loop with no incrementer. it's odd but it works + if (useRawADC) { + for (int i = 0; i < 256;) { + tempbuff[3] += adc_buf[obufn][i++]; + tempbuff[2] += adc_buf[obufn][i++]; + tempbuff[1] += adc_buf[obufn][i++]; + tempbuff[0] += adc_buf[obufn][i++]; + } + } + else { + for (int i = 0; i < 256;) { + tempbuff[7] += adc_buf[obufn][i++]; + tempbuff[6] += adc_buf[obufn][i++]; + tempbuff[5] += adc_buf[obufn][i++]; + tempbuff[4] += adc_buf[obufn][i++]; + tempbuff[3] += adc_buf[obufn][i++]; + tempbuff[2] += adc_buf[obufn][i++]; + tempbuff[1] += adc_buf[obufn][i++]; + tempbuff[0] += adc_buf[obufn][i++]; + } + } + + //for (int i = 0; i < 256;i++) Logger::debug("%i - %i", i, adc_buf[obufn][i]); + + //now, all of the ADC values are summed over 32/64 readings. So, divide by 32/64 (shift by 5/6) to get the average + //then add that to the old value we had stored and divide by two to average those. Lots of averaging going on. + if (useRawADC) { + for (int j = 0; j < 4; j++) { + adc_values[j] += (tempbuff[j] >> 6); + adc_values[j] = adc_values[j] >> 1; + } + } + else { + for (int j = 0; j < 8; j++) { + adc_values[j] += (tempbuff[j] >> 5); + adc_values[j] = adc_values[j] >> 1; + //Logger::debug("A%i: %i", j, adc_values[j]); + } + } + + for (int i = 0; i < NUM_ANALOG; i++) { + int val; + if (useRawADC) val = getRawADC(i); + else val = getDiffADC(i); // addNewADCVal(i, val); // adc_out_vals[i] = getADCAvg(i); - adc_out_vals[i] = val; - } + adc_out_vals[i] = val; + } - obufn = bufn; - } + obufn = bufn; + } } diff --git a/sys_io.h b/sys_io.h index f6be740..e8b1a50 100644 --- a/sys_io.h +++ b/sys_io.h @@ -24,7 +24,7 @@ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ + */ #ifndef SYS_IO_H_ @@ -44,8 +44,8 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #define ADE7913_WRITE 0 #define ADE7913_READ 4 -#define ADE7913_AMP_READING 0 -#define ADE7913_ADC1_READING 1 << 3 +#define ADE7913_AMP_READING 0 +#define ADE7913_ADC1_READING 1 << 3 #define ADE7913_ADC2_READING 2 << 3 #define ADE7913_ADC_CRC 4 << 3 #define ADE7913_CTRL_CRC 5 << 3 @@ -61,8 +61,8 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #define ADE7913_TEMPOS 0x18 << 3 typedef struct { - uint16_t offset; - uint16_t gain; + uint16_t offset; + uint16_t gain; } ADC_COMP; void setup_sys_io();