mirror of
https://codeberg.org/Freeyourgadget/Gadgetbridge
synced 2024-11-28 12:56:49 +01:00
Lefun: Add comments
This commit is contained in:
parent
6974a86b87
commit
1242009b55
@ -22,6 +22,9 @@ import java.util.UUID;
|
||||
|
||||
import static nodomain.freeyourgadget.gadgetbridge.service.btle.AbstractBTLEDeviceSupport.BASE_UUID;
|
||||
|
||||
/**
|
||||
* Constants used with Lefun device support
|
||||
*/
|
||||
public class LefunConstants {
|
||||
// BLE UUIDs
|
||||
public static final UUID UUID_SERVICE_LEFUN = UUID.fromString(String.format(BASE_UUID, "18D0"));
|
||||
@ -31,16 +34,12 @@ public class LefunConstants {
|
||||
// Coordinator constants
|
||||
public static final String ADVERTISEMENT_NAME = "Lefun";
|
||||
public static final String MANUFACTURER_NAME = "Teng Jin Da";
|
||||
public static int NUM_ALARM_SLOTS = 5;
|
||||
|
||||
// Commands
|
||||
public static final byte CMD_REQUEST_ID = (byte)0xab;
|
||||
public static final byte CMD_REQUEST_ID = (byte) 0xab;
|
||||
public static final byte CMD_RESPONSE_ID = 0x5a;
|
||||
|
||||
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;
|
||||
@ -67,25 +66,23 @@ public class LefunConstants {
|
||||
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 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;
|
||||
public static final int PPG_TYPE_COUNT = 3;
|
||||
|
||||
// DB activity kinds
|
||||
public static final int DB_ACTIVITY_KIND_UNKNOWN = 0;
|
||||
public static final int DB_ACTIVITY_KIND_ACTIVITY = 1;
|
||||
public static final int DB_ACTIVITY_KIND_HEART_RATE = 2;
|
||||
public static final int DB_ACTIVITY_KIND_LIGHT_SLEEP = 3;
|
||||
public static final int DB_ACTIVITY_KIND_DEEP_SLEEP = 4;
|
||||
|
||||
// Pseudo-intensity
|
||||
public static final int INTENSITY_MIN = 0;
|
||||
public static final int INTENSITY_DEEP_SLEEP = 1;
|
||||
public static final int INTENSITY_LIGHT_SLEEP = 2;
|
||||
public static final int INTENSITY_AWAKE = 3;
|
||||
public static final int INTENSITY_MAX = 4;
|
||||
public static int NUM_ALARM_SLOTS = 5;
|
||||
}
|
||||
|
@ -41,6 +41,9 @@ import static nodomain.freeyourgadget.gadgetbridge.devices.lefun.LefunConstants.
|
||||
import static nodomain.freeyourgadget.gadgetbridge.devices.lefun.LefunConstants.MANUFACTURER_NAME;
|
||||
import static nodomain.freeyourgadget.gadgetbridge.devices.lefun.LefunConstants.NUM_ALARM_SLOTS;
|
||||
|
||||
/**
|
||||
* Device coordinator for Lefun band
|
||||
*/
|
||||
public class LefunDeviceCoordinator extends AbstractDeviceCoordinator {
|
||||
@Override
|
||||
protected void deleteDevice(@NonNull GBDevice gbDevice, @NonNull Device device, @NonNull DaoSession session) throws GBException {
|
||||
|
@ -18,6 +18,9 @@
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
package nodomain.freeyourgadget.gadgetbridge.devices.lefun;
|
||||
|
||||
/**
|
||||
* Feature support utilities for Lefun devices
|
||||
*/
|
||||
public class LefunFeatureSupport {
|
||||
public static final int SUPPORT_HEART_RATE = 1 << 2;
|
||||
public static final int SUPPORT_BLOOD_PRESSURE = 1 << 3;
|
||||
@ -31,10 +34,27 @@ public class LefunFeatureSupport {
|
||||
public static final int RESERVE_WALLPAPER = 1 << 6;
|
||||
public static final int RESERVE_REMOTE_CAMERA = 1 << 7;
|
||||
|
||||
/**
|
||||
* Checks whether a feature is supported
|
||||
*
|
||||
* @param deviceSupport the feature flags from the device
|
||||
* @param featureSupport the feature you want to check
|
||||
* @return whether feature is supported
|
||||
*/
|
||||
public static boolean checkSupported(short deviceSupport, int featureSupport) {
|
||||
return (deviceSupport & featureSupport) == featureSupport;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether a feature is not reserved
|
||||
* <p>
|
||||
* Reserve flags indicate a feature is not available if set. This function takes care of the
|
||||
* inverting for you, so if you get true, the feature is available.
|
||||
*
|
||||
* @param deviceReserve the reserve flags from the device
|
||||
* @param featureReserve the reserve flag you want to check
|
||||
* @return whether feature is supported
|
||||
*/
|
||||
public static boolean checkNotReserved(short deviceReserve, int featureReserve) {
|
||||
return !((deviceReserve & featureReserve) == featureReserve);
|
||||
}
|
||||
|
@ -24,14 +24,15 @@ import androidx.annotation.Nullable;
|
||||
import de.greenrobot.dao.AbstractDao;
|
||||
import de.greenrobot.dao.Property;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.AbstractSampleProvider;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.SampleProvider;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.AbstractActivitySample;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.DaoSession;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.LefunActivitySample;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.LefunActivitySampleDao;
|
||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.ActivityKind;
|
||||
|
||||
/**
|
||||
* Sample provider for Lefun devices
|
||||
*/
|
||||
public class LefunSampleProvider extends AbstractSampleProvider<LefunActivitySample> {
|
||||
public LefunSampleProvider(GBDevice device, DaoSession session) {
|
||||
super(device, session);
|
||||
@ -91,7 +92,7 @@ public class LefunSampleProvider extends AbstractSampleProvider<LefunActivitySam
|
||||
|
||||
@Override
|
||||
public float normalizeIntensity(int rawIntensity) {
|
||||
return rawIntensity / (float)LefunConstants.INTENSITY_MAX;
|
||||
return rawIntensity / (float) LefunConstants.INTENSITY_MAX;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -23,32 +23,28 @@ import java.nio.ByteOrder;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.lefun.LefunConstants;
|
||||
|
||||
/**
|
||||
* Base class for Lefun Bluetooth commands and responses
|
||||
*/
|
||||
public abstract class BaseCommand {
|
||||
// Common constants
|
||||
/**
|
||||
* Common get operation type
|
||||
*/
|
||||
public static final byte OP_GET = 0;
|
||||
/**
|
||||
* Common set operation type
|
||||
*/
|
||||
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 || response.length < response[1])
|
||||
throw new IllegalArgumentException("Response is too short");
|
||||
if (calculateChecksum(response, 0, response[1] - 1) != response[response[1] - 1])
|
||||
throw new IllegalArgumentException("Incorrect message checksum");
|
||||
ByteBuffer buffer = ByteBuffer.wrap(response, LefunConstants.CMD_HEADER_LENGTH - 1,
|
||||
response[1] - 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);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates command checksum
|
||||
*
|
||||
* @param data the data to generate checksum from
|
||||
* @param offset the offset in data to start calculating from
|
||||
* @param length the number of bytes to include in calculation
|
||||
* @return the computed checksum
|
||||
*/
|
||||
public static byte calculateChecksum(byte[] data, int offset, int length) {
|
||||
int checksum = 0;
|
||||
for (int i = offset; i < offset + length; ++i) {
|
||||
@ -62,7 +58,51 @@ public abstract class BaseCommand {
|
||||
b >>= 1;
|
||||
}
|
||||
}
|
||||
return (byte)checksum;
|
||||
return (byte) checksum;
|
||||
}
|
||||
|
||||
/**
|
||||
* When implemented in a subclass, parses the response from a device
|
||||
*
|
||||
* @param id the command ID
|
||||
* @param params the params buffer
|
||||
*/
|
||||
abstract protected void deserializeParams(byte id, ByteBuffer params);
|
||||
|
||||
/**
|
||||
* When implemented in a subclass, provides the arguments to send in the command
|
||||
*
|
||||
* @param params the params buffer to write to
|
||||
* @return the command ID
|
||||
*/
|
||||
abstract protected byte serializeParams(ByteBuffer params);
|
||||
|
||||
/**
|
||||
* Deserialize a response from the device
|
||||
*
|
||||
* @param response the response data to deserialize
|
||||
*/
|
||||
public void deserialize(byte[] response) {
|
||||
if (response.length < LefunConstants.CMD_HEADER_LENGTH || response.length < response[1])
|
||||
throw new IllegalArgumentException("Response is too short");
|
||||
if (calculateChecksum(response, 0, response[1] - 1) != response[response[1] - 1])
|
||||
throw new IllegalArgumentException("Incorrect message checksum");
|
||||
ByteBuffer buffer = ByteBuffer.wrap(response, LefunConstants.CMD_HEADER_LENGTH - 1,
|
||||
response[1] - LefunConstants.CMD_HEADER_LENGTH);
|
||||
buffer.order(ByteOrder.BIG_ENDIAN);
|
||||
deserializeParams(response[2], buffer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Serializes a command to send to the device
|
||||
*
|
||||
* @return the data to send to the device
|
||||
*/
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -87,25 +127,57 @@ public abstract class BaseCommand {
|
||||
return request;
|
||||
}
|
||||
|
||||
/**
|
||||
* Throws a standard parameters length exception
|
||||
*/
|
||||
protected void throwUnexpectedLength() {
|
||||
throw new IllegalArgumentException("Unexpected parameters length");
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks for valid command ID and throws if wrong ID provided
|
||||
*
|
||||
* @param id command ID from device
|
||||
* @param expectedId expected command ID
|
||||
*/
|
||||
protected void validateId(byte id, byte expectedId) {
|
||||
if (id != expectedId)
|
||||
throw new IllegalArgumentException("Wrong command ID");
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks for valid command ID and command length
|
||||
*
|
||||
* @param id command ID from device
|
||||
* @param params params buffer from device
|
||||
* @param expectedId expected command ID
|
||||
* @param expectedLength expected params length
|
||||
*/
|
||||
protected void validateIdAndLength(byte id, ByteBuffer params, byte expectedId, int expectedLength) {
|
||||
validateId(id, expectedId);
|
||||
if (params.limit() - params.position() != expectedLength)
|
||||
throwUnexpectedLength();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets whether a bit is set
|
||||
*
|
||||
* @param value the value to check against
|
||||
* @param mask the bitmask
|
||||
* @return whether the bits indicated by the bitmask are set
|
||||
*/
|
||||
protected boolean getBit(int value, int mask) {
|
||||
return (value & mask) != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a bit in a value
|
||||
*
|
||||
* @param value the value to modify
|
||||
* @param mask the bitmask
|
||||
* @param set whether to set or clear the bits
|
||||
* @return the modified value
|
||||
*/
|
||||
protected int setBit(int value, int mask, boolean set) {
|
||||
if (set) {
|
||||
return value | mask;
|
||||
@ -114,26 +186,43 @@ public abstract class BaseCommand {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a bit in a value
|
||||
*
|
||||
* @param value the value to modify
|
||||
* @param mask the bitmask
|
||||
* @param set whether to set or clear the bits
|
||||
* @return the modified value
|
||||
*/
|
||||
protected short setBit(short value, int mask, boolean set) {
|
||||
if (set) {
|
||||
return (short)(value | mask);
|
||||
return (short) (value | mask);
|
||||
} else {
|
||||
return (short)(value & ~mask);
|
||||
return (short) (value & ~mask);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a bit in a value
|
||||
*
|
||||
* @param value the value to modify
|
||||
* @param mask the bitmask
|
||||
* @param set whether to set or clear the bits
|
||||
* @return the modified value
|
||||
*/
|
||||
protected byte setBit(byte value, int mask, boolean set) {
|
||||
if (set) {
|
||||
return (byte)(value | mask);
|
||||
return (byte) (value | mask);
|
||||
} else {
|
||||
return (byte)(value & ~mask);
|
||||
return (byte) (value & ~mask);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Find index of first bit that is set
|
||||
* @param value
|
||||
* @return
|
||||
*
|
||||
* @param value the value to look at
|
||||
* @return the index of the lowest set bit, starting at 0 for least significant bit; -1 if no bits set
|
||||
*/
|
||||
protected int getLowestSetBitIndex(int value) {
|
||||
if (value == 0) return -1;
|
||||
|
@ -102,6 +102,9 @@ import nodomain.freeyourgadget.gadgetbridge.service.devices.lefun.requests.Start
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.GB;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.Prefs;
|
||||
|
||||
/**
|
||||
* Device support class for Lefun devices
|
||||
*/
|
||||
public class LefunDeviceSupport extends AbstractBTLEDeviceSupport {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(LefunDeviceSupport.class);
|
||||
|
||||
@ -111,6 +114,9 @@ public class LefunDeviceSupport extends AbstractBTLEDeviceSupport {
|
||||
private int lastStepsCount = -1;
|
||||
private int lastStepsTimestamp;
|
||||
|
||||
/**
|
||||
* Instantiates a new instance of LefunDeviceSupport
|
||||
*/
|
||||
public LefunDeviceSupport() {
|
||||
super(LOG);
|
||||
addSupportedService(GattService.UUID_SERVICE_GENERIC_ACCESS);
|
||||
@ -449,6 +455,11 @@ public class LefunDeviceSupport extends AbstractBTLEDeviceSupport {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends unit of measurement to the device
|
||||
*
|
||||
* @param builder the transaction builder to append to
|
||||
*/
|
||||
private void sendUnitsSetting(TransactionBuilder builder) {
|
||||
Prefs prefs = GBApplication.getPrefs();
|
||||
String units = prefs.getString(SettingsActivity.PREF_MEASUREMENT_SYSTEM,
|
||||
@ -463,6 +474,11 @@ public class LefunDeviceSupport extends AbstractBTLEDeviceSupport {
|
||||
sendGeneralSettings(builder, (byte) 0xff, lefunUnits);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a features command with the currently enabled features set
|
||||
*
|
||||
* @return the features command
|
||||
*/
|
||||
private FeaturesCommand getCurrentEnabledFeatures() {
|
||||
SharedPreferences prefs = GBApplication.getDeviceSpecificSharedPrefs(getDevice().getAddress());
|
||||
boolean raiseToWakeEnabled = prefs.getBoolean(DeviceSettingsPreferenceConst.PREF_LIFTWRIST_NOSHED, true);
|
||||
@ -479,6 +495,13 @@ public class LefunDeviceSupport extends AbstractBTLEDeviceSupport {
|
||||
return cmd;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends general settings to the device
|
||||
*
|
||||
* @param builder the transaction builder to append to
|
||||
* @param amPm AM/PM indicator setting
|
||||
* @param units units of measurement setting
|
||||
*/
|
||||
private void sendGeneralSettings(TransactionBuilder builder, byte amPm, byte units) {
|
||||
boolean givenBuilder = builder != null;
|
||||
try {
|
||||
@ -497,6 +520,11 @@ public class LefunDeviceSupport extends AbstractBTLEDeviceSupport {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends the user profile to the device
|
||||
*
|
||||
* @param builder the transaction builder to append to
|
||||
*/
|
||||
private void sendUserProfile(TransactionBuilder builder) {
|
||||
boolean givenBuilder = builder != null;
|
||||
try {
|
||||
@ -515,6 +543,11 @@ public class LefunDeviceSupport extends AbstractBTLEDeviceSupport {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends enabled features settings to the device
|
||||
*
|
||||
* @param cmd the features command to send
|
||||
*/
|
||||
private void sendEnabledFeaturesSetting(FeaturesCommand cmd) {
|
||||
try {
|
||||
TransactionBuilder builder = performInitialized(SetEnabledFeaturesRequest.class.getSimpleName());
|
||||
@ -529,6 +562,11 @@ public class LefunDeviceSupport extends AbstractBTLEDeviceSupport {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends the sedentary reminder interval setting to the device
|
||||
*
|
||||
* @param period the reminder interval
|
||||
*/
|
||||
private void sendSedentaryReminderIntervalSetting(int period) {
|
||||
try {
|
||||
TransactionBuilder builder = performInitialized(SetSedentaryReminderIntervalRequest.class.getSimpleName());
|
||||
@ -543,6 +581,11 @@ public class LefunDeviceSupport extends AbstractBTLEDeviceSupport {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends the hydration reminder interval setting to the device
|
||||
*
|
||||
* @param period the reminder interval
|
||||
*/
|
||||
private void sendHydrationReminderIntervalSetting(int period) {
|
||||
try {
|
||||
TransactionBuilder builder = performInitialized(SetHydrationReminderIntervalRequest.class.getSimpleName());
|
||||
@ -557,6 +600,11 @@ public class LefunDeviceSupport extends AbstractBTLEDeviceSupport {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends the language selection to the device
|
||||
*
|
||||
* @param language the language selection
|
||||
*/
|
||||
private void sendLanguageSetting(byte language) {
|
||||
try {
|
||||
TransactionBuilder builder = performInitialized(SetLanguageRequest.class.getSimpleName());
|
||||
@ -571,6 +619,12 @@ public class LefunDeviceSupport extends AbstractBTLEDeviceSupport {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores received general settings to prefs
|
||||
*
|
||||
* @param amPm AM/PM indicator setting
|
||||
* @param units units of measurement setting
|
||||
*/
|
||||
public void receiveGeneralSettings(int amPm, int units) {
|
||||
SharedPreferences prefs = GBApplication.getDeviceSpecificSharedPrefs(getDevice().getAddress());
|
||||
boolean ampmEnabled = amPm == SettingsCommand.AM_PM_12_HOUR;
|
||||
@ -579,6 +633,11 @@ public class LefunDeviceSupport extends AbstractBTLEDeviceSupport {
|
||||
.apply();
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores received enabled features settings to prefs
|
||||
*
|
||||
* @param cmd the features command
|
||||
*/
|
||||
public void receiveEnabledFeaturesSetting(FeaturesCommand cmd) {
|
||||
SharedPreferences prefs = GBApplication.getDeviceSpecificSharedPrefs(getDevice().getAddress());
|
||||
prefs.edit()
|
||||
@ -593,6 +652,11 @@ public class LefunDeviceSupport extends AbstractBTLEDeviceSupport {
|
||||
.apply();
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores received sedentary reminder interval setting to prefs
|
||||
*
|
||||
* @param period the interval
|
||||
*/
|
||||
public void receiveSedentaryReminderIntervalSetting(int period) {
|
||||
SharedPreferences prefs = GBApplication.getDeviceSpecificSharedPrefs(getDevice().getAddress());
|
||||
prefs.edit()
|
||||
@ -600,6 +664,11 @@ public class LefunDeviceSupport extends AbstractBTLEDeviceSupport {
|
||||
.apply();
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores received hydration reminder interval setting to prefs
|
||||
*
|
||||
* @param period the interval
|
||||
*/
|
||||
public void receiveHydrationReminderIntervalSetting(int period) {
|
||||
SharedPreferences prefs = GBApplication.getDeviceSpecificSharedPrefs(getDevice().getAddress());
|
||||
prefs.edit()
|
||||
@ -689,6 +758,13 @@ public class LefunDeviceSupport extends AbstractBTLEDeviceSupport {
|
||||
return super.onCharacteristicChanged(gatt, characteristic);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles commands from the device that are not typically associated with a request
|
||||
*
|
||||
* @param commandId the command ID
|
||||
* @param data the entire response
|
||||
* @return whether the response has been handled
|
||||
*/
|
||||
private boolean handleAsynchronousResponse(byte commandId, byte[] data) {
|
||||
// Assume data already checked for correct response code and length
|
||||
switch (commandId) {
|
||||
@ -702,6 +778,12 @@ public class LefunDeviceSupport extends AbstractBTLEDeviceSupport {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles live steps data
|
||||
*
|
||||
* @param data the response
|
||||
* @return whether the response has been handled
|
||||
*/
|
||||
private boolean handleAsynchronousActivity(byte[] data) {
|
||||
try {
|
||||
GetStepsDataCommand cmd = new GetStepsDataCommand();
|
||||
@ -715,6 +797,12 @@ public class LefunDeviceSupport extends AbstractBTLEDeviceSupport {
|
||||
}
|
||||
|
||||
// Adapted from nodomain.freeyourgadget.gadgetbridge.service.devices.makibeshr3.MakibesHR3DeviceSupport.broadcastSample
|
||||
|
||||
/**
|
||||
* Broadcasts live sample
|
||||
*
|
||||
* @param command the steps data
|
||||
*/
|
||||
private void broadcastSample(GetStepsDataCommand command) {
|
||||
Calendar now = Calendar.getInstance();
|
||||
int timestamp = (int) (now.getTimeInMillis() / 1000);
|
||||
@ -735,6 +823,12 @@ public class LefunDeviceSupport extends AbstractBTLEDeviceSupport {
|
||||
LocalBroadcastManager.getInstance(getContext()).sendBroadcast(intent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles PPG result from earlier request
|
||||
*
|
||||
* @param data the response
|
||||
* @return whether the response has been handled
|
||||
*/
|
||||
private boolean handleAsynchronousPpgResult(byte[] data) {
|
||||
try {
|
||||
PpgResultCommand cmd = new PpgResultCommand();
|
||||
@ -747,6 +841,12 @@ public class LefunDeviceSupport extends AbstractBTLEDeviceSupport {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles find phone request
|
||||
*
|
||||
* @param data the response
|
||||
* @return whether the response has been handled
|
||||
*/
|
||||
private boolean handleAntiLoss(byte[] data) {
|
||||
try {
|
||||
FindPhoneCommand cmd = new FindPhoneCommand();
|
||||
@ -761,12 +861,26 @@ public class LefunDeviceSupport extends AbstractBTLEDeviceSupport {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback when device info has been obtained
|
||||
*/
|
||||
public void completeInitialization() {
|
||||
gbDevice.setState(GBDevice.State.INITIALIZED);
|
||||
gbDevice.sendDeviceUpdateIntent(getContext());
|
||||
onReadConfiguration("");
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts Lefun datetime format to Unix timestamp
|
||||
*
|
||||
* @param year the year (2 digits based on 2000)
|
||||
* @param month the month
|
||||
* @param day the day
|
||||
* @param hour the hour
|
||||
* @param minute the minute
|
||||
* @param second the second
|
||||
* @return Unix timestamp of the datetime
|
||||
*/
|
||||
private int dateToTimestamp(byte year, byte month, byte day, byte hour, byte minute, byte second) {
|
||||
Calendar calendar = Calendar.getInstance();
|
||||
calendar.set(
|
||||
@ -780,6 +894,13 @@ public class LefunDeviceSupport extends AbstractBTLEDeviceSupport {
|
||||
return (int) (calendar.getTimeInMillis() / 1000);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches an activity sample given the timestamp
|
||||
*
|
||||
* @param session DAO session
|
||||
* @param timestamp the timestamp
|
||||
* @return fetched activity or null if none exists
|
||||
*/
|
||||
private LefunActivitySample getActivitySample(DaoSession session, int timestamp) {
|
||||
LefunActivitySampleDao dao = session.getLefunActivitySampleDao();
|
||||
Long userId = DBHelper.getUser(session).getId();
|
||||
@ -792,6 +913,11 @@ public class LefunDeviceSupport extends AbstractBTLEDeviceSupport {
|
||||
return q.unique();
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes activity data and stores it
|
||||
*
|
||||
* @param command the activity data
|
||||
*/
|
||||
public void handleActivityData(GetActivityDataCommand command) {
|
||||
try (DBHandler handler = GBApplication.acquireDB()) {
|
||||
DaoSession session = handler.getDaoSession();
|
||||
@ -818,6 +944,13 @@ public class LefunDeviceSupport extends AbstractBTLEDeviceSupport {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes PPG data and stores it
|
||||
*
|
||||
* @param timestamp the timestamp
|
||||
* @param ppgType the PPG type
|
||||
* @param ppgData the data from the PPG operation
|
||||
*/
|
||||
private void handlePpgData(int timestamp, int ppgType, byte[] ppgData) {
|
||||
int ppgData0 = ppgData[0] & 0xff;
|
||||
int ppgData1 = ppgData.length > 1 ? ppgData[1] & 0xff : 0;
|
||||
@ -851,6 +984,11 @@ public class LefunDeviceSupport extends AbstractBTLEDeviceSupport {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes PPG data from bulk get operation
|
||||
*
|
||||
* @param command the PPG data
|
||||
*/
|
||||
public void handlePpgData(GetPpgDataCommand command) {
|
||||
int timestamp = dateToTimestamp(command.getYear(), command.getMonth(), command.getDay(),
|
||||
command.getHour(), command.getMinute(), command.getSecond());
|
||||
@ -859,6 +997,11 @@ public class LefunDeviceSupport extends AbstractBTLEDeviceSupport {
|
||||
handlePpgData(timestamp, ppgType, ppgData);
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes PPG result received as a result of requesting PPG operation
|
||||
*
|
||||
* @param command the PPG result
|
||||
*/
|
||||
public void handlePpgData(PpgResultCommand command) {
|
||||
int timestamp = (int) (Calendar.getInstance().getTimeInMillis() / 1000);
|
||||
int ppgType = command.getPpgType();
|
||||
@ -866,6 +1009,11 @@ public class LefunDeviceSupport extends AbstractBTLEDeviceSupport {
|
||||
handlePpgData(timestamp, ppgType, ppgData);
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes bulk sleep data
|
||||
*
|
||||
* @param command the sleep data
|
||||
*/
|
||||
public void handleSleepData(GetSleepDataCommand command) {
|
||||
try (DBHandler handler = GBApplication.acquireDB()) {
|
||||
DaoSession session = handler.getDaoSession();
|
||||
@ -915,6 +1063,9 @@ public class LefunDeviceSupport extends AbstractBTLEDeviceSupport {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs the next queued request
|
||||
*/
|
||||
public void runNextQueuedRequest() {
|
||||
Request request = queuedRequests.poll();
|
||||
if (request != null) {
|
||||
|
@ -31,7 +31,14 @@ import nodomain.freeyourgadget.gadgetbridge.service.devices.lefun.LefunDeviceSup
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.miband.operations.OperationStatus;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.GB;
|
||||
|
||||
/**
|
||||
* Represents a request that receives several responses
|
||||
*/
|
||||
public abstract class MultiFetchRequest extends Request {
|
||||
/**
|
||||
* Instantiates a new MultiFetchRequest
|
||||
* @param support the device support
|
||||
*/
|
||||
protected MultiFetchRequest(LefunDeviceSupport support) {
|
||||
super(support, null);
|
||||
removeAfterHandling = false;
|
||||
@ -97,5 +104,9 @@ public abstract class MultiFetchRequest extends Request {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the display operation name
|
||||
* @return the operation name
|
||||
*/
|
||||
protected abstract String getOperationName();
|
||||
}
|
||||
|
@ -34,16 +34,31 @@ import nodomain.freeyourgadget.gadgetbridge.service.devices.miband.operations.Op
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.GB;
|
||||
|
||||
// Ripped from nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.Request
|
||||
|
||||
/**
|
||||
* Basic request for operations with Lefun devices
|
||||
*/
|
||||
public abstract class Request extends AbstractBTLEOperation<LefunDeviceSupport> {
|
||||
protected TransactionBuilder builder;
|
||||
protected boolean removeAfterHandling = true;
|
||||
private Logger logger = (Logger) LoggerFactory.getLogger(getName());
|
||||
|
||||
/**
|
||||
* Instantiates Request
|
||||
*
|
||||
* @param support the device support
|
||||
* @param builder the transaction builder to use
|
||||
*/
|
||||
protected Request(LefunDeviceSupport support, TransactionBuilder builder) {
|
||||
super(support);
|
||||
this.builder = builder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the transaction builder
|
||||
*
|
||||
* @return the transaction builder
|
||||
*/
|
||||
public TransactionBuilder getTransactionBuilder() {
|
||||
return builder;
|
||||
}
|
||||
@ -57,36 +72,81 @@ public abstract class Request extends AbstractBTLEOperation<LefunDeviceSupport>
|
||||
getSupport().performConnected(builder.getTransaction());
|
||||
}
|
||||
|
||||
/**
|
||||
* When implemented in a subclass, provides the request bytes to send to the device
|
||||
*
|
||||
* @return the request bytes
|
||||
*/
|
||||
public abstract byte[] createRequest();
|
||||
|
||||
/**
|
||||
* When overridden in a subclass, handles the response to the current command
|
||||
*
|
||||
* @param data the response data
|
||||
*/
|
||||
public void handleResponse(byte[] data) {
|
||||
operationStatus = OperationStatus.FINISHED;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the class name of this instance
|
||||
*
|
||||
* @return the class name
|
||||
*/
|
||||
public String getName() {
|
||||
Class thisClass = getClass();
|
||||
while (thisClass.isAnonymousClass()) thisClass = thisClass.getSuperclass();
|
||||
return thisClass.getSimpleName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs a debug message
|
||||
*
|
||||
* @param message the message to log
|
||||
*/
|
||||
protected void log(String message) {
|
||||
logger.debug(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* When implemented in a subclass, returns the command ID associated with the current request
|
||||
*
|
||||
* @return the command ID
|
||||
*/
|
||||
public abstract int getCommandId();
|
||||
|
||||
/**
|
||||
* Gets whether the request will queue itself
|
||||
*
|
||||
* @return whether the request is self-queuing
|
||||
*/
|
||||
public boolean isSelfQueue() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets whether the request expects a response
|
||||
*
|
||||
* @return whether the request expects a response
|
||||
*/
|
||||
public boolean expectsResponse() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets whether the response should be removed from in progress requests list after handling
|
||||
*
|
||||
* @return whether the response should be removed after handling
|
||||
*/
|
||||
public boolean shouldRemoveAfterHandling() {
|
||||
return removeAfterHandling;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reports an error to the user
|
||||
*
|
||||
* @param message the message to show
|
||||
*/
|
||||
protected void reportFailure(String message) {
|
||||
GB.toast(getContext(), message, Toast.LENGTH_SHORT, GB.ERROR);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user