diff --git a/bridge/bridge_ios.cpp b/bridge/bridge_ios.cpp index 82f35994..cf2b0d69 100644 --- a/bridge/bridge_ios.cpp +++ b/bridge/bridge_ios.cpp @@ -43,6 +43,14 @@ static void carStateToBridge(const CarState& cs, BridgeCarState* out) { out->selfdriveActive = cs.selfdriveActive; out->experimentalMode = cs.experimentalMode; out->changingLane = cs.changingLane; + out->tpmsPressureFL = cs.tpmsPressureFL; + out->tpmsPressureFR = cs.tpmsPressureFR; + out->tpmsPressureRL = cs.tpmsPressureRL; + out->tpmsPressureRR = cs.tpmsPressureRR; + out->tpmsTempFL = cs.tpmsTempFL; + out->tpmsTempFR = cs.tpmsTempFR; + out->tpmsTempRL = cs.tpmsTempRL; + out->tpmsTempRR = cs.tpmsTempRR; } static std::atomic receiveLoopRunning{false}; diff --git a/bridge/bridge_ios.h b/bridge/bridge_ios.h index 51251d6d..c0743a8b 100644 --- a/bridge/bridge_ios.h +++ b/bridge/bridge_ios.h @@ -50,6 +50,16 @@ typedef struct { double selfdriveActive; double experimentalMode; double changingLane; + + // TPMS: pressure (bar, -1 = none) and temperature (degC, -100 = none) per wheel. + double tpmsPressureFL; + double tpmsPressureFR; + double tpmsPressureRL; + double tpmsPressureRR; + double tpmsTempFL; + double tpmsTempFR; + double tpmsTempRL; + double tpmsTempRR; } BridgeCarState; // Context diff --git a/bridge/car/car_state.h b/bridge/car/car_state.h index dd1829ba..19888cb1 100644 --- a/bridge/car/car_state.h +++ b/bridge/car/car_state.h @@ -46,13 +46,26 @@ struct CarState { double experimentalMode = 0; double changingLane = 0; + // Tyre pressure (bar) and temperature (degC) per wheel from VCSEC_TPMSData; + // pressure -1 = no reading, temperature -100 = no reading. + double tpmsPressureFL = -1; + double tpmsPressureFR = -1; + double tpmsPressureRL = -1; + double tpmsPressureRR = -1; + double tpmsTempFL = -100; + double tpmsTempFR = -100; + double tpmsTempRL = -100; + double tpmsTempRR = -100; + // Vehicle VIN, empty until fully assembled by the mapper. static constexpr size_t VIN_LENGTH = 17; char vin[VIN_LENGTH + 1] = {}; static constexpr size_t VIN_DOUBLE_COUNT = 3; static constexpr size_t VIN_OFFSET = 36; - static constexpr size_t FIELD_COUNT = VIN_OFFSET + VIN_DOUBLE_COUNT; + static constexpr size_t TPMS_OFFSET = VIN_OFFSET + VIN_DOUBLE_COUNT; + static constexpr size_t TPMS_COUNT = 8; + static constexpr size_t FIELD_COUNT = TPMS_OFFSET + TPMS_COUNT; void toArray(double* out) const { // Party bus @@ -103,5 +116,15 @@ struct CarState { char padded[VIN_DOUBLE_COUNT * sizeof(double)] = {}; std::memcpy(padded, vin, VIN_LENGTH); std::memcpy(out + VIN_OFFSET, padded, sizeof(padded)); + + // TPMS (after VIN): pressures FL FR RL RR, then temperatures FL FR RL RR. + out[TPMS_OFFSET + 0] = tpmsPressureFL; + out[TPMS_OFFSET + 1] = tpmsPressureFR; + out[TPMS_OFFSET + 2] = tpmsPressureRL; + out[TPMS_OFFSET + 3] = tpmsPressureRR; + out[TPMS_OFFSET + 4] = tpmsTempFL; + out[TPMS_OFFSET + 5] = tpmsTempFR; + out[TPMS_OFFSET + 6] = tpmsTempRL; + out[TPMS_OFFSET + 7] = tpmsTempRR; } }; diff --git a/bridge/car/cars/tesla.h b/bridge/car/cars/tesla.h index e21a2b9a..e0cff503 100644 --- a/bridge/car/cars/tesla.h +++ b/bridge/car/cars/tesla.h @@ -5,6 +5,7 @@ #include #include #include +#include #include "car/car_state_mapper.h" @@ -185,6 +186,27 @@ class TeslaDashKitMapper : public CarStateMapper { updateVehicleBus(cp, cs); vin_.update(cp, cs); + // TPMS: pressures come from mux 5 (all four wheels, 0.025 bar resolution); + // temperatures from muxes 0-3 (one sensor each). Their per-sensor pressure is + // coarser (0.05 bar) and would alternate with mux 5, so it is not used. + // Fields keep their last value until a frame carries that wheel again. + // getRaw fails until a frame has been seen; get() would read 0 and look like mux 0. + uint64_t tpmsIndex = 0; + if (cp.getRaw(1, "VCSEC_TPMSData", "VCSEC_TPMSDataIndex", &tpmsIndex)) { + if (tpmsIndex == 5) { + double* pressures[4] = {&cs.tpmsPressureFL, &cs.tpmsPressureFR, &cs.tpmsPressureRL, &cs.tpmsPressureRR}; + static const char* const kP[4] = {"FL", "FR", "RL", "RR"}; + for (int w = 0; w < 4; w++) { + double v = cp.get(1, "VCSEC_TPMSData", std::string("VCSEC_TPMSPressure") + kP[w]); + if (v >= 0.5 && v < 6.36) *pressures[w] = v; + } + } else if (tpmsIndex <= 3) { + // Mux 0 RR, 1 RL, 2 FR, 3 FL (verified against mux 5 in CAN logs). + double* tempOfMux[4] = {&cs.tpmsTempRR, &cs.tpmsTempRL, &cs.tpmsTempFR, &cs.tpmsTempFL}; + double t = cp.get(1, "VCSEC_TPMSData", "VCSEC_TPMSTemperature" + std::to_string(tpmsIndex)); + if (t < 214.5) *tempOfMux[tpmsIndex] = t; + } + } } private: diff --git a/dashpilot-android/app/src/main/assets/vehicles/tesla/bus_1_tesla_vehicle.dbc b/dashpilot-android/app/src/main/assets/vehicles/tesla/bus_1_tesla_vehicle.dbc index 1cd7e981..958cb5ef 100644 --- a/dashpilot-android/app/src/main/assets/vehicles/tesla/bus_1_tesla_vehicle.dbc +++ b/dashpilot-android/app/src/main/assets/vehicles/tesla/bus_1_tesla_vehicle.dbc @@ -115,24 +115,24 @@ BO_ 322 VCLEFT_liftgateStatus: 8 VEH SG_ VCLEFT_liftgateStrutDutyCycle m1 : 3|8@1- (1,0) [-100|100] "%" X SG_ VCLEFT_liftgateUIChimeRequest m0 : 18|3@1+ (1,0) [0|4] "" X -BO_ 537 VCSEC_TPMSData: 5 CH - SG_ VCSEC_TPMSDataIndex M : 0|2@1+ (1,0) [0|3] "" Receiver - SG_ VCSEC_TPMSBatVoltage0 m0 : 24|8@1+ (0.01,1.5) [1.5|4.04] "V" X - SG_ VCSEC_TPMSBatVoltage1 m1 : 24|8@1+ (0.01,1.5) [1.5|4.04] "V" X - SG_ VCSEC_TPMSBatVoltage2 m2 : 24|8@1+ (0.01,1.5) [1.5|4.04] "V" X - SG_ VCSEC_TPMSBatVoltage3 m3 : 24|8@1+ (0.01,1.5) [1.5|4.04] "V" X - SG_ VCSEC_TPMSLocation0 m0 : 32|3@1+ (1,0) [0|4] "" X - SG_ VCSEC_TPMSLocation1 m1 : 32|3@1+ (1,0) [0|4] "" X - SG_ VCSEC_TPMSLocation2 m2 : 32|3@1+ (1,0) [0|4] "" X - SG_ VCSEC_TPMSLocation3 m3 : 32|3@1+ (1,0) [0|4] "" X - SG_ VCSEC_TPMSPressure0 m0 : 8|8@1+ (0.025,0) [0|6.35] "bar" X - SG_ VCSEC_TPMSPressure1 m1 : 8|8@1+ (0.025,0) [0|6.35] "bar" X - SG_ VCSEC_TPMSPressure2 m2 : 8|8@1+ (0.025,0) [0|6.35] "bar" X - SG_ VCSEC_TPMSPressure3 m3 : 8|8@1+ (0.025,0) [0|6.35] "bar" X - SG_ VCSEC_TPMSTemperature0 m0 : 16|8@1+ (1,-40) [-40|214] "C" X - SG_ VCSEC_TPMSTemperature1 m1 : 16|8@1+ (1,-40) [-40|214] "C" X - SG_ VCSEC_TPMSTemperature2 m2 : 16|8@1+ (1,-40) [-40|214] "C" X - SG_ VCSEC_TPMSTemperature3 m3 : 16|8@1+ (1,-40) [-40|214] "C" X +BO_ 537 VCSEC_TPMSData: 7 CH + SG_ VCSEC_TPMSDataIndex M : 0|3@1+ (1,0) [0|5] "" Receiver + SG_ VCSEC_TPMSPressureFL m5 : 16|8@1+ (0.025,0) [0|6.375] "bar" X + SG_ VCSEC_TPMSPressureFR m5 : 24|8@1+ (0.025,0) [0|6.375] "bar" X + SG_ VCSEC_TPMSPressureRL m5 : 32|8@1+ (0.025,0) [0|6.375] "bar" X + SG_ VCSEC_TPMSPressureRR m5 : 40|8@1+ (0.025,0) [0|6.375] "bar" X + SG_ VCSEC_TPMSPressure0 m0 : 16|8@1+ (0.05,-1) [-1|11.75] "bar" X + SG_ VCSEC_TPMSPressure1 m1 : 16|8@1+ (0.05,-1) [-1|11.75] "bar" X + SG_ VCSEC_TPMSPressure2 m2 : 16|8@1+ (0.05,-1) [-1|11.75] "bar" X + SG_ VCSEC_TPMSPressure3 m3 : 16|8@1+ (0.05,-1) [-1|11.75] "bar" X + SG_ VCSEC_TPMSTemperature0 m0 : 24|8@1+ (1,-40) [-40|215] "C" X + SG_ VCSEC_TPMSTemperature1 m1 : 24|8@1+ (1,-40) [-40|215] "C" X + SG_ VCSEC_TPMSTemperature2 m2 : 24|8@1+ (1,-40) [-40|215] "C" X + SG_ VCSEC_TPMSTemperature3 m3 : 24|8@1+ (1,-40) [-40|215] "C" X + SG_ VCSEC_TPMSBatVoltage0 m0 : 32|8@1+ (0.01,1.5) [1.5|4.04] "V" X + SG_ VCSEC_TPMSBatVoltage1 m1 : 32|8@1+ (0.01,1.5) [1.5|4.04] "V" X + SG_ VCSEC_TPMSBatVoltage2 m2 : 32|8@1+ (0.01,1.5) [1.5|4.04] "V" X + SG_ VCSEC_TPMSBatVoltage3 m3 : 32|8@1+ (0.01,1.5) [1.5|4.04] "V" X BO_ 1066 VCSEC_TPMSConnectionData: 8 VEH SG_ VCSEC_TPMSConnectionTypeCurrent0 : 11|2@1+ (1,0) [0|2] "" X diff --git a/dashpilot-android/app/src/main/java/com/softwiredtech/dashpilot/datamodel/dash/CarState.kt b/dashpilot-android/app/src/main/java/com/softwiredtech/dashpilot/datamodel/dash/CarState.kt index 8bc2975f..faa9247d 100644 --- a/dashpilot-android/app/src/main/java/com/softwiredtech/dashpilot/datamodel/dash/CarState.kt +++ b/dashpilot-android/app/src/main/java/com/softwiredtech/dashpilot/datamodel/dash/CarState.kt @@ -43,6 +43,16 @@ data class CarState( val changingLane: Boolean = false, + // TPMS: pressure (bar, -1 = none) and temperature (degC, -100 = none) per wheel. + val tpmsPressureFL: Float = -1f, + val tpmsPressureFR: Float = -1f, + val tpmsPressureRL: Float = -1f, + val tpmsPressureRR: Float = -1f, + val tpmsTempFL: Float = -100f, + val tpmsTempFR: Float = -100f, + val tpmsTempRL: Float = -100f, + val tpmsTempRR: Float = -100f, + // Empty until fully assembled from the CAN stream by the native mapper. val vin: String = "" ) { @@ -56,7 +66,7 @@ data class CarState( ) companion object { - const val FIELD_COUNT = 39 + const val FIELD_COUNT = 47 private const val KM_TO_MILES = 0.621371f private val MILES_COUNTRIES = setOf("US", "GB", "MM", "LR") diff --git a/dashpilot-android/app/src/main/java/com/softwiredtech/dashpilot/vehicle/CanFrameDecoder.kt b/dashpilot-android/app/src/main/java/com/softwiredtech/dashpilot/vehicle/CanFrameDecoder.kt index 96f595f9..603df1ef 100644 --- a/dashpilot-android/app/src/main/java/com/softwiredtech/dashpilot/vehicle/CanFrameDecoder.kt +++ b/dashpilot-android/app/src/main/java/com/softwiredtech/dashpilot/vehicle/CanFrameDecoder.kt @@ -65,7 +65,16 @@ class CanFrameDecoder( hvacRecirc = values[33].toFloat(), hvacKeepClimateOn = values[34].toFloat(), powerLevel = values[35].toFloat(), - vin = decodeVin(values, offset = 36) + vin = decodeVin(values, offset = 36), + // TPMS after VIN (see CarState::TPMS_OFFSET): pressures FL FR RL RR, temperatures FL FR RL RR. + tpmsPressureFL = values[39].toFloat(), + tpmsPressureFR = values[40].toFloat(), + tpmsPressureRL = values[41].toFloat(), + tpmsPressureRR = values[42].toFloat(), + tpmsTempFL = values[43].toFloat(), + tpmsTempFR = values[44].toFloat(), + tpmsTempRL = values[45].toFloat(), + tpmsTempRR = values[46].toFloat() ) } diff --git a/dashpilot-android/bridge/tests/tesla_vin_mapper_test.cpp b/dashpilot-android/bridge/tests/tesla_vin_mapper_test.cpp index bcc28db8..50c56224 100644 --- a/dashpilot-android/bridge/tests/tesla_vin_mapper_test.cpp +++ b/dashpilot-android/bridge/tests/tesla_vin_mapper_test.cpp @@ -140,7 +140,7 @@ void empty_vin_encodes_as_zero_doubles() { CarState cs; double out[CarState::FIELD_COUNT]; cs.toArray(out); - for (size_t i = CarState::VIN_OFFSET; i < CarState::FIELD_COUNT; i++) { + for (size_t i = CarState::VIN_OFFSET; i < CarState::TPMS_OFFSET; i++) { CHECK(out[i] == 0.0); } } diff --git a/dashpilot-ios/dashpilot/Models/CarState.swift b/dashpilot-ios/dashpilot/Models/CarState.swift index 94360ba3..1030a748 100644 --- a/dashpilot-ios/dashpilot/Models/CarState.swift +++ b/dashpilot-ios/dashpilot/Models/CarState.swift @@ -43,6 +43,16 @@ struct CarState: Codable { var experimentalMode: Bool = false var changingLane: Bool = false + // Tyre pressure (bar, -1 = none) and temperature (degC, -100 = none) per wheel. + var tpmsPressureFL: Float = -1 + var tpmsPressureFR: Float = -1 + var tpmsPressureRL: Float = -1 + var tpmsPressureRR: Float = -1 + var tpmsTempFL: Float = -100 + var tpmsTempFR: Float = -100 + var tpmsTempRL: Float = -100 + var tpmsTempRR: Float = -100 + init() {} init(from bridge: BridgeCarState) { @@ -82,6 +92,14 @@ struct CarState: Codable { selfdriveActive = bridge.selfdriveActive > 0 experimentalMode = bridge.experimentalMode > 0 changingLane = bridge.changingLane > 0 + tpmsPressureFL = Float(bridge.tpmsPressureFL) + tpmsPressureFR = Float(bridge.tpmsPressureFR) + tpmsPressureRL = Float(bridge.tpmsPressureRL) + tpmsPressureRR = Float(bridge.tpmsPressureRR) + tpmsTempFL = Float(bridge.tpmsTempFL) + tpmsTempFR = Float(bridge.tpmsTempFR) + tpmsTempRL = Float(bridge.tpmsTempRL) + tpmsTempRR = Float(bridge.tpmsTempRR) } private static let kmToMiles: Float = 0.621371 diff --git a/dashpilot-ios/dashpilot/Resources/vehicles/tesla/bus_1_tesla_vehicle.dbc b/dashpilot-ios/dashpilot/Resources/vehicles/tesla/bus_1_tesla_vehicle.dbc index 1cd7e981..958cb5ef 100644 --- a/dashpilot-ios/dashpilot/Resources/vehicles/tesla/bus_1_tesla_vehicle.dbc +++ b/dashpilot-ios/dashpilot/Resources/vehicles/tesla/bus_1_tesla_vehicle.dbc @@ -115,24 +115,24 @@ BO_ 322 VCLEFT_liftgateStatus: 8 VEH SG_ VCLEFT_liftgateStrutDutyCycle m1 : 3|8@1- (1,0) [-100|100] "%" X SG_ VCLEFT_liftgateUIChimeRequest m0 : 18|3@1+ (1,0) [0|4] "" X -BO_ 537 VCSEC_TPMSData: 5 CH - SG_ VCSEC_TPMSDataIndex M : 0|2@1+ (1,0) [0|3] "" Receiver - SG_ VCSEC_TPMSBatVoltage0 m0 : 24|8@1+ (0.01,1.5) [1.5|4.04] "V" X - SG_ VCSEC_TPMSBatVoltage1 m1 : 24|8@1+ (0.01,1.5) [1.5|4.04] "V" X - SG_ VCSEC_TPMSBatVoltage2 m2 : 24|8@1+ (0.01,1.5) [1.5|4.04] "V" X - SG_ VCSEC_TPMSBatVoltage3 m3 : 24|8@1+ (0.01,1.5) [1.5|4.04] "V" X - SG_ VCSEC_TPMSLocation0 m0 : 32|3@1+ (1,0) [0|4] "" X - SG_ VCSEC_TPMSLocation1 m1 : 32|3@1+ (1,0) [0|4] "" X - SG_ VCSEC_TPMSLocation2 m2 : 32|3@1+ (1,0) [0|4] "" X - SG_ VCSEC_TPMSLocation3 m3 : 32|3@1+ (1,0) [0|4] "" X - SG_ VCSEC_TPMSPressure0 m0 : 8|8@1+ (0.025,0) [0|6.35] "bar" X - SG_ VCSEC_TPMSPressure1 m1 : 8|8@1+ (0.025,0) [0|6.35] "bar" X - SG_ VCSEC_TPMSPressure2 m2 : 8|8@1+ (0.025,0) [0|6.35] "bar" X - SG_ VCSEC_TPMSPressure3 m3 : 8|8@1+ (0.025,0) [0|6.35] "bar" X - SG_ VCSEC_TPMSTemperature0 m0 : 16|8@1+ (1,-40) [-40|214] "C" X - SG_ VCSEC_TPMSTemperature1 m1 : 16|8@1+ (1,-40) [-40|214] "C" X - SG_ VCSEC_TPMSTemperature2 m2 : 16|8@1+ (1,-40) [-40|214] "C" X - SG_ VCSEC_TPMSTemperature3 m3 : 16|8@1+ (1,-40) [-40|214] "C" X +BO_ 537 VCSEC_TPMSData: 7 CH + SG_ VCSEC_TPMSDataIndex M : 0|3@1+ (1,0) [0|5] "" Receiver + SG_ VCSEC_TPMSPressureFL m5 : 16|8@1+ (0.025,0) [0|6.375] "bar" X + SG_ VCSEC_TPMSPressureFR m5 : 24|8@1+ (0.025,0) [0|6.375] "bar" X + SG_ VCSEC_TPMSPressureRL m5 : 32|8@1+ (0.025,0) [0|6.375] "bar" X + SG_ VCSEC_TPMSPressureRR m5 : 40|8@1+ (0.025,0) [0|6.375] "bar" X + SG_ VCSEC_TPMSPressure0 m0 : 16|8@1+ (0.05,-1) [-1|11.75] "bar" X + SG_ VCSEC_TPMSPressure1 m1 : 16|8@1+ (0.05,-1) [-1|11.75] "bar" X + SG_ VCSEC_TPMSPressure2 m2 : 16|8@1+ (0.05,-1) [-1|11.75] "bar" X + SG_ VCSEC_TPMSPressure3 m3 : 16|8@1+ (0.05,-1) [-1|11.75] "bar" X + SG_ VCSEC_TPMSTemperature0 m0 : 24|8@1+ (1,-40) [-40|215] "C" X + SG_ VCSEC_TPMSTemperature1 m1 : 24|8@1+ (1,-40) [-40|215] "C" X + SG_ VCSEC_TPMSTemperature2 m2 : 24|8@1+ (1,-40) [-40|215] "C" X + SG_ VCSEC_TPMSTemperature3 m3 : 24|8@1+ (1,-40) [-40|215] "C" X + SG_ VCSEC_TPMSBatVoltage0 m0 : 32|8@1+ (0.01,1.5) [1.5|4.04] "V" X + SG_ VCSEC_TPMSBatVoltage1 m1 : 32|8@1+ (0.01,1.5) [1.5|4.04] "V" X + SG_ VCSEC_TPMSBatVoltage2 m2 : 32|8@1+ (0.01,1.5) [1.5|4.04] "V" X + SG_ VCSEC_TPMSBatVoltage3 m3 : 32|8@1+ (0.01,1.5) [1.5|4.04] "V" X BO_ 1066 VCSEC_TPMSConnectionData: 8 VEH SG_ VCSEC_TPMSConnectionTypeCurrent0 : 11|2@1+ (1,0) [0|2] "" X