use of android.bluetooth.BluetoothGattCharacteristic in project nikeplus-fuelband-se-reversed by evilsocket.
the class BLEIoQueue method next.
private void next() {
BLEIoOperation op = _ops.poll();
if (op == null) {
Logger.d("No I/O operations to execute.");
return;
}
_current = op;
boolean ok = false;
BluetoothGattDescriptor desc = op.get_descriptor();
BluetoothGattCharacteristic charact = op.get_characteristic();
byte[] data = op.get_data();
if (op.get_type() == Type.NOTIFY_START) {
ok = _gatt.setCharacteristicNotification(charact, true);
if (ok) {
desc.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
ok = _gatt.writeDescriptor(desc);
}
} else if (op.get_type() == Type.WRITE_DESCRIPTOR) {
desc.setValue(data);
ok = _gatt.writeDescriptor(desc);
} else if (op.get_type() == Type.WRITE_CHARACTERISTICS) {
charact.setValue(data);
Packet p = new Packet(charact.getValue());
Logger.d(">> " + p.toString());
ok = _gatt.writeCharacteristic(charact);
} else if (op.get_type() == Type.READ_CHARACTERISTICS) {
ok = _gatt.readCharacteristic(charact);
} else {
Logger.e("Unhandled Operation");
}
if (ok == false) {
Logger.e("Operation failed, fetching next ...");
next();
}
}
use of android.bluetooth.BluetoothGattCharacteristic in project nikeplus-fuelband-se-reversed by evilsocket.
the class MainActivity method onCreate.
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Logger.setLogView(this, (TextView) findViewById(R.id.log_view));
_btManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
_btAdapter = _btManager.getAdapter();
if (_btAdapter.isEnabled() == false) {
Logger.w("Bluetooth is disabled.");
Intent enableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableIntent, REQUEST_ENABLE_BT);
}
_leScanCallback = new BluetoothAdapter.LeScanCallback() {
@Override
public void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord) {
if (_scanning == false)
return;
try {
/*
* Parse device advertisment data.
*/
final Bundle advData = AdvertisementData.parse(scanRecord);
/*
* Is this a nike device?
*/
if (Arrays.equals(advData.getByteArray("COMPANYCODE"), NIKE_COMPANY_CODE)) {
Logger.i("FOUND NIKE DEVICE [" + device + "]");
dumpDeviceAdvData(advData);
_scanning = false;
_btAdapter.stopLeScan(_leScanCallback);
Logger.i("Connecting to GATT server ...");
_ioqueue = new BLEIoQueue(new BLEIoQueue.QueueCallbacks() {
private BluetoothGattService _CopperheadService = null;
private BluetoothGattCharacteristic _CommandChannel = null;
private BluetoothGattCharacteristic _ResponseChannel = null;
// add a raw packet to the queue
private void addPacket(BLEIoQueue queue, byte[] data, BLEIoOperation.OnResponseCallback callback) {
BLEIoOperation op = new BLEIoOperation(BLEIoOperation.Type.WRITE_CHARACTERISTICS, "Sending command.", callback);
op.set_data(data);
op.set_characteristic(_CommandChannel);
queue.add(op);
}
private void addPacket(BLEIoQueue queue, String s, BLEIoOperation.OnResponseCallback callback) {
byte[] buffer = new byte[s.length() / 2];
for (int i = 0, j = 0; i < s.length(); i += 2, ++j) {
buffer[j] = (byte) ((Character.digit(s.charAt(i), 16) << 4) + Character.digit(s.charAt(i + 1), 16));
}
addPacket(queue, buffer, callback);
}
// create the needed packet to request a specific setting from the device
private void requestSetting(BLEIoQueue queue, int code) {
CopperheadPacket oppacket = new CopperheadPacket(5);
oppacket.setOpcode((byte) 10);
ByteBuffer b = oppacket.getPayloadBuffer();
b.put((byte) 1);
b.put((byte) code);
Packet p = Packet.wrap(oppacket);
p.setProtocolLayer(CommandResponseOperation.ProtocolLayer.COMMAND);
p.setPacketCount(0);
p.setPacketIndex(0);
p.setSequenceNumber(1);
addPacket(queue, p.getBuffer(), new BLEIoOperation.OnResponseCallback() {
@Override
public void onData(Packet config) {
byte[] raw = config.getBuffer();
try {
Utils.processGetSettingsResponse(raw);
} catch (Exception e) {
Logger.e(e.toString());
}
}
});
}
@Override
public void onServicesDiscovered(BLEIoQueue queue, BluetoothGatt gatt, int status) {
dumpServices(gatt);
_CopperheadService = gatt.getService(COPPERHEAD_SERVICE_UUID);
if (_CopperheadService == null) {
Logger.e("No Copperhead service found.");
return;
}
/*
* Get command and response channels.
*/
_CommandChannel = _CopperheadService.getCharacteristic(COPPERHEAD_CMD_UUID);
_ResponseChannel = _CopperheadService.getCharacteristic(COPPERHEAD_RSP_UUID);
if (_CommandChannel == null) {
Logger.e("Could not find COPPERHEAD_CMD_UUID");
return;
} else if (_ResponseChannel == null) {
Logger.e("Could not find COPPERHEAD_RSP_UUID");
return;
}
/*
* Enable the response channel to receive incoming data notifications.
*/
BluetoothGattDescriptor rsp_config_desc = _ResponseChannel.getDescriptor(CLIENT_CHARACTERISTIC_CONFIG_UUID);
if (rsp_config_desc == null) {
Logger.e("RSP has no client config.");
return;
}
BLEIoOperation notify = new BLEIoOperation(BLEIoOperation.Type.NOTIFY_START, "Enable response channel notifications.");
notify.set_characteristic(_ResponseChannel);
notify.set_descriptor(rsp_config_desc);
queue.add(notify);
final BLEIoQueue fq = queue;
Packet auth = new Packet(19);
/*
* Send the "START AUTH" packet -> 0x90 0x01 0x01 0x00 .....
*/
auth.setProtocolLayer(CommandResponseOperation.ProtocolLayer.SESSION);
auth.setPacketCount(0);
auth.setPacketIndex(0);
auth.setSequenceNumber(1);
auth.setCommandBytes((byte) 1, (byte) 1);
addPacket(queue, auth.getBuffer(), new BLEIoOperation.OnResponseCallback() {
@Override
public void onData(Packet challenge_packet) {
Logger.d("<< " + challenge_packet.toString());
ByteBuffer buffer = challenge_packet.getBuffered(ByteOrder.LITTLE_ENDIAN);
// remove op code and length
int opcode = buffer.get();
int length = buffer.get();
switch(buffer.get()) {
case 0x41:
Logger.i("Received authentication challenge");
/*
* Get 16 bytes of AUTH nonce
*/
byte[] nonce = new byte[16];
buffer.get(nonce);
if ((nonce == null) || (nonce.length != 16)) {
Logger.e("Missing or invalid authentication challenge nonce");
} else {
CopperheadCRC32 crc = new CopperheadCRC32();
byte[] auth_token = Utils.hexToBytes("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF");
Logger.d("NONCE: " + Utils.bytesToHex(nonce));
/*
* Create the response packet: 0xb0 0x03 0x02 [2 BYTES OF CRC] 0x00 ...
*/
Packet resp_packet = new Packet(19);
resp_packet.setProtocolLayer(CommandResponseOperation.ProtocolLayer.SESSION);
resp_packet.setPacketCount(0);
resp_packet.setPacketIndex(0);
resp_packet.setSequenceNumber(challenge_packet.getSequenceNumber() + 1);
ByteBuffer response = ByteBuffer.allocate(18);
response.put((byte) 0x03);
response.put((byte) 0x02);
crc.update(nonce);
crc.update(auth_token);
short sum = (short) ((0xFFFF & crc.getValue()) ^ (0xFFFF & crc.getValue() >>> 16));
response.putShort(sum);
resp_packet.setPayload(response.array());
addPacket(fq, resp_packet.getBuffer(), new BLEIoOperation.OnResponseCallback() {
@Override
public void onData(Packet challenge_response) {
Logger.d("<< " + challenge_response.toString());
ByteBuffer buffer = challenge_response.getBuffered(ByteOrder.LITTLE_ENDIAN);
// remove op code and length
int opcode = buffer.get();
int length = buffer.get();
/*
* Get the authentication reply code.
*/
int reply = buffer.get();
if (reply == 0x42) {
Logger.i("Succesfully authenticated.");
// Request some settings
requestSetting(fq, Utils.getSettingCode("BAND_COLOR"));
requestSetting(fq, Utils.getSettingCode("FUEL"));
requestSetting(fq, Utils.getSettingCode("FIRST_NAME"));
requestSetting(fq, Utils.getSettingCode("SERIAL_NUMBER"));
} else {
Logger.e("Authentication failure, reply: " + reply);
}
}
});
}
break;
default:
Logger.e("Unknown auth code.");
}
}
});
}
});
device.connectGatt(MainActivity.this, false, _ioqueue);
}
} catch (Exception e) {
Logger.e(e.toString());
}
}
};
Logger.i("Starting scann ...");
_scanning = true;
_btAdapter.startLeScan(_leScanCallback);
}
use of android.bluetooth.BluetoothGattCharacteristic in project BleSensorTag by StevenRudenko.
the class BleServicesAdapter method getChildView.
@Override
public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View convertView, ViewGroup parent) {
final ChildViewHolder holder;
if (convertView == null) {
holder = new ChildViewHolder();
convertView = inflater.inflate(R.layout.li_characteristic, parent, false);
holder.name = (TextView) convertView.findViewById(R.id.name);
holder.uuid = (TextView) convertView.findViewById(R.id.uuid);
holder.modes = (TextView) convertView.findViewById(R.id.modes);
holder.seek = (SeekBar) convertView.findViewById(R.id.seek);
holder.seek.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
if (serviceListener == null || def == null || !fromUser) {
return;
}
final BaseSensor<?> sensor = (BaseSensor<?>) def.getSensor(holder.service.getUuid().toString());
if (sensor == null) {
return;
}
if (sensor instanceof TiPeriodicalSensor) {
final TiPeriodicalSensor periodicalSensor = (TiPeriodicalSensor) sensor;
periodicalSensor.setPeriod(progress + periodicalSensor.getMinPeriod());
serviceListener.onServiceUpdated(holder.service);
}
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
}
});
convertView.setTag(holder);
} else {
holder = (ChildViewHolder) convertView.getTag();
}
final BluetoothGattCharacteristic item = getChild(groupPosition, childPosition);
final String uuid = item.getUuid().toString();
final String name;
final String modes = getModeString(item.getProperties());
holder.service = item.getService();
final String serviceUUID = item.getService().getUuid().toString();
final Sensor<?> sensor = def != null ? (Sensor<?>) def.getSensor(serviceUUID) : null;
// reset visibility
holder.uuid.setVisibility(View.VISIBLE);
holder.seek.setVisibility(View.GONE);
if (sensor != null) {
name = sensor.getCharacteristicName(uuid);
if (sensor instanceof BaseSensor) {
final BaseSensor<?> tiSensor = (BaseSensor<?>) sensor;
if (tiSensor.isConfigUUID(uuid)) {
if (sensor instanceof TiPeriodicalSensor) {
final TiPeriodicalSensor periodicalSensor = (TiPeriodicalSensor) sensor;
final int max = periodicalSensor.getMaxPeriod() - periodicalSensor.getMinPeriod();
final int value = periodicalSensor.getPeriod() - periodicalSensor.getMinPeriod();
holder.seek.setMax(max);
holder.seek.setProgress(value);
holder.seek.setVisibility(View.VISIBLE);
holder.uuid.setVisibility(View.GONE);
}
}
}
} else {
name = "Unknown";
}
holder.name.setText(name);
holder.uuid.setText(uuid);
holder.modes.setText(modes);
return convertView;
}
use of android.bluetooth.BluetoothGattCharacteristic in project Gadgetbridge by Freeyourgadget.
the class UpdateFirmwareOperation method sendFirmwareData.
/**
* Method that uploads a firmware (fwbytes) to the Mi Band.
* The firmware has to be split into chunks of 20 bytes each, and periodically a COMMAND_SYNC command has to be issued to the Mi Band.
* <p/>
* The Mi Band will send a notification after receiving this data to confirm if the firmware looks good to it.
*
* @param fwbytes
* @return whether the transfer succeeded or not. Only a BT layer exception will cause the transmission to fail.
* @see MiBandSupport#handleNotificationNotif
*/
private boolean sendFirmwareData(byte[] fwbytes) {
int len = fwbytes.length;
final int packetLength = 20;
int packets = len / packetLength;
BluetoothGattCharacteristic characteristicControlPoint = getCharacteristic(MiBandService.UUID_CHARACTERISTIC_CONTROL_POINT);
BluetoothGattCharacteristic characteristicFWData = getCharacteristic(MiBandService.UUID_CHARACTERISTIC_FIRMWARE_DATA);
try {
// going from 0 to len
int firmwareProgress = 0;
TransactionBuilder builder = performInitialized("send firmware packet");
if (prefs.getBoolean("mi_low_latency_fw_update", true)) {
getSupport().setLowLatency(builder);
}
for (int i = 0; i < packets; i++) {
byte[] fwChunk = Arrays.copyOfRange(fwbytes, i * packetLength, i * packetLength + packetLength);
builder.write(characteristicFWData, fwChunk);
firmwareProgress += packetLength;
int progressPercent = (int) ((((float) firmwareProgress) / len) * 100);
if ((i > 0) && (i % 50 == 0)) {
builder.write(characteristicControlPoint, new byte[] { MiBandService.COMMAND_SYNC });
builder.add(new SetProgressAction(getContext().getString(R.string.updatefirmwareoperation_update_in_progress), true, progressPercent, getContext()));
}
}
if (firmwareProgress < len) {
byte[] lastChunk = Arrays.copyOfRange(fwbytes, packets * packetLength, len);
builder.write(characteristicFWData, lastChunk);
firmwareProgress = len;
}
builder.write(characteristicControlPoint, new byte[] { MiBandService.COMMAND_SYNC });
builder.queue(getQueue());
} catch (IOException ex) {
LOG.error("Unable to send fw to MI", ex);
GB.updateInstallNotification(getContext().getString(R.string.updatefirmwareoperation_firmware_not_sent), false, 0, getContext());
return false;
}
return true;
}
use of android.bluetooth.BluetoothGattCharacteristic in project Gadgetbridge by Freeyourgadget.
the class MiBand2Support method setWearLocation.
/**
* Part of device initialization process. Do not call manually.
*
* @param builder
* @return
*/
private MiBand2Support setWearLocation(TransactionBuilder builder) {
LOG.info("Attempting to set wear location...");
BluetoothGattCharacteristic characteristic = getCharacteristic(MiBand2Service.UUID_UNKNOWN_CHARACTERISTIC8);
if (characteristic != null) {
builder.notify(characteristic, true);
int location = MiBandCoordinator.getWearLocation(getDevice().getAddress());
switch(location) {
case // left hand
0:
builder.write(characteristic, MiBand2Service.WEAR_LOCATION_LEFT_WRIST);
break;
case // right hand
1:
builder.write(characteristic, MiBand2Service.WEAR_LOCATION_RIGHT_WRIST);
break;
}
// TODO: this should actually be in some kind of finally-block in the queue. It should also be sent asynchronously after the notifications have completely arrived and processed.
builder.notify(characteristic, false);
}
return this;
}
Aggregations