Skip to content

Commit 0e9eb76

Browse files
authored
Merge pull request #15 from crc-32/emulator
Emulator packet support
2 parents a8316f7 + 6dd0699 commit 0e9eb76

File tree

11 files changed

+80
-15
lines changed

11 files changed

+80
-15
lines changed

gradle.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
kotlin.code.style=official
22

33
group=io.rebble.libpebblecommon
4-
version=0.0.19
4+
version=0.0.20
55
org.gradle.jvmargs=-Xms1G

src/androidMain/kotlin/util/DataBuffer.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,4 +80,8 @@ actual class DataBuffer {
8080
actualBuf.putLong(ulong.toLong())
8181
}
8282
actual fun getULong(): ULong = actualBuf.long.toULong()
83+
84+
actual fun rewind() {
85+
actualBuf.rewind()
86+
}
8387
}
Lines changed: 30 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
package io.rebble.libpebblecommon.packets
22

3-
import io.rebble.libpebblecommon.exceptions.PacketDecodeException
4-
import io.rebble.libpebblecommon.protocolhelpers.PebblePacket
53
import io.rebble.libpebblecommon.structmapper.SBytes
64
import io.rebble.libpebblecommon.structmapper.SUShort
75
import io.rebble.libpebblecommon.structmapper.StructMapper
@@ -10,35 +8,57 @@ import io.rebble.libpebblecommon.util.DataBuffer
108
const val HEADER_SIGNATURE = 0xFEEDU
119
const val FOOTER_SIGNATURE = 0xBEEFU
1210

13-
open class QemuInboundPacket {
11+
open class QemuPacket(protocol: Protocol) {
1412
val m = StructMapper()
1513
val signature = SUShort(m, HEADER_SIGNATURE.toUShort())
16-
val protocol = SUShort(m)
14+
val protocol = SUShort(m, protocol.value)
1715
val length = SUShort(m)
1816

19-
class QemuSPP: QemuInboundPacket() {
20-
val payload = SBytes(m)
17+
enum class Protocol(val value: UShort) {
18+
SPP(1U),
19+
Tap(2U),
20+
BluetoothConnection(3U),
21+
Compass(4U),
22+
Battery(5U),
23+
Accel(6U),
24+
Vibration(7U),
25+
Button(8U),
26+
TimeFormat(9U),
27+
TimelinePeek(10U),
28+
ContentSize(11U),
29+
RebbleTest(100U),
30+
Invalid(UShort.MAX_VALUE)
31+
}
32+
33+
class QemuSPP(data: UByteArray? = null): QemuPacket(Protocol.SPP) {
34+
val payload = SBytes(m, data?.size?:-1, data?: ubyteArrayOf())
2135
val footer = SUShort(m, FOOTER_SIGNATURE.toUShort())
2236

2337
init {
24-
payload.linkWithSize(length)
38+
if (data == null) payload.linkWithSize(length)
2539
}
2640
}
2741

2842
companion object {
29-
fun deserialize(packet: UByteArray): QemuInboundPacket {
43+
fun deserialize(packet: UByteArray): QemuPacket {
3044
val buf = DataBuffer(packet)
3145
val meta = StructMapper()
3246
val header = SUShort(meta)
3347
val protocol = SUShort(meta)
3448
meta.fromBytes(buf)
49+
buf.rewind()
3550
return when (protocol.get()) {
36-
1u.toUShort() -> QemuSPP().also { it.m.fromBytes(buf) }
51+
Protocol.SPP.value -> QemuSPP().also { it.m.fromBytes(buf) }
3752
else -> {
3853
println("Warning: QEMU packet left generic")
39-
QemuInboundPacket().also { it.m.fromBytes(buf) }
54+
QemuPacket(Protocol.Invalid).also { it.m.fromBytes(buf) }
4055
}
4156
}
4257
}
4358
}
59+
60+
fun serialize(): UByteArray {
61+
length.set((m.size-(4*UShort.SIZE_BYTES)).toUShort()) //total size - header+footer = payload length
62+
return m.toBytes()
63+
}
4464
}

src/commonMain/kotlin/io/rebble/libpebblecommon/packets/blobdb/Timeline.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,9 @@ class TimelineItem(
9999
override fun toBytes(): UByteArray = m.toBytes()
100100

101101
override fun fromBytes(bytes: DataBuffer) = m.fromBytes(bytes)
102+
103+
override val size: Int
104+
get() = m.size
102105
}
103106

104107
class Attribute() : StructMappable() {

src/commonMain/kotlin/io/rebble/libpebblecommon/structmapper/StructMappable.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,6 @@ abstract class StructMappable : Mappable {
1212
override fun fromBytes(bytes: DataBuffer) {
1313
m.fromBytes(bytes)
1414
}
15+
16+
override val size get() = m.size
1517
}

src/commonMain/kotlin/io/rebble/libpebblecommon/structmapper/StructMapper.kt

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package io.rebble.libpebblecommon.structmapper
22

3+
import io.rebble.libpebblecommon.exceptions.PacketDecodeException
34
import io.rebble.libpebblecommon.util.DataBuffer
45

56
/**
@@ -34,8 +35,16 @@ class StructMapper: Mappable {
3435
}
3536

3637
override fun fromBytes(bytes: DataBuffer) {
37-
getStruct().forEach {
38-
it.fromBytes(bytes)
38+
getStruct().forEachIndexed { i: Int, mappable: Mappable ->
39+
try {
40+
mappable.fromBytes(bytes)
41+
}catch (e: Exception) {
42+
throw PacketDecodeException("Unable to deserialize mappable ${mappable::class.simpleName} at index $i (${mappable})", e)
43+
}
44+
3945
}
4046
}
47+
48+
override val size: Int
49+
get() = getStruct().fold(0, {t,el -> t+el.size})
4150
}

src/commonMain/kotlin/io/rebble/libpebblecommon/structmapper/types.kt

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,11 @@ interface Mappable {
2323
* @param bytes the data to read, seek position is incremented
2424
*/
2525
fun fromBytes(bytes: DataBuffer)
26+
27+
/**
28+
* The projected size in bytes of the raw data returned by [toBytes]
29+
*/
30+
val size: Int
2631
}
2732

2833
interface NumberStructElement {
@@ -41,15 +46,14 @@ open class StructElement<T>(
4146
default: T,
4247
endianness: Char = '|'
4348
) : Mappable { //TODO: Element-level endianness on deserialization
44-
var size = size
49+
override var size = size
4550
get() {
4651
return linkedSize?.valueNumber?.toInt() ?: field
4752
}
4853
set(value) {
4954
field = value
5055
linkedSize = null
5156
}
52-
5357
private var linkedSize: NumberStructElement? = null
5458
private set
5559

@@ -353,6 +357,9 @@ class SFixedList<T : Mappable>(
353357
}
354358
}
355359

360+
override val size: Int
361+
get() = list.fold(0, {t,el -> t+el.size})
362+
356363
/**
357364
* Link the count of this element to the value of another struct element. Count will
358365
* automatically match value of the target element.
@@ -402,6 +409,9 @@ class SOptional<T>(
402409
}
403410
}
404411

412+
override val size: Int
413+
get() = if (present) value.size else 0
414+
405415
fun get(): T? {
406416
return if (present) value.get() else null
407417
}

src/commonMain/kotlin/io/rebble/libpebblecommon/util/DataBuffer.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ expect class DataBuffer {
3535

3636
fun setEndian(endian: Char)
3737

38+
fun rewind()
39+
3840
/**
3941
* Total length of the buffer
4042
*/

src/commonTest/kotlin/Tests.kt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import io.rebble.libpebblecommon.packets.PingPong
2+
import io.rebble.libpebblecommon.packets.QemuPacket
23
import io.rebble.libpebblecommon.protocolhelpers.PebblePacket
34
import kotlin.test.Test
45
import kotlin.test.assertEquals
@@ -33,4 +34,10 @@ class Tests {
3334

3435
assertEquals(bytesToHex(expect), bytesToHex(packet.serialize()))
3536
}
37+
38+
@Test
39+
fun serializeQemuPacket() {
40+
val packet = QemuPacket.QemuSPP(ubyteArrayOf(0xCAu,0xFEu,0x10u))
41+
assertUByteArrayEquals(ubyteArrayOf(0xFEu, 0xEDu, 0x00u, 0x01u, 0x00u, 0x03u, 0xCAu, 0xFEu, 0x10u, 0xBEu, 0xEFu), packet.serialize())
42+
}
3643
}

src/iosMain/kotlin/util/DataBuffer.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,4 +167,8 @@ actual class DataBuffer {
167167
return pULong.value
168168
}
169169
}
170+
171+
actual fun rewind() {
172+
TODO("iOS rewind buffer")
173+
}
170174
}

0 commit comments

Comments
 (0)