diff --git a/OVMS.V3/components/vehicle/vehicle.h b/OVMS.V3/components/vehicle/vehicle.h index e23fb1e..173b775 100644 --- a/OVMS.V3/components/vehicle/vehicle.h +++ b/OVMS.V3/components/vehicle/vehicle.h @@ -273,14 +273,6 @@ typedef struct uint32_t lastused; // Timestamp of last channel access } vwtp_channel_t; -enum class OvmsStatus : short { - OK = 0, - Warn = 1, - Alert = 2 -}; -inline bool operator<(OvmsStatus lhs, OvmsStatus rhs) { - return static_cast(lhs) < static_cast(rhs); -} class OvmsVehicle : public InternalRamAllocated { @@ -639,7 +631,7 @@ class OvmsVehicle : public InternalRamAllocated float* m_bms_vmins; // BMS minimum voltages seen (since reset) float* m_bms_vmaxs; // BMS maximum voltages seen (since reset) float* m_bms_vdevmaxs; // BMS maximum voltage deviations seen (since reset) - OvmsStatus* m_bms_valerts; // BMS voltage deviation alerts (since reset) + short* m_bms_valerts; // BMS voltage deviation alerts (since reset) int m_bms_valerts_new; // BMS new voltage alerts since last notification int m_bms_vstddev_cnt; // BMS internal stddev counter float m_bms_vstddev_avg; // BMS internal stddev average @@ -648,7 +640,7 @@ class OvmsVehicle : public InternalRamAllocated float* m_bms_tmins; // BMS minimum temperatures seen (since reset) float* m_bms_tmaxs; // BMS maximum temperatures seen (since reset) float* m_bms_tdevmaxs; // BMS maximum temperature deviations seen (since reset) - OvmsStatus* m_bms_talerts; // BMS temperature deviation alerts (since reset) + short* m_bms_talerts; // BMS temperature deviation alerts (since reset) int m_bms_talerts_new; // BMS new temperature alerts since last notification bool m_bms_has_temperatures; // True if BMS has a complete set of temperature values std::vector m_bms_bitset_v; // BMS tracking: true if corresponding voltage set @@ -696,6 +688,8 @@ class OvmsVehicle : public InternalRamAllocated void BmsResetCellStats(); virtual void BmsStatus(int verbosity, OvmsWriter* writer); virtual bool FormatBmsAlerts(int verbosity, OvmsWriter* writer, bool show_warnings); + bool BmsCheckChangeCellArrangementVoltage(int readings, int readingspermodule = 0); + bool BmsCheckChangeCellArrangementTemperature(int readings, int readingspermodule = 0); }; template OvmsVehicle* CreateVehicle() diff --git a/OVMS.V3/components/vehicle/vehicle_bms.cpp b/OVMS.V3/components/vehicle/vehicle_bms.cpp index 7fb84f1..a6e5694 100644 --- a/OVMS.V3/components/vehicle/vehicle_bms.cpp +++ b/OVMS.V3/components/vehicle/vehicle_bms.cpp @@ -60,7 +60,7 @@ void OvmsVehicle::BmsSetCellArrangementVoltage(int readings, int readingspermodu if (m_bms_vdevmaxs != NULL) delete m_bms_vdevmaxs; m_bms_vdevmaxs = new float[readings]; if (m_bms_valerts != NULL) delete m_bms_valerts; - m_bms_valerts = new OvmsStatus[readings]; + m_bms_valerts = new short[readings]; m_bms_valerts_new = 0; m_bms_bitset_v.clear(); @@ -72,6 +72,129 @@ void OvmsVehicle::BmsSetCellArrangementVoltage(int readings, int readingspermodu BmsResetCellVoltages(true); } +// Internal entry for changing cell arrangements. +struct reading_entry_t + { + int cell_no; + float entry; + }; + +/** + * Changes the cell arrangement for Voltage, if needs be restoring any readings that were there. + * Really should only do work the first time it is called.. as for any one car, the number of readings + * should be consistent. + * @return true If the cell arrangement was changed. + */ +bool OvmsVehicle::BmsCheckChangeCellArrangementVoltage(int readings, int readingspermodule /*=0*/) + { + bool res = false; + if (readingspermodule <= 0) + { + // Passing in 0 will leave the readings per module unchanged. + readingspermodule = m_bms_readingspermodule_v; + } + if (readings != m_bms_readings_v) + { + res = true; + if (m_bms_bitset_cv == 0) + { + BmsSetCellArrangementVoltage(readings, readingspermodule); + } + else + { + // Store (potentially) sparse readings into a vector. + std::vector cells; + // At most we will need the number of voltages set in the bitset. + cells.reserve(m_bms_bitset_cv); + reading_entry_t reading; + int maxv = readings; + if (m_bms_readings_v < maxv) + { + maxv = m_bms_readings_v; + } + for (int i = 0; i< maxv; ++i) + { + if (m_bms_bitset_v[i]) + { + reading.cell_no = i; + reading.entry = m_bms_voltages[i]; + cells.insert(cells.end(),reading); + } + } + BmsSetCellArrangementVoltage(readings, readingspermodule); + for ( std::vector::iterator iter = cells.begin(); iter != cells.end(); ++iter) + { + BmsSetCellVoltage(iter->cell_no, iter->entry); + } + } + } + else if (readingspermodule != m_bms_readingspermodule_v) + { + // This only changes the read-out. + m_bms_readingspermodule_v = readingspermodule; + res = true; + } + return res; + } + +/** + * Changes the cell arrangement for Temperature, if needs be restoring any readings that were there. + * Really should only do work the first time it is called.. as for any one car, the number of readings + * should be consistent. + * @return true If the cell arrangement was changed. + */ +bool OvmsVehicle::BmsCheckChangeCellArrangementTemperature(int readings, int readingspermodule /*=0*/) + { + bool res = false; + if (readingspermodule <= 0) + { + // Passing in 0 will leave the readings per module unchanged. + readingspermodule = m_bms_readingspermodule_t; + } + if (readings != m_bms_readings_t) + { + res = true; + if (m_bms_bitset_ct == 0) + { + BmsSetCellArrangementTemperature(readings, readingspermodule); + } + else + { + // Store (potentially) sparse readings into a vector. + std::vector cells; + // At most we will need the number of Temperatures set in the bitset. + cells.reserve(m_bms_bitset_ct); + reading_entry_t reading; + int maxv = readings; + if (m_bms_readings_t < maxv) + { + maxv = m_bms_readings_t; + } + for (int i = 0; i< maxv; ++i) + { + if (m_bms_bitset_t[i]) + { + reading.cell_no = i; + reading.entry = m_bms_temperatures[i]; + cells.insert(cells.end(),reading); + } + } + BmsSetCellArrangementTemperature(readings, readingspermodule); + for ( std::vector::iterator iter = cells.begin(); iter != cells.end(); ++iter) + { + BmsSetCellTemperature(iter->cell_no, iter->entry); + } + } + } + else if (readingspermodule != m_bms_readingspermodule_t) + { + // This only changes the read-out. + m_bms_readingspermodule_t = readingspermodule; + res = true; + } + return res; + } + void OvmsVehicle::BmsSetCellArrangementTemperature(int readings, int readingspermodule) { if (m_bms_temperatures != NULL) delete m_bms_temperatures; @@ -83,7 +206,7 @@ void OvmsVehicle::BmsSetCellArrangementTemperature(int readings, int readingsper if (m_bms_tdevmaxs != NULL) delete m_bms_tdevmaxs; m_bms_tdevmaxs = new float[readings]; if (m_bms_talerts != NULL) delete m_bms_talerts; - m_bms_talerts = new OvmsStatus[readings]; + m_bms_talerts = new short[readings]; m_bms_talerts_new = 0; m_bms_bitset_t.clear(); @@ -245,20 +368,20 @@ void OvmsVehicle::BmsSetCellVoltage(int index, float value) dev = ROUNDPREC(m_bms_voltages[i] - avg, 5); if (ABS(dev) > ABS(m_bms_vdevmaxs[i])) m_bms_vdevmaxs[i] = dev; - if (ABS(dev) >= stddev + thr_alert && m_bms_valerts[i] <= OvmsStatus::Warn) + if (ABS(dev) >= stddev + thr_alert && m_bms_valerts[i] < 2) { - m_bms_valerts[i] = OvmsStatus::Alert; + m_bms_valerts[i] = 2; m_bms_valerts_new++; // trigger notification } - else if (ABS(dev) >= stddev + thr_warn && m_bms_valerts[i] < OvmsStatus::Warn) - m_bms_valerts[i] = OvmsStatus::Warn; + else if (ABS(dev) >= stddev + thr_warn && m_bms_valerts[i] < 1) + m_bms_valerts[i] = 1; } // Publish deviation maximums & alerts: if (stddev > StandardMetrics.ms_v_bat_pack_vstddev_max->AsFloat()) StandardMetrics.ms_v_bat_pack_vstddev_max->SetValue(stddev); StandardMetrics.ms_v_bat_cell_vdevmax->SetElemValues(0, m_bms_readings_v, m_bms_vdevmaxs); - StandardMetrics.ms_v_bat_cell_valert->SetElemValues(0, m_bms_readings_v, (short *)m_bms_valerts); + StandardMetrics.ms_v_bat_cell_valert->SetElemValues(0, m_bms_readings_v, m_bms_valerts); } // complete: @@ -319,13 +442,13 @@ void OvmsVehicle::BmsSetCellTemperature(int index, float value) dev = ROUNDPREC(m_bms_temperatures[i] - avg, 2); if (ABS(dev) > ABS(m_bms_tdevmaxs[i])) m_bms_tdevmaxs[i] = dev; - if (ABS(dev) >= stddev + thr_alert && m_bms_talerts[i] < OvmsStatus::Alert) + if (ABS(dev) >= stddev + thr_alert && m_bms_talerts[i] < 2) { - m_bms_talerts[i] = OvmsStatus::Alert; + m_bms_talerts[i] = 2; m_bms_talerts_new++; // trigger notification } - else if (ABS(dev) >= stddev + thr_warn && m_bms_valerts[i] < OvmsStatus::Warn) - m_bms_talerts[i] = OvmsStatus::Warn; + else if (ABS(dev) >= stddev + thr_warn && m_bms_valerts[i] < 1) + m_bms_talerts[i] = 1; } // publish to metrics: @@ -341,7 +464,7 @@ void OvmsVehicle::BmsSetCellTemperature(int index, float value) StandardMetrics.ms_v_bat_cell_tmin->SetElemValues(0, m_bms_readings_t, m_bms_tmins); StandardMetrics.ms_v_bat_cell_tmax->SetElemValues(0, m_bms_readings_t, m_bms_tmaxs); StandardMetrics.ms_v_bat_cell_tdevmax->SetElemValues(0, m_bms_readings_t, m_bms_tdevmaxs); - StandardMetrics.ms_v_bat_cell_talert->SetElemValues(0, m_bms_readings_t, (short *) m_bms_talerts); + StandardMetrics.ms_v_bat_cell_talert->SetElemValues(0, m_bms_readings_t, m_bms_talerts); // complete: m_bms_has_temperatures = true; @@ -382,7 +505,7 @@ void OvmsVehicle::BmsResetCellVoltages(bool full /*=false*/) m_bms_vmins[k] = 0; m_bms_vmaxs[k] = 0; m_bms_vdevmaxs[k] = 0; - m_bms_valerts[k] = OvmsStatus::OK; + m_bms_valerts[k] = 0; } m_bms_valerts_new = 0; m_bms_vstddev_cnt = 0; @@ -409,7 +532,7 @@ void OvmsVehicle::BmsResetCellTemperatures(bool full /*=false*/) m_bms_tmins[k] = 0; m_bms_tmaxs[k] = 0; m_bms_tdevmaxs[k] = 0; - m_bms_talerts[k] = OvmsStatus::OK; + m_bms_talerts[k] = 0; } m_bms_talerts_new = 0; if (full) StandardMetrics.ms_v_bat_cell_temp->ClearValue(); @@ -439,24 +562,14 @@ void OvmsVehicle::BmsStatus(int verbosity, OvmsWriter* writer) int vwarn=0, valert=0; int twarn=0, talert=0; - for (c=0; cputs("Voltage:"); writer->printf(" Average: %5.3fV [%5.3fV - %5.3fV]\n", @@ -525,18 +638,14 @@ bool OvmsVehicle::FormatBmsAlerts(int verbosity, OvmsWriter* writer, bool show_w writer->printf("Voltage: StdDev %dmV", (int)(StdMetrics.ms_v_bat_pack_vstddev_max->AsFloat() * 1000)); for (int i=0; iGetElemValue(i)); - switch (sts) - { - case OvmsStatus::OK: continue; - case OvmsStatus::Warn: if (!show_warnings) continue; - case OvmsStatus::Alert: ; - } + int sts = StdMetrics.ms_v_bat_cell_valert->GetElemValue(i); + if (sts == 0) continue; + if (sts == 1 && !show_warnings) continue; has_valerts++; if (verbose || has_valerts <= 5) { int dev = StdMetrics.ms_v_bat_cell_vdevmax->GetElemValue(i) * 1000; - writer->printf("\n %c #%02d: %+4dmV", (sts==OvmsStatus::Warn) ? '?' : '!', i+1, dev); + writer->printf("\n %c #%02d: %+4dmV", (sts==1) ? '?' : '!', i+1, dev); } else { @@ -551,18 +660,14 @@ bool OvmsVehicle::FormatBmsAlerts(int verbosity, OvmsWriter* writer, bool show_w writer->printf("Temperature: StdDev %.1fC", StdMetrics.ms_v_bat_pack_tstddev_max->AsFloat()); for (int i=0; iGetElemValue(i)); - switch (sts) - { - case OvmsStatus::OK: continue; - case OvmsStatus::Warn: if (!show_warnings) continue; - case OvmsStatus::Alert: ; - } + int sts = StdMetrics.ms_v_bat_cell_talert->GetElemValue(i); + if (sts == 0) continue; + if (sts == 1 && !show_warnings) continue; has_talerts++; if (verbose || has_talerts <= 5) { float dev = StdMetrics.ms_v_bat_cell_tdevmax->GetElemValue(i); - writer->printf("\n %c #%02d: %+3.1fC", (sts==OvmsStatus::Warn) ? '?' : '!', i+1, dev); + writer->printf("\n %c #%02d: %+3.1fC", (sts==1) ? '?' : '!', i+1, dev); } else {