mirror of
https://codeberg.org/Freeyourgadget/Gadgetbridge
synced 2024-11-04 17:27:24 +01:00
Lefun: Add command serializers
This commit is contained in:
parent
fd56db55c4
commit
265260810a
@ -23,9 +23,52 @@ import java.util.UUID;
|
|||||||
import static nodomain.freeyourgadget.gadgetbridge.service.btle.AbstractBTLEDeviceSupport.BASE_UUID;
|
import static nodomain.freeyourgadget.gadgetbridge.service.btle.AbstractBTLEDeviceSupport.BASE_UUID;
|
||||||
|
|
||||||
public class LefunConstants {
|
public class LefunConstants {
|
||||||
|
// BLE UUIDs
|
||||||
public static final UUID UUID_SERVICE_LEFUN = UUID.fromString(String.format(BASE_UUID, "18D0"));
|
public static final UUID UUID_SERVICE_LEFUN = UUID.fromString(String.format(BASE_UUID, "18D0"));
|
||||||
|
|
||||||
|
// Coordinator constants
|
||||||
public static final String ADVERTISEMENT_NAME = "Lefun";
|
public static final String ADVERTISEMENT_NAME = "Lefun";
|
||||||
public static final String MANUFACTURER_NAME = "Teng Jin Da";
|
public static final String MANUFACTURER_NAME = "Teng Jin Da";
|
||||||
public static int NUM_ALARM_SLOTS = 5;
|
public static int NUM_ALARM_SLOTS = 5;
|
||||||
|
|
||||||
|
// Commands
|
||||||
|
public static final byte CMD_REQUEST_ID = (byte)0xab;
|
||||||
|
public static final byte CMD_RESPONSE_ID = 0x55;
|
||||||
|
|
||||||
|
public static final int CMD_MAX_LENGTH = 20;
|
||||||
|
// 3 header bytes plus checksum
|
||||||
|
public static final int CMD_HEADER_LENGTH = 4;
|
||||||
|
|
||||||
|
public static final byte CMD_FIRMWARE_INFO = 0x00;
|
||||||
|
public static final byte CMD_BONDING_REQUEST = 0x01;
|
||||||
|
public static final byte CMD_SETTINGS = 0x02;
|
||||||
|
public static final byte CMD_BATTERY_LEVEL = 0x03;
|
||||||
|
public static final byte CMD_TIME = 0x04;
|
||||||
|
public static final byte CMD_ALARM = 0x05;
|
||||||
|
public static final byte CMD_PROFILE = 0x06;
|
||||||
|
public static final byte CMD_UI_PAGES = 0x07;
|
||||||
|
public static final byte CMD_FEATURES = 0x08;
|
||||||
|
public static final byte CMD_FIND_DEVICE = 0x09;
|
||||||
|
public static final byte CMD_FIND_PHONE = 0x0a;
|
||||||
|
public static final byte CMD_SEDENTARY_REMINDER_INTERVAL = 0x0b;
|
||||||
|
public static final byte CMD_HYDRATION_REMINDER_INTERVAL = 0x0c;
|
||||||
|
public static final byte CMD_REMOTE_CAMERA = 0x0d;
|
||||||
|
public static final byte CMD_REMOTE_CAMERA_TRIGGERED = 0x0e;
|
||||||
|
public static final byte CMD_PPG_START = 0x0f;
|
||||||
|
public static final byte CMD_PPG_RESULT = 0x10;
|
||||||
|
public static final byte CMD_PPG_DATA = 0x11;
|
||||||
|
public static final byte CMD_STEPS_DATA = 0x12;
|
||||||
|
public static final byte CMD_ACTIVITY_DATA = 0x13;
|
||||||
|
public static final byte CMD_SLEEP_TIME_DATA = 0x14;
|
||||||
|
public static final byte CMD_SLEEP_DATA = 0x15;
|
||||||
|
public static final byte CMD_NOTIFICATION = 0x17;
|
||||||
|
public static final byte CMD_LANGUAGE = 0x21;
|
||||||
|
public static final byte CMD_UNKNOWN_22 = 0x22;
|
||||||
|
public static final byte CMD_UNKNOWN_25 = 0x25;
|
||||||
|
public static final byte CMD_UNKNOWN_80 = (byte)0x80;
|
||||||
|
|
||||||
|
public static final int PPG_TYPE_INVALID = -1;
|
||||||
|
public static final int PPG_TYPE_HEART_RATE = 0;
|
||||||
|
public static final int PPG_TYPE_BLOOD_PRESSURE = 1;
|
||||||
|
public static final int PPG_TYPE_BLOOD_OXYGEN = 2;
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,41 @@
|
|||||||
|
/* Copyright (C) 2016-2020 Andreas Shimokawa, Carsten Pfeiffer, Daniele
|
||||||
|
Gobbetti
|
||||||
|
Copyright (C) 2020 Yukai Li
|
||||||
|
|
||||||
|
This file is part of Gadgetbridge.
|
||||||
|
|
||||||
|
Gadgetbridge is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Affero General Public License as published
|
||||||
|
by the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
Gadgetbridge is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU Affero General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Affero General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||||
|
package nodomain.freeyourgadget.gadgetbridge.devices.lefun;
|
||||||
|
|
||||||
|
public class LefunFeatureSupport {
|
||||||
|
public static final int SUPPORT_HEART_RATE = 1 << 2;
|
||||||
|
public static final int SUPPORT_BLOOD_PRESSURE = 1 << 3;
|
||||||
|
public static final int SUPPORT_FAKE_ECG = 1 << 10;
|
||||||
|
public static final int SUPPORT_ECG = 1 << 11;
|
||||||
|
public static final int SUPPORT_WALLPAPER_UPLOAD = 1 << 12;
|
||||||
|
|
||||||
|
public static final int RESERVE_BLOOD_OXYGEN = 1 << 0;
|
||||||
|
public static final int RESERVE_CLOCK_FACE_UPLOAD = 1 << 3;
|
||||||
|
public static final int RESERVE_CONTACTS = 1 << 5;
|
||||||
|
public static final int RESERVE_WALLPAPER = 1 << 6;
|
||||||
|
public static final int RESERVE_REMOTE_CAMERA = 1 << 7;
|
||||||
|
|
||||||
|
public static boolean checkSupported(short deviceSupport, int featureSupport) {
|
||||||
|
return (deviceSupport & featureSupport) == featureSupport;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean checkNotReserved(short deviceReserve, int featureReserve) {
|
||||||
|
return !((deviceReserve & featureReserve) == featureReserve);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,174 @@
|
|||||||
|
/* Copyright (C) 2016-2020 Andreas Shimokawa, Carsten Pfeiffer, Daniele
|
||||||
|
Gobbetti
|
||||||
|
Copyright (C) 2020 Yukai Li
|
||||||
|
|
||||||
|
This file is part of Gadgetbridge.
|
||||||
|
|
||||||
|
Gadgetbridge is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Affero General Public License as published
|
||||||
|
by the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
Gadgetbridge is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU Affero General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Affero General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||||
|
package nodomain.freeyourgadget.gadgetbridge.devices.lefun.commands;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.devices.lefun.LefunConstants;
|
||||||
|
|
||||||
|
public class AlarmCommand extends BaseCommand {
|
||||||
|
public static final int DOW_SUNDAY = 0;
|
||||||
|
public static final int DOW_MONDAY = 1;
|
||||||
|
public static final int DOW_TUESDAY = 2;
|
||||||
|
public static final int DOW_WEDNESDAY = 3;
|
||||||
|
public static final int DOW_THURSDAY = 4;
|
||||||
|
public static final int DOW_FRIDAY = 5;
|
||||||
|
public static final int DOW_SATURDAY = 6;
|
||||||
|
|
||||||
|
private byte op;
|
||||||
|
private byte index;
|
||||||
|
private boolean enabled;
|
||||||
|
// Snooze is not implemented how you think it would be
|
||||||
|
// Number of snoozes is decremented every time the alarm triggers, and the alarm time
|
||||||
|
// is moved forward by number of minutes in snooze time. It never gets reset to the
|
||||||
|
// original time.
|
||||||
|
private byte numOfSnoozes;
|
||||||
|
private byte snoozeTime;
|
||||||
|
private byte dayOfWeek;
|
||||||
|
private byte hour;
|
||||||
|
private byte minute;
|
||||||
|
|
||||||
|
private boolean setSuccess;
|
||||||
|
|
||||||
|
public byte getOp() {
|
||||||
|
return op;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setOp(byte op) {
|
||||||
|
if (op != OP_GET && op != OP_SET)
|
||||||
|
throw new IllegalArgumentException("Operation must be get or set");
|
||||||
|
this.op = op;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte getIndex() {
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setIndex(byte index) {
|
||||||
|
if (index < 0 || index >= LefunConstants.NUM_ALARM_SLOTS)
|
||||||
|
throw new IllegalArgumentException("Index must be between 0 and "
|
||||||
|
+ (LefunConstants.NUM_ALARM_SLOTS - 1) + " inclusive");
|
||||||
|
this.index = index;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isEnabled() {
|
||||||
|
return enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEnabled(boolean enabled) {
|
||||||
|
this.enabled = enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte getNumOfSnoozes() {
|
||||||
|
return numOfSnoozes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNumOfSnoozes(byte numOfSnoozes) {
|
||||||
|
this.numOfSnoozes = numOfSnoozes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte getSnoozeTime() {
|
||||||
|
return snoozeTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSnoozeTime(byte snoozeTime) {
|
||||||
|
this.snoozeTime = snoozeTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean getDayOfWeek(int day) {
|
||||||
|
if (day < 0 || day > 6)
|
||||||
|
throw new IllegalArgumentException("Invalid day of week");
|
||||||
|
return getBit(dayOfWeek, 1 << day);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDayOfWeek(int day, boolean enabled) {
|
||||||
|
if (day < 0 || day > 6)
|
||||||
|
throw new IllegalArgumentException("Invalid day of week");
|
||||||
|
dayOfWeek = setBit(dayOfWeek, 1 << day, enabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte getHour() {
|
||||||
|
return hour;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setHour(byte hour) {
|
||||||
|
if (hour < 0 || hour > 23)
|
||||||
|
throw new IllegalArgumentException("Hour must be between 0 and 23 inclusive");
|
||||||
|
this.hour = hour;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte getMinute() {
|
||||||
|
return minute;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMinute(byte minute) {
|
||||||
|
if (minute < 0 || minute > 59)
|
||||||
|
throw new IllegalArgumentException("Minute must be between 0 and 59 inclusive");
|
||||||
|
this.minute = minute;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isSetSuccess() {
|
||||||
|
return setSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void deserializeParams(byte id, ByteBuffer params) {
|
||||||
|
validateId(id, LefunConstants.CMD_ALARM);
|
||||||
|
|
||||||
|
if (params.limit() < 2)
|
||||||
|
throwUnexpectedLength();
|
||||||
|
|
||||||
|
op = params.get();
|
||||||
|
index = params.get();
|
||||||
|
if (op == OP_GET) {
|
||||||
|
if (params.limit() != 8)
|
||||||
|
throwUnexpectedLength();
|
||||||
|
|
||||||
|
enabled = params.get() == 1;
|
||||||
|
numOfSnoozes = params.get();
|
||||||
|
snoozeTime = params.get();
|
||||||
|
dayOfWeek = params.get();
|
||||||
|
hour = params.get();
|
||||||
|
minute = params.get();
|
||||||
|
} else if (op == OP_SET) {
|
||||||
|
if (params.limit() != 3)
|
||||||
|
throwUnexpectedLength();
|
||||||
|
|
||||||
|
setSuccess = params.get() == 1;
|
||||||
|
} else {
|
||||||
|
throw new IllegalArgumentException("Invalid operation type received");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected byte serializeParams(ByteBuffer params) {
|
||||||
|
params.put(op);
|
||||||
|
// No alarm ID for get; all of them are returned
|
||||||
|
if (op == OP_SET) {
|
||||||
|
params.put(index);
|
||||||
|
params.put((byte)(enabled ? 1: 0));
|
||||||
|
params.put(numOfSnoozes);
|
||||||
|
params.put(snoozeTime);
|
||||||
|
params.put(dayOfWeek);
|
||||||
|
params.put(hour);
|
||||||
|
params.put(minute);
|
||||||
|
}
|
||||||
|
return LefunConstants.CMD_ALARM;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,148 @@
|
|||||||
|
/* Copyright (C) 2016-2020 Andreas Shimokawa, Carsten Pfeiffer, Daniele
|
||||||
|
Gobbetti
|
||||||
|
Copyright (C) 2020 Yukai Li
|
||||||
|
|
||||||
|
This file is part of Gadgetbridge.
|
||||||
|
|
||||||
|
Gadgetbridge is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Affero General Public License as published
|
||||||
|
by the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
Gadgetbridge is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU Affero General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Affero General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||||
|
package nodomain.freeyourgadget.gadgetbridge.devices.lefun.commands;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.nio.ByteOrder;
|
||||||
|
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.devices.lefun.LefunConstants;
|
||||||
|
|
||||||
|
public abstract class BaseCommand {
|
||||||
|
// Common constants
|
||||||
|
public static final byte OP_GET = 0;
|
||||||
|
public static final byte OP_SET = 1;
|
||||||
|
|
||||||
|
abstract protected void deserializeParams(byte id, ByteBuffer params);
|
||||||
|
abstract protected byte serializeParams(ByteBuffer params);
|
||||||
|
|
||||||
|
public void deserialize(byte[] response) {
|
||||||
|
if (response.length < LefunConstants.CMD_HEADER_LENGTH)
|
||||||
|
throw new IllegalArgumentException("Response is too short");
|
||||||
|
if (calculateChecksum(response, 0, response.length - 1) != response[response.length - 1])
|
||||||
|
throw new IllegalArgumentException("Incorrect message checksum");
|
||||||
|
ByteBuffer buffer = ByteBuffer.wrap(response, LefunConstants.CMD_HEADER_LENGTH - 1,
|
||||||
|
response.length - LefunConstants.CMD_HEADER_LENGTH);
|
||||||
|
buffer.order(ByteOrder.BIG_ENDIAN);
|
||||||
|
deserializeParams(response[2], buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] serialize() {
|
||||||
|
ByteBuffer buffer = ByteBuffer.allocate(LefunConstants.CMD_MAX_LENGTH - LefunConstants.CMD_HEADER_LENGTH);
|
||||||
|
buffer.order(ByteOrder.BIG_ENDIAN);
|
||||||
|
byte id = serializeParams(buffer);
|
||||||
|
return makeCommand(id, buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
static protected byte calculateChecksum(byte[] data, int offset, int length) {
|
||||||
|
byte checksum = 0;
|
||||||
|
for (int i = offset; i < offset + length; ++i) {
|
||||||
|
byte b = data[i];
|
||||||
|
for (int j = 0; j < 8; ++j) {
|
||||||
|
if (((b ^ checksum) & 1) == 0) {
|
||||||
|
checksum >>= 1;
|
||||||
|
} else {
|
||||||
|
checksum = (byte) ((checksum ^ 0x18) >> 1 | 0x80);
|
||||||
|
}
|
||||||
|
b >>= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return checksum;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Builds a command given ID and parameters buffer.
|
||||||
|
*
|
||||||
|
* @param id the command ID
|
||||||
|
* @param params the parameters buffer
|
||||||
|
* @return the assembled command buffer
|
||||||
|
*/
|
||||||
|
protected byte[] makeCommand(byte id, ByteBuffer params) {
|
||||||
|
if (params.position() > LefunConstants.CMD_MAX_LENGTH - LefunConstants.CMD_HEADER_LENGTH)
|
||||||
|
throw new IllegalArgumentException("params is too long to fit");
|
||||||
|
|
||||||
|
int paramsLength = params.position();
|
||||||
|
byte[] request = new byte[paramsLength + LefunConstants.CMD_HEADER_LENGTH];
|
||||||
|
request[0] = LefunConstants.CMD_REQUEST_ID;
|
||||||
|
request[1] = (byte) request.length;
|
||||||
|
request[2] = id;
|
||||||
|
params.flip();
|
||||||
|
params.get(request, LefunConstants.CMD_HEADER_LENGTH - 1, paramsLength);
|
||||||
|
request[request.length - 1] = calculateChecksum(request, 0, request.length - 1);
|
||||||
|
return request;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void throwUnexpectedLength() {
|
||||||
|
throw new IllegalArgumentException("Unexpected parameters length");
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void validateId(byte id, byte expectedId) {
|
||||||
|
if (id != expectedId)
|
||||||
|
throw new IllegalArgumentException("Wrong command ID");
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void validateIdAndLength(byte id, ByteBuffer params, byte expectedId, int expectedLength) {
|
||||||
|
validateId(id, expectedId);
|
||||||
|
if (params.limit() != expectedLength)
|
||||||
|
throwUnexpectedLength();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected boolean getBit(int value, int mask) {
|
||||||
|
return (value & mask) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected int setBit(int value, int mask, boolean set) {
|
||||||
|
if (set) {
|
||||||
|
return value | mask;
|
||||||
|
} else {
|
||||||
|
return value & ~mask;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected short setBit(short value, int mask, boolean set) {
|
||||||
|
if (set) {
|
||||||
|
return (short)(value | mask);
|
||||||
|
} else {
|
||||||
|
return (short)(value & ~mask);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected byte setBit(byte value, int mask, boolean set) {
|
||||||
|
if (set) {
|
||||||
|
return (byte)(value | mask);
|
||||||
|
} else {
|
||||||
|
return (byte)(value & ~mask);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find index of first bit that is set
|
||||||
|
* @param value
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
protected int getLowestSetBitIndex(int value) {
|
||||||
|
if (value == 0) return -1;
|
||||||
|
|
||||||
|
int i = 0;
|
||||||
|
while ((value & 1) == 0) {
|
||||||
|
++i;
|
||||||
|
value >>= 1;
|
||||||
|
}
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,84 @@
|
|||||||
|
/* Copyright (C) 2016-2020 Andreas Shimokawa, Carsten Pfeiffer, Daniele
|
||||||
|
Gobbetti
|
||||||
|
Copyright (C) 2020 Yukai Li
|
||||||
|
|
||||||
|
This file is part of Gadgetbridge.
|
||||||
|
|
||||||
|
Gadgetbridge is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Affero General Public License as published
|
||||||
|
by the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
Gadgetbridge is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU Affero General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Affero General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||||
|
package nodomain.freeyourgadget.gadgetbridge.devices.lefun.commands;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.devices.lefun.LefunConstants;
|
||||||
|
|
||||||
|
public class Cmd22Command extends BaseCommand {
|
||||||
|
private byte op;
|
||||||
|
private short unknown;
|
||||||
|
|
||||||
|
private boolean setSuccess;
|
||||||
|
|
||||||
|
public byte getOp() {
|
||||||
|
return op;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setOp(byte op) {
|
||||||
|
if (op != OP_GET && op != OP_SET)
|
||||||
|
throw new IllegalArgumentException("Operation must be get or set");
|
||||||
|
this.op = op;
|
||||||
|
}
|
||||||
|
|
||||||
|
public short getUnknown() {
|
||||||
|
return unknown;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUnknown(short unknown) {
|
||||||
|
this.unknown = unknown;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isSetSuccess() {
|
||||||
|
return setSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void deserializeParams(byte id, ByteBuffer params) {
|
||||||
|
validateId(id, LefunConstants.CMD_UNKNOWN_22);
|
||||||
|
|
||||||
|
if (params.limit() < 1)
|
||||||
|
throwUnexpectedLength();
|
||||||
|
|
||||||
|
op = params.get();
|
||||||
|
if (op == OP_GET) {
|
||||||
|
if (params.limit() != 3)
|
||||||
|
throwUnexpectedLength();
|
||||||
|
|
||||||
|
unknown = params.getShort();
|
||||||
|
} else if (op == OP_SET) {
|
||||||
|
if (params.limit() != 2)
|
||||||
|
throwUnexpectedLength();
|
||||||
|
|
||||||
|
setSuccess = params.get() == 1;
|
||||||
|
} else {
|
||||||
|
throw new IllegalArgumentException("Invalid operation type received");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected byte serializeParams(ByteBuffer params) {
|
||||||
|
params.put(op);
|
||||||
|
if (op == OP_SET) {
|
||||||
|
params.putShort(unknown);
|
||||||
|
}
|
||||||
|
return LefunConstants.CMD_UNKNOWN_22;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,86 @@
|
|||||||
|
/* Copyright (C) 2016-2020 Andreas Shimokawa, Carsten Pfeiffer, Daniele
|
||||||
|
Gobbetti
|
||||||
|
Copyright (C) 2020 Yukai Li
|
||||||
|
|
||||||
|
This file is part of Gadgetbridge.
|
||||||
|
|
||||||
|
Gadgetbridge is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Affero General Public License as published
|
||||||
|
by the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
Gadgetbridge is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU Affero General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Affero General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||||
|
package nodomain.freeyourgadget.gadgetbridge.devices.lefun.commands;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.devices.lefun.LefunConstants;
|
||||||
|
|
||||||
|
public class Cmd25Command extends BaseCommand {
|
||||||
|
private byte op;
|
||||||
|
private int unknown;
|
||||||
|
|
||||||
|
private boolean setSuccess;
|
||||||
|
|
||||||
|
public byte getOp() {
|
||||||
|
return op;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setOp(byte op) {
|
||||||
|
if (op != OP_GET && op != OP_SET)
|
||||||
|
throw new IllegalArgumentException("Operation must be get or set");
|
||||||
|
this.op = op;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getUnknown() {
|
||||||
|
return unknown;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUnknown(int unknown) {
|
||||||
|
if (unknown < 0 || unknown > 65000)
|
||||||
|
throw new IllegalArgumentException("Value must be between 0 and 65000 inclusive");
|
||||||
|
this.unknown = unknown;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isSetSuccess() {
|
||||||
|
return setSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void deserializeParams(byte id, ByteBuffer params) {
|
||||||
|
validateId(id, LefunConstants.CMD_UNKNOWN_25);
|
||||||
|
|
||||||
|
if (params.limit() < 1)
|
||||||
|
throwUnexpectedLength();
|
||||||
|
|
||||||
|
op = params.get();
|
||||||
|
if (op == OP_GET) {
|
||||||
|
if (params.limit() != 5)
|
||||||
|
throwUnexpectedLength();
|
||||||
|
|
||||||
|
unknown = params.getInt();
|
||||||
|
} else if (op == OP_SET) {
|
||||||
|
if (params.limit() != 2)
|
||||||
|
throwUnexpectedLength();
|
||||||
|
|
||||||
|
setSuccess = params.get() == 1;
|
||||||
|
} else {
|
||||||
|
throw new IllegalArgumentException("Invalid operation type received");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected byte serializeParams(ByteBuffer params) {
|
||||||
|
params.put(op);
|
||||||
|
if (op == OP_SET) {
|
||||||
|
params.putInt(unknown);
|
||||||
|
}
|
||||||
|
return LefunConstants.CMD_UNKNOWN_25;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,95 @@
|
|||||||
|
/* Copyright (C) 2016-2020 Andreas Shimokawa, Carsten Pfeiffer, Daniele
|
||||||
|
Gobbetti
|
||||||
|
Copyright (C) 2020 Yukai Li
|
||||||
|
|
||||||
|
This file is part of Gadgetbridge.
|
||||||
|
|
||||||
|
Gadgetbridge is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Affero General Public License as published
|
||||||
|
by the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
Gadgetbridge is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU Affero General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Affero General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||||
|
package nodomain.freeyourgadget.gadgetbridge.devices.lefun.commands;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.devices.lefun.LefunConstants;
|
||||||
|
|
||||||
|
public class FeaturesCommand extends BaseCommand {
|
||||||
|
public static final int FEATURE_RAISE_TO_WAKE = 0;
|
||||||
|
public static final int FEATURE_SEDENTARY_REMINDER = 1;
|
||||||
|
public static final int FEATURE_HYDRATION_REMINDER = 2;
|
||||||
|
public static final int FEATURE_REMOTE_CAMERA = 3;
|
||||||
|
public static final int FEATURE_UNKNOWN_4 = 4;
|
||||||
|
public static final int FEATURE_ANTI_LOST = 5;
|
||||||
|
|
||||||
|
private byte op;
|
||||||
|
private short features;
|
||||||
|
|
||||||
|
private boolean setSuccess;
|
||||||
|
|
||||||
|
public byte getOp() {
|
||||||
|
return op;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setOp(byte op) {
|
||||||
|
if (op != OP_GET && op != OP_SET)
|
||||||
|
throw new IllegalArgumentException("Operation must be get or set");
|
||||||
|
this.op = op;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean getFeature(int index) {
|
||||||
|
if (index < 0 || index > 5)
|
||||||
|
throw new IllegalArgumentException("Index must be between 0 and 5 inclusive");
|
||||||
|
return getBit(features, 1 << index);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFeature(int index, boolean enabled) {
|
||||||
|
if (index < 0 || index > 5)
|
||||||
|
throw new IllegalArgumentException("Index must be between 0 and 5 inclusive");
|
||||||
|
features = setBit(features, 1 << index, enabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isSetSuccess() {
|
||||||
|
return setSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void deserializeParams(byte id, ByteBuffer params) {
|
||||||
|
validateId(id, LefunConstants.CMD_FEATURES);
|
||||||
|
|
||||||
|
if (params.limit() < 1)
|
||||||
|
throwUnexpectedLength();
|
||||||
|
|
||||||
|
op = params.get();
|
||||||
|
if (op == OP_GET) {
|
||||||
|
if (params.limit() != 3)
|
||||||
|
throwUnexpectedLength();
|
||||||
|
|
||||||
|
features = params.getShort();
|
||||||
|
} else if (op == OP_SET) {
|
||||||
|
if (params.limit() != 2)
|
||||||
|
throwUnexpectedLength();
|
||||||
|
|
||||||
|
setSuccess = params.get() == 1;
|
||||||
|
} else {
|
||||||
|
throw new IllegalArgumentException("Invalid operation type received");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected byte serializeParams(ByteBuffer params) {
|
||||||
|
params.put(op);
|
||||||
|
if (op == OP_SET) {
|
||||||
|
params.putShort(features);
|
||||||
|
}
|
||||||
|
return LefunConstants.CMD_FEATURES;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,43 @@
|
|||||||
|
package nodomain.freeyourgadget.gadgetbridge.devices.lefun.commands;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
|
/* Copyright (C) 2016-2020 Andreas Shimokawa, Carsten Pfeiffer, Daniele
|
||||||
|
Gobbetti
|
||||||
|
Copyright (C) 2020 Yukai Li
|
||||||
|
|
||||||
|
This file is part of Gadgetbridge.
|
||||||
|
|
||||||
|
Gadgetbridge is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Affero General Public License as published
|
||||||
|
by the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
Gadgetbridge is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU Affero General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Affero General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.devices.lefun.LefunConstants;
|
||||||
|
|
||||||
|
public class FindDeviceCommand extends BaseCommand {
|
||||||
|
private boolean success;
|
||||||
|
|
||||||
|
public boolean isSuccess() {
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void deserializeParams(byte id, ByteBuffer params) {
|
||||||
|
validateIdAndLength(id, params, LefunConstants.CMD_FIND_DEVICE, 1);
|
||||||
|
|
||||||
|
success = params.get() == 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected byte serializeParams(ByteBuffer params) {
|
||||||
|
return LefunConstants.CMD_FIND_DEVICE;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,35 @@
|
|||||||
|
/* Copyright (C) 2016-2020 Andreas Shimokawa, Carsten Pfeiffer, Daniele
|
||||||
|
Gobbetti
|
||||||
|
Copyright (C) 2020 Yukai Li
|
||||||
|
|
||||||
|
This file is part of Gadgetbridge.
|
||||||
|
|
||||||
|
Gadgetbridge is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Affero General Public License as published
|
||||||
|
by the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
Gadgetbridge is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU Affero General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Affero General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||||
|
package nodomain.freeyourgadget.gadgetbridge.devices.lefun.commands;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.devices.lefun.LefunConstants;
|
||||||
|
|
||||||
|
public class FindPhoneCommand extends BaseCommand {
|
||||||
|
@Override
|
||||||
|
protected void deserializeParams(byte id, ByteBuffer params) {
|
||||||
|
validateIdAndLength(id, params, LefunConstants.CMD_FIND_PHONE, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected byte serializeParams(ByteBuffer params) {
|
||||||
|
return LefunConstants.CMD_FIND_PHONE;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,110 @@
|
|||||||
|
/* Copyright (C) 2016-2020 Andreas Shimokawa, Carsten Pfeiffer, Daniele
|
||||||
|
Gobbetti
|
||||||
|
Copyright (C) 2020 Yukai Li
|
||||||
|
|
||||||
|
This file is part of Gadgetbridge.
|
||||||
|
|
||||||
|
Gadgetbridge is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Affero General Public License as published
|
||||||
|
by the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
Gadgetbridge is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU Affero General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Affero General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||||
|
package nodomain.freeyourgadget.gadgetbridge.devices.lefun.commands;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.devices.lefun.LefunConstants;
|
||||||
|
|
||||||
|
public class GetActivityDataCommand extends BaseCommand {
|
||||||
|
private byte daysAgo;
|
||||||
|
private byte totalRecords;
|
||||||
|
private byte currentRecord;
|
||||||
|
private byte year;
|
||||||
|
private byte month;
|
||||||
|
private byte day;
|
||||||
|
private byte hour;
|
||||||
|
private byte minute;
|
||||||
|
private short steps;
|
||||||
|
private short distance; // m
|
||||||
|
private short calories; // calories
|
||||||
|
|
||||||
|
public byte getDaysAgo() {
|
||||||
|
return daysAgo;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDaysAgo(byte daysAgo) {
|
||||||
|
if (daysAgo < 0 || daysAgo > 6)
|
||||||
|
throw new IllegalArgumentException("Days ago must be between 0 and 6 inclusive");
|
||||||
|
this.daysAgo = daysAgo;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte getTotalRecords() {
|
||||||
|
return totalRecords;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte getCurrentRecord() {
|
||||||
|
return currentRecord;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte getYear() {
|
||||||
|
return year;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte getMonth() {
|
||||||
|
return month;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte getDay() {
|
||||||
|
return day;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte getHour() {
|
||||||
|
return hour;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte getMinute() {
|
||||||
|
return minute;
|
||||||
|
}
|
||||||
|
|
||||||
|
public short getSteps() {
|
||||||
|
return steps;
|
||||||
|
}
|
||||||
|
|
||||||
|
public short getDistance() {
|
||||||
|
return distance;
|
||||||
|
}
|
||||||
|
|
||||||
|
public short getCalories() {
|
||||||
|
return calories;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void deserializeParams(byte id, ByteBuffer params) {
|
||||||
|
validateIdAndLength(id, params, LefunConstants.CMD_ACTIVITY_DATA, 14);
|
||||||
|
|
||||||
|
daysAgo = params.get();
|
||||||
|
totalRecords = params.get();
|
||||||
|
currentRecord = params.get();
|
||||||
|
year = params.get();
|
||||||
|
month = params.get();
|
||||||
|
day = params.get();
|
||||||
|
hour = params.get();
|
||||||
|
minute = params.get();
|
||||||
|
steps = params.getShort();
|
||||||
|
distance = params.getShort();
|
||||||
|
calories = params.getShort();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected byte serializeParams(ByteBuffer params) {
|
||||||
|
params.put(daysAgo);
|
||||||
|
return LefunConstants.CMD_ACTIVITY_DATA;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,43 @@
|
|||||||
|
/* Copyright (C) 2016-2020 Andreas Shimokawa, Carsten Pfeiffer, Daniele
|
||||||
|
Gobbetti
|
||||||
|
Copyright (C) 2020 Yukai Li
|
||||||
|
|
||||||
|
This file is part of Gadgetbridge.
|
||||||
|
|
||||||
|
Gadgetbridge is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Affero General Public License as published
|
||||||
|
by the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
Gadgetbridge is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU Affero General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Affero General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||||
|
package nodomain.freeyourgadget.gadgetbridge.devices.lefun.commands;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.devices.lefun.LefunConstants;
|
||||||
|
|
||||||
|
public class GetBatteryLevelCommand extends BaseCommand {
|
||||||
|
private byte batteryLevel;
|
||||||
|
|
||||||
|
public byte getBatteryLevel() {
|
||||||
|
return batteryLevel;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void deserializeParams(byte id, ByteBuffer params) {
|
||||||
|
validateIdAndLength(id, params, LefunConstants.CMD_BATTERY_LEVEL, 1);
|
||||||
|
|
||||||
|
batteryLevel = params.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected byte serializeParams(ByteBuffer params) {
|
||||||
|
return LefunConstants.CMD_BATTERY_LEVEL;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,78 @@
|
|||||||
|
package nodomain.freeyourgadget.gadgetbridge.devices.lefun.commands;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
/* Copyright (C) 2016-2020 Andreas Shimokawa, Carsten Pfeiffer, Daniele
|
||||||
|
Gobbetti
|
||||||
|
Copyright (C) 2020 Yukai Li
|
||||||
|
|
||||||
|
This file is part of Gadgetbridge.
|
||||||
|
|
||||||
|
Gadgetbridge is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Affero General Public License as published
|
||||||
|
by the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
Gadgetbridge is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU Affero General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Affero General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.devices.lefun.LefunConstants;
|
||||||
|
|
||||||
|
public class GetFirmwareInfoCommand extends BaseCommand {
|
||||||
|
private short supportCode;
|
||||||
|
private short devTypeReserveCode;
|
||||||
|
private String typeCode;
|
||||||
|
private short hardwareVersion;
|
||||||
|
private short softwareVersion;
|
||||||
|
private String vendorCode;
|
||||||
|
|
||||||
|
public short getSupportCode() {
|
||||||
|
return supportCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public short getDevTypeReserveCode() {
|
||||||
|
return devTypeReserveCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTypeCode() {
|
||||||
|
return typeCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public short getHardwareVersion() {
|
||||||
|
return hardwareVersion;
|
||||||
|
}
|
||||||
|
|
||||||
|
public short getSoftwareVersion() {
|
||||||
|
return softwareVersion;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getVendorCode() {
|
||||||
|
return vendorCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void deserializeParams(byte id, ByteBuffer params) {
|
||||||
|
validateIdAndLength(id, params, LefunConstants.CMD_FIRMWARE_INFO, 16);
|
||||||
|
|
||||||
|
supportCode = (short)(params.get() | (params.get() << 8));
|
||||||
|
devTypeReserveCode = params.getShort();
|
||||||
|
byte[] typeCodeBytes = new byte[4];
|
||||||
|
params.get(typeCodeBytes);
|
||||||
|
typeCode = new String(typeCodeBytes, StandardCharsets.US_ASCII);
|
||||||
|
hardwareVersion = params.getShort();
|
||||||
|
softwareVersion = params.getShort();
|
||||||
|
byte[] vendorCodeBytes = new byte[4];
|
||||||
|
params.get(vendorCodeBytes);
|
||||||
|
vendorCode = new String(vendorCodeBytes, StandardCharsets.US_ASCII);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected byte serializeParams(ByteBuffer params) {
|
||||||
|
return LefunConstants.CMD_FIRMWARE_INFO;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,118 @@
|
|||||||
|
package nodomain.freeyourgadget.gadgetbridge.devices.lefun.commands;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.devices.lefun.LefunConstants;
|
||||||
|
|
||||||
|
public class GetPpgDataCommand extends BaseCommand {
|
||||||
|
private byte ppgType;
|
||||||
|
private short totalRecords;
|
||||||
|
private short currentRecord;
|
||||||
|
private byte year;
|
||||||
|
private byte month;
|
||||||
|
private byte day;
|
||||||
|
private byte hour;
|
||||||
|
private byte minute;
|
||||||
|
private byte second;
|
||||||
|
private byte[] ppgData;
|
||||||
|
|
||||||
|
public int getPpgType() {
|
||||||
|
return getLowestSetBitIndex(ppgType);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPpgType(int type) {
|
||||||
|
if (type < 0 || type > 2)
|
||||||
|
throw new IllegalArgumentException("Invalid PPG type");
|
||||||
|
this.ppgType = (byte)(1 << type);
|
||||||
|
}
|
||||||
|
|
||||||
|
public short getTotalRecords() {
|
||||||
|
return totalRecords;
|
||||||
|
}
|
||||||
|
|
||||||
|
public short getCurrentRecord() {
|
||||||
|
return currentRecord;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte getYear() {
|
||||||
|
return year;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte getMonth() {
|
||||||
|
return month;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte getDay() {
|
||||||
|
return day;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte getHour() {
|
||||||
|
return hour;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte getMinute() {
|
||||||
|
return minute;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte getSecond() {
|
||||||
|
return second;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] getPpgData() {
|
||||||
|
return ppgData;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void deserializeParams(byte id, ByteBuffer params) {
|
||||||
|
validateId(id, LefunConstants.CMD_PPG_DATA);
|
||||||
|
|
||||||
|
if (params.limit() < 9)
|
||||||
|
throwUnexpectedLength();
|
||||||
|
|
||||||
|
ppgType = params.get();
|
||||||
|
totalRecords = params.get();
|
||||||
|
currentRecord = params.get();
|
||||||
|
year = params.get();
|
||||||
|
month = params.get();
|
||||||
|
day = params.get();
|
||||||
|
hour = params.get();
|
||||||
|
minute = params.get();
|
||||||
|
second = params.get();
|
||||||
|
|
||||||
|
int typeIndex = getPpgType();
|
||||||
|
int dataLength;
|
||||||
|
switch (typeIndex) {
|
||||||
|
case LefunConstants.PPG_TYPE_HEART_RATE:
|
||||||
|
case LefunConstants.PPG_TYPE_BLOOD_OXYGEN:
|
||||||
|
dataLength = 1;
|
||||||
|
break;
|
||||||
|
case LefunConstants.PPG_TYPE_BLOOD_PRESSURE:
|
||||||
|
dataLength = 2;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new IllegalArgumentException("Unknown PPG type");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (params.limit() < dataLength + 9)
|
||||||
|
throwUnexpectedLength();
|
||||||
|
|
||||||
|
ppgData = new byte[dataLength];
|
||||||
|
params.get(ppgData);
|
||||||
|
|
||||||
|
// Extended count/index
|
||||||
|
if (params.limit() == dataLength + 11)
|
||||||
|
{
|
||||||
|
totalRecords |= params.get() << 8;
|
||||||
|
currentRecord |= params.get() << 8;
|
||||||
|
}
|
||||||
|
else if (params.limit() > dataLength + 11) {
|
||||||
|
throwUnexpectedLength();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected byte serializeParams(ByteBuffer params) {
|
||||||
|
params.put(ppgType);
|
||||||
|
return LefunConstants.CMD_PPG_DATA;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,102 @@
|
|||||||
|
package nodomain.freeyourgadget.gadgetbridge.devices.lefun.commands;
|
||||||
|
|
||||||
|
/* Copyright (C) 2016-2020 Andreas Shimokawa, Carsten Pfeiffer, Daniele
|
||||||
|
Gobbetti
|
||||||
|
Copyright (C) 2020 Yukai Li
|
||||||
|
|
||||||
|
This file is part of Gadgetbridge.
|
||||||
|
|
||||||
|
Gadgetbridge is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Affero General Public License as published
|
||||||
|
by the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
Gadgetbridge is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU Affero General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Affero General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.devices.lefun.LefunConstants;
|
||||||
|
|
||||||
|
public class GetSleepDataCommand extends BaseCommand {
|
||||||
|
public static final int SLEEP_TYPE_AWAKE = 1;
|
||||||
|
public static final int SLEEP_TYPE_LIGHT_SLEEP = 2;
|
||||||
|
public static final int SLEEP_TYPE_DEEP_SLEEP = 3;
|
||||||
|
|
||||||
|
private byte daysAgo;
|
||||||
|
private short totalRecords;
|
||||||
|
private short currentRecord;
|
||||||
|
private byte year;
|
||||||
|
private byte month;
|
||||||
|
private byte day;
|
||||||
|
private byte hour;
|
||||||
|
private byte minute;
|
||||||
|
private byte sleepType;
|
||||||
|
|
||||||
|
public byte getDaysAgo() {
|
||||||
|
return daysAgo;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDaysAgo(byte daysAgo) {
|
||||||
|
if (daysAgo < 0 || daysAgo > 6)
|
||||||
|
throw new IllegalArgumentException("Days ago must be between 0 and 6 inclusive");
|
||||||
|
this.daysAgo = daysAgo;
|
||||||
|
}
|
||||||
|
|
||||||
|
public short getTotalRecords() {
|
||||||
|
return totalRecords;
|
||||||
|
}
|
||||||
|
|
||||||
|
public short getCurrentRecord() {
|
||||||
|
return currentRecord;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte getYear() {
|
||||||
|
return year;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte getMonth() {
|
||||||
|
return month;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte getDay() {
|
||||||
|
return day;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte getHour() {
|
||||||
|
return hour;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte getMinute() {
|
||||||
|
return minute;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte getSleepType() {
|
||||||
|
return sleepType;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void deserializeParams(byte id, ByteBuffer params) {
|
||||||
|
validateIdAndLength(id, params, LefunConstants.CMD_SLEEP_DATA, 11);
|
||||||
|
|
||||||
|
daysAgo = params.get();
|
||||||
|
totalRecords = params.getShort();
|
||||||
|
currentRecord = params.getShort();
|
||||||
|
year = params.get();
|
||||||
|
month = params.get();
|
||||||
|
day = params.get();
|
||||||
|
hour = params.get();
|
||||||
|
minute = params.get();
|
||||||
|
sleepType = params.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected byte serializeParams(ByteBuffer params) {
|
||||||
|
params.put(daysAgo);
|
||||||
|
return LefunConstants.CMD_SLEEP_DATA;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,75 @@
|
|||||||
|
/* Copyright (C) 2016-2020 Andreas Shimokawa, Carsten Pfeiffer, Daniele
|
||||||
|
Gobbetti
|
||||||
|
Copyright (C) 2020 Yukai Li
|
||||||
|
|
||||||
|
This file is part of Gadgetbridge.
|
||||||
|
|
||||||
|
Gadgetbridge is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Affero General Public License as published
|
||||||
|
by the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
Gadgetbridge is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU Affero General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Affero General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||||
|
package nodomain.freeyourgadget.gadgetbridge.devices.lefun.commands;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.devices.lefun.LefunConstants;
|
||||||
|
|
||||||
|
public class GetSleepTimeCommand extends BaseCommand {
|
||||||
|
private byte daysAgo;
|
||||||
|
private byte year;
|
||||||
|
private byte month;
|
||||||
|
private byte day;
|
||||||
|
private short minutes;
|
||||||
|
|
||||||
|
public byte getDaysAgo() {
|
||||||
|
return daysAgo;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDaysAgo(byte daysAgo) {
|
||||||
|
if (daysAgo < 0 || daysAgo > 6)
|
||||||
|
throw new IllegalArgumentException("Days ago must be between 0 and 6 inclusive");
|
||||||
|
this.daysAgo = daysAgo;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte getYear() {
|
||||||
|
return year;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte getMonth() {
|
||||||
|
return month;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte getDay() {
|
||||||
|
return day;
|
||||||
|
}
|
||||||
|
|
||||||
|
public short getMinutes() {
|
||||||
|
return minutes;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void deserializeParams(byte id, ByteBuffer params) {
|
||||||
|
validateIdAndLength(id, params, LefunConstants.CMD_SLEEP_TIME_DATA, 6);
|
||||||
|
|
||||||
|
daysAgo = params.get();
|
||||||
|
year = params.get();
|
||||||
|
month = params.get();
|
||||||
|
day = params.get();
|
||||||
|
minutes = params.getShort();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected byte serializeParams(ByteBuffer params) {
|
||||||
|
params.put(daysAgo);
|
||||||
|
return LefunConstants.CMD_SLEEP_TIME_DATA;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,86 @@
|
|||||||
|
/* Copyright (C) 2016-2020 Andreas Shimokawa, Carsten Pfeiffer, Daniele
|
||||||
|
Gobbetti
|
||||||
|
Copyright (C) 2020 Yukai Li
|
||||||
|
|
||||||
|
This file is part of Gadgetbridge.
|
||||||
|
|
||||||
|
Gadgetbridge is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Affero General Public License as published
|
||||||
|
by the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
Gadgetbridge is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU Affero General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Affero General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||||
|
package nodomain.freeyourgadget.gadgetbridge.devices.lefun.commands;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.devices.lefun.LefunConstants;
|
||||||
|
|
||||||
|
public class GetStepsDataCommand extends BaseCommand {
|
||||||
|
private byte daysAgo;
|
||||||
|
private byte year;
|
||||||
|
private byte month;
|
||||||
|
private byte day;
|
||||||
|
private int steps;
|
||||||
|
private int distance; // m
|
||||||
|
private int calories; // calories
|
||||||
|
|
||||||
|
public byte getDaysAgo() {
|
||||||
|
return daysAgo;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDaysAgo(byte daysAgo) {
|
||||||
|
if (daysAgo < 0 || daysAgo > 6)
|
||||||
|
throw new IllegalArgumentException("Days ago must be between 0 and 6 inclusive");
|
||||||
|
this.daysAgo = daysAgo;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte getYear() {
|
||||||
|
return year;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte getMonth() {
|
||||||
|
return month;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte getDay() {
|
||||||
|
return day;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getSteps() {
|
||||||
|
return steps;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getDistance() {
|
||||||
|
return distance;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getCalories() {
|
||||||
|
return calories;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void deserializeParams(byte id, ByteBuffer params) {
|
||||||
|
validateIdAndLength(id, params, LefunConstants.CMD_STEPS_DATA, 16);
|
||||||
|
|
||||||
|
daysAgo = params.get();
|
||||||
|
year = params.get();
|
||||||
|
month = params.get();
|
||||||
|
day = params.get();
|
||||||
|
steps = params.getInt();
|
||||||
|
distance = params.getInt();
|
||||||
|
calories = params.getInt();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected byte serializeParams(ByteBuffer params) {
|
||||||
|
params.put(daysAgo);
|
||||||
|
return LefunConstants.CMD_STEPS_DATA;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,86 @@
|
|||||||
|
/* Copyright (C) 2016-2020 Andreas Shimokawa, Carsten Pfeiffer, Daniele
|
||||||
|
Gobbetti
|
||||||
|
Copyright (C) 2020 Yukai Li
|
||||||
|
|
||||||
|
This file is part of Gadgetbridge.
|
||||||
|
|
||||||
|
Gadgetbridge is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Affero General Public License as published
|
||||||
|
by the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
Gadgetbridge is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU Affero General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Affero General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||||
|
package nodomain.freeyourgadget.gadgetbridge.devices.lefun.commands;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.devices.lefun.LefunConstants;
|
||||||
|
|
||||||
|
public class HydrationReminderIntervalCommand extends BaseCommand {
|
||||||
|
private byte op;
|
||||||
|
private byte hydrationReminderInterval;
|
||||||
|
|
||||||
|
private boolean setSuccess;
|
||||||
|
|
||||||
|
public byte getOp() {
|
||||||
|
return op;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setOp(byte op) {
|
||||||
|
if (op != OP_GET && op != OP_SET)
|
||||||
|
throw new IllegalArgumentException("Operation must be get or set");
|
||||||
|
this.op = op;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte getHydrationReminderInterval() {
|
||||||
|
return hydrationReminderInterval;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setHydrationReminderInterval(byte hydrationReminderInterval) {
|
||||||
|
if (hydrationReminderInterval == 0)
|
||||||
|
throw new IllegalArgumentException("Interval must be non-zero");
|
||||||
|
this.hydrationReminderInterval = hydrationReminderInterval;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isSetSuccess() {
|
||||||
|
return setSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void deserializeParams(byte id, ByteBuffer params) {
|
||||||
|
validateId(id, LefunConstants.CMD_HYDRATION_REMINDER_INTERVAL);
|
||||||
|
|
||||||
|
if (params.limit() < 1)
|
||||||
|
throwUnexpectedLength();
|
||||||
|
|
||||||
|
op = params.get();
|
||||||
|
if (op == OP_GET) {
|
||||||
|
if (params.limit() != 2)
|
||||||
|
throwUnexpectedLength();
|
||||||
|
|
||||||
|
hydrationReminderInterval = params.get();
|
||||||
|
} else if (op == OP_SET) {
|
||||||
|
if (params.limit() != 2)
|
||||||
|
throwUnexpectedLength();
|
||||||
|
|
||||||
|
setSuccess = params.get() == 1;
|
||||||
|
} else {
|
||||||
|
throw new IllegalArgumentException("Invalid operation type received");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected byte serializeParams(ByteBuffer params) {
|
||||||
|
params.put(op);
|
||||||
|
if (op == OP_SET) {
|
||||||
|
params.put(hydrationReminderInterval);
|
||||||
|
}
|
||||||
|
return LefunConstants.CMD_HYDRATION_REMINDER_INTERVAL;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,121 @@
|
|||||||
|
/* Copyright (C) 2016-2020 Andreas Shimokawa, Carsten Pfeiffer, Daniele
|
||||||
|
Gobbetti
|
||||||
|
Copyright (C) 2020 Yukai Li
|
||||||
|
|
||||||
|
This file is part of Gadgetbridge.
|
||||||
|
|
||||||
|
Gadgetbridge is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Affero General Public License as published
|
||||||
|
by the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
Gadgetbridge is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU Affero General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Affero General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||||
|
package nodomain.freeyourgadget.gadgetbridge.devices.lefun.commands;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.devices.lefun.LefunConstants;
|
||||||
|
|
||||||
|
public class NotificationCommand extends BaseCommand {
|
||||||
|
public static final byte SERVICE_TYPE_CALL = 0;
|
||||||
|
public static final byte SERVICE_TYPE_TEXT = 1;
|
||||||
|
public static final byte SERVICE_TYPE_QQ = 2;
|
||||||
|
public static final byte SERVICE_TYPE_WECHAT = 3;
|
||||||
|
public static final byte SERVICE_TYPE_EXTENDED = 4;
|
||||||
|
|
||||||
|
public static final byte EXTENDED_SERVICE_TYPE_FACEBOOK = 1;
|
||||||
|
public static final byte EXTENDED_SERVICE_TYPE_TWITTER = 2;
|
||||||
|
public static final byte EXTENDED_SERVICE_TYPE_LINKEDIN = 3;
|
||||||
|
public static final byte EXTENDED_SERVICE_TYPE_WHATSAPP = 4;
|
||||||
|
public static final byte EXTENDED_SERVICE_TYPE_LINE = 5;
|
||||||
|
public static final byte EXTENDED_SERVICE_TYPE_KAKAOTALK = 6;
|
||||||
|
|
||||||
|
private byte serviceType;
|
||||||
|
private byte totalPieces;
|
||||||
|
private byte currentPiece;
|
||||||
|
private byte extendedServiceType;
|
||||||
|
private byte[] payload;
|
||||||
|
|
||||||
|
public int getServiceType() {
|
||||||
|
return getLowestSetBitIndex(serviceType);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setServiceType(int type) {
|
||||||
|
if (type < 0 || type > 4)
|
||||||
|
throw new IllegalArgumentException("Invalid service type");
|
||||||
|
this.serviceType = (byte)(1 << type);
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte getTotalPieces() {
|
||||||
|
return totalPieces;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTotalPieces(byte totalPieces) {
|
||||||
|
// This check isn't on device, but should probably be added
|
||||||
|
if (totalPieces == 0)
|
||||||
|
throw new IllegalArgumentException("Total pieces must not be 0");
|
||||||
|
this.totalPieces = totalPieces;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte getCurrentPiece() {
|
||||||
|
return currentPiece;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCurrentPiece(byte currentPiece) {
|
||||||
|
// This check isn't on device, but should probably be added
|
||||||
|
if (currentPiece == 0)
|
||||||
|
throw new IllegalArgumentException("Current piece must not be 0");
|
||||||
|
this.currentPiece = currentPiece;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte getExtendedServiceType() {
|
||||||
|
return extendedServiceType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setExtendedServiceType(byte extendedServiceType) {
|
||||||
|
this.extendedServiceType = extendedServiceType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] getPayload() {
|
||||||
|
return payload;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPayload(byte[] payload) {
|
||||||
|
if (payload == null)
|
||||||
|
throw new IllegalArgumentException("Payload must not be null");
|
||||||
|
if (payload.length > 13)
|
||||||
|
throw new IllegalArgumentException("Payload is too long");
|
||||||
|
this.payload = payload;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void deserializeParams(byte id, ByteBuffer params) {
|
||||||
|
// We should not receive a response for this
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected byte serializeParams(ByteBuffer params) {
|
||||||
|
boolean hasExtendedServiceType = (serviceType & (1 << SERVICE_TYPE_EXTENDED)) != 0
|
||||||
|
&& (extendedServiceType & 0x0f) != 0 ;
|
||||||
|
int maxPayloadLength = hasExtendedServiceType ? 12 : 13;
|
||||||
|
|
||||||
|
if (payload.length > maxPayloadLength)
|
||||||
|
throw new IllegalStateException("Payload is too long");
|
||||||
|
|
||||||
|
params.put(serviceType);
|
||||||
|
params.put(totalPieces);
|
||||||
|
params.put(currentPiece);
|
||||||
|
if (hasExtendedServiceType)
|
||||||
|
params.put(extendedServiceType);
|
||||||
|
params.put(payload);
|
||||||
|
|
||||||
|
return LefunConstants.CMD_NOTIFICATION;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,72 @@
|
|||||||
|
/* Copyright (C) 2016-2020 Andreas Shimokawa, Carsten Pfeiffer, Daniele
|
||||||
|
Gobbetti
|
||||||
|
Copyright (C) 2020 Yukai Li
|
||||||
|
|
||||||
|
This file is part of Gadgetbridge.
|
||||||
|
|
||||||
|
Gadgetbridge is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Affero General Public License as published
|
||||||
|
by the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
Gadgetbridge is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU Affero General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Affero General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||||
|
package nodomain.freeyourgadget.gadgetbridge.devices.lefun.commands;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.devices.lefun.LefunConstants;
|
||||||
|
|
||||||
|
public class PpgResultCommand extends BaseCommand {
|
||||||
|
private byte ppgType;
|
||||||
|
private byte[] ppgData;
|
||||||
|
|
||||||
|
public int getPpgType() {
|
||||||
|
return getLowestSetBitIndex(ppgType);
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] getPpgData() {
|
||||||
|
return ppgData;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void deserializeParams(byte id, ByteBuffer params) {
|
||||||
|
validateId(id, LefunConstants.CMD_PPG_RESULT);
|
||||||
|
|
||||||
|
if (params.limit() < 1)
|
||||||
|
throwUnexpectedLength();
|
||||||
|
|
||||||
|
ppgType = params.get();
|
||||||
|
|
||||||
|
int typeIndex = getPpgType();
|
||||||
|
int dataLength;
|
||||||
|
switch (typeIndex) {
|
||||||
|
case LefunConstants.PPG_TYPE_HEART_RATE:
|
||||||
|
case LefunConstants.PPG_TYPE_BLOOD_OXYGEN:
|
||||||
|
dataLength = 1;
|
||||||
|
break;
|
||||||
|
case LefunConstants.PPG_TYPE_BLOOD_PRESSURE:
|
||||||
|
dataLength = 2;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new IllegalArgumentException("Unknown PPG type");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (params.limit() != dataLength + 1)
|
||||||
|
throwUnexpectedLength();
|
||||||
|
|
||||||
|
ppgData = new byte[dataLength];
|
||||||
|
params.get(ppgData);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected byte serializeParams(ByteBuffer params) {
|
||||||
|
// No handler on device side
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,130 @@
|
|||||||
|
/* Copyright (C) 2016-2020 Andreas Shimokawa, Carsten Pfeiffer, Daniele
|
||||||
|
Gobbetti
|
||||||
|
Copyright (C) 2020 Yukai Li
|
||||||
|
|
||||||
|
This file is part of Gadgetbridge.
|
||||||
|
|
||||||
|
Gadgetbridge is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Affero General Public License as published
|
||||||
|
by the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
Gadgetbridge is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU Affero General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Affero General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||||
|
package nodomain.freeyourgadget.gadgetbridge.devices.lefun.commands;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.devices.lefun.LefunConstants;
|
||||||
|
|
||||||
|
public class ProfileCommand extends BaseCommand {
|
||||||
|
public static final byte GENDER_FEMALE = 0;
|
||||||
|
public static final byte GENDER_MALE = 1;
|
||||||
|
|
||||||
|
private byte op;
|
||||||
|
private byte gender;
|
||||||
|
private byte height; // cm
|
||||||
|
private byte weight; // kg
|
||||||
|
private byte age; // years
|
||||||
|
|
||||||
|
private boolean setSuccess;
|
||||||
|
|
||||||
|
public byte getOp() {
|
||||||
|
return op;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setOp(byte op) {
|
||||||
|
if (op != OP_GET && op != OP_SET)
|
||||||
|
throw new IllegalArgumentException("Operation must be get or set");
|
||||||
|
this.op = op;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte getGender() {
|
||||||
|
return gender;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setGender(byte gender) {
|
||||||
|
if (gender != GENDER_FEMALE && gender != GENDER_MALE)
|
||||||
|
throw new IllegalArgumentException("Invalid gender");
|
||||||
|
this.gender = gender;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte getHeight() {
|
||||||
|
return height;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setHeight(byte height) {
|
||||||
|
int intHeight = (int)height & 0xff;
|
||||||
|
if (intHeight < 40 || intHeight > 210)
|
||||||
|
throw new IllegalArgumentException("Height must be between 40 and 210 cm inclusive");
|
||||||
|
this.height = height;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte getWeight() {
|
||||||
|
return weight;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setWeight(byte weight) {
|
||||||
|
int intWeight = (int)weight & 0xff;
|
||||||
|
if (intWeight < 5 || intWeight > 200)
|
||||||
|
throw new IllegalArgumentException("Weight must be between 5 and 200 kg inclusive");
|
||||||
|
this.weight = weight;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte getAge() {
|
||||||
|
return age;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAge(byte age) {
|
||||||
|
if (age < 0 || age > 110)
|
||||||
|
throw new IllegalArgumentException("Age must be between 0 and 110 years inclusive");
|
||||||
|
this.age = age;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isSetSuccess() {
|
||||||
|
return setSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void deserializeParams(byte id, ByteBuffer params) {
|
||||||
|
validateId(id, LefunConstants.CMD_PROFILE);
|
||||||
|
|
||||||
|
if (params.limit() < 1)
|
||||||
|
throwUnexpectedLength();
|
||||||
|
|
||||||
|
op = params.get();
|
||||||
|
if (op == OP_GET) {
|
||||||
|
if (params.limit() != 5)
|
||||||
|
throwUnexpectedLength();
|
||||||
|
|
||||||
|
gender = params.get();
|
||||||
|
height = params.get();
|
||||||
|
weight = params.get();
|
||||||
|
age = params.get();
|
||||||
|
} else if (op == OP_SET) {
|
||||||
|
if (params.limit() != 2)
|
||||||
|
throwUnexpectedLength();
|
||||||
|
|
||||||
|
setSuccess = params.get() == 1;
|
||||||
|
} else {
|
||||||
|
throw new IllegalArgumentException("Invalid operation type received");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected byte serializeParams(ByteBuffer params) {
|
||||||
|
params.put(op);
|
||||||
|
if (op == OP_SET) {
|
||||||
|
params.put(gender);
|
||||||
|
params.put(height);
|
||||||
|
params.put(weight);
|
||||||
|
params.put(age);
|
||||||
|
}
|
||||||
|
return LefunConstants.CMD_PROFILE;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,36 @@
|
|||||||
|
/* Copyright (C) 2016-2020 Andreas Shimokawa, Carsten Pfeiffer, Daniele
|
||||||
|
Gobbetti
|
||||||
|
Copyright (C) 2020 Yukai Li
|
||||||
|
|
||||||
|
This file is part of Gadgetbridge.
|
||||||
|
|
||||||
|
Gadgetbridge is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Affero General Public License as published
|
||||||
|
by the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
Gadgetbridge is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU Affero General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Affero General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||||
|
package nodomain.freeyourgadget.gadgetbridge.devices.lefun.commands;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.devices.lefun.LefunConstants;
|
||||||
|
|
||||||
|
public class RemoteCameraTriggeredCommand extends BaseCommand {
|
||||||
|
@Override
|
||||||
|
protected void deserializeParams(byte id, ByteBuffer params) {
|
||||||
|
validateIdAndLength(id, params, LefunConstants.CMD_REMOTE_CAMERA_TRIGGERED, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected byte serializeParams(ByteBuffer params) {
|
||||||
|
// No handler on device side
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,46 @@
|
|||||||
|
/* Copyright (C) 2016-2020 Andreas Shimokawa, Carsten Pfeiffer, Daniele
|
||||||
|
Gobbetti
|
||||||
|
Copyright (C) 2020 Yukai Li
|
||||||
|
|
||||||
|
This file is part of Gadgetbridge.
|
||||||
|
|
||||||
|
Gadgetbridge is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Affero General Public License as published
|
||||||
|
by the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
Gadgetbridge is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU Affero General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Affero General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||||
|
package nodomain.freeyourgadget.gadgetbridge.devices.lefun.commands;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.devices.lefun.LefunConstants;
|
||||||
|
|
||||||
|
public class RequestBondingCommand extends BaseCommand {
|
||||||
|
public static final byte STATUS_ALREADY_BONDED = 0;
|
||||||
|
public static final byte STATUS_BONDING_SUCCESSFUL = 1;
|
||||||
|
|
||||||
|
private byte status;
|
||||||
|
|
||||||
|
public byte getStatus() {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void deserializeParams(byte id, ByteBuffer params) {
|
||||||
|
validateIdAndLength(id, params, LefunConstants.CMD_BONDING_REQUEST, 1);
|
||||||
|
|
||||||
|
status = params.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected byte serializeParams(ByteBuffer params) {
|
||||||
|
return LefunConstants.CMD_BONDING_REQUEST;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,86 @@
|
|||||||
|
/* Copyright (C) 2016-2020 Andreas Shimokawa, Carsten Pfeiffer, Daniele
|
||||||
|
Gobbetti
|
||||||
|
Copyright (C) 2020 Yukai Li
|
||||||
|
|
||||||
|
This file is part of Gadgetbridge.
|
||||||
|
|
||||||
|
Gadgetbridge is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Affero General Public License as published
|
||||||
|
by the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
Gadgetbridge is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU Affero General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Affero General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||||
|
package nodomain.freeyourgadget.gadgetbridge.devices.lefun.commands;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.devices.lefun.LefunConstants;
|
||||||
|
|
||||||
|
public class SedentaryReminderIntervalCommand extends BaseCommand {
|
||||||
|
private byte op;
|
||||||
|
private byte sedentaryReminderInterval;
|
||||||
|
|
||||||
|
private boolean setSuccess;
|
||||||
|
|
||||||
|
public byte getOp() {
|
||||||
|
return op;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setOp(byte op) {
|
||||||
|
if (op != OP_GET && op != OP_SET)
|
||||||
|
throw new IllegalArgumentException("Operation must be get or set");
|
||||||
|
this.op = op;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte getSedentaryReminderInterval() {
|
||||||
|
return sedentaryReminderInterval;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSedentaryReminderInterval(byte sedentaryReminderInterval) {
|
||||||
|
if (sedentaryReminderInterval == 0)
|
||||||
|
throw new IllegalArgumentException("Interval must be non-zero");
|
||||||
|
this.sedentaryReminderInterval = sedentaryReminderInterval;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isSetSuccess() {
|
||||||
|
return setSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void deserializeParams(byte id, ByteBuffer params) {
|
||||||
|
validateId(id, LefunConstants.CMD_SEDENTARY_REMINDER_INTERVAL);
|
||||||
|
|
||||||
|
if (params.limit() < 1)
|
||||||
|
throwUnexpectedLength();
|
||||||
|
|
||||||
|
op = params.get();
|
||||||
|
if (op == OP_GET) {
|
||||||
|
if (params.limit() != 2)
|
||||||
|
throwUnexpectedLength();
|
||||||
|
|
||||||
|
sedentaryReminderInterval = params.get();
|
||||||
|
} else if (op == OP_SET) {
|
||||||
|
if (params.limit() != 2)
|
||||||
|
throwUnexpectedLength();
|
||||||
|
|
||||||
|
setSuccess = params.get() == 1;
|
||||||
|
} else {
|
||||||
|
throw new IllegalArgumentException("Invalid operation type received");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected byte serializeParams(ByteBuffer params) {
|
||||||
|
params.put(op);
|
||||||
|
if (op == OP_SET) {
|
||||||
|
params.put(sedentaryReminderInterval);
|
||||||
|
}
|
||||||
|
return LefunConstants.CMD_SEDENTARY_REMINDER_INTERVAL;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,54 @@
|
|||||||
|
package nodomain.freeyourgadget.gadgetbridge.devices.lefun.commands;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.devices.lefun.LefunConstants;
|
||||||
|
|
||||||
|
/* Copyright (C) 2016-2020 Andreas Shimokawa, Carsten Pfeiffer, Daniele
|
||||||
|
Gobbetti
|
||||||
|
Copyright (C) 2020 Yukai Li
|
||||||
|
|
||||||
|
This file is part of Gadgetbridge.
|
||||||
|
|
||||||
|
Gadgetbridge is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Affero General Public License as published
|
||||||
|
by the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
Gadgetbridge is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU Affero General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Affero General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||||
|
public class SetLanguageCommand extends BaseCommand {
|
||||||
|
private byte language;
|
||||||
|
|
||||||
|
private boolean setSuccess;
|
||||||
|
|
||||||
|
public byte getLanguage() {
|
||||||
|
return language;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLanguage(byte language) {
|
||||||
|
this.language = language;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isSetSuccess() {
|
||||||
|
return setSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void deserializeParams(byte id, ByteBuffer params) {
|
||||||
|
validateIdAndLength(id, params, LefunConstants.CMD_LANGUAGE, 1);
|
||||||
|
|
||||||
|
setSuccess = params.get() == 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected byte serializeParams(ByteBuffer params) {
|
||||||
|
params.put(language);
|
||||||
|
return LefunConstants.CMD_LANGUAGE;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,54 @@
|
|||||||
|
/* Copyright (C) 2016-2020 Andreas Shimokawa, Carsten Pfeiffer, Daniele
|
||||||
|
Gobbetti
|
||||||
|
Copyright (C) 2020 Yukai Li
|
||||||
|
|
||||||
|
This file is part of Gadgetbridge.
|
||||||
|
|
||||||
|
Gadgetbridge is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Affero General Public License as published
|
||||||
|
by the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
Gadgetbridge is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU Affero General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Affero General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||||
|
package nodomain.freeyourgadget.gadgetbridge.devices.lefun.commands;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.devices.lefun.LefunConstants;
|
||||||
|
|
||||||
|
public class SetRemoteCameraCommand extends BaseCommand {
|
||||||
|
private boolean remoteCameraEnabled;
|
||||||
|
|
||||||
|
private boolean setSuccess;
|
||||||
|
|
||||||
|
public boolean getRemoteCameraEnabled() {
|
||||||
|
return remoteCameraEnabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRemoteCameraEnabled(boolean remoteCameraEnabled) {
|
||||||
|
this.remoteCameraEnabled = remoteCameraEnabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isSetSuccess() {
|
||||||
|
return setSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void deserializeParams(byte id, ByteBuffer params) {
|
||||||
|
validateIdAndLength(id, params, LefunConstants.CMD_REMOTE_CAMERA, 1);
|
||||||
|
|
||||||
|
setSuccess = params.get() == 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected byte serializeParams(ByteBuffer params) {
|
||||||
|
params.put((byte)(remoteCameraEnabled ? 1 : 0));
|
||||||
|
return LefunConstants.CMD_REMOTE_CAMERA;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,117 @@
|
|||||||
|
/* Copyright (C) 2016-2020 Andreas Shimokawa, Carsten Pfeiffer, Daniele
|
||||||
|
Gobbetti
|
||||||
|
Copyright (C) 2020 Yukai Li
|
||||||
|
|
||||||
|
This file is part of Gadgetbridge.
|
||||||
|
|
||||||
|
Gadgetbridge is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Affero General Public License as published
|
||||||
|
by the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
Gadgetbridge is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU Affero General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Affero General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||||
|
package nodomain.freeyourgadget.gadgetbridge.devices.lefun.commands;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.devices.lefun.LefunConstants;
|
||||||
|
|
||||||
|
public class SettingsCommand extends BaseCommand {
|
||||||
|
public static final byte AM_PM_24_HOUR = 0;
|
||||||
|
public static final byte AM_PM_12_HOUR = 1;
|
||||||
|
public static final byte MEASUREMENT_UNIT_METRIC = 0;
|
||||||
|
public static final byte MEASUREMENT_UNIT_IMPERIAL = 1;
|
||||||
|
|
||||||
|
private byte op;
|
||||||
|
private byte option1;
|
||||||
|
private byte amPmIndicator;
|
||||||
|
private byte measurementUnit;
|
||||||
|
|
||||||
|
private boolean setSuccess;
|
||||||
|
|
||||||
|
public byte getOp() {
|
||||||
|
return op;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setOp(byte op) {
|
||||||
|
if (op != OP_GET && op != OP_SET)
|
||||||
|
throw new IllegalArgumentException("Operation must be get or set");
|
||||||
|
this.op = op;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte getOption1() {
|
||||||
|
return option1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setOption1(byte option1) {
|
||||||
|
if (option1 < 0 || option1 > 24)
|
||||||
|
throw new IllegalArgumentException("option1 must be between 0 and 24 inclusive");
|
||||||
|
this.option1 = option1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte getAmPmIndicator() {
|
||||||
|
return amPmIndicator;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAmPmIndicator(byte amPmIndicator) {
|
||||||
|
if (amPmIndicator != AM_PM_12_HOUR && amPmIndicator != AM_PM_24_HOUR)
|
||||||
|
throw new IllegalArgumentException("Indicator must be 12 or 24 hours");
|
||||||
|
this.amPmIndicator = amPmIndicator;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte getMeasurementUnit() {
|
||||||
|
return measurementUnit;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMeasurementUnit(byte measurementUnit) {
|
||||||
|
if (measurementUnit != MEASUREMENT_UNIT_METRIC && measurementUnit != MEASUREMENT_UNIT_IMPERIAL)
|
||||||
|
throw new IllegalArgumentException(("Unit must be metric or imperial"));
|
||||||
|
this.measurementUnit = measurementUnit;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isSetSuccess() {
|
||||||
|
return setSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void deserializeParams(byte id, ByteBuffer params) {
|
||||||
|
validateId(id, LefunConstants.CMD_SETTINGS);
|
||||||
|
|
||||||
|
if (params.limit() < 1)
|
||||||
|
throwUnexpectedLength();
|
||||||
|
|
||||||
|
op = params.get();
|
||||||
|
if (op == OP_GET) {
|
||||||
|
if (params.limit() != 4)
|
||||||
|
throwUnexpectedLength();
|
||||||
|
|
||||||
|
option1 = params.get();
|
||||||
|
amPmIndicator = params.get();
|
||||||
|
measurementUnit = params.get();
|
||||||
|
} else if (op == OP_SET) {
|
||||||
|
if (params.limit() != 2)
|
||||||
|
throwUnexpectedLength();
|
||||||
|
|
||||||
|
setSuccess = params.get() == 1;
|
||||||
|
} else {
|
||||||
|
throw new IllegalArgumentException("Invalid operation type received");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected byte serializeParams(ByteBuffer params) {
|
||||||
|
params.put(op);
|
||||||
|
if (op == OP_SET) {
|
||||||
|
params.put(option1);
|
||||||
|
params.put(amPmIndicator);
|
||||||
|
params.put(measurementUnit);
|
||||||
|
}
|
||||||
|
return LefunConstants.CMD_SETTINGS;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,57 @@
|
|||||||
|
/* Copyright (C) 2016-2020 Andreas Shimokawa, Carsten Pfeiffer, Daniele
|
||||||
|
Gobbetti
|
||||||
|
Copyright (C) 2020 Yukai Li
|
||||||
|
|
||||||
|
This file is part of Gadgetbridge.
|
||||||
|
|
||||||
|
Gadgetbridge is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Affero General Public License as published
|
||||||
|
by the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
Gadgetbridge is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU Affero General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Affero General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||||
|
package nodomain.freeyourgadget.gadgetbridge.devices.lefun.commands;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.devices.lefun.LefunConstants;
|
||||||
|
|
||||||
|
public class StartPpgSensingCommand extends BaseCommand {
|
||||||
|
private byte ppgType;
|
||||||
|
|
||||||
|
private boolean setSuccess;
|
||||||
|
|
||||||
|
public int getPpgType() {
|
||||||
|
return getLowestSetBitIndex(ppgType);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPpgType(int type) {
|
||||||
|
if (type < 0 || type > 2)
|
||||||
|
throw new IllegalArgumentException("Invalid PPG type");
|
||||||
|
this.ppgType = (byte)(1 << type);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isSetSuccess() {
|
||||||
|
return setSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void deserializeParams(byte id, ByteBuffer params) {
|
||||||
|
validateIdAndLength(id, params, LefunConstants.CMD_PPG_START, 2);
|
||||||
|
|
||||||
|
ppgType = params.get();
|
||||||
|
setSuccess = params.get() == 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected byte serializeParams(ByteBuffer params) {
|
||||||
|
params.put(ppgType);
|
||||||
|
return LefunConstants.CMD_PPG_START;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,149 @@
|
|||||||
|
/* Copyright (C) 2016-2020 Andreas Shimokawa, Carsten Pfeiffer, Daniele
|
||||||
|
Gobbetti
|
||||||
|
Copyright (C) 2020 Yukai Li
|
||||||
|
|
||||||
|
This file is part of Gadgetbridge.
|
||||||
|
|
||||||
|
Gadgetbridge is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Affero General Public License as published
|
||||||
|
by the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
Gadgetbridge is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU Affero General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Affero General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||||
|
package nodomain.freeyourgadget.gadgetbridge.devices.lefun.commands;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.devices.lefun.LefunConstants;
|
||||||
|
|
||||||
|
public class TimeCommand extends BaseCommand {
|
||||||
|
private byte op;
|
||||||
|
private byte year;
|
||||||
|
private byte month;
|
||||||
|
private byte day;
|
||||||
|
private byte hour;
|
||||||
|
private byte minute;
|
||||||
|
private byte second;
|
||||||
|
|
||||||
|
private boolean setSuccess;
|
||||||
|
|
||||||
|
public byte getOp() {
|
||||||
|
if (op != OP_GET && op != OP_SET)
|
||||||
|
throw new IllegalArgumentException("Operation must be get or set");
|
||||||
|
return op;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setOp(byte op) {
|
||||||
|
this.op = op;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte getYear() {
|
||||||
|
return year;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setYear(byte year) {
|
||||||
|
this.year = year;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte getMonth() {
|
||||||
|
return month;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMonth(byte month) {
|
||||||
|
if (month < 1 || month > 12)
|
||||||
|
throw new IllegalArgumentException("Month must be between 1 and 12 inclusive");
|
||||||
|
this.month = month;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte getDay() {
|
||||||
|
return day;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDay(byte day) {
|
||||||
|
if (day < 1 || day > 31)
|
||||||
|
throw new IllegalArgumentException("Day must be between 1 and 31 inclusive");
|
||||||
|
this.day = day;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte getHour() {
|
||||||
|
return hour;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setHour(byte hour) {
|
||||||
|
if (hour < 0 || hour > 23)
|
||||||
|
throw new IllegalArgumentException("Hour must be between 0 and 23 inclusive");
|
||||||
|
this.hour = hour;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte getMinute() {
|
||||||
|
return minute;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMinute(byte minute) {
|
||||||
|
if (minute < 0 || minute > 59)
|
||||||
|
throw new IllegalArgumentException("Minute must be between 0 and 59 inclusive");
|
||||||
|
this.minute = minute;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte getSecond() {
|
||||||
|
return second;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSecond(byte second) {
|
||||||
|
if (second < 0 || second > 59)
|
||||||
|
throw new IllegalArgumentException("Second must be between 0 and 59 inclusive");
|
||||||
|
this.second = second;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isSetSuccess() {
|
||||||
|
return setSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void deserializeParams(byte id, ByteBuffer params) {
|
||||||
|
validateId(id, LefunConstants.CMD_TIME);
|
||||||
|
|
||||||
|
if (params.limit() < 1)
|
||||||
|
throwUnexpectedLength();
|
||||||
|
|
||||||
|
op = params.get();
|
||||||
|
if (op == OP_GET) {
|
||||||
|
if (params.limit() != 7)
|
||||||
|
throwUnexpectedLength();
|
||||||
|
|
||||||
|
year = params.get();
|
||||||
|
month = params.get();
|
||||||
|
day = params.get();
|
||||||
|
hour = params.get();
|
||||||
|
minute = params.get();
|
||||||
|
second = params.get();
|
||||||
|
} else if (op == OP_SET) {
|
||||||
|
if (params.limit() != 2)
|
||||||
|
throwUnexpectedLength();
|
||||||
|
|
||||||
|
setSuccess = params.get() == 1;
|
||||||
|
} else {
|
||||||
|
throw new IllegalArgumentException("Invalid operation type received");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected byte serializeParams(ByteBuffer params) {
|
||||||
|
params.put(op);
|
||||||
|
if (op == OP_SET) {
|
||||||
|
params.put(year);
|
||||||
|
params.put(month);
|
||||||
|
params.put(day);
|
||||||
|
params.put(hour);
|
||||||
|
params.put(minute);
|
||||||
|
params.put(second);
|
||||||
|
}
|
||||||
|
return LefunConstants.CMD_TIME;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,91 @@
|
|||||||
|
/* Copyright (C) 2016-2020 Andreas Shimokawa, Carsten Pfeiffer, Daniele
|
||||||
|
Gobbetti
|
||||||
|
Copyright (C) 2020 Yukai Li
|
||||||
|
|
||||||
|
This file is part of Gadgetbridge.
|
||||||
|
|
||||||
|
Gadgetbridge is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Affero General Public License as published
|
||||||
|
by the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
Gadgetbridge is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU Affero General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Affero General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||||
|
package nodomain.freeyourgadget.gadgetbridge.devices.lefun.commands;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.devices.lefun.LefunConstants;
|
||||||
|
|
||||||
|
public class UiPagesCommand extends BaseCommand {
|
||||||
|
// I don't know which pages since they're not implemented in my watch, so no
|
||||||
|
// constants here for now
|
||||||
|
|
||||||
|
private byte op;
|
||||||
|
private short pages;
|
||||||
|
|
||||||
|
private boolean setSuccess;
|
||||||
|
|
||||||
|
public byte getOp() {
|
||||||
|
return op;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setOp(byte op) {
|
||||||
|
if (op != OP_GET && op != OP_SET)
|
||||||
|
throw new IllegalArgumentException("Operation must be get or set");
|
||||||
|
this.op = op;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean getPage(int index) {
|
||||||
|
if (index < 0 || index >= 16)
|
||||||
|
throw new IllegalArgumentException("Index must be between 0 and 15 inclusive");
|
||||||
|
return getBit(pages, 1 << index);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPage(int index, boolean enabled) {
|
||||||
|
if (index < 0 || index >= 16)
|
||||||
|
throw new IllegalArgumentException("Index must be between 0 and 15 inclusive");
|
||||||
|
pages = setBit(pages, 1 << index, enabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isSetSuccess() {
|
||||||
|
return setSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void deserializeParams(byte id, ByteBuffer params) {
|
||||||
|
validateId(id, LefunConstants.CMD_UI_PAGES);
|
||||||
|
|
||||||
|
if (params.limit() < 1)
|
||||||
|
throwUnexpectedLength();
|
||||||
|
|
||||||
|
op = params.get();
|
||||||
|
if (op == OP_GET) {
|
||||||
|
if (params.limit() != 3)
|
||||||
|
throwUnexpectedLength();
|
||||||
|
|
||||||
|
pages = params.getShort();
|
||||||
|
} else if (op == OP_SET) {
|
||||||
|
if (params.limit() != 2)
|
||||||
|
throwUnexpectedLength();
|
||||||
|
|
||||||
|
setSuccess = params.get() == 1;
|
||||||
|
} else {
|
||||||
|
throw new IllegalArgumentException("Invalid operation type received");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected byte serializeParams(ByteBuffer params) {
|
||||||
|
params.put(op);
|
||||||
|
if (op == OP_SET) {
|
||||||
|
params.putShort(pages);
|
||||||
|
}
|
||||||
|
return LefunConstants.CMD_UI_PAGES;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user