/* ; Project: Open Vehicle Monitor System ; Date: 29th December 2017 ; ; (C) 2017 Geir Øyvind Vælidalo ; ; Permission is hereby granted, free of charge, to any person obtaining a copy ; of this software and associated documentation files (the "Software"), to deal ; in the Software without restriction, including without limitation the rights ; to use, copy, modify, merge, publish, distribute, sublicense, and/or sell ; copies of the Software, and to permit persons to whom the Software is ; furnished to do so, subject to the following conditions: ; ; The above copyright notice and this permission notice shall be included in ; all copies or substantial portions of the Software. ; ; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 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. */ #include "vehicle_kiasoulev.h" static const char *TAG = "v-kiasoulev"; /** * Incoming poll reply messages */ void OvmsVehicleKiaSoulEv::IncomingPollReply(canbus* bus, uint16_t type, uint16_t pid, uint8_t* data, uint8_t length, uint16_t mlremain) { //ESP_LOGW(TAG, "%03x TYPE:%x PID:%02x %x %02x %02x %02x %02x %02x %02x %02x %02x", m_poll_moduleid_low, type, pid, length, data[0], data[1], data[2], data[3], // data[4], data[5], data[6], data[7]); switch (m_poll_moduleid_low) { // ****** SJB ***** case 0x779: IncomingSJB(bus, type, pid, data, length, mlremain); break; // ****** OBC ****** case 0x79c: IncomingOBC(bus, type, pid, data, length, mlremain); break; // ****** TPMS ****** case 0x7de: IncomingTPMS(bus, type, pid, data, length, mlremain); break; // ******* VMCU ****** case 0x7ea: IncomingVMCU(bus, type, pid, data, length, mlremain); break; // ***** BMC **** case 0x7ec: IncomingBMC(bus, type, pid, data, length, mlremain); break; // ***** LDC **** case 0x7cd: IncomingLDC(bus, type, pid, data, length, mlremain); break; default: ESP_LOGD(TAG, "Unknown module: %03x", m_poll_moduleid_low); break; } } /** * Handle incoming messages from TPMS poll. */ void OvmsVehicleKiaSoulEv::IncomingTPMS(canbus* bus, uint16_t type, uint16_t pid, uint8_t* data, uint8_t length, uint16_t mlremain) { uint8_t bVal; uint32_t lVal; switch (pid) { case 0x06: if (m_poll_ml_frame == 0) { lVal = CAN_UINT32(4); SET_TPMS_ID(0, lVal); } else if (m_poll_ml_frame == 1) { bVal = CAN_BYTE(0); if (bVal > 0) StdMetrics.ms_v_tpms_pressure->SetElemValue(MS_V_TPMS_IDX_FL, TO_PSI(bVal), PSI); StdMetrics.ms_v_tpms_temp->SetElemValue(MS_V_TPMS_IDX_FL, TO_CELCIUS(CAN_BYTE(1)), Celcius); lVal = (kia_tpms_id[1] & 0x000000ff) | (CAN_UINT32(4) & 0xffffff00); SET_TPMS_ID(1, lVal); } else if (m_poll_ml_frame == 2) { lVal = (uint32_t) CAN_BYTE(0) | (kia_tpms_id[1] & 0xffffff00); SET_TPMS_ID(1, lVal); bVal = CAN_BYTE(1); if (bVal > 0) StdMetrics.ms_v_tpms_pressure->SetElemValue(MS_V_TPMS_IDX_FR, TO_PSI(bVal), PSI); StdMetrics.ms_v_tpms_temp->SetElemValue(MS_V_TPMS_IDX_FR, TO_CELCIUS(CAN_BYTE(2)), Celcius); lVal = (kia_tpms_id[2] & 0x0000ffff) | (CAN_UINT32(5) & 0xffff0000); SET_TPMS_ID(2, lVal); } else if (m_poll_ml_frame == 3) { lVal = ((uint32_t) CAN_UINT(0)) | (kia_tpms_id[2] & 0xffff0000); SET_TPMS_ID(2, lVal); bVal = CAN_BYTE(2); if (bVal > 0) StdMetrics.ms_v_tpms_pressure->SetElemValue(MS_V_TPMS_IDX_RL, TO_PSI(bVal), PSI); StdMetrics.ms_v_tpms_temp->SetElemValue(MS_V_TPMS_IDX_RL, TO_CELCIUS(CAN_BYTE(3)), Celcius); lVal = (kia_tpms_id[3] & 0x00ffffff) | ((uint32_t) CAN_BYTE(6) << 24); SET_TPMS_ID(3, lVal); } else if (m_poll_ml_frame == 4) { lVal = (CAN_UINT24(0)) | (kia_tpms_id[3] & 0xff000000); SET_TPMS_ID(3, lVal); bVal = CAN_BYTE(3); if (bVal > 0) StdMetrics.ms_v_tpms_pressure->SetElemValue(MS_V_TPMS_IDX_RR, TO_PSI(bVal), PSI); StdMetrics.ms_v_tpms_temp->SetElemValue(MS_V_TPMS_IDX_RR, TO_CELCIUS(CAN_BYTE(4)), Celcius); } break; } } /** * Handle incoming messages from On Board Charger-poll * * - OBC-voltage * - Pilot signal duty cycle * - Charger temperature */ void OvmsVehicleKiaSoulEv::IncomingOBC(canbus* bus, uint16_t type, uint16_t pid, uint8_t* data, uint8_t length, uint16_t mlremain) { switch (pid) { case 0x02: if (m_poll_ml_frame == 1) { kia_obc_ac_voltage = (float) CAN_UINT(2) / 10.0; //} else if (vehicle_poll_ml_frame == 2) { //ks_obc_ampere = ((UINT) can_databuffer[4 + CAN_ADJ] << 8) // | (UINT) can_databuffer[5 + CAN_ADJ]; } else if (m_poll_ml_frame == 2) { m_obc_pilot_duty->SetValue( (float) CAN_BYTE(6) / 3.0 ); } else if (m_poll_ml_frame == 3) { StdMetrics.ms_v_charge_temp->SetValue( (float) (CAN_BYTE(0)+CAN_BYTE(1)+CAN_BYTE(2))/3, Celcius ); } break; } } /** * Handle incoming messages from VMCU-poll * * - Gear shifter position * - VIN * - RPM * - Motor temperature * - Inverter temperature */ void OvmsVehicleKiaSoulEv::IncomingVMCU(canbus* bus, uint16_t type, uint16_t pid, uint8_t* data, uint8_t length, uint16_t mlremain) { INT base; uint8_t bVal; switch (pid) { case 0x00: if (m_poll_ml_frame == 1) { ks_shift_bits.value = CAN_BYTE(3); } break; case 0x02: // VIN (multi-line response): if (type == VEHICLE_POLL_TYPE_OBDIIVEHICLE) { base = m_poll_ml_offset - length; for (bVal = 0; (bVal < length) && ((base + bVal)0) m_vin[base + bVal-1] = CAN_BYTE(bVal); if (m_poll_ml_remain == 0 && base+bVal>=0) m_vin[base + bVal] = 0; //Set VIN StandardMetrics.ms_v_vin->SetValue(m_vin); } if (type == VEHICLE_POLL_TYPE_OBDIIGROUP) { if (m_poll_ml_frame == 1) { //StdMetrics.ms_v_mot_rpm->SetValue( ((uint16_t)CAN_BYTE(5)<<8) | (uint16_t)CAN_BYTE(6) ); } else if (m_poll_ml_frame == 3) { StdMetrics.ms_v_mot_temp->SetValue( TO_CELCIUS(CAN_BYTE(4)), Celcius); StdMetrics.ms_v_inv_temp->SetValue( TO_CELCIUS(CAN_BYTE(5)), Celcius ); } } break; } } /** * Handle incoming messages from BMC-poll * * - Pilot signal available * - ChaDeMo / J1772 * - Battery current * - Battery voltage * - Battery module temp 1-8 * - Cell voltage max / min + cell # * + more */ void OvmsVehicleKiaSoulEv::IncomingBMC(canbus* bus, uint16_t type, uint16_t pid, uint8_t* data, uint8_t length, uint16_t mlremain) { UINT base; uint8_t bVal; switch (pid) { case 0x01: // diag page 01: skip first frame (no data) if (m_poll_ml_frame > 0) { if (m_poll_ml_frame == 1) // 02 21 01 - 21 { m_c_power->SetValue( (float)CAN_UINT(1)/100.0, kW); bVal = CAN_BYTE(5); StdMetrics.ms_v_charge_pilot->SetValue((bVal & 0x80) > 0); ks_charge_bits.ChargingChademo = ((bVal & 0x40) > 0); ks_charge_bits.ChargingJ1772 = ((bVal & 0x20) > 0); ks_battery_current = (ks_battery_current & 0x00FF) | ((UINT) CAN_BYTE(6) << 8); } else if (m_poll_ml_frame == 2) // 02 21 01 - 22 { ks_battery_current = (ks_battery_current & 0xFF00) | (UINT) CAN_BYTE(0); StdMetrics.ms_v_bat_current->SetValue((float)ks_battery_current/10.0, Amps); StdMetrics.ms_v_bat_voltage->SetValue((float)CAN_UINT(1)/10.0, Volts); StdMetrics.ms_v_bat_power->SetValue(StdMetrics.ms_v_bat_current->AsFloat(Amps)*StdMetrics.ms_v_bat_voltage->AsFloat(Volts), Watts); BmsRestartCellTemperatures(); BmsSetCellTemperature(0, CAN_BYTE(3)); BmsSetCellTemperature(1, CAN_BYTE(4)); BmsSetCellTemperature(2, CAN_BYTE(5)); BmsSetCellTemperature(3, CAN_BYTE(6)); StdMetrics.ms_v_bat_temp->SetValue(((float)CAN_BYTE(3) + CAN_BYTE(4) + CAN_BYTE(5) + CAN_BYTE(6)) / 4.0, Celcius); } else if (m_poll_ml_frame == 3) // 02 21 01 - 23 { BmsSetCellTemperature(4, CAN_BYTE(0)); BmsSetCellTemperature(5, CAN_BYTE(1)); BmsSetCellTemperature(6, CAN_BYTE(2)); BmsSetCellTemperature(7, CAN_BYTE(4)); //TODO What about the 30kWh-version? m_b_cell_volt_max->SetValue((float)CAN_BYTE(5)/50.0, Volts); m_b_cell_volt_max_no->SetValue(CAN_BYTE(6)); } else if (m_poll_ml_frame == 4) // 02 21 01 - 24 { m_b_cell_volt_min->SetValue((float)CAN_BYTE(0)/50.0, Volts); m_b_cell_volt_min_no->SetValue(CAN_BYTE(1)); ks_battery_fan_feedback = CAN_BYTE(2); ks_charge_bits.FanStatus = CAN_BYTE(3) & 0xF; StdMetrics.ms_v_bat_12v_voltage->SetValue ((float)CAN_BYTE(4)/10.0 , Volts); kia_battery_cum_charge_current = (kia_battery_cum_charge_current & 0x0000FFFF) | ((uint32_t) CAN_UINT(5) << 16); } else if (m_poll_ml_frame == 5) // 02 21 01 - 25 { kia_battery_cum_charge_current = (kia_battery_cum_charge_current & 0xFFFF0000) | ((uint32_t) CAN_UINT(0)); kia_battery_cum_discharge_current = CAN_UINT32(2); kia_battery_cum_charge = (kia_battery_cum_charge & 0x00FFFFFF) | ((uint32_t) CAN_BYTE(6)) << 24; } else if (m_poll_ml_frame == 6) // 02 21 01 - 26 { kia_battery_cum_charge = (kia_battery_cum_charge & 0xFF000000) | ((uint32_t) CAN_UINT24(0)); kia_battery_cum_discharge = CAN_UINT32(3); } else if (m_poll_ml_frame == 7) // 02 21 01 - 27 { kia_battery_cum_op_time = CAN_UINT32(0) / 3600; } } break; case 0x02: //Cell voltages case 0x03: case 0x04: // diag page 02-04: skip first frame (no data) if(m_poll_ml_frame==0 && pid==2) BmsRestartCellVoltages(); if(m_poll_ml_frame>0) { base = ((pid-2)*32) + (m_poll_ml_frame-1) * 7; for (bVal = 0; bVal < length && ((base + bVal)<96); bVal++) { //ESP_LOGI(TAG, "[%d %d] = %f", pid, base+bVal, (float)CAN_BYTE(bVal) * 0.02); BmsSetCellVoltage((uint8_t)(base + bVal), (float)CAN_BYTE(bVal) * 0.02); } } break; case 0x05: if (m_poll_ml_frame == 1) { base = 95; for (bVal = 0; bVal < length && ((base + bVal)<96); bVal++) { if(CAN_BYTE(bVal)!=0 ) // For 30kWh version. { //ESP_LOGI(TAG, "[%d %d] = %f", pid, base+bVal, (float)CAN_BYTE(bVal) * 0.02); BmsSetCellVoltage((uint8_t)(base + bVal), (float)CAN_BYTE(bVal) * 0.02); } } m_b_inlet_temperature->SetValue( CAN_BYTE(5) ); m_b_min_temperature->SetValue( CAN_BYTE(6) ); } else if (m_poll_ml_frame == 2) { m_b_max_temperature->SetValue( CAN_BYTE(0) ); } else if (m_poll_ml_frame == 3) { //ks_air_bag_hwire_duty = can_databuffer[5 + CAN_ADJ]; m_b_heat_1_temperature->SetValue( CAN_BYTE(5) ); m_b_heat_2_temperature->SetValue( CAN_BYTE(6) ); } else if (m_poll_ml_frame == 4) { m_b_cell_det_max->SetValue( (float)CAN_UINT(0)/10.0 ); m_b_cell_det_max_no->SetValue( CAN_BYTE(2) ); m_b_cell_det_min->SetValue( (float)CAN_UINT(3)/10.0 ); m_b_cell_det_min_no->SetValue( CAN_BYTE(5) ); } break; } } /** * Handle incoming messages from LDC-poll * * - LDC out voltage * - LDC out current * - LDC in voltage * - LDC temperature */ void OvmsVehicleKiaSoulEv::IncomingLDC(canbus* bus, uint16_t type, uint16_t pid, uint8_t* data, uint8_t length, uint16_t mlremain) { switch (pid) { case 0x01: // 12V system ks_ldc_enabled = (CAN_BYTE(0) & 0x07) != 0; if( CAN_BYTE(0)==0x07 ) { m_ldc_out_voltage->SetValue( CAN_BYTE(1) / 10.0 ); m_ldc_out_current->SetValue( CAN_BYTE(2) ); m_ldc_in_voltage->SetValue( CAN_BYTE(3) * 2 ); m_ldc_temperature->SetValue( CAN_BYTE(4) - 100 ); } break; } } /** * Handle incoming messages from SJB-poll */ void OvmsVehicleKiaSoulEv::IncomingSJB(canbus* bus, uint16_t type, uint16_t pid, uint8_t* data, uint8_t length, uint16_t mlremain) { //ESP_LOGW(TAG, "779X %02x %02x %02x %02x %02x %02x %02x %02x %02x", pid, m_poll_ml_frame, CAN_BYTE(0), CAN_BYTE(1), CAN_BYTE(2), CAN_BYTE(3), CAN_BYTE(4), CAN_BYTE(5), CAN_BYTE(6)); switch (pid) { case 0x04: if (m_poll_ml_frame == 1) { //ESP_LOGW(TAG, "779 8 21 %02x %02x %02x %02x %02x %02x %02x", CAN_BYTE(0), CAN_BYTE(1), CAN_BYTE(2), CAN_BYTE(3), CAN_BYTE(4), CAN_BYTE(5), CAN_BYTE(6)); } break; } }