mirror of
https://codeberg.org/Freeyourgadget/Gadgetbridge
synced 2024-12-15 05:07:54 +01:00
Make use of GattServer in BtLEQueue, improve initialization sequence, improve pairing sequence and fix a few bugs
This commit is contained in:
parent
f01c9414f5
commit
e82ac8dfd7
@ -1,228 +0,0 @@
|
|||||||
/* Copyright (C) 2018-2019 Andreas Böhler, Daniele Gobbetti
|
|
||||||
based on code from BlueWatcher, https://github.com/masterjc/bluewatcher
|
|
||||||
|
|
||||||
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.service.devices.casiogb6900;
|
|
||||||
|
|
||||||
import android.bluetooth.BluetoothDevice;
|
|
||||||
import android.bluetooth.BluetoothGattCharacteristic;
|
|
||||||
import android.bluetooth.BluetoothGattDescriptor;
|
|
||||||
import android.bluetooth.BluetoothGattServer;
|
|
||||||
import android.bluetooth.BluetoothGattServerCallback;
|
|
||||||
import android.bluetooth.BluetoothGattService;
|
|
||||||
import android.bluetooth.BluetoothManager;
|
|
||||||
import android.content.Context;
|
|
||||||
import android.content.Intent;
|
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
|
|
||||||
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventMusicControl;
|
|
||||||
import nodomain.freeyourgadget.gadgetbridge.devices.casiogb6900.CasioGB6900Constants;
|
|
||||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
|
||||||
import nodomain.freeyourgadget.gadgetbridge.model.DeviceService;
|
|
||||||
import nodomain.freeyourgadget.gadgetbridge.service.DeviceCommunicationService;
|
|
||||||
|
|
||||||
class CasioGATTServer extends BluetoothGattServerCallback {
|
|
||||||
private static final Logger LOG = LoggerFactory.getLogger(CasioGATTServer.class);
|
|
||||||
|
|
||||||
private Context mContext;
|
|
||||||
private BluetoothGattServer mBluetoothGattServer;
|
|
||||||
private CasioGB6900DeviceSupport mDeviceSupport = null;
|
|
||||||
private final GBDeviceEventMusicControl musicCmd = new GBDeviceEventMusicControl();
|
|
||||||
|
|
||||||
CasioGATTServer(Context context, CasioGB6900DeviceSupport deviceSupport) {
|
|
||||||
mContext = context;
|
|
||||||
mDeviceSupport = deviceSupport;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setContext(Context ctx) {
|
|
||||||
mContext = ctx;
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean initialize() {
|
|
||||||
if(mContext == null) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
BluetoothManager bluetoothManager = (BluetoothManager) mContext.getSystemService(Context.BLUETOOTH_SERVICE);
|
|
||||||
if (bluetoothManager == null) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
mBluetoothGattServer = bluetoothManager.openGattServer(mContext, this);
|
|
||||||
if (mBluetoothGattServer == null) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
BluetoothGattService casioGATTService = new BluetoothGattService(CasioGB6900Constants.WATCH_CTRL_SERVICE_UUID, BluetoothGattService.SERVICE_TYPE_PRIMARY);
|
|
||||||
BluetoothGattCharacteristic bluetoothgGATTCharacteristic = new BluetoothGattCharacteristic(CasioGB6900Constants.KEY_CONTAINER_CHARACTERISTIC_UUID, BluetoothGattCharacteristic.PROPERTY_WRITE_NO_RESPONSE, BluetoothGattCharacteristic.PERMISSION_WRITE);
|
|
||||||
bluetoothgGATTCharacteristic.setValue(new byte[0]);
|
|
||||||
|
|
||||||
BluetoothGattCharacteristic bluetoothgGATTCharacteristic2 = new BluetoothGattCharacteristic(CasioGB6900Constants.NAME_OF_APP_CHARACTERISTIC_UUID, BluetoothGattCharacteristic.PROPERTY_READ, BluetoothGattCharacteristic.PERMISSION_READ | BluetoothGattCharacteristic.PERMISSION_READ_ENCRYPTED);
|
|
||||||
bluetoothgGATTCharacteristic2.setValue(CasioGB6900Constants.MUSIC_MESSAGE.getBytes());
|
|
||||||
|
|
||||||
BluetoothGattDescriptor bluetoothGattDescriptor = new BluetoothGattDescriptor(CasioGB6900Constants.CCC_DESCRIPTOR_UUID, BluetoothGattDescriptor.PERMISSION_READ | BluetoothGattDescriptor.PERMISSION_WRITE);
|
|
||||||
bluetoothGattDescriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
|
|
||||||
|
|
||||||
bluetoothgGATTCharacteristic2.addDescriptor(bluetoothGattDescriptor);
|
|
||||||
|
|
||||||
casioGATTService.addCharacteristic(bluetoothgGATTCharacteristic);
|
|
||||||
casioGATTService.addCharacteristic(bluetoothgGATTCharacteristic2);
|
|
||||||
mBluetoothGattServer.addService(casioGATTService);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onCharacteristicReadRequest(BluetoothDevice device, int requestId, int offset, BluetoothGattCharacteristic characteristic) {
|
|
||||||
|
|
||||||
if (!characteristic.getUuid().equals(CasioGB6900Constants.NAME_OF_APP_CHARACTERISTIC_UUID)) {
|
|
||||||
LOG.warn("unexpected read request");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
LOG.info("will send response to read request from device: " + device.getAddress());
|
|
||||||
|
|
||||||
if (!this.mBluetoothGattServer.sendResponse(device, requestId, 0, offset, CasioGB6900Constants.MUSIC_MESSAGE.getBytes())) {
|
|
||||||
LOG.warn("error sending response");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
private GBDeviceEventMusicControl.Event parse3Button(int button) {
|
|
||||||
GBDeviceEventMusicControl.Event event;
|
|
||||||
switch(button) {
|
|
||||||
case 3:
|
|
||||||
event = GBDeviceEventMusicControl.Event.NEXT;
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
event = GBDeviceEventMusicControl.Event.PREVIOUS;
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
event = GBDeviceEventMusicControl.Event.PLAYPAUSE;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
LOG.warn("Unhandled button received: " + button);
|
|
||||||
event = GBDeviceEventMusicControl.Event.UNKNOWN;
|
|
||||||
}
|
|
||||||
return event;
|
|
||||||
}
|
|
||||||
|
|
||||||
private GBDeviceEventMusicControl.Event parse2Button(int button) {
|
|
||||||
GBDeviceEventMusicControl.Event event;
|
|
||||||
switch(button) {
|
|
||||||
case 2:
|
|
||||||
event = GBDeviceEventMusicControl.Event.PLAYPAUSE;
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
event = GBDeviceEventMusicControl.Event.NEXT;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
LOG.warn("Unhandled button received: " + button);
|
|
||||||
event = GBDeviceEventMusicControl.Event.UNKNOWN;
|
|
||||||
}
|
|
||||||
return event;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onCharacteristicWriteRequest(BluetoothDevice device, int requestId, BluetoothGattCharacteristic characteristic,
|
|
||||||
boolean preparedWrite, boolean responseNeeded, int offset, byte[] value) {
|
|
||||||
|
|
||||||
if (!characteristic.getUuid().equals(CasioGB6900Constants.KEY_CONTAINER_CHARACTERISTIC_UUID)) {
|
|
||||||
LOG.warn("unexpected write request");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(mDeviceSupport == null) {
|
|
||||||
LOG.warn("mDeviceSupport is null, did initialization complete?");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if((value[0] & 0x03) == 0) {
|
|
||||||
int button = value[1] & 0x0f;
|
|
||||||
LOG.info("Button pressed: " + button);
|
|
||||||
switch(mDeviceSupport.getModel())
|
|
||||||
{
|
|
||||||
case MODEL_CASIO_5600B:
|
|
||||||
musicCmd.event = parse2Button(button);
|
|
||||||
break;
|
|
||||||
case MODEL_CASIO_6900B:
|
|
||||||
musicCmd.event = parse3Button(button);
|
|
||||||
break;
|
|
||||||
case MODEL_CASIO_GENERIC:
|
|
||||||
musicCmd.event = parse3Button(button);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
LOG.warn("Unhandled device");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
mDeviceSupport.evaluateGBDeviceEvent(musicCmd);
|
|
||||||
mDeviceSupport.evaluateGBDeviceEvent(musicCmd);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
LOG.info("received from device: " + value.toString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onConnectionStateChange(BluetoothDevice device, int status, int newState) {
|
|
||||||
|
|
||||||
LOG.info("Connection state change for device: " + device.getAddress() + " status = " + status + " newState = " + newState);
|
|
||||||
if (newState == BluetoothGattServer.STATE_DISCONNECTED) {
|
|
||||||
LOG.info("CASIO GATT server noticed disconnect.");
|
|
||||||
}
|
|
||||||
if (newState == BluetoothGattServer.STATE_CONNECTED) {
|
|
||||||
GBDevice.State devState = mDeviceSupport.getDevice().getState();
|
|
||||||
Intent deviceCommunicationServiceIntent = new Intent(mContext, DeviceCommunicationService.class);
|
|
||||||
if (devState.equals(GBDevice.State.WAITING_FOR_RECONNECT) || devState.equals(GBDevice.State.NOT_CONNECTED)) {
|
|
||||||
LOG.info("Forcing re-connect because GATT server has been reconnected.");
|
|
||||||
deviceCommunicationServiceIntent.setAction(DeviceService.ACTION_CONNECT);
|
|
||||||
deviceCommunicationServiceIntent.putExtra(GBDevice.EXTRA_DEVICE, device);
|
|
||||||
LocalBroadcastManager.getInstance(mContext).sendBroadcast(deviceCommunicationServiceIntent);
|
|
||||||
//PendingIntent reconnectPendingIntent = PendingIntent.getService(mContext, 2, deviceCommunicationServiceIntent, PendingIntent.FLAG_UPDATE_CURRENT);
|
|
||||||
//builder.addAction(R.drawable.ic_notification, context.getString(R.string.controlcenter_connect), reconnectPendingIntent);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onDescriptorWriteRequest(BluetoothDevice device, int requestId, BluetoothGattDescriptor descriptor,
|
|
||||||
boolean preparedWrite, boolean responseNeeded, int offset, byte[] value) {
|
|
||||||
|
|
||||||
LOG.info("onDescriptorWriteRequest() notifications enabled = " + (value[0] == 1));
|
|
||||||
if (!this.mBluetoothGattServer.sendResponse(device, requestId, 0, offset, value)) {
|
|
||||||
LOG.warn("onDescriptorWriteRequest() error sending response!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onServiceAdded(int status, BluetoothGattService service) {
|
|
||||||
LOG.info("onServiceAdded() status = " + status + " service = " + service.getUuid());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onNotificationSent(BluetoothDevice bluetoothDevice, int status) {
|
|
||||||
LOG.info("onNotificationSent() status = " + status + " to device " + bluetoothDevice.getAddress());
|
|
||||||
}
|
|
||||||
|
|
||||||
void close() {
|
|
||||||
if (mBluetoothGattServer != null) {
|
|
||||||
mBluetoothGattServer.clearServices();
|
|
||||||
mBluetoothGattServer.close();
|
|
||||||
mBluetoothGattServer = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,72 +0,0 @@
|
|||||||
/* Copyright (C) 2018-2019 Andreas Böhler
|
|
||||||
based on code from BlueWatcher, https://github.com/masterjc/bluewatcher
|
|
||||||
|
|
||||||
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.service.devices.casiogb6900;
|
|
||||||
import android.content.Context;
|
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
public class CasioGATTThread extends Thread {
|
|
||||||
CasioGATTServer mServer = null;
|
|
||||||
private static final Logger LOG = LoggerFactory.getLogger(CasioGATTThread.class);
|
|
||||||
private boolean mStopFlag = false;
|
|
||||||
private final Object waitObject = new Object();
|
|
||||||
|
|
||||||
public CasioGATTThread(Context context, CasioGB6900DeviceSupport deviceSupport)
|
|
||||||
{
|
|
||||||
mServer = new CasioGATTServer(context, deviceSupport);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setContext(Context ctx) {
|
|
||||||
mServer.setContext(ctx);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
if (!mServer.initialize()) {
|
|
||||||
LOG.error("Error initializing CasioGATTServer. Has the context been set?");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
long waitTime = 60 * 1000;
|
|
||||||
|
|
||||||
while (!mStopFlag) {
|
|
||||||
synchronized (waitObject) {
|
|
||||||
try {
|
|
||||||
waitObject.wait(waitTime);
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mStopFlag) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
mServer.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void quit() {
|
|
||||||
mStopFlag = true;
|
|
||||||
synchronized (waitObject) {
|
|
||||||
waitObject.notify();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
@ -17,12 +17,13 @@
|
|||||||
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||||
package nodomain.freeyourgadget.gadgetbridge.service.devices.casiogb6900;
|
package nodomain.freeyourgadget.gadgetbridge.service.devices.casiogb6900;
|
||||||
|
|
||||||
import android.bluetooth.BluetoothAdapter;
|
import android.bluetooth.BluetoothDevice;
|
||||||
import android.bluetooth.BluetoothGatt;
|
import android.bluetooth.BluetoothGatt;
|
||||||
import android.bluetooth.BluetoothGattCharacteristic;
|
import android.bluetooth.BluetoothGattCharacteristic;
|
||||||
|
import android.bluetooth.BluetoothGattDescriptor;
|
||||||
import android.bluetooth.BluetoothGattService;
|
import android.bluetooth.BluetoothGattService;
|
||||||
import android.content.Context;
|
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
@ -35,6 +36,7 @@ import java.util.UUID;
|
|||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventFindPhone;
|
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventFindPhone;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventMusicControl;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.devices.casiogb6900.CasioGB6900Constants;
|
import nodomain.freeyourgadget.gadgetbridge.devices.casiogb6900.CasioGB6900Constants;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.model.Alarm;
|
import nodomain.freeyourgadget.gadgetbridge.model.Alarm;
|
||||||
@ -48,22 +50,24 @@ import nodomain.freeyourgadget.gadgetbridge.model.WeatherSpec;
|
|||||||
import nodomain.freeyourgadget.gadgetbridge.service.btle.AbstractBTLEDeviceSupport;
|
import nodomain.freeyourgadget.gadgetbridge.service.btle.AbstractBTLEDeviceSupport;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.service.btle.GattCharacteristic;
|
import nodomain.freeyourgadget.gadgetbridge.service.btle.GattCharacteristic;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.service.btle.GattService;
|
import nodomain.freeyourgadget.gadgetbridge.service.btle.GattService;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.service.btle.ServerTransactionBuilder;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.service.btle.TransactionBuilder;
|
import nodomain.freeyourgadget.gadgetbridge.service.btle.TransactionBuilder;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.service.devices.casiogb6900.operations.InitOperation;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.util.GB;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.util.StringUtils;
|
import nodomain.freeyourgadget.gadgetbridge.util.StringUtils;
|
||||||
|
|
||||||
public class CasioGB6900DeviceSupport extends AbstractBTLEDeviceSupport {
|
public class CasioGB6900DeviceSupport extends AbstractBTLEDeviceSupport {
|
||||||
private static final Logger LOG = LoggerFactory.getLogger(CasioGB6900DeviceSupport.class);
|
private static final Logger LOG = LoggerFactory.getLogger(CasioGB6900DeviceSupport.class);
|
||||||
|
|
||||||
private ArrayList<BluetoothGattCharacteristic> mCasioCharacteristics = new ArrayList<BluetoothGattCharacteristic>();
|
private ArrayList<BluetoothGattCharacteristic> mCasioCharacteristics = new ArrayList<BluetoothGattCharacteristic>();
|
||||||
private CasioGATTThread mThread;
|
|
||||||
private CasioHandlerThread mHandlerThread = null;
|
private CasioHandlerThread mHandlerThread = null;
|
||||||
private MusicSpec mBufferMusicSpec = null;
|
private MusicSpec mBufferMusicSpec = null;
|
||||||
private MusicStateSpec mBufferMusicStateSpec = null;
|
private MusicStateSpec mBufferMusicStateSpec = null;
|
||||||
private BluetoothGatt mBtGatt = null;
|
private BluetoothGatt mBtGatt = null;
|
||||||
private CasioGB6900Constants.Model mModel = CasioGB6900Constants.Model.MODEL_CASIO_GENERIC;
|
private CasioGB6900Constants.Model mModel = CasioGB6900Constants.Model.MODEL_CASIO_GENERIC;
|
||||||
private byte[] mBleSettings = null;
|
private boolean mFirstConnect = false;
|
||||||
|
|
||||||
private static final int mCasioSleepTime = 80;
|
private static final int mCasioSleepTime = 50;
|
||||||
|
|
||||||
public CasioGB6900DeviceSupport() {
|
public CasioGB6900DeviceSupport() {
|
||||||
super(LOG);
|
super(LOG);
|
||||||
@ -79,14 +83,30 @@ public class CasioGB6900DeviceSupport extends AbstractBTLEDeviceSupport {
|
|||||||
addSupportedService(CasioGB6900Constants.TX_POWER_SERVICE_UUID);
|
addSupportedService(CasioGB6900Constants.TX_POWER_SERVICE_UUID);
|
||||||
addSupportedService(CasioGB6900Constants.LINK_LOSS_SERVICE);
|
addSupportedService(CasioGB6900Constants.LINK_LOSS_SERVICE);
|
||||||
addSupportedService(CasioGB6900Constants.IMMEDIATE_ALERT_SERVICE_UUID);
|
addSupportedService(CasioGB6900Constants.IMMEDIATE_ALERT_SERVICE_UUID);
|
||||||
mThread = new CasioGATTThread(getContext(), this);
|
|
||||||
|
BluetoothGattService casioGATTService = new BluetoothGattService(CasioGB6900Constants.WATCH_CTRL_SERVICE_UUID, BluetoothGattService.SERVICE_TYPE_PRIMARY);
|
||||||
|
BluetoothGattCharacteristic bluetoothGATTCharacteristic = new BluetoothGattCharacteristic(CasioGB6900Constants.KEY_CONTAINER_CHARACTERISTIC_UUID, BluetoothGattCharacteristic.PROPERTY_WRITE_NO_RESPONSE, BluetoothGattCharacteristic.PERMISSION_WRITE);
|
||||||
|
bluetoothGATTCharacteristic.setValue(new byte[0]);
|
||||||
|
|
||||||
|
BluetoothGattCharacteristic bluetoothGATTCharacteristic2 = new BluetoothGattCharacteristic(CasioGB6900Constants.NAME_OF_APP_CHARACTERISTIC_UUID, BluetoothGattCharacteristic.PROPERTY_READ, BluetoothGattCharacteristic.PERMISSION_READ | BluetoothGattCharacteristic.PERMISSION_READ_ENCRYPTED);
|
||||||
|
bluetoothGATTCharacteristic2.setValue(CasioGB6900Constants.MUSIC_MESSAGE.getBytes());
|
||||||
|
|
||||||
|
BluetoothGattDescriptor bluetoothGattDescriptor = new BluetoothGattDescriptor(CasioGB6900Constants.CCC_DESCRIPTOR_UUID, BluetoothGattDescriptor.PERMISSION_READ | BluetoothGattDescriptor.PERMISSION_WRITE);
|
||||||
|
bluetoothGattDescriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
|
||||||
|
|
||||||
|
bluetoothGATTCharacteristic2.addDescriptor(bluetoothGattDescriptor);
|
||||||
|
|
||||||
|
casioGATTService.addCharacteristic(bluetoothGATTCharacteristic);
|
||||||
|
casioGATTService.addCharacteristic(bluetoothGATTCharacteristic2);
|
||||||
|
|
||||||
|
addSupportedServerService(casioGATTService);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setContext(GBDevice gbDevice, BluetoothAdapter btAdapter, Context context) {
|
public boolean connectFirstTime() {
|
||||||
super.setContext(gbDevice, btAdapter, context);
|
GB.toast(getContext(), "After first connect, disable and enable bluetooth on your Casio watch to really connect", Toast.LENGTH_SHORT, GB.INFO);
|
||||||
mThread.setContext(context);
|
mFirstConnect = true;
|
||||||
mThread.start();
|
return super.connect();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -103,12 +123,6 @@ public class CasioGB6900DeviceSupport extends AbstractBTLEDeviceSupport {
|
|||||||
mHandlerThread.interrupt();
|
mHandlerThread.interrupt();
|
||||||
mHandlerThread = null;
|
mHandlerThread = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(mThread != null) {
|
|
||||||
mThread.quit();
|
|
||||||
mThread.interrupt();
|
|
||||||
mThread = null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -121,6 +135,14 @@ public class CasioGB6900DeviceSupport extends AbstractBTLEDeviceSupport {
|
|||||||
protected TransactionBuilder initializeDevice(TransactionBuilder builder) {
|
protected TransactionBuilder initializeDevice(TransactionBuilder builder) {
|
||||||
LOG.info("Initializing");
|
LOG.info("Initializing");
|
||||||
|
|
||||||
|
if(mFirstConnect) {
|
||||||
|
gbDevice.setState(GBDevice.State.INITIALIZED);
|
||||||
|
gbDevice.sendDeviceUpdateIntent(getContext());
|
||||||
|
getDevice().setFirmwareVersion("N/A");
|
||||||
|
getDevice().setFirmwareVersion2("N/A");
|
||||||
|
return builder;
|
||||||
|
}
|
||||||
|
|
||||||
String name = gbDevice.getName();
|
String name = gbDevice.getName();
|
||||||
|
|
||||||
if(name.contains("5600B")) {
|
if(name.contains("5600B")) {
|
||||||
@ -131,17 +153,27 @@ public class CasioGB6900DeviceSupport extends AbstractBTLEDeviceSupport {
|
|||||||
mModel = CasioGB6900Constants.Model.MODEL_CASIO_GENERIC;
|
mModel = CasioGB6900Constants.Model.MODEL_CASIO_GENERIC;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
new InitOperation(this, builder).perform();
|
||||||
|
} catch (IOException e) {
|
||||||
|
GB.toast(getContext(), "Initializing Casio watch failed", Toast.LENGTH_SHORT, GB.ERROR, e);
|
||||||
|
}
|
||||||
|
/*
|
||||||
gbDevice.setState(GBDevice.State.INITIALIZING);
|
gbDevice.setState(GBDevice.State.INITIALIZING);
|
||||||
gbDevice.sendDeviceUpdateIntent(getContext());
|
gbDevice.sendDeviceUpdateIntent(getContext());
|
||||||
|
*/
|
||||||
|
|
||||||
|
getDevice().setFirmwareVersion("N/A");
|
||||||
|
getDevice().setFirmwareVersion2("N/A");
|
||||||
|
|
||||||
addCharacteristics();
|
|
||||||
|
|
||||||
builder.setGattCallback(this);
|
builder.setGattCallback(this);
|
||||||
|
|
||||||
enableNotifications(builder, true);
|
|
||||||
|
|
||||||
configureWatch(builder);
|
configureWatch(builder);
|
||||||
|
|
||||||
|
addCharacteristics();
|
||||||
|
enableNotifications(builder, true);
|
||||||
|
|
||||||
LOG.info("Initialization Done");
|
LOG.info("Initialization Done");
|
||||||
|
|
||||||
return builder;
|
return builder;
|
||||||
@ -251,52 +283,22 @@ public class CasioGB6900DeviceSupport extends AbstractBTLEDeviceSupport {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void readBleSettings() {
|
|
||||||
try {
|
|
||||||
TransactionBuilder builder = performInitialized("readBleSettings");
|
|
||||||
builder.read(getCharacteristic(CasioGB6900Constants.CASIO_SETTING_FOR_BLE_CHARACTERISTIC_UUID));
|
|
||||||
builder.queue(getQueue());
|
|
||||||
} catch(IOException e) {
|
|
||||||
LOG.error("Error reading BLE settings: " + e.getMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void configureBleSettings() {
|
|
||||||
// These values seem to improve connection stability _on my phone_
|
|
||||||
// Maybe they should be configurable?
|
|
||||||
int slaveLatency = 2;
|
|
||||||
int connInterval = 300;
|
|
||||||
|
|
||||||
mBleSettings[5] = (byte)(connInterval & 0xff);
|
|
||||||
mBleSettings[6] = (byte)((connInterval >> 8) & 0xff);
|
|
||||||
mBleSettings[7] = (byte)(slaveLatency & 0xff);
|
|
||||||
mBleSettings[8] = (byte)((slaveLatency >> 8) & 0xff);
|
|
||||||
|
|
||||||
mBleSettings[9] = 0; // Setting for Disconnect!?
|
|
||||||
}
|
|
||||||
|
|
||||||
private void writeBleSettings() {
|
|
||||||
try {
|
|
||||||
TransactionBuilder builder = performInitialized("writeBleSettings");
|
|
||||||
builder.write(getCharacteristic(CasioGB6900Constants.CASIO_SETTING_FOR_BLE_CHARACTERISTIC_UUID), mBleSettings);
|
|
||||||
builder.queue(getQueue());
|
|
||||||
} catch(IOException e) {
|
|
||||||
LOG.error("Error writing BLE settings: " + e.getMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
private boolean handleInitResponse(byte data) {
|
private boolean handleInitResponse(byte data) {
|
||||||
boolean handled = false;
|
boolean handled = false;
|
||||||
switch(data)
|
switch(data)
|
||||||
{
|
{
|
||||||
case (byte) 1:
|
case (byte) 1:
|
||||||
LOG.info("Initialization done, setting state to INITIALIZED");
|
LOG.info("Initialization done, setting state to INITIALIZED");
|
||||||
if(mHandlerThread == null) {
|
if(mHandlerThread != null) {
|
||||||
mHandlerThread = new CasioHandlerThread(getDevice(), getContext(), this);
|
if(mHandlerThread.isAlive()) {
|
||||||
|
mHandlerThread.quit();
|
||||||
|
mHandlerThread.interrupt();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
mHandlerThread = new CasioHandlerThread(getDevice(), getContext(), this);
|
||||||
mHandlerThread.start();
|
mHandlerThread.start();
|
||||||
gbDevice.setState(GBDevice.State.INITIALIZED);
|
gbDevice.setState(GBDevice.State.INITIALIZED);
|
||||||
gbDevice.sendDeviceUpdateIntent(getContext());
|
gbDevice.sendDeviceUpdateIntent(getContext());
|
||||||
readBleSettings();
|
|
||||||
handled = true;
|
handled = true;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@ -351,7 +353,7 @@ public class CasioGB6900DeviceSupport extends AbstractBTLEDeviceSupport {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean handleCasioCom(byte[] data) {
|
private boolean handleCasioCom(byte[] data, boolean handleTime) {
|
||||||
boolean handled = false;
|
boolean handled = false;
|
||||||
|
|
||||||
if(data.length < 3) {
|
if(data.length < 3) {
|
||||||
@ -365,7 +367,11 @@ public class CasioGB6900DeviceSupport extends AbstractBTLEDeviceSupport {
|
|||||||
handled = handleInitResponse(data[2]);
|
handled = handleInitResponse(data[2]);
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
handled = handleTimeRequests(data[2]);
|
if(handleTime) {
|
||||||
|
handled = handleTimeRequests(data[2]);
|
||||||
|
} else {
|
||||||
|
handled = true;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case 7:
|
case 7:
|
||||||
handled = handleServerFeatureRequests(data[2]);
|
handled = handleServerFeatureRequests(data[2]);
|
||||||
@ -376,7 +382,7 @@ public class CasioGB6900DeviceSupport extends AbstractBTLEDeviceSupport {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onCharacteristicRead(BluetoothGatt gatt,
|
public boolean onCharacteristicRead(BluetoothGatt gatt,
|
||||||
BluetoothGattCharacteristic characteristic, int status) {
|
BluetoothGattCharacteristic characteristic, int status) {
|
||||||
|
|
||||||
UUID characteristicUUID = characteristic.getUuid();
|
UUID characteristicUUID = characteristic.getUuid();
|
||||||
byte[] data = characteristic.getValue();
|
byte[] data = characteristic.getValue();
|
||||||
@ -391,63 +397,6 @@ public class CasioGB6900DeviceSupport extends AbstractBTLEDeviceSupport {
|
|||||||
}
|
}
|
||||||
LOG.info(str);
|
LOG.info(str);
|
||||||
}
|
}
|
||||||
else if(characteristicUUID.equals(CasioGB6900Constants.CASIO_SETTING_FOR_BLE_CHARACTERISTIC_UUID)) {
|
|
||||||
mBleSettings = data;
|
|
||||||
String str = "Read Casio Setting for BLE: ";
|
|
||||||
for(int i=0; i<data.length; i++) {
|
|
||||||
str += String.format("0x%1x ", data[i]);
|
|
||||||
}
|
|
||||||
/* Definition of parameters - for future reference */
|
|
||||||
|
|
||||||
// data[0]; // BLE alert for call, mail and other
|
|
||||||
// data[1]; // BLE alert for Calendar
|
|
||||||
// data[2]; // BLE alert for SNS
|
|
||||||
// data[3]; // BLE alert for vibration and alarm
|
|
||||||
// data[4]; // BLE alert for animation
|
|
||||||
// data[5]; // Connection Interval
|
|
||||||
// data[6]; // Connection Interval
|
|
||||||
// data[7]; // Slave Latency
|
|
||||||
// data[8]; // Slave Latency
|
|
||||||
|
|
||||||
// Alert definitions:
|
|
||||||
// 0 = Off
|
|
||||||
// 1 = Sound
|
|
||||||
// 2 = Vibration
|
|
||||||
// 3 = Sound and Vibration
|
|
||||||
//int callAlert = (data[0] >> 6) & 0x03;
|
|
||||||
//LOG.info("Call Alert: " + callAlert);
|
|
||||||
//int mailAlert = (data[0] >> 2) & 0x03;
|
|
||||||
//LOG.info("Mail Alert: " + mailAlert);
|
|
||||||
//int snsAlert = (data[2] >> 4) & 0x03;
|
|
||||||
//LOG.info("SNS Alert: " + snsAlert);
|
|
||||||
//int calAlert = (data[1] >> 6) & 0x03;
|
|
||||||
//LOG.info("Calendart Alert: " + calAlert);
|
|
||||||
//int otherAlert = (data[0] & 0x03);
|
|
||||||
//LOG.info("Other Alert: " + otherAlert);
|
|
||||||
//int vibrationValue = (data[3] & 0x0f);
|
|
||||||
//LOG.info("Vibration Value: " + vibrationValue);
|
|
||||||
//int alarmValue = (data[3] >> 4) & 0x0f;
|
|
||||||
// Vibration pattern; A = 0, B = 1, C = 2
|
|
||||||
//LOG.info("Alarm Value: " + alarmValue);
|
|
||||||
//int animationValue = data[4] & 0x40;
|
|
||||||
// Length of Alarm, only 2, 5 and 10 possible
|
|
||||||
//LOG.info("Animation Value: " + animationValue);
|
|
||||||
// 0 = on
|
|
||||||
// 64 = off
|
|
||||||
//int useDisableMtuReqBit = data[4] & 0x08;
|
|
||||||
// 8 = on
|
|
||||||
// 0 = off!?
|
|
||||||
//LOG.info("useDisableMtuReqBit: " + useDisableMtuReqBit);
|
|
||||||
|
|
||||||
//int slaveLatency = ((data[7] & 0xff) | ((data[8] & 0xff) << 8));
|
|
||||||
//int connInterval = ((data[5] & 0xff) | ((data[6] & 0xff) << 8));
|
|
||||||
//LOG.info("Slave Latency: " + slaveLatency);
|
|
||||||
//LOG.info("Connection Interval: " + connInterval);
|
|
||||||
//LOG.info(str);
|
|
||||||
|
|
||||||
configureBleSettings();
|
|
||||||
writeBleSettings();
|
|
||||||
}
|
|
||||||
else {
|
else {
|
||||||
return super.onCharacteristicRead(gatt, characteristic, status);
|
return super.onCharacteristicRead(gatt, characteristic, status);
|
||||||
}
|
}
|
||||||
@ -466,11 +415,11 @@ public class CasioGB6900DeviceSupport extends AbstractBTLEDeviceSupport {
|
|||||||
return true;
|
return true;
|
||||||
|
|
||||||
if(characteristicUUID.equals(CasioGB6900Constants.CASIO_A_NOT_W_REQ_NOT)) {
|
if(characteristicUUID.equals(CasioGB6900Constants.CASIO_A_NOT_W_REQ_NOT)) {
|
||||||
handled = handleCasioCom(data);
|
handled = handleCasioCom(data, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(characteristicUUID.equals(CasioGB6900Constants.CASIO_A_NOT_COM_SET_NOT)) {
|
if(characteristicUUID.equals(CasioGB6900Constants.CASIO_A_NOT_COM_SET_NOT)) {
|
||||||
handled = handleCasioCom(data);
|
handled = handleCasioCom(data, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(characteristicUUID.equals(CasioGB6900Constants.ALERT_LEVEL_CHARACTERISTIC_UUID)) {
|
if(characteristicUUID.equals(CasioGB6900Constants.ALERT_LEVEL_CHARACTERISTIC_UUID)) {
|
||||||
@ -481,7 +430,7 @@ public class CasioGB6900DeviceSupport extends AbstractBTLEDeviceSupport {
|
|||||||
else {
|
else {
|
||||||
findPhoneEvent.event = GBDeviceEventFindPhone.Event.STOP;
|
findPhoneEvent.event = GBDeviceEventFindPhone.Event.STOP;
|
||||||
}
|
}
|
||||||
evaluateGBDeviceEvent(findPhoneEvent);
|
evaluateGBDeviceEvent(findPhoneEvent);
|
||||||
handled = true;
|
handled = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -501,6 +450,8 @@ public class CasioGB6900DeviceSupport extends AbstractBTLEDeviceSupport {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void showNotification(byte icon, String title, String message) {
|
private void showNotification(byte icon, String title, String message) {
|
||||||
|
if(!isConnected())
|
||||||
|
return;
|
||||||
try {
|
try {
|
||||||
TransactionBuilder builder = performInitialized("showNotification");
|
TransactionBuilder builder = performInitialized("showNotification");
|
||||||
int len;
|
int len;
|
||||||
@ -558,6 +509,10 @@ public class CasioGB6900DeviceSupport extends AbstractBTLEDeviceSupport {
|
|||||||
public void onSetAlarms(ArrayList<? extends Alarm> alarms) {
|
public void onSetAlarms(ArrayList<? extends Alarm> alarms) {
|
||||||
int alarmOffset = 4;
|
int alarmOffset = 4;
|
||||||
byte[] data = new byte[20];
|
byte[] data = new byte[20];
|
||||||
|
|
||||||
|
if(!isConnected())
|
||||||
|
return;
|
||||||
|
|
||||||
for(int i=0; i<alarms.size(); i++)
|
for(int i=0; i<alarms.size(); i++)
|
||||||
{
|
{
|
||||||
Alarm alm = alarms.get(i);
|
Alarm alm = alarms.get(i);
|
||||||
@ -584,6 +539,9 @@ public class CasioGB6900DeviceSupport extends AbstractBTLEDeviceSupport {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onSetTime() {
|
public void onSetTime() {
|
||||||
|
if(!isConnected())
|
||||||
|
return;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
TransactionBuilder builder = performInitialized("SetTime");
|
TransactionBuilder builder = performInitialized("SetTime");
|
||||||
writeCasioLocalTimeInformation(builder);
|
writeCasioLocalTimeInformation(builder);
|
||||||
@ -622,6 +580,9 @@ public class CasioGB6900DeviceSupport extends AbstractBTLEDeviceSupport {
|
|||||||
|
|
||||||
private void sendMusicInfo()
|
private void sendMusicInfo()
|
||||||
{
|
{
|
||||||
|
if(!isConnected())
|
||||||
|
return;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
TransactionBuilder builder = performInitialized("sendMusicInfo");
|
TransactionBuilder builder = performInitialized("sendMusicInfo");
|
||||||
String info = "";
|
String info = "";
|
||||||
@ -716,6 +677,9 @@ public class CasioGB6900DeviceSupport extends AbstractBTLEDeviceSupport {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onFindDevice(boolean start) {
|
public void onFindDevice(boolean start) {
|
||||||
|
if(!isConnected())
|
||||||
|
return;
|
||||||
|
|
||||||
if(start) {
|
if(start) {
|
||||||
try {
|
try {
|
||||||
TransactionBuilder builder = performInitialized("findDevice");
|
TransactionBuilder builder = performInitialized("findDevice");
|
||||||
@ -781,4 +745,95 @@ public class CasioGB6900DeviceSupport extends AbstractBTLEDeviceSupport {
|
|||||||
public void onSendWeather(WeatherSpec weatherSpec) {
|
public void onSendWeather(WeatherSpec weatherSpec) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onCharacteristicReadRequest(BluetoothDevice device, int requestId, int offset, BluetoothGattCharacteristic characteristic) {
|
||||||
|
|
||||||
|
if (!characteristic.getUuid().equals(CasioGB6900Constants.NAME_OF_APP_CHARACTERISTIC_UUID)) {
|
||||||
|
LOG.warn("unexpected read request");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG.info("will send response to read request from device: " + device.getAddress());
|
||||||
|
|
||||||
|
try {
|
||||||
|
ServerTransactionBuilder builder = performServer("sendNameOfApp");
|
||||||
|
builder.writeServerResponse(device, requestId, 0, offset, CasioGB6900Constants.MUSIC_MESSAGE.getBytes());
|
||||||
|
builder.queue(getQueue());
|
||||||
|
} catch (IOException e) {
|
||||||
|
LOG.warn("sendMusicInfo failed: " + e.getMessage());
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private GBDeviceEventMusicControl.Event parse3Button(int button) {
|
||||||
|
GBDeviceEventMusicControl.Event event;
|
||||||
|
switch(button) {
|
||||||
|
case 3:
|
||||||
|
event = GBDeviceEventMusicControl.Event.NEXT;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
event = GBDeviceEventMusicControl.Event.PREVIOUS;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
event = GBDeviceEventMusicControl.Event.PLAYPAUSE;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
LOG.warn("Unhandled button received: " + button);
|
||||||
|
event = GBDeviceEventMusicControl.Event.UNKNOWN;
|
||||||
|
}
|
||||||
|
return event;
|
||||||
|
}
|
||||||
|
|
||||||
|
private GBDeviceEventMusicControl.Event parse2Button(int button) {
|
||||||
|
GBDeviceEventMusicControl.Event event;
|
||||||
|
switch(button) {
|
||||||
|
case 2:
|
||||||
|
event = GBDeviceEventMusicControl.Event.PLAYPAUSE;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
event = GBDeviceEventMusicControl.Event.NEXT;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
LOG.warn("Unhandled button received: " + button);
|
||||||
|
event = GBDeviceEventMusicControl.Event.UNKNOWN;
|
||||||
|
}
|
||||||
|
return event;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onCharacteristicWriteRequest(BluetoothDevice device, int requestId, BluetoothGattCharacteristic characteristic,
|
||||||
|
boolean preparedWrite, boolean responseNeeded, int offset, byte[] value) {
|
||||||
|
|
||||||
|
GBDeviceEventMusicControl musicCmd = new GBDeviceEventMusicControl();
|
||||||
|
if (!characteristic.getUuid().equals(CasioGB6900Constants.KEY_CONTAINER_CHARACTERISTIC_UUID)) {
|
||||||
|
LOG.warn("unexpected write request");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if((value[0] & 0x03) == 0) {
|
||||||
|
int button = value[1] & 0x0f;
|
||||||
|
LOG.info("Button pressed: " + button);
|
||||||
|
switch(getModel())
|
||||||
|
{
|
||||||
|
case MODEL_CASIO_5600B:
|
||||||
|
musicCmd.event = parse2Button(button);
|
||||||
|
break;
|
||||||
|
case MODEL_CASIO_6900B:
|
||||||
|
musicCmd.event = parse3Button(button);
|
||||||
|
break;
|
||||||
|
case MODEL_CASIO_GENERIC:
|
||||||
|
musicCmd.event = parse3Button(button);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
LOG.warn("Unhandled device");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
evaluateGBDeviceEvent(musicCmd);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
LOG.info("received from device: " + value.toString());
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -33,7 +33,6 @@ public class CasioHandlerThread extends GBDeviceIoThread {
|
|||||||
private boolean mQuit = false;
|
private boolean mQuit = false;
|
||||||
private CasioGB6900DeviceSupport mDeviceSupport;
|
private CasioGB6900DeviceSupport mDeviceSupport;
|
||||||
private final Object waitObject = new Object();
|
private final Object waitObject = new Object();
|
||||||
//private CasioGATTServer mServer = null;
|
|
||||||
|
|
||||||
private int TX_PERIOD = 60;
|
private int TX_PERIOD = 60;
|
||||||
|
|
||||||
@ -43,7 +42,6 @@ public class CasioHandlerThread extends GBDeviceIoThread {
|
|||||||
super(gbDevice, context);
|
super(gbDevice, context);
|
||||||
LOG.info("Initializing Casio Handler Thread");
|
LOG.info("Initializing Casio Handler Thread");
|
||||||
mQuit = false;
|
mQuit = false;
|
||||||
//mServer = new CasioGATTServer(context, deviceSupport);
|
|
||||||
mDeviceSupport = deviceSupport;
|
mDeviceSupport = deviceSupport;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -51,13 +49,6 @@ public class CasioHandlerThread extends GBDeviceIoThread {
|
|||||||
public void run() {
|
public void run() {
|
||||||
mQuit = false;
|
mQuit = false;
|
||||||
|
|
||||||
/*
|
|
||||||
if(!mServer.initialize()) {
|
|
||||||
LOG.error("Error initializing CasioGATTServer. Has the context been set?");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
long waitTime = TX_PERIOD * 1000;
|
long waitTime = TX_PERIOD * 1000;
|
||||||
while (!mQuit) {
|
while (!mQuit) {
|
||||||
|
|
||||||
|
@ -0,0 +1,168 @@
|
|||||||
|
/* Copyright (C) 2016-2018 Andreas Böhler
|
||||||
|
|
||||||
|
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.service.devices.casiogb6900.operations;
|
||||||
|
|
||||||
|
import android.bluetooth.BluetoothGatt;
|
||||||
|
import android.bluetooth.BluetoothGattCharacteristic;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.devices.casiogb6900.CasioGB6900Constants;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.service.btle.AbstractBTLEOperation;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.service.btle.TransactionBuilder;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.service.btle.actions.SetDeviceStateAction;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.service.devices.casiogb6900.CasioGB6900DeviceSupport;
|
||||||
|
|
||||||
|
public class InitOperation extends AbstractBTLEOperation<CasioGB6900DeviceSupport> {
|
||||||
|
private static final Logger LOG = LoggerFactory.getLogger(InitOperation.class);
|
||||||
|
|
||||||
|
private final TransactionBuilder builder;
|
||||||
|
private byte[] mBleSettings = null;
|
||||||
|
|
||||||
|
|
||||||
|
public InitOperation(CasioGB6900DeviceSupport support, TransactionBuilder builder) {
|
||||||
|
super(support);
|
||||||
|
this.builder = builder;
|
||||||
|
builder.setGattCallback(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void doPerform() throws IOException {
|
||||||
|
builder.add(new SetDeviceStateAction(getDevice(), GBDevice.State.INITIALIZING, getContext()));
|
||||||
|
TransactionBuilder builder = getSupport().createTransactionBuilder("readBleSettings");
|
||||||
|
builder.setGattCallback(this);
|
||||||
|
builder.read(getCharacteristic(CasioGB6900Constants.CASIO_SETTING_FOR_BLE_CHARACTERISTIC_UUID));
|
||||||
|
getSupport().performImmediately(builder);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TransactionBuilder performInitialized(String taskName) throws IOException {
|
||||||
|
throw new UnsupportedOperationException("This IS the initialization class, you cannot call this method");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onCharacteristicChanged(BluetoothGatt gatt,
|
||||||
|
BluetoothGattCharacteristic characteristic) {
|
||||||
|
UUID characteristicUUID = characteristic.getUuid();
|
||||||
|
LOG.info("Unhandled characteristic changed: " + characteristicUUID);
|
||||||
|
return super.onCharacteristicChanged(gatt, characteristic);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void configureBleSettings() {
|
||||||
|
// These values seem to improve connection stability _on my phone_
|
||||||
|
// Maybe they should be configurable?
|
||||||
|
int slaveLatency = 2;
|
||||||
|
int connInterval = 300;
|
||||||
|
|
||||||
|
mBleSettings[5] = (byte)(connInterval & 0xff);
|
||||||
|
mBleSettings[6] = (byte)((connInterval >> 8) & 0xff);
|
||||||
|
mBleSettings[7] = (byte)(slaveLatency & 0xff);
|
||||||
|
mBleSettings[8] = (byte)((slaveLatency >> 8) & 0xff);
|
||||||
|
|
||||||
|
mBleSettings[9] = 0; // Setting for Disconnect!?
|
||||||
|
}
|
||||||
|
|
||||||
|
private void writeBleSettings() {
|
||||||
|
try {
|
||||||
|
TransactionBuilder builder = getSupport().createTransactionBuilder("writeBleInit");
|
||||||
|
builder.setGattCallback(this);
|
||||||
|
builder.write(getCharacteristic(CasioGB6900Constants.CASIO_SETTING_FOR_BLE_CHARACTERISTIC_UUID), mBleSettings);
|
||||||
|
getSupport().performImmediately(builder);
|
||||||
|
} catch(IOException e) {
|
||||||
|
LOG.error("Error writing BLE settings: " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onCharacteristicRead(BluetoothGatt gatt,
|
||||||
|
BluetoothGattCharacteristic characteristic, int status) {
|
||||||
|
|
||||||
|
UUID characteristicUUID = characteristic.getUuid();
|
||||||
|
byte[] data = characteristic.getValue();
|
||||||
|
|
||||||
|
if(data.length == 0)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if(characteristicUUID.equals(CasioGB6900Constants.CASIO_SETTING_FOR_BLE_CHARACTERISTIC_UUID)) {
|
||||||
|
mBleSettings = data;
|
||||||
|
String str = "Read Casio Setting for BLE: ";
|
||||||
|
for(int i=0; i<data.length; i++) {
|
||||||
|
str += String.format("0x%1x ", data[i]);
|
||||||
|
}
|
||||||
|
/* Definition of parameters - for future reference */
|
||||||
|
|
||||||
|
// data[0]; // BLE alert for call, mail and other
|
||||||
|
// data[1]; // BLE alert for Calendar
|
||||||
|
// data[2]; // BLE alert for SNS
|
||||||
|
// data[3]; // BLE alert for vibration and alarm
|
||||||
|
// data[4]; // BLE alert for animation
|
||||||
|
// data[5]; // Connection Interval
|
||||||
|
// data[6]; // Connection Interval
|
||||||
|
// data[7]; // Slave Latency
|
||||||
|
// data[8]; // Slave Latency
|
||||||
|
|
||||||
|
// Alert definitions:
|
||||||
|
// 0 = Off
|
||||||
|
// 1 = Sound
|
||||||
|
// 2 = Vibration
|
||||||
|
// 3 = Sound and Vibration
|
||||||
|
//int callAlert = (data[0] >> 6) & 0x03;
|
||||||
|
//LOG.info("Call Alert: " + callAlert);
|
||||||
|
//int mailAlert = (data[0] >> 2) & 0x03;
|
||||||
|
//LOG.info("Mail Alert: " + mailAlert);
|
||||||
|
//int snsAlert = (data[2] >> 4) & 0x03;
|
||||||
|
//LOG.info("SNS Alert: " + snsAlert);
|
||||||
|
//int calAlert = (data[1] >> 6) & 0x03;
|
||||||
|
//LOG.info("Calendart Alert: " + calAlert);
|
||||||
|
//int otherAlert = (data[0] & 0x03);
|
||||||
|
//LOG.info("Other Alert: " + otherAlert);
|
||||||
|
//int vibrationValue = (data[3] & 0x0f);
|
||||||
|
//LOG.info("Vibration Value: " + vibrationValue);
|
||||||
|
//int alarmValue = (data[3] >> 4) & 0x0f;
|
||||||
|
// Vibration pattern; A = 0, B = 1, C = 2
|
||||||
|
//LOG.info("Alarm Value: " + alarmValue);
|
||||||
|
//int animationValue = data[4] & 0x40;
|
||||||
|
// Length of Alarm, only 2, 5 and 10 possible
|
||||||
|
//LOG.info("Animation Value: " + animationValue);
|
||||||
|
// 0 = on
|
||||||
|
// 64 = off
|
||||||
|
//int useDisableMtuReqBit = data[4] & 0x08;
|
||||||
|
// 8 = on
|
||||||
|
// 0 = off!?
|
||||||
|
//LOG.info("useDisableMtuReqBit: " + useDisableMtuReqBit);
|
||||||
|
|
||||||
|
//int slaveLatency = ((data[7] & 0xff) | ((data[8] & 0xff) << 8));
|
||||||
|
//int connInterval = ((data[5] & 0xff) | ((data[6] & 0xff) << 8));
|
||||||
|
//LOG.info("Slave Latency: " + slaveLatency);
|
||||||
|
//LOG.info("Connection Interval: " + connInterval);
|
||||||
|
//LOG.info(str);
|
||||||
|
|
||||||
|
configureBleSettings();
|
||||||
|
writeBleSettings();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return super.onCharacteristicRead(gatt, characteristic, status);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user