From 1150ad2b8df5d33a79744c2f3c92ed76401360fc Mon Sep 17 00:00:00 2001 From: Andreas Shimokawa Date: Sat, 22 Aug 2015 00:14:14 +0200 Subject: [PATCH] Pebble: Support taking Pebble Time screenshots. Closes #97. --- .../devices/pebble/PebbleProtocol.java | 125 +++++++++++++++--- .../freeyourgadget/gadgetbridge/util/GB.java | 8 +- 2 files changed, 114 insertions(+), 19 deletions(-) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java index 82329a9f..58d5e41b 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java @@ -202,6 +202,97 @@ public class PebbleProtocol extends GBDeviceProtocol { GBDeviceEventScreenshot mDevEventScreenshot = null; int mScreenshotRemaining = -1; + //monochrome black + white + static final byte[] clut_pebble = { + 0x00, 0x00, 0x00, 0x00, + (byte) 0xff, (byte) 0xff, (byte) 0xff, 0x00 + }; + + // linear BGR222 (6 bit, 64 entries) + static final byte[] clut_pebbletime = new byte[]{ + 0x00, 0x00, 0x00, 0x00, + 0x55, 0x00, 0x00, 0x00, + (byte) 0xaa, 0x00, 0x00, 0x00, + (byte) 0xff, 0x00, 0x00, 0x00, + + 0x00, 0x55, 0x00, 0x00, + 0x55, 0x55, 0x00, 0x00, + (byte) 0xaa, 0x55, 0x00, 0x00, + (byte) 0xff, 0x55, 0x00, 0x00, + + 0x00, (byte) 0xaa, 0x00, 0x00, + 0x55, (byte) 0xaa, 0x00, 0x00, + (byte) 0xaa, (byte) 0xaa, 0x00, 0x00, + (byte) 0xff, (byte) 0xaa, 0x00, 0x00, + + 0x00, (byte) 0xff, 0x00, 0x00, + 0x55, (byte) 0xff, 0x00, 0x00, + (byte) 0xaa, (byte) 0xff, 0x00, 0x00, + (byte) 0xff, (byte) 0xff, 0x00, 0x00, + + 0x00, 0x00, 0x55, 0x00, + 0x55, 0x00, 0x55, 0x00, + (byte) 0xaa, 0x00, 0x55, 0x00, + (byte) 0xff, 0x00, 0x55, 0x00, + + 0x00, 0x55, 0x55, 0x00, + 0x55, 0x55, 0x55, 0x00, + (byte) 0xaa, 0x55, 0x55, 0x00, + (byte) 0xff, 0x55, 0x55, 0x00, + + 0x00, (byte) 0xaa, 0x55, 0x00, + 0x55, (byte) 0xaa, 0x55, 0x00, + (byte) 0xaa, (byte) 0xaa, 0x55, 0x00, + (byte) 0xff, (byte) 0xaa, 0x55, 0x00, + + 0x00, (byte) 0xff, 0x55, 0x00, + 0x55, (byte) 0xff, 0x55, 0x00, + (byte) 0xaa, (byte) 0xff, 0x55, 0x00, + (byte) 0xff, (byte) 0xff, 0x55, 0x00, + + 0x00, 0x00, (byte) 0xaa, 0x00, + 0x55, 0x00, (byte) 0xaa, 0x00, + (byte) 0xaa, 0x00, (byte) 0xaa, 0x00, + (byte) 0xff, 0x00, (byte) 0xaa, 0x00, + + 0x00, 0x55, (byte) 0xaa, 0x00, + 0x55, 0x55, (byte) 0xaa, 0x00, + (byte) 0xaa, 0x55, (byte) 0xaa, 0x00, + (byte) 0xff, 0x55, (byte) 0xaa, 0x00, + + 0x00, (byte) 0xaa, (byte) 0xaa, 0x00, + 0x55, (byte) 0xaa, (byte) 0xaa, 0x00, + (byte) 0xaa, (byte) 0xaa, (byte) 0xaa, 0x00, + (byte) 0xff, (byte) 0xaa, (byte) 0xaa, 0x00, + + 0x00, (byte) 0xff, (byte) 0xaa, 0x00, + 0x55, (byte) 0xff, (byte) 0xaa, 0x00, + (byte) 0xaa, (byte) 0xff, (byte) 0xaa, 0x00, + (byte) 0xff, (byte) 0xff, (byte) 0xaa, 0x00, + + 0x00, 0x00, (byte) 0xff, 0x00, + 0x55, 0x00, (byte) 0xff, 0x00, + (byte) 0xaa, 0x00, (byte) 0xff, 0x00, + (byte) 0xff, 0x00, (byte) 0xff, 0x00, + + 0x00, 0x55, (byte) 0xff, 0x00, + 0x55, 0x55, (byte) 0xff, 0x00, + (byte) 0xaa, 0x55, (byte) 0xff, 0x00, + (byte) 0xff, 0x55, (byte) 0xff, 0x00, + + 0x00, (byte) 0xaa, (byte) 0xff, 0x00, + 0x55, (byte) 0xaa, (byte) 0xff, 0x00, + (byte) 0xaa, (byte) 0xaa, (byte) 0xff, 0x00, + (byte) 0xff, (byte) 0xaa, (byte) 0xff, 0x00, + + 0x00, (byte) 0xff, (byte) 0xff, 0x00, + 0x55, (byte) 0xff, (byte) 0xff, 0x00, + (byte) 0xaa, (byte) 0xff, (byte) 0xff, 0x00, + (byte) 0xff, (byte) 0xff, (byte) 0xff, 0x00, + + }; + + byte last_id = -1; private ArrayList tmpUUIDS = new ArrayList<>(); @@ -477,7 +568,7 @@ public class PebbleProtocol extends GBDeviceProtocol { buf.putInt(timestamp); // 32-bit timestamp buf.putShort((short) 0); // duration buf.put((byte) 0x01); // type (0x01 = notification) - buf.putShort((short) 0x0001); // flags 0x0001 = ? + buf.putShort((short) 0x001f); // flags 0x0001 = ? buf.put((byte) 0x04); // layout (0x04 = notification?) buf.putShort(attributes_length); // total length of all attributes and actions in bytes buf.put(attributes_count); @@ -506,7 +597,7 @@ public class PebbleProtocol extends GBDeviceProtocol { if (mForceProtocol) { // ACTION - buf.put((byte) 0x01); // id + buf.put((byte) 0x00); // id buf.put((byte) 0x04); // dismiss action buf.put((byte) 0x01); // number attributes buf.put((byte) 0x01); // attribute id (title) @@ -921,34 +1012,38 @@ public class PebbleProtocol extends GBDeviceProtocol { byte result = buf.get(); mDevEventScreenshot = new GBDeviceEventScreenshot(); int version = buf.getInt(); - if (result != 0 || version != 1) { // pebble time not yet + if (result != 0) { return null; } mDevEventScreenshot.width = buf.getInt(); mDevEventScreenshot.height = buf.getInt(); - mDevEventScreenshot.bpp = 1; - mDevEventScreenshot.clut = new byte[]{ - 0x00, 0x00, 0x00, 0x00, (byte) 0xff, - (byte) 0xff, (byte) 0xff, 0x00 - }; - mScreenshotRemaining = (mDevEventScreenshot.width * mDevEventScreenshot.height) / 8; - if (mScreenshotRemaining > 50000) { - mScreenshotRemaining = -1; // ignore too big values - return null; + if (version == 1) { + mDevEventScreenshot.bpp = 1; + mDevEventScreenshot.clut = clut_pebble; + } else { + mDevEventScreenshot.bpp = 8; + mDevEventScreenshot.clut = clut_pebbletime; } + + mScreenshotRemaining = (mDevEventScreenshot.width * mDevEventScreenshot.height * mDevEventScreenshot.bpp) / 8; + mDevEventScreenshot.data = new byte[mScreenshotRemaining]; length -= 13; } if (mScreenshotRemaining == -1) { return null; } - for (int i = 0; i < length; i++) { - byte corrected = reverseBits(buf.get()); + byte corrected = buf.get(); + if (mDevEventScreenshot.bpp == 1) { + corrected = reverseBits(corrected); + } else { + corrected = (byte) (corrected & 0b00111111); + } + mDevEventScreenshot.data[mDevEventScreenshot.data.length - mScreenshotRemaining + i] = corrected; } - mScreenshotRemaining -= length; LOG.info("Screenshot remaining bytes " + mScreenshotRemaining); if (mScreenshotRemaining == 0) { diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/GB.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/GB.java index 0a46040a..1b5437b7 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/GB.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/GB.java @@ -151,16 +151,16 @@ public class GB { headerbuf.putInt(screenshot.width); headerbuf.putInt(-screenshot.height); headerbuf.putShort((short) 1); // planes - headerbuf.putShort((short) 1); // bit count + headerbuf.putShort((short) screenshot.bpp); headerbuf.putInt(0); // compression headerbuf.putInt(0); // length of pixeldata in byte (uncompressed=0) headerbuf.putInt(0); // pixels per meter (x) headerbuf.putInt(0); // pixels per meter (y) - headerbuf.putInt(2); // number of colors in CLUT - headerbuf.putInt(2); // numbers of used colors + headerbuf.putInt(screenshot.clut.length / 4); // number of colors in CLUT + headerbuf.putInt(0); // numbers of used colors headerbuf.put(screenshot.clut); fos.write(headerbuf.array()); - int rowbytes = screenshot.width / 8; + int rowbytes = (screenshot.width * screenshot.bpp) / 8; byte[] pad = new byte[rowbytes % 4]; for (int i = 0; i < screenshot.height; i++) { fos.write(screenshot.data, rowbytes * i, rowbytes);