Pebble: Support taking Pebble Time screenshots. Closes #97.
This commit is contained in:
parent
12337836bc
commit
1150ad2b8d
|
@ -202,6 +202,97 @@ public class PebbleProtocol extends GBDeviceProtocol {
|
||||||
GBDeviceEventScreenshot mDevEventScreenshot = null;
|
GBDeviceEventScreenshot mDevEventScreenshot = null;
|
||||||
int mScreenshotRemaining = -1;
|
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;
|
byte last_id = -1;
|
||||||
private ArrayList<UUID> tmpUUIDS = new ArrayList<>();
|
private ArrayList<UUID> tmpUUIDS = new ArrayList<>();
|
||||||
|
|
||||||
|
@ -477,7 +568,7 @@ public class PebbleProtocol extends GBDeviceProtocol {
|
||||||
buf.putInt(timestamp); // 32-bit timestamp
|
buf.putInt(timestamp); // 32-bit timestamp
|
||||||
buf.putShort((short) 0); // duration
|
buf.putShort((short) 0); // duration
|
||||||
buf.put((byte) 0x01); // type (0x01 = notification)
|
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.put((byte) 0x04); // layout (0x04 = notification?)
|
||||||
buf.putShort(attributes_length); // total length of all attributes and actions in bytes
|
buf.putShort(attributes_length); // total length of all attributes and actions in bytes
|
||||||
buf.put(attributes_count);
|
buf.put(attributes_count);
|
||||||
|
@ -506,7 +597,7 @@ public class PebbleProtocol extends GBDeviceProtocol {
|
||||||
|
|
||||||
if (mForceProtocol) {
|
if (mForceProtocol) {
|
||||||
// ACTION
|
// ACTION
|
||||||
buf.put((byte) 0x01); // id
|
buf.put((byte) 0x00); // id
|
||||||
buf.put((byte) 0x04); // dismiss action
|
buf.put((byte) 0x04); // dismiss action
|
||||||
buf.put((byte) 0x01); // number attributes
|
buf.put((byte) 0x01); // number attributes
|
||||||
buf.put((byte) 0x01); // attribute id (title)
|
buf.put((byte) 0x01); // attribute id (title)
|
||||||
|
@ -921,34 +1012,38 @@ public class PebbleProtocol extends GBDeviceProtocol {
|
||||||
byte result = buf.get();
|
byte result = buf.get();
|
||||||
mDevEventScreenshot = new GBDeviceEventScreenshot();
|
mDevEventScreenshot = new GBDeviceEventScreenshot();
|
||||||
int version = buf.getInt();
|
int version = buf.getInt();
|
||||||
if (result != 0 || version != 1) { // pebble time not yet
|
if (result != 0) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
mDevEventScreenshot.width = buf.getInt();
|
mDevEventScreenshot.width = buf.getInt();
|
||||||
mDevEventScreenshot.height = 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 (version == 1) {
|
||||||
if (mScreenshotRemaining > 50000) {
|
mDevEventScreenshot.bpp = 1;
|
||||||
mScreenshotRemaining = -1; // ignore too big values
|
mDevEventScreenshot.clut = clut_pebble;
|
||||||
return null;
|
} else {
|
||||||
|
mDevEventScreenshot.bpp = 8;
|
||||||
|
mDevEventScreenshot.clut = clut_pebbletime;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mScreenshotRemaining = (mDevEventScreenshot.width * mDevEventScreenshot.height * mDevEventScreenshot.bpp) / 8;
|
||||||
|
|
||||||
mDevEventScreenshot.data = new byte[mScreenshotRemaining];
|
mDevEventScreenshot.data = new byte[mScreenshotRemaining];
|
||||||
length -= 13;
|
length -= 13;
|
||||||
}
|
}
|
||||||
if (mScreenshotRemaining == -1) {
|
if (mScreenshotRemaining == -1) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < length; i++) {
|
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;
|
mDevEventScreenshot.data[mDevEventScreenshot.data.length - mScreenshotRemaining + i] = corrected;
|
||||||
}
|
}
|
||||||
|
|
||||||
mScreenshotRemaining -= length;
|
mScreenshotRemaining -= length;
|
||||||
LOG.info("Screenshot remaining bytes " + mScreenshotRemaining);
|
LOG.info("Screenshot remaining bytes " + mScreenshotRemaining);
|
||||||
if (mScreenshotRemaining == 0) {
|
if (mScreenshotRemaining == 0) {
|
||||||
|
|
|
@ -151,16 +151,16 @@ public class GB {
|
||||||
headerbuf.putInt(screenshot.width);
|
headerbuf.putInt(screenshot.width);
|
||||||
headerbuf.putInt(-screenshot.height);
|
headerbuf.putInt(-screenshot.height);
|
||||||
headerbuf.putShort((short) 1); // planes
|
headerbuf.putShort((short) 1); // planes
|
||||||
headerbuf.putShort((short) 1); // bit count
|
headerbuf.putShort((short) screenshot.bpp);
|
||||||
headerbuf.putInt(0); // compression
|
headerbuf.putInt(0); // compression
|
||||||
headerbuf.putInt(0); // length of pixeldata in byte (uncompressed=0)
|
headerbuf.putInt(0); // length of pixeldata in byte (uncompressed=0)
|
||||||
headerbuf.putInt(0); // pixels per meter (x)
|
headerbuf.putInt(0); // pixels per meter (x)
|
||||||
headerbuf.putInt(0); // pixels per meter (y)
|
headerbuf.putInt(0); // pixels per meter (y)
|
||||||
headerbuf.putInt(2); // number of colors in CLUT
|
headerbuf.putInt(screenshot.clut.length / 4); // number of colors in CLUT
|
||||||
headerbuf.putInt(2); // numbers of used colors
|
headerbuf.putInt(0); // numbers of used colors
|
||||||
headerbuf.put(screenshot.clut);
|
headerbuf.put(screenshot.clut);
|
||||||
fos.write(headerbuf.array());
|
fos.write(headerbuf.array());
|
||||||
int rowbytes = screenshot.width / 8;
|
int rowbytes = (screenshot.width * screenshot.bpp) / 8;
|
||||||
byte[] pad = new byte[rowbytes % 4];
|
byte[] pad = new byte[rowbytes % 4];
|
||||||
for (int i = 0; i < screenshot.height; i++) {
|
for (int i = 0; i < screenshot.height; i++) {
|
||||||
fos.write(screenshot.data, rowbytes * i, rowbytes);
|
fos.write(screenshot.data, rowbytes * i, rowbytes);
|
||||||
|
|
Loading…
Reference in New Issue