BLE(Bluetooth Low Energy) - android

I try to implement Connection between two devices(Any ios/Android) and transfer text using BLE
I try too many demos from GitHub and also try from documentation step by step but I am not getting a success
some time give Error like :
> GATT server 133
or
>android.bluetooth.BluetoothGattCharacteristic android.bluetooth.BluetoothGattService.getCharacteristic(java.util.UUID)' on a null object reference
Please help me
Thank you so much
Here is the my two activity code one ble class and one activity to call function from BLE claass
I want just pass small text to android to android or android to ios using ble
please help I tried from too many days
================================================================
public class MainActivity extends AppCompatActivity {
ArrayList<String> getDevicess;
List<BluetoothDevice> getConnectedDevicess;
TextView tvscan;
TextView tvConnected;
TextView tvsend;
Ble ble;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tvsend = (TextView) findViewById(R.id.tvsend);
getDevicess = new ArrayList<>();
getConnectedDevicess = new ArrayList<>();
ble = new Ble(this, getApplicationContext(), "zad");
ble.enableBle();
ble.checkPermission(0);
ble.scanLeDevice(true, 1000);
//after scan and connect click on send button then give error
tvsend.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
ble.writeCharacteristics(hexStringToByteArray("abcdefg"), UUID.fromString("fffffff0-00f7-4000-b000-000000000000"), UUID.fromString("fffffff5-00f7-4000-b000-000000000000"));
}
});
}
public byte[] hexStringToByteArray(String s) {
int len = s.length()-1;
byte[] data = new byte[len / 2];
for (int i = 0; i < len; i += 2) {
data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4) + Character.digit(s.charAt(i + 1), 16));
}
return data;
}
}
===========================================BLE CLass==================
// Function To Write Characteristics .. !
#TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2)
public void writeCharacteristics(byte[] data, UUID DLE_SERVICE, UUID DLE_WRITE_CHAR) {
BluetoothGattService Service = mBluetoothGatt.getService(DLE_SERVICE);
if (Service == null) {
Log.d(TAG, "service not found!");
//return false;
}
BluetoothGattCharacteristic charc1 = Service.getCharacteristic(DLE_WRITE_CHAR);
if (charc1 == null) {
Log.d(TAG, "char not found!");
Log.d(TAG, "CHARAC_-TRST" + charc1.getUuid());
// return false;
}
// charc1.setValue(new byte[]{0x00, 0x05, 0x10, 0x01, 0x3E, 0x01, 0x23});
charc1.setValue(data);
boolean stat = mBluetoothGatt.writeCharacteristic(charc1);
Log.d(TAG, "FINISHED WRITTING CHAR 1 status write :(status)" + stat);
if (data != null && data.length > 0) {
final StringBuilder stringBuilder = new StringBuilder(data.length);
for (byte byteChar : data)
stringBuilder.append(String.format("%02X ", byteChar));
}
}

This snippet is problematic:
public void displayBleService(List<BluetoothGattService> gattServices) {
Log.d(TAG, "display Services");
List<BluetoothGattCharacteristic> characteristics = new ArrayList<BluetoothGattCharacteristic>();
for (BluetoothGattService services : gattServices) {
Log.d(TAG, "SERVICES == ." + services.getUuid());
characteristics = services.getCharacteristics();
for (BluetoothGattCharacteristic characteristic : characteristics) {
Log.d(TAG, "CAHRACTERISTICS == ." + characteristic.getUuid() + "--" + characteristic.getProperties());
//enableNotification(characteristic, true);
}
}
}
the services is null, and thus the services.getCharacteristics() is provoking the NPE.
Please debug your code, and make sure you have BLUETOOTH_ADMIN permission as well. Feel free to add necessary null-guards as well at your own discretion.

Related

How to update the textview in a Bluetooh LeScanCallback?

I am using BluetoothAdapter.LeScanCallback to scan for BLE devices. Once I get the required scanned data, I would like to display it on a textview. However, the textview is not updated with the scanned data. Appreciate if anyone could help on this.
private TextView TV_uuid;
private TextView TV_major;
private TextView TV_minor;
//Find BLE devices
private Runnable scanRunnable = new Runnable() {
#Override
public void run() {
if (isScanning) {
if (btAdapter != null) {
btAdapter.stopLeScan(leScanCallback);
}
} else {
if (btAdapter != null) {
btAdapter.startLeScan(leScanCallback);
}
}
isScanning = !isScanning;
scanHandler.postDelayed(this, scan_interval_ms);
}
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
TV_uuid = (TextView)findViewById(R.id.tv_uuid2);
TV_major = (TextView)findViewById(R.id.tv_major2);
TV_minor = (TextView)findViewById(R.id.tv_minor2);
//start scan BLE
scanHandler.post(scanRunnable);
}
private BluetoothAdapter.LeScanCallback leScanCallback = new BluetoothAdapter.LeScanCallback() {
#Override
public void onLeScan(final BluetoothDevice bluetoothDevice, final int rssi, final byte[] scanData) {
if (scanData[7] == 0x02 && scanData[8] == 0x15) { // iBeacon indicator
UUID uuid = getGuidFromByteArray(Arrays.copyOfRange(scanData, 9, 25));
int major = (scanData[25] & 0xff) * 0x100 + (scanData[26] & 0xff);
int minor = (scanData[27] & 0xff) * 0x100 + (scanData[28] & 0xff);
byte txpw = scanData[29];
Log.i(TAG, "iBeacon Major = " + major + " | Minor = " + minor + " TxPw " + (int)txpw + " | UUID = " + uuid.toString());
TV_uuid.setText(uuid.toString());
TV_major.setText(major);
TV_minor.setText(minor);
}
}
};
If I remember correctly, that callback runs on a separate thread, so you shouldn't put view updates in the callback directly. If you just want to test, you can wrap the view updates inside a runOnUiThread() call and see if that works.
runOnUiThread(new Runnable(){
public void run(){
//set the value of your textviews here
}
}
}
Ideally though you should be decouple the scanning from the Activity. I'd put BLE scanning code inside a service that is either bound by a client Activity, or sends update to listening clients using LiveData / local broadcast manager.
Probably if (scanData[7] == 0x02 && scanData[8] == 0x15) is preventing the code to execute. Or you forgot to start the scan and install the onLeScanCallback listener

android | BLE write value to characteristic

I've got problem with writing value to BLE characteristic. I send correctly array of bytes , however the major is not being changed. I've got few characteristics and there's no problem to read them. However there's a problem with writing to every of them new value. This is my "reading" part :
#Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
super.onServicesDiscovered(gatt, status);
if (status == BluetoothGatt.GATT_SUCCESS) {
List<BluetoothGattService> services = gatt.getServices();
for (BluetoothGattService service : services) {
registerService(service);
characteristics = new ArrayList<BluetoothGattCharacteristic>();
characteristics.add(services.get(4).getCharacteristics().get(0));
characteristics.add(services.get(4).getCharacteristics().get(1));
characteristics.add(services.get(4).getCharacteristics().get(2));
characteristics.add(services.get(4).getCharacteristics().get(3));
characteristics.add(services.get(4).getCharacteristics().get(4));
characteristics.add(services.get(4).getCharacteristics().get(5));
characteristics.add(services.get(4).getCharacteristics().get(6));
characteristics.add(services.get(4).getCharacteristics().get(7));
characteristics.add(services.get(4).getCharacteristics().get(8));
characteristics.add(services.get(4).getCharacteristics().get(9));
characteristics.add(services.get(4).getCharacteristics().get(10));
characteristics.add(services.get(4).getCharacteristics().get(11));
characteristics.add(services.get(5).getCharacteristics().get(0));
characteristics.add(services.get(6).getCharacteristics().get(0));
if (Characteristics.PARAMETERS_SERVICE_UUID.equals(service.getUuid()))
registerParametersCharacteristics(characteristics);
Log.e(TAG, "onServicesDiscovered: " + service.getUuid() );
requesReadCharacteristics(gatt);
}
callback.connectedStateChanged(true);
} else
disconnect();
}
public void requesReadCharacteristics(BluetoothGatt gatt) {
if (characteristics.get(characteristics.size() - 1).getUuid().equals(Characteristics.TEMPERATURE_CHARACTERISTIC_UUID)) {
Log.e(TAG, "requesReadCharacteristics: TRUE");
}
if (characteristics.get(characteristics.size() - 1).getUuid().equals(Characteristics.ACCELEROMETER_CHARACTERISTIC_UUID)) {
Log.e(TAG, "requesReadCharacteristics: TRUE");
}
gatt.readCharacteristic(characteristics.get(characteristics.size() - 1));
}
To write new value to characteristic I've got method :
public void setMajor(int major) {
byte[] bytes = new byte[]{(byte) (major & 0xFF), (byte) ((major >> 8) & 0xFF)};
if (majorCharacteristic != null) {
BluetoothCommunicationManager.getInstance().add(new WriteCharacteristicCommand(majorCharacteristic, bluetoothGatt, bytes));
Log.e(TAG, "setMajor:" + Arrays.toString(bytes));
}
else
Log.e(TAG, "setMajor: NU" + Arrays.toString(bytes));
}
and a class to handle it :
public class WriteCharacteristicCommand implements BTLECommand {
private final BluetoothGatt gatt;
private final BluetoothGattCharacteristic characteristic;
private final byte[] value;
public WriteCharacteristicCommand(BluetoothGattCharacteristic characteristic, BluetoothGatt gatt, byte[] value) {
this.gatt = gatt;
this.characteristic = characteristic;
this.value = value;
}
#Override
public void process() {
characteristic.setValue(value);
gatt.writeCharacteristic(characteristic);
}
}
I found on logs, that when I set new value every characteristics are reading again ... twice, and than again fo the third time , and that's when old value is being set up again. Strange but that what's happen'. Any idea what I'm doing wrong ? Thanks in advance!
You can only have one outstanding GATT operation at a time (read / write a descriptor / characteristic). You need to wait for the corresponding completion callback (onCharacteristicRead etc) until you can send the next request.

Is the procedure correct to write Characteristic in Bluetooth Low Energy?

I have a button in MainActivity which is used to write a byte[] to BLE device:
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Write Char"
android:id="#+id/button2"
android:onClick="onClickWrite" />
And the function onClickWrite is
public void onClickWrite(View v){
if(mBluetoothLeService != null) {
byte [] data= new byte[3];
data[0] = (byte)(0 & 0xFF);
data[1] = (byte)(255 & 0xFF);
data[2] = (byte)(0 & 0xFF);
mBluetoothLeService.sendData(data);
}
}
where sendData is a modified function in class [BluetoothLeService][1]. It worked well when I press the button. However, Let is careful to look at the sendData function. It searches service and Characteristic again when I press the button. Is it correct procedure for write a Characteristic in BLE?
public void sendData(byte[] data){
String lService = "00001c00-d102-11e1-9b23-00025b00a5A5";
String lCharacteristic = "00001c03-d102-11e1-9b23-00025b00a5a5";
BluetoothGattService mBluetoothLeService = null;
BluetoothGattCharacteristic mBluetoothGattCharacteristic = null;
for (BluetoothGattService service : mBluetoothGatt.getServices()) {
if ((service == null) || (service.getUuid() == null)) {
Log.d("TAG","Something is null");
continue;
}
if (lService.equalsIgnoreCase(service.getUuid().toString())) {
Log.d("TAG","service.getUuid().toString()="+service.getUuid().toString());
mBluetoothLeService = service;
}
}
if(mBluetoothLeService!=null) {
mBluetoothGattCharacteristic =
mBluetoothLeService.getCharacteristic(UUID.fromString(lRgbCharacteristic));
}
else{
Log.d("TAG","mBluetoothLeService is null");
}
if(mBluetoothGattCharacteristic!=null) {
mBluetoothGattCharacteristic.setValue(data);
boolean write = mBluetoothGatt.writeCharacteristic(mBluetoothGattCharacteristic);
Log.d("TAG","writeCharacteristic:"+write);
}
else{
Log.d("TAG", "mBluetoothGattCharacteristic is null");
}
}
Yes.
(filling unnecessarily required length)

Using android nfc adaptor in android library

i wrote a sample code to sending APDU to contactless smartcard by phone nfc reader and it worked succesfully. Now i want to write a android library to perform some operations like verify PIN and etc. these functions must connect to contactless smartcard and send apdu to it and return the result. The problem is here :(
This is my sample code which works:
public class MainActivity extends Activity {
private NfcAdapter mAdapter = null;
static IsoDep myTag;
private TextView lblStatus;
private Button btnSelectApplet;
private PendingIntent mPendingIntent;
boolean mFirstDetected=false;
boolean mShowAtr=false;
private String[][] mTechLists;
private IntentFilter[] mFilters;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
lblStatus = (TextView) findViewById(R.id.lblStatus);
btnSelectApplet = (Button) findViewById(R.id.btnSelect);
btnSelectApplet.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
byte[] select = new byte[] {0x00, (byte)0xa4, 0x04, 0x00, 0x09, (byte)0xa0, 0x00,
0x00, 0x03, 0x08, 0x00, 0x00, 0x10, 0x00, 0x1a};
byte[] res = transceives(select);
}
});
resolveIntent(getIntent());
mAdapter = NfcAdapter.getDefaultAdapter(this);
mPendingIntent = PendingIntent.getActivity(this, 0, new Intent(this, getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), 0);
IntentFilter ndef = new IntentFilter(NfcAdapter.ACTION_TAG_DISCOVERED);
try
{
ndef.addDataType("*/*");
}
catch (IntentFilter.MalformedMimeTypeException e)
{
throw new RuntimeException("fail", e);
}
mFilters = new IntentFilter[] { ndef, };
mTechLists = new String[][] { new String[] { IsoDep.class.getName() } };
}
private static byte[] transceives (byte[] data)
{
byte[] ra = null;
try
{
ra = myTag.transceive(data);
}
catch (IOException e)
{
}
try
{
}
catch (Exception e1)
{
e1.printStackTrace();
}
return (ra);
}
private void resolveIntent(Intent intent)
{
String action = intent.getAction();
if (NfcAdapter.ACTION_TAG_DISCOVERED.equals(action) || NfcAdapter.ACTION_TECH_DISCOVERED.equals(action) || NfcAdapter.ACTION_NDEF_DISCOVERED.equals(action)) {
Parcelable tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
final Tag t = (Tag) tag;
myTag = IsoDep.get(t);
mFirstDetected = true;
if (myTag != null) {
if (!myTag.isConnected()) {
try {
myTag.connect();
myTag.setTimeout(5000);
} catch (IOException e) {
e.printStackTrace();
return;
}
}
if (myTag.isConnected()) {
String szATR = null;
try {
mShowAtr = true;
szATR = " 3B " + getATRLeString(myTag.getHistoricalBytes()) + "80 01 " + getHexString(myTag.getHistoricalBytes()) + "" + getATRXorString(myTag.getHistoricalBytes());
} catch (Exception e) {
mShowAtr = false;
szATR = "CARD DETECTED ";
}
lblStatus.setText(szATR);
} else {
lblStatus.setText("Not Connected!");
}
if (mFirstDetected == true && myTag.isConnected()) {
} else {
lblStatus.setText("Not Connected!");
}
}
}
}
private static String getATRLeString(byte[] data) throws Exception
{
return String.format("%02X ", data.length | 0x80);
}
private static String getATRXorString(byte[] b) throws Exception
{
int Lrc=0x00;
Lrc = b.length | 0x80;
Lrc = Lrc^0x81;
for (int i=0; i < b.length; i++)
{
Lrc = Lrc^(b[i] & 0xFF);
}
return String.format("%02X ", Lrc);
}
private static String getHexString(byte[] data) throws Exception
{
String szDataStr = "";
for (int ii=0; ii < data.length; ii++)
{
szDataStr += String.format("%02X ", data[ii] & 0xFF);
}
return szDataStr;
}
#Override
protected void onNewIntent(Intent intent)
{
setIntent(intent);
resolveIntent(intent);
}
#Override
public void onResume()
{
super.onResume();
if (mAdapter != null)
{
mAdapter.enableForegroundDispatch(this, mPendingIntent, mFilters, mTechLists);
}
}
}
Sample code used enableForegroundDispatch function to detect smartcard in NFC field. When smartcard detected, onNewIntent is called.
I want put all of the code in android library module X and use it in Activity Y like
Activity Y extend X
or
X x = new X()
and call it functions. how could i implement it?
I have a problem when i want to call
mAdapter = NfcAdapter.getDefaultAdapter(this);
if i use this code:
mAdapter = NfcAdapter.getDefaultAdapter(context);// context pass from Y Activity to X(Android library)
the function
mAdapter.enableForegroundDispatch(this , mPendingIntent, mFilters, mTechLists); // In X (Android library)
doesn't work correctly because it doesn't use Y activity (it used X axtivity).
How can i solve my problem such way all code will be in X(android library)?
Thanks.
as per my understanding, you are trying to access some of the methods from other activity,
here I suggest you to create third class for that NFC module methods,
create singleton method that returns a static instance of that model class.
you can access that instance from any of your Activity.
you also can set a callback in a class and another method call from another class of activity.
Hope this will help you. ask if anything not clear.
Happy Coding :)

Does not get data from Arduino - bluetooth to Android Device

I want to communication between Arduino with Bluetooth and Android Device
In Arduino, I am using
SoftwareSerial.h
and below is the code
#include <SoftwareSerial.h>
int ledPin1 = 5;
int state = 0;
int flag = 0;
SoftwareSerial mySerial(0, 1);
void setup() {
// put your setup code here, to run once:
pinMode(ledPin1, OUTPUT);
digitalWrite(ledPin1, LOW);
Serial.begin(9600);
mySerial.begin(9600);
}
void loop() {
// put your main code here, to run repeatedly:
if(Serial.available()>0){
state = Serial.read();
flag = 0;
}
if (mySerial.available()) {
int k = mySerial.read();
mySerial.write(k);
}
}
and from Android side I am using BluetoothSPPLibrary
there is class named BluetoothService.java
in that there is ConnectedThread
public void run()
{
Log.d(TAG, "run: Called");
byte[] buffer;
ArrayList<Integer> arr_byte = new ArrayList<Integer>();
// Keep listening to the InputStream while connected
while (true) {
try {
int data = mmInStream.read();
Log.d(TAG, "run: "+data);
if(data == 0x0A) {
} else if(data == 0x0D) {
buffer = new byte[arr_byte.size()];
for(int i = 0 ; i < arr_byte.size() ; i++) {
buffer[i] = arr_byte.get(i).byteValue();
}
// Send the obtained bytes to the UI Activity
mHandler.obtainMessage(BluetoothState.MESSAGE_READ
, buffer.length, -1, buffer).sendToTarget();
arr_byte = new ArrayList<Integer>();
} else {
arr_byte.add(data);
}
} catch (IOException e) {
connectionLost();
// Start the service over to restart listening mode
BluetoothService.this.start(BluetoothService.this.isAndroid);
break;
}
}
}
but
int data = mmInStream.read();
here data is not coming from above code
You're missing some information here. Which Arduino board are you using? Based on the fact you're trying to send bluetooth using a Serial connection, I'm assuming you have an external bluetooth chip/board, which is it? If you are using one are you absolutely sure it's wired correctly. Is it using Bluetooth or Bluetooth Low Energy, the two have very different protocols. That information will help.

Categories

Resources