mirror of
https://github.com/twinksoftware/Gearslip.git
synced 2026-11-11 00:12:24 +01:00
fix car sensor channel, mark Metrolist working
Sensors live in service field 2, not 5 (that's the mic), so the channel never opened. Message ids were also one off and the start request was missing min_update_period.
This commit is contained in:
1 parent
96d16d048c
commit
024850bf48
5 files changed
+59
-11
No files matched your search
@@ -460,10 +460,12 @@ class GearslipRunner(
|
|||||||
log.w("head unit refused the sensor channel (status=$status)")
|
log.w("head unit refused the sensor channel (status=$status)")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// SensorRequest { required int32 sensor_type = 1; }
|
// SensorRequest { required SensorType type = 1; required int64 min_update_period = 2; }
|
||||||
|
// A period of 0 asks for every update the car sends.
|
||||||
sensorTypes.forEach { type ->
|
sensorTypes.forEach { type ->
|
||||||
send(
|
send(
|
||||||
MSG_SENSOR_START_REQUEST, Protobuf.varintField(1, type.toLong()),
|
MSG_SENSOR_START_REQUEST,
|
||||||
|
Protobuf.varintField(1, type.toLong()) + Protobuf.varintField(2, 0L),
|
||||||
encrypted = true, channel = sensorChannelId,
|
encrypted = true, channel = sensorChannelId,
|
||||||
)
|
)
|
||||||
log.i("-> SensorStartRequest(sensor_type=$type)")
|
log.i("-> SensorStartRequest(sensor_type=$type)")
|
||||||
@@ -478,6 +480,11 @@ class GearslipRunner(
|
|||||||
log.i("<- SensorEvent:\n" + Protobuf.describe(body))
|
log.i("<- SensorEvent:\n" + Protobuf.describe(body))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SensorError { required SensorType sensor_type = 1; required SensorErrorType sensor_error_type = 2; }
|
||||||
|
MSG_SENSOR_ERROR -> log.w(
|
||||||
|
"<- SensorError: type=${Protobuf.readInt32Field(body, 1)} error=${Protobuf.readInt32Field(body, 2)}",
|
||||||
|
)
|
||||||
|
|
||||||
else -> log.i("<- unhandled sensor message id=$messageId (${body.size} bytes)")
|
else -> log.i("<- unhandled sensor message id=$messageId (${body.size} bytes)")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -988,9 +995,11 @@ class GearslipRunner(
|
|||||||
|
|
||||||
// aap_protobuf/service/sensor/... - same "first specific message on this channel type
|
// aap_protobuf/service/sensor/... - same "first specific message on this channel type
|
||||||
// starts at 0x8000" numbering as media/input above.
|
// starts at 0x8000" numbering as media/input above.
|
||||||
const val MSG_SENSOR_START_REQUEST = 32768
|
// aasdk SensorMessageId: REQUEST, RESPONSE, BATCH, ERROR.
|
||||||
const val MSG_SENSOR_START_RESPONSE = 32769
|
const val MSG_SENSOR_START_REQUEST = 32769
|
||||||
const val MSG_SENSOR_EVENT_INDICATION = 32770
|
const val MSG_SENSOR_START_RESPONSE = 32770
|
||||||
|
const val MSG_SENSOR_EVENT_INDICATION = 32771
|
||||||
|
const val MSG_SENSOR_ERROR = 32772
|
||||||
|
|
||||||
const val STREAM_MEDIA = 3
|
const val STREAM_MEDIA = 3
|
||||||
const val CODEC_H264_BP = 3
|
const val CODEC_H264_BP = 3
|
||||||
|
|||||||
@@ -196,9 +196,9 @@ object ServiceDiscovery {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The head unit's sensor feed, from SensorSourceService (Service field 5):
|
* The head unit's sensor feed, from SensorSourceService (Service field 2; field 5 is the car's mic):
|
||||||
* SensorSourceService { repeated SensorType sensors = 1; }
|
* SensorSourceService { repeated Sensor sensors = 1; }
|
||||||
* SensorType { required int32 type = 1; }
|
* Sensor { required SensorType sensor_type = 1; }
|
||||||
*
|
*
|
||||||
* Field numbers for what actually rides inside each SensorEvent once subscribed are not
|
* Field numbers for what actually rides inside each SensorEvent once subscribed are not
|
||||||
* pinned down here - unlike video/audio/input, there's no independent source to check them
|
* pinned down here - unlike video/audio/input, there's no independent source to check them
|
||||||
@@ -210,7 +210,7 @@ object ServiceDiscovery {
|
|||||||
for (channel in Wire.allBytes(Wire.fields(response), 1)) {
|
for (channel in Wire.allBytes(Wire.fields(response), 1)) {
|
||||||
val service = Wire.fields(channel)
|
val service = Wire.fields(channel)
|
||||||
val id = Wire.varint(service, 1)?.toInt() ?: continue
|
val id = Wire.varint(service, 1)?.toInt() ?: continue
|
||||||
val sensorSource = Wire.bytes(service, 5) ?: continue
|
val sensorSource = Wire.bytes(service, 2) ?: continue
|
||||||
val types = Wire.allBytes(Wire.fields(sensorSource), 1).mapNotNull {
|
val types = Wire.allBytes(Wire.fields(sensorSource), 1).mapNotNull {
|
||||||
Wire.varint(Wire.fields(it), 1)?.toInt()
|
Wire.varint(Wire.fields(it), 1)?.toInt()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -87,8 +87,8 @@ object SensorType {
|
|||||||
18 to "Tire pressure",
|
18 to "Tire pressure",
|
||||||
19 to "Accelerometer",
|
19 to "Accelerometer",
|
||||||
20 to "Gyroscope",
|
20 to "Gyroscope",
|
||||||
21 to "Gravity",
|
21 to "GPS satellites",
|
||||||
22 to "Wheel tick / distance",
|
22 to "Toll card",
|
||||||
)
|
)
|
||||||
|
|
||||||
fun name(id: Int): String = NAMES[id]?.let { "$it (#$id)" } ?: "Sensor #$id"
|
fun name(id: Int): String = NAMES[id]?.let { "$it (#$id)" } ?: "Sensor #$id"
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ object KnownApps {
|
|||||||
"in.krosbits.musicolet", // Musicolet: browse, play, seek, lyrics
|
"in.krosbits.musicolet", // Musicolet: browse, play, seek, lyrics
|
||||||
"com.kododake.aabrowser", // Aardvark: browser template, starts, draws, takes touches
|
"com.kododake.aabrowser", // Aardvark: browser template, starts, draws, takes touches
|
||||||
"com.vivi.vivimusic", // Vivi Music: browse, play, seek, works well
|
"com.vivi.vivimusic", // Vivi Music: browse, play, seek, works well
|
||||||
|
"com.metrolist.music", // Metrolist: browse, play, works
|
||||||
"nl.flitsmeister", // Flitsmeister: map, routing, alerts - works well
|
"nl.flitsmeister", // Flitsmeister: map, routing, alerts - works well
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,38 @@
|
|||||||
|
package app.seb3thehacker.gearslip
|
||||||
|
|
||||||
|
import org.junit.Assert.assertEquals
|
||||||
|
import org.junit.Assert.assertNotNull
|
||||||
|
import org.junit.Test
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The 2018 Uconnect's sensor and mic services, from `archive/spike/car-run-2026-09-16-run2.log`.
|
||||||
|
* Channel 7 offers sensors in Service field 2; channel 3 is the mic in field 5. Reading the wrong
|
||||||
|
* field finds nothing at all, so the sensor channel never opens.
|
||||||
|
*/
|
||||||
|
class ServiceDiscoverySensorTest {
|
||||||
|
|
||||||
|
private fun varintField(field: Int, value: Long) = Protobuf.varintField(field, value)
|
||||||
|
|
||||||
|
private fun lenField(field: Int, body: ByteArray): ByteArray =
|
||||||
|
Protobuf.varint(((field shl 3) or 2).toLong()) + Protobuf.varint(body.size.toLong()) + body
|
||||||
|
|
||||||
|
private fun micSource() = lenField(
|
||||||
|
1,
|
||||||
|
varintField(1, 3L) + lenField(5, varintField(1, 1L) + lenField(2, varintField(1, 16_000L))),
|
||||||
|
)
|
||||||
|
|
||||||
|
private fun sensorSource(types: List<Int>): ByteArray {
|
||||||
|
val sensors = types.fold(ByteArray(0)) { acc, t -> acc + lenField(1, varintField(1, t.toLong())) }
|
||||||
|
return lenField(1, varintField(1, 7L) + lenField(2, sensors + varintField(2, 256L)))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun findsUconnectSensorsInFieldTwo() {
|
||||||
|
val response = micSource() + sensorSource(listOf(1, 3, 10, 13, 20, 21))
|
||||||
|
val sensors = ServiceDiscovery.findSensorService(response)
|
||||||
|
assertNotNull(sensors)
|
||||||
|
sensors!!
|
||||||
|
assertEquals(7, sensors.serviceId)
|
||||||
|
assertEquals(listOf(1, 3, 10, 13, 20, 21), sensors.types)
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in new issue
Block a user