Skip to content

Commit f3200e5

Browse files
authored
Merge pull request #20 from matejdro/screenshots
add screenshot packets
2 parents 1ee8fb3 + 4ed11ed commit f3200e5

File tree

4 files changed

+136
-0
lines changed

4 files changed

+136
-0
lines changed
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
package io.rebble.libpebblecommon.packets
2+
3+
import io.rebble.libpebblecommon.protocolhelpers.PacketRegistry
4+
import io.rebble.libpebblecommon.protocolhelpers.PebblePacket
5+
import io.rebble.libpebblecommon.protocolhelpers.ProtocolEndpoint
6+
import io.rebble.libpebblecommon.structmapper.SUByte
7+
import io.rebble.libpebblecommon.structmapper.SUInt
8+
import io.rebble.libpebblecommon.structmapper.SUnboundBytes
9+
import io.rebble.libpebblecommon.structmapper.StructMappable
10+
11+
class ScreenshotRequest : PebblePacket(ProtocolEndpoint.SCREENSHOT) {
12+
/**
13+
* Command. Only one command (take screenshot, value 0) is supported for now
14+
*/
15+
val command = SUByte(m, 0u)
16+
}
17+
18+
class ScreenshotResponse : PebblePacket(ProtocolEndpoint.SCREENSHOT) {
19+
val data = SUnboundBytes(m)
20+
}
21+
22+
class ScreenshotHeader : StructMappable() {
23+
/**
24+
* @see ScreenshotResponseCode
25+
*/
26+
val responseCode = SUByte(m)
27+
28+
/**
29+
* @see ScreenshotVersion
30+
*/
31+
val version = SUInt(m)
32+
33+
val width = SUInt(m)
34+
val height = SUInt(m)
35+
val data = SUnboundBytes(m)
36+
}
37+
38+
enum class ScreenshotResponseCode(val rawCode: UByte) {
39+
OK(0u),
40+
MalformedCommand(0u),
41+
OutOfMemory(0u),
42+
AlreadyInProgress(0u);
43+
44+
companion object {
45+
fun fromRawCode(rawCode: UByte): ScreenshotResponseCode {
46+
return values().firstOrNull { it.rawCode == rawCode }
47+
?: error("Unknown screenshot response code: $rawCode")
48+
}
49+
}
50+
}
51+
52+
enum class ScreenshotVersion(val rawCode: UInt) {
53+
BLACK_WHITE_1_BIT(1u),
54+
COLOR_8_BIT(2u);
55+
56+
companion object {
57+
fun fromRawCode(rawCode: UInt): ScreenshotVersion {
58+
return values().firstOrNull { it.rawCode == rawCode }
59+
?: error("Unknown screenshots version: $rawCode")
60+
}
61+
}
62+
}
63+
64+
fun screenshotPacketsRegister() {
65+
PacketRegistry.register(ProtocolEndpoint.SCREENSHOT) {
66+
ScreenshotResponse()
67+
}
68+
}

src/commonMain/kotlin/io/rebble/libpebblecommon/protocolhelpers/PacketRegistry.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ object PacketRegistry {
2626
appFetchIncomingPacketsRegister()
2727
putBytesIncomingPacketsRegister()
2828
appReorderIncomingRegister()
29+
screenshotPacketsRegister()
2930
}
3031

3132
/**
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package io.rebble.libpebblecommon.services
2+
3+
import io.rebble.libpebblecommon.ProtocolHandler
4+
import io.rebble.libpebblecommon.packets.ScreenshotRequest
5+
import io.rebble.libpebblecommon.packets.ScreenshotResponse
6+
import io.rebble.libpebblecommon.protocolhelpers.PebblePacket
7+
import io.rebble.libpebblecommon.protocolhelpers.ProtocolEndpoint
8+
import kotlinx.coroutines.channels.Channel
9+
10+
class ScreenshotService(private val protocolHandler: ProtocolHandler) : ProtocolService {
11+
val receivedMessages = Channel<ScreenshotResponse>(Channel.BUFFERED)
12+
13+
init {
14+
protocolHandler.registerReceiveCallback(ProtocolEndpoint.SCREENSHOT, this::receive)
15+
}
16+
17+
suspend fun send(packet: ScreenshotRequest) {
18+
protocolHandler.send(packet)
19+
}
20+
21+
fun receive(packet: PebblePacket) {
22+
if (packet !is ScreenshotResponse) {
23+
throw IllegalStateException("Received invalid packet type: $packet")
24+
}
25+
26+
receivedMessages.offer(packet)
27+
}
28+
29+
}

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

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -331,6 +331,44 @@ class SBytes(
331331
}
332332
}
333333

334+
/**
335+
* Byte array without bounded size. It reads until whole packet buffer is read.
336+
*
337+
* This must be declared as last object
338+
*
339+
* Only for reading from watch.
340+
*/
341+
class SUnboundBytes(
342+
mapper: StructMapper,
343+
endianness: Char = '|'
344+
) : StructElement<UByteArray>(
345+
{ buf, el ->
346+
throw UnsupportedOperationException("SUnboundBytes is read-only")
347+
},
348+
{ buf, el ->
349+
val leftBytes = buf.length - buf.readPosition
350+
val value = buf.getBytes(leftBytes)
351+
el.set(if (el.isLittleEndian) value.reversedArray() else value)
352+
},
353+
mapper, 0, ubyteArrayOf(), endianness
354+
) {
355+
356+
override fun toString(): String {
357+
return "SUnboundBytes(value=${get().contentToString()})"
358+
}
359+
360+
override fun equals(other: Any?): Boolean {
361+
if (this === other) return true
362+
if (other !is SUnboundBytes) return false
363+
if (get() != other.get()) return false
364+
return true
365+
}
366+
367+
override fun hashCode(): Int {
368+
return get().hashCode()
369+
}
370+
}
371+
334372
/**
335373
* Represents a fixed size list of T
336374
* @param T the type (must inherit Mappable)

0 commit comments

Comments
 (0)