Initial commit (project based on widgets)

This commit is contained in:
Yury Shuvakin
2022-08-01 21:53:36 +03:00
parent d9396cdc2f
commit 14a7aa699f
411 changed files with 95119 additions and 0 deletions

744
commands.cpp Normal file
View File

@@ -0,0 +1,744 @@
/*
Original copyright 2018 Benjamin Vedder benjamin@vedder.se and the VESC Tool project ( https://github.com/vedderb/vesc_tool )
Forked to:
Copyright 2018 Danny Bokma github@diebie.nl (https://github.com/DieBieEngineering/DieBieMS-Tool)
Now forked to:
Copyright 2019 - 2020 Kevin Dionne kevin.dionne@ennoid.me (https://github.com/EnnoidMe/ENNOID-BMS-Tool)
This file is part of ENNOID-BMS Tool.
ENNOID-BMS Tool is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
ENNOID-BMS Tool is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "commands.h"
#include <QDebug>
#include <QSettings>
Commands::Commands(QObject *parent) : QObject(parent)
{
mSendCan = QSettings().value("send_can", false).toBool();
mCanId = QSettings().value("can_id", 0).toInt();
mIsLimitedMode = false;
// Firmware state
mFirmwareIsUploading = false;
mFirmwareState = 0;
mFimwarePtr = 0;
mFirmwareTimer = 0;
mFirmwareRetries = 0;
mFirmwareUploadStatus = "FW Upload Status";
mCheckNextbmsConfig = false;
mTimer = new QTimer(this);
mTimer->setInterval(10);
mTimer->start();
mbmsConfig = 0;
mTimeoutCount = 50;
mTimeoutFwVer = 0;
mTimeoutBMSconf = 0;
mTimeoutValues = 0;
mTimeoutCells = 0;
mTimeoutAux = 0;
mTimeoutExp = 0;
mTimeoutPingCan = 0;
connect(mTimer, SIGNAL(timeout()), this, SLOT(timerSlot()));
}
void Commands::setLimitedMode(bool is_limited)
{
mIsLimitedMode = is_limited;
}
bool Commands::isLimitedMode()
{
return mIsLimitedMode;
}
void Commands::setSendCan(bool sendCan, int id)
{
mSendCan = sendCan;
QSettings().setValue("send_can", sendCan);
if (id >= 0) {
setCanSendId(id);
}
}
bool Commands::getSendCan()
{
return mSendCan;
}
void Commands::setCanSendId(unsigned int id)
{
mCanId = id;
QSettings().setValue("can_id", id);
}
int Commands::getCanSendId()
{
return mCanId;
}
void Commands::processPacket(QByteArray data)
{
VByteArray vb(data);
COMM_PACKET_ID id = (COMM_PACKET_ID)vb.vbPopFrontUint8();
switch (id) {
case COMM_FW_VERSION: {
mTimeoutFwVer = 0;
int fw_major;
int fw_minor;
QString hw;
QByteArray uuid;
if (vb.size() >= 2) {
fw_major = vb.vbPopFrontInt8();
fw_minor = vb.vbPopFrontInt8();
hw = vb.vbPopFrontString();
if (vb.size() >= 12) {
uuid.append(vb.left(12));
vb.remove(0, 12);
}
} else {
fw_major = -1;
fw_minor = -1;
}
emit fwVersionReceived(fw_major, fw_minor, hw, uuid);
} break;
case COMM_ERASE_NEW_APP:
case COMM_WRITE_NEW_APP_DATA:
firmwareUploadUpdate(!vb.at(0));
break;
case COMM_GET_VALUES: {
mTimeoutValues = 0;
BMS_VALUES values;
values.packVoltage = vb.vbPopFrontDouble32(1e3);
values.packCurrent = vb.vbPopFrontDouble32(1e3);
values.soC = vb.vbPopFrontUint8();
values.cVHigh = vb.vbPopFrontDouble32(1e3);
values.cVAverage = vb.vbPopFrontDouble32(1e3);
values.cVLow = vb.vbPopFrontDouble32(1e3);
values.cVMisMatch = vb.vbPopFrontDouble32(1e3);
values.loadLCVoltage = vb.vbPopFrontDouble16(1e1);
values.loadLCCurrent = vb.vbPopFrontDouble16(1e1);
values.chargerVoltage = vb.vbPopFrontDouble16(1e1);
values.tempBattHigh = vb.vbPopFrontDouble16(1e1);
values.tempBattAverage = vb.vbPopFrontDouble16(1e1);
values.tempBattLow = vb.vbPopFrontDouble16(1e1);
values.tempBMSHigh = vb.vbPopFrontDouble16(1e1);
values.tempBMSAverage = vb.vbPopFrontDouble16(1e1);
values.tempBMSLow = vb.vbPopFrontDouble16(1e1);
values.humidity = vb.vbPopFrontDouble16(1e1);
values.opState = opStateToStr((OperationalStateTypedef)vb.vbPopFrontUint8());
values.balanceActive = vb.vbPopFrontUint8();
values.faultState = faultStateToStr((bms_fault_code)vb.vbPopFrontUint8());
emit valuesReceived(values);
} break;
case COMM_GET_BMS_CELLS:{
mTimeoutCells = 0;
int mCellAmount;
QVector<double> mCellVoltages;
mCellVoltages.clear();
mCellAmount = vb.vbPopFrontUint8();
for(int cellValuePointer = 0; cellValuePointer < mCellAmount; cellValuePointer++){
mCellVoltages.append(vb.vbPopFrontDouble16(1e3));
}
emit cellsReceived(mCellAmount,mCellVoltages);
} break;
case COMM_GET_BMS_AUX:{
mTimeoutAux = 0;
int mAuxAmount;
QVector<double> mAuxVoltages;
mAuxVoltages.clear();
mAuxAmount = vb.vbPopFrontUint8();
for(int auxValuePointer = 0; auxValuePointer < mAuxAmount; auxValuePointer++){
mAuxVoltages.append(vb.vbPopFrontDouble16(1e1));
}
emit auxReceived(mAuxAmount,mAuxVoltages);
} break;
case COMM_GET_BMS_EXP_TEMP:{
mTimeoutExp = 0;
int mExpTempAmount;
QVector<double> mExpTempVoltages;
mExpTempVoltages.clear();
mExpTempAmount = vb.vbPopFrontUint8();
for(int expTempValuePointer = 0; expTempValuePointer < mExpTempAmount; expTempValuePointer++){
mExpTempVoltages.append(vb.vbPopFrontDouble16(1e1));
}
emit expTempReceived(mExpTempAmount,mExpTempVoltages);
} break;
case COMM_PRINT:
emit printReceived(QString::fromLatin1(vb));
break;
case COMM_ROTOR_POSITION:
emit rotorPosReceived(vb.vbPopFrontDouble32(1e5));
break;
case COMM_GET_MCCONF:
case COMM_GET_MCCONF_DEFAULT:
mTimeoutBMSconf = 0;
if (mbmsConfig) {
mbmsConfig->deSerialize(vb);
mbmsConfig->updateDone();
if (mCheckNextbmsConfig) {
mCheckNextbmsConfig = false;
emit bmsConfigCheckResult(mbmsConfig->checkDifference(&mbmsConfigLast));
}
}
break;
case COMM_SET_MCCONF:
emit ackReceived("BMS Write OK");
break;
case COMM_STORE_BMS_CONF:
if (mbmsConfig) {
mbmsConfig->storingDone();
}
break;
case COMM_PING_CAN: {
mTimeoutPingCan = 0;
QVector<int> devs;
while(vb.size() > 0) {
devs.append(vb.vbPopFrontUint8());
}
emit pingCanRx(devs, false);
} break;
default:
break;
}
}
void Commands::getFwVersion()
{
if (mTimeoutFwVer > 0) {
return;
}
mTimeoutFwVer = mTimeoutCount;
VByteArray vb;
vb.vbAppendInt8(COMM_FW_VERSION);
emitData(vb);
}
void Commands::getValues()
{
if (mTimeoutValues > 0) {
return;
}
mTimeoutValues = mTimeoutCount;
VByteArray vb;
vb.vbAppendInt8(COMM_GET_VALUES);
emitData(vb);
}
void Commands::getCells()
{
if (mTimeoutCells > 0) {
return;
}
mTimeoutCells = mTimeoutCount;
VByteArray vb;
vb.vbAppendInt8(COMM_GET_BMS_CELLS);
emitData(vb);
}
void Commands::getAux()
{
if (mTimeoutAux > 0) {
return;
}
mTimeoutAux = mTimeoutCount;
VByteArray vb;
vb.vbAppendInt8(COMM_GET_BMS_AUX);
emitData(vb);
}
void Commands::getExpansionTemp()
{
if (mTimeoutExp > 0) {
return;
}
mTimeoutExp = mTimeoutCount;
VByteArray vb;
vb.vbAppendInt8(COMM_GET_BMS_EXP_TEMP);
emitData(vb);
}
void Commands::sendTerminalCmd(QString cmd)
{
VByteArray vb;
vb.vbAppendInt8(COMM_TERMINAL_CMD);
vb.append(cmd.toLatin1());
emitData(vb);
}
void Commands::setDetect(disp_pos_mode mode)
{
VByteArray vb;
vb.vbAppendInt8(COMM_SET_DETECT);
vb.vbAppendInt8(mode);
emitData(vb);
}
void Commands::samplePrint(debug_sampling_mode mode, int sample_len, int dec)
{
VByteArray vb;
vb.vbAppendInt8(COMM_SAMPLE_PRINT);
vb.vbAppendInt8(mode);
vb.vbAppendUint16(sample_len);
vb.vbAppendUint8(dec);
emitData(vb);
}
void Commands::getBMSconf()
{
if (mTimeoutBMSconf > 0) {
return;
}
mTimeoutBMSconf = mTimeoutCount;
mCheckNextbmsConfig = false;
VByteArray vb;
vb.vbAppendInt8(COMM_GET_MCCONF);
emitData(vb);
}
void Commands::getBMSconfDefault()
{
if (mTimeoutBMSconf > 0) {
return;
}
mTimeoutBMSconf = mTimeoutCount;
mCheckNextbmsConfig = false;
VByteArray vb;
vb.vbAppendInt8(COMM_GET_MCCONF_DEFAULT);
emitData(vb);
}
void Commands::setBMSconf(bool check)
{
if (mbmsConfig) {
mbmsConfigLast = *mbmsConfig;
VByteArray vb;
vb.vbAppendInt8(COMM_SET_MCCONF);
mbmsConfig->serialize(vb);
emitData(vb);
if (check) {
checkbmsConfig();
}
}
}
void Commands::reboot()
{
VByteArray vb;
vb.vbAppendInt8(COMM_REBOOT);
emitData(vb);
}
void Commands::sendAlive()
{
VByteArray vb;
vb.vbAppendInt8(COMM_ALIVE);
emitData(vb);
}
void Commands::pairNrf(int ms)
{
VByteArray vb;
vb.vbAppendInt8(COMM_NRF_START_PAIRING);
vb.vbAppendInt32(ms);
emitData(vb);
}
void Commands::timerSlot()
{
if (mFirmwareIsUploading) {
if (mFirmwareTimer) {
mFirmwareTimer--;
} else {
firmwareUploadUpdate(true);
}
}
if (mTimeoutFwVer > 0) mTimeoutFwVer--;
if (mTimeoutBMSconf > 0) mTimeoutBMSconf--;
if (mTimeoutValues > 0) mTimeoutValues--;
if (mTimeoutCells > 0) mTimeoutCells--;
if (mTimeoutAux > 0) mTimeoutAux--;
if (mTimeoutExp > 0) mTimeoutExp--;
}
void Commands::emitData(QByteArray data)
{
// Only allow firmware commands in limited mode
if (mIsLimitedMode && data.at(0) > COMM_WRITE_NEW_APP_DATA) {
return;
}
if (mSendCan) {
data.prepend((char)mCanId);
data.prepend((char)COMM_FORWARD_CAN);
}
emit dataToSend(data);
}
void Commands::firmwareUploadUpdate(bool isTimeout)
{
if (!mFirmwareIsUploading) {
return;
}
const int app_packet_size = 200;
const int retries = 5;
const int timeout = 350;
if (mFirmwareState == 0) {
mFirmwareUploadStatus = "Buffer Erase";
if (isTimeout) {
// Erase timed out, abort.
mFirmwareIsUploading = false;
mFimwarePtr = 0;
mFirmwareUploadStatus = "Buffer Erase Timeout";
} else {
mFirmwareState++;
mFirmwareRetries = retries;
mFirmwareTimer = timeout;
firmwareUploadUpdate(true);
}
} else if (mFirmwareState == 1) {
mFirmwareUploadStatus = "CRC/Size Write";
if (isTimeout) {
if (mFirmwareRetries > 0) {
mFirmwareRetries--;
mFirmwareTimer = timeout;
} else {
mFirmwareIsUploading = false;
mFimwarePtr = 0;
mFirmwareState = 0;
mFirmwareUploadStatus = "CRC/Size Write Timeout";
return;
}
quint16 crc = Packet::crc16((const unsigned char*)mNewFirmware.constData(), mNewFirmware.size());
VByteArray vb;
vb.append((char)COMM_WRITE_NEW_APP_DATA);
vb.vbAppendUint32(0);
vb.vbAppendUint32(mNewFirmware.size());
vb.vbAppendUint16(crc);
emitData(vb);
} else {
mFirmwareState++;
mFirmwareRetries = retries;
mFirmwareTimer = timeout;
firmwareUploadUpdate(true);
}
} else if (mFirmwareState == 2) {
mFirmwareUploadStatus = "FW Data Write";
if (isTimeout) {
if (mFirmwareRetries > 0) {
mFirmwareRetries--;
mFirmwareTimer = timeout;
} else {
mFirmwareIsUploading = false;
mFimwarePtr = 0;
mFirmwareState = 0;
mFirmwareUploadStatus = "FW Data Write Timeout";
return;
}
int fw_size_left = mNewFirmware.size() - mFimwarePtr;
int send_size = fw_size_left > app_packet_size ? app_packet_size : fw_size_left;
VByteArray vb;
vb.append((char)COMM_WRITE_NEW_APP_DATA);
if (mFirmwareIsBootloader) {
vb.vbAppendUint32(mFimwarePtr + (1024 * 2 * 50));
} else {
vb.vbAppendUint32(mFimwarePtr + 6);
}
vb.append(mNewFirmware.mid(mFimwarePtr, send_size));
emitData(vb);
} else {
mFirmwareRetries = retries;
mFirmwareTimer = timeout;
mFimwarePtr += app_packet_size;
if (mFimwarePtr >= mNewFirmware.size()) {
mFirmwareIsUploading = false;
mFimwarePtr = 0;
mFirmwareState = 0;
mFirmwareUploadStatus = "FW Upload Done";
// Upload done. Enter bootloader!
if (!mFirmwareIsBootloader) {
QByteArray buffer;
buffer.append((char)COMM_JUMP_TO_BOOTLOADER);
emitData(buffer);
}
} else {
firmwareUploadUpdate(true);
}
}
}
}
QString Commands::opStateToStr(OperationalStateTypedef fault)
{
switch (fault) {
case OP_STATE_INIT: return "Init";
case OP_STATE_CHARGING: return "Charging";
case OP_STATE_PRE_CHARGE: return "PreCharging";
case OP_STATE_LOAD_ENABLED: return "Load enabled";
case OP_STATE_BATTERY_DEAD: return "Battery dead";
case OP_STATE_POWER_DOWN: return "Power down";
case OP_STATE_EXTERNAL: return "External";
case OP_STATE_ERROR: return "Error";
case OP_STATE_ERROR_PRECHARGE: return "ErrPreCharge";
case OP_STATE_BALANCING: return "Balancing";
case OP_STATE_CHARGED: return "Charged";
case OP_STATE_FORCEON: return "ForceOn";
default: return "Unknown fault";
}
}
QString Commands::faultStateToStr(bms_fault_code fault)
{
switch (fault) {
case FAULT_CODE_NONE: return "System OK";
case FAULT_CODE_PACK_OVER_VOLTAGE: return "Pack overvoltage";
case FAULT_CODE_PACK_UNDER_VOLTAGE: return "Pack undervoltage";
case FAULT_CODE_LOAD_OVER_VOLTAGE: return "Load overvoltage";
case FAULT_CODE_LOAD_UNDER_VOLTAGE: return "Load undervoltage";
case FAULT_CODE_CHARGER_OVER_VOLTAGE: return "Charger overvoltage";
case FAULT_CODE_CHARGER_UNDER_VOLTAGE: return "Charger undervoltgae";
case FAULT_CODE_CELL_HARD_OVER_VOLTAGE: return "Cell hard overvoltage";
case FAULT_CODE_CELL_HARD_UNDER_VOLTAGE: return "Cell hard undervoltage";
case FAULT_CODE_CELL_SOFT_OVER_VOLTAGE: return "Cell soft overvoltage";
case FAULT_CODE_CELL_SOFT_UNDER_VOLTAGE: return "Cell soft undervoltage";
case FAULT_CODE_MAX_UVP_OVP_ERRORS: return "MAX OVP/UVP errors";
case FAULT_CODE_MAX_UVT_OVT_ERRORS: return "MAX OVT/UVT errors";
case FAULT_CODE_OVER_CURRENT: return "Over current";
case FAULT_CODE_OVER_TEMP_BMS: return "Over temp BMS";
case FAULT_CODE_UNDER_TEMP_BMS: return "Under temp BMS";
case FAULT_CODE_DISCHARGE_OVER_TEMP_CELLS: return "Discharge over temp cell";
case FAULT_CODE_DISCHARGE_UNDER_TEMP_CELLS: return "Discharge under temp cell";
case FAULT_CODE_CHARGE_OVER_TEMP_CELLS: return "Charge over temp cell";
case FAULT_CODE_CHARGE_UNDER_TEMP_CELLS: return "Charge under temp cell";
case FAULT_CODE_PRECHARGE_TIMEOUT: return "Precharge timeout";
case FAULT_CODE_DISCHARGE_RETRY: return "Discharge retry";
case FAULT_CODE_CHARGE_RETRY: return "Charge retry";
case FAULT_CODE_CHARGER_DISCONNECT: return "Charge retry";
default: return "Unknown fault";
}
}
void Commands::setbmsConfig(ConfigParams *bmsConfig)
{
mbmsConfig = bmsConfig;
connect(mbmsConfig, SIGNAL(updateRequested()), this, SLOT(getBMSconf()));
connect(mbmsConfig, SIGNAL(updateRequestDefault()), this, SLOT(getBMSconfDefault()));
}
void Commands::startFirmwareUpload(QByteArray &newFirmware, bool isBootloader)
{
mFirmwareIsBootloader = isBootloader;
mFirmwareIsUploading = true;
mFirmwareState = mFirmwareIsBootloader ? 2 : 0;
mFimwarePtr = 0;
mFirmwareTimer = 500;
mFirmwareRetries = 5;
mNewFirmware.clear();
mNewFirmware.append(newFirmware);
mFirmwareUploadStatus = "Buffer Erase";
if (mFirmwareIsBootloader) {
firmwareUploadUpdate(true);
} else {
VByteArray vb;
vb.vbAppendInt8(COMM_ERASE_NEW_APP);
vb.vbAppendUint32(mNewFirmware.size());
emitData(vb);
}
}
double Commands::getFirmwareUploadProgress()
{
if (mFirmwareIsUploading) {
return (double)mFimwarePtr / (double)mNewFirmware.size();
} else {
return -1.0;
}
}
QString Commands::getFirmwareUploadStatus()
{
return mFirmwareUploadStatus;
}
void Commands::cancelFirmwareUpload()
{
if (mFirmwareIsUploading) {
mFirmwareIsUploading = false;
mFimwarePtr = 0;
mFirmwareState = 0;
mFirmwareUploadStatus = "Cancelled";
}
}
void Commands::checkbmsConfig()
{
mCheckNextbmsConfig = true;
VByteArray vb;
vb.vbAppendInt8(COMM_GET_MCCONF);
emitData(vb);
}
void Commands::storeBMSConfig()
{
VByteArray vb;
vb.vbAppendInt8(COMM_STORE_BMS_CONF);
emitData(vb);
}
void Commands::emitEmptyValues()
{
BMS_VALUES values;
values.packVoltage = 0.0;
values.packCurrent = 0.0;
values.soC = 0.0;
values.cVHigh = 0.0;
values.cVAverage = 0.0;
values.cVLow = 0.0;
values.cVMisMatch = 0.0;
values.loadLCVoltage = 0.0;
values.loadLCCurrent = 0.0;
values.loadHCVoltage = 0.0;
values.loadHCCurrent = 0.0;
values.chargerVoltage = 0.0;
values.auxVoltage = 0.0;
values.auxCurrent = 0.0;
values.tempBattHigh = 0.0;
values.tempBattAverage = 0.0;
values.tempBattLow = 0.0;
values.tempBMSHigh = 0.0;
values.tempBMSAverage = 0.0;
values.tempBMSLow = 0.0;
values.humidity = 0.0;
values.opState = "Unknown";
values.balanceActive = 0.0;
values.faultState = "Unknown";
emit valuesReceived(values);
}
void Commands::emitEmptySetupValues()
{
BMS_VALUES values;
values.packVoltage = 0.0;
values.packCurrent = 0.0;
values.soC = 0.0;
values.cVHigh = 0.0;
values.cVAverage = 0.0;
values.cVLow = 0.0;
values.cVMisMatch = 0.0;
values.loadLCVoltage = 0.0;
values.loadLCCurrent = 0.0;
values.loadHCVoltage = 0.0;
values.loadHCCurrent = 0.0;
values.chargerVoltage = 0.0;
values.auxVoltage = 0.0;
values.auxCurrent = 0.0;
values.tempBattHigh = 0.0;
values.tempBattAverage = 0.0;
values.tempBattLow = 0.0;
values.tempBMSHigh = 0.0;
values.tempBMSAverage = 0.0;
values.tempBMSLow = 0.0;
values.opState = OP_STATE_INIT;
values.balanceActive = 1;
values.faultState = FAULT_CODE_NONE;
emit valuesSetupReceived(values);
}
void Commands::pingCan()
{
if (mTimeoutPingCan > 0) {
return;
}
mTimeoutPingCan = 500;
VByteArray vb;
vb.vbAppendInt8(COMM_PING_CAN);
emitData(vb);
}