/* Copyright (C) 2023-2024 Johannes Krude 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 . */ package nodomain.freeyourgadget.gadgetbridge.service.devices.casio.gb6900; 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.casio.CasioConstants; 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.casio.gb6900.CasioGB6900DeviceSupport; public class InitOperation extends AbstractBTLEOperation { 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.setCallback(this); } @Override protected void doPerform() throws IOException { builder.add(new SetDeviceStateAction(getDevice(), GBDevice.State.INITIALIZING, getContext())); TransactionBuilder builder = getSupport().createTransactionBuilder("readBleSettings"); builder.setCallback(this); builder.read(getCharacteristic(CasioConstants.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.setCallback(this); builder.write(getCharacteristic(CasioConstants.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(CasioConstants.CASIO_SETTING_FOR_BLE_CHARACTERISTIC_UUID)) { mBleSettings = data; StringBuilder str = new StringBuilder("Read Casio Setting for BLE: "); for (byte datum : data) { str.append(String.format("0x%1x ", datum)); } /* 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; } }