I am a novice in android development, so please forgive if the descriptions are not totally correct.
I am using the Android BTLE example app as a template and am attempting to send simple hex values to a Microchip RN4020 module. I can successfully send data (specifically time data using the calendar function) and they appear on my PuTTY window. However the problem is that the data is being 'transmitted' from the application (on my Samsung j5) as an ASCII representation.... in other words, the Calendar function returns the minute as say 20 (20hex = 32 decimal), which is somehow ending up as ASCII 20 on my PuTTY terminal (i.e. 32 30).
I am sending the data as a Byte array, which as I understand it constrains the range of values to be -127 to +127. So to combat this I have attempted to break the value into upper and lower nibbles and send these as separate bytes.....same problem. The value appearing is the ASCII 2 0....(i.e. 32 30).
I have taken the liberty of posting below my code (apologies for the 'clunkiness' of it). I strongly suspect it is a really rudimentary error, but I cant find how to transmit the 'hex values' Please help
regards
J
public void onClickTest(View v){
if(mBluetoothLeService != null) {
Calendar calendar = Calendar.getInstance();
//Data_1[0] = (Integer.toHexString((byte)calendar.get(Calendar.SECOND) & 0xFF)); //Alarm Set
int temp = 0;
int temp1 = 0;
byte first = 0;
byte second = 0;
temp = calendar.get(Calendar.HOUR_OF_DAY);
temp1 = temp;
temp = temp & 0xf0;
temp = temp >> 4;
temp1 = temp1 & 0x0f;
first = (byte)temp;
second = (byte)temp1;
Data_1[0] = first;
Data_1[1] = second; //Alarm Set
//Data_1[1] = 0xff; //Update clock
// Data_1[2] = calendar.get(Calendar.SECOND);
// Data_1[2] = calendar.get(Calendar.SECOND);
// Data_1[3] = (char)calendar.get(Calendar.MINUTE);
// Data_1[4] = (char)calendar.get(Calendar.HOUR_OF_DAY);
// Data_1[5] = (byte)calendar.get(Calendar.DAY_OF_WEEK);
// Data_1[6] = (byte)calendar.get(Calendar.MONTH);
// Data_1[7] = (byte)calendar.get(Calendar.YEAR);
//myArray = (Arrays.toString(Data_1));
mBluetoothLeService.writeCustomCharacteristicString(Data_1);
This is the actual LE service bit
public void writeCustomCharacteristicString(byte[] value) {
if (mBluetoothAdapter == null || mBluetoothGatt == null) {
Log.w(TAG, "BluetoothAdapter not initialized");
return;
}
/*check if the service is available on the device*/
BluetoothGattService mCustomService1 = mBluetoothGatt.getService(UUID.fromString("12345678-9012-3456-7890-1234567890FF"));
if(mCustomService1 == null){
Log.w(TAG, "Custom BLE Service not found");
return;
}
/*get the read characteristic from the service*/
BluetoothGattCharacteristic mWriteCharacteristic1 = mCustomService1.getCharacteristic(UUID.fromString("12345678-9012-3456-7890-123456789011"));
mWriteCharacteristic1.setValue(value);
if(mBluetoothGatt.writeCharacteristic(mWriteCharacteristic1) == false){
Log.w(TAG, "Failed to write characteristic");
}
}
Related
I have this bluetooth temperature sensor https://www.aliexpress.com/item/nRF51822-Bluetooth-4-0-BLE-SOC-Temperature-Atmospheric-Pressure-Acceleration-Sensor-Module-Gyroscope-Light-Sensor-MPU6050/32859423925.html?spm=a2g0s.9042311.0.0.e3534c4dT9GRz3 and I am trying to read temperature out of it.
I can connect to it, get services via
BluetoothGatt.getService(UUID.fromString("6e400001-b5a3-f393-e0a9-e50e24dcca9e")
and get characteristics via
BluetoothGattCharacteristic mReadCharacteristic = mCustomService.getCharacteristic(UUID.fromString("6e400005-b5a3-f393-e0a9-e50e24dcca9e"));
result:
mReadCharacteristic = {BluetoothGattCharacteristic#5322}
mDescriptors = {ArrayList#5326} size = 1
mInstance = 20
mKeySize = 16
mPermissions = 0
mProperties = 16
mService = {BluetoothGattService#5295}
mUuid = {UUID#5327} "6e400005-b5a3-f393-e0a9-e50e24dcca9e"
mValue = null
mWriteType = 2
Then I call mBluetoothGatt.readCharacteristic(mReadCharacteristic)
and hope to get data via BluetoothGattCallback, but readCharacteristic always returns false
if ((characteristic.getProperties() & BluetoothGattCharacteristic.PROPERTY_READ) == 0) {
return false;
}
properties = 16 PROPERTY_READ = 5
What am I doing wrong ?
Properties is a bitmask which operations the characteristic supports. As shown at https://developer.android.com/reference/android/bluetooth/BluetoothGattCharacteristic.html, 16 means notify and not read, so the characteristic can not be read. Maybe you should try to register for notifications instead?
I have a Sony Xperia Z3. I am using it to interact with MIFARE Classic smart cards.
When using a native MIFARE card, I'm able to read the card correctly.
However if I'm using a MIFARE Classic emulated, I get a SAK that is not correct. In stead of 0x38 I get 0x20 (32) and the following error when using MifareClassic.get(tag)
java.lang.RuntimeException: Tag incorrectly enumerated as MIFARE Classic, SAK = 32
I don't know why my mobile incorrectly reads the SAK.
The same card is correctly read on other devices supporting MIFARE as a Nexus S, etc.
Any idea why this exception?
TA
Try to use this patch as tag = cleanupTag(tag) before calling MifareClassic.get(tag)
For more information read MifareClassicTool Sony Z3 issue
private Tag cleanupTag(Tag oTag){
if (oTag == null)
return null;
String[] sTechList = oTag.getTechList();
Parcel oParcel = Parcel.obtain();
oTag.writeToParcel(oParcel, 0);
oParcel.setDataPosition(0);
int len = oParcel.readInt();
byte[] id = null;
if (len >= 0) {
id = new byte[len];
oParcel.readByteArray(id);
}
int[] oTechList = new int[oParcel.readInt()];
oParcel.readIntArray(oTechList);
Bundle[] oTechExtras = oParcel.createTypedArray(Bundle.CREATOR);
int serviceHandle = oParcel.readInt();
int isMock = oParcel.readInt();
IBinder tagService;
if (isMock == 0) {
tagService = oParcel.readStrongBinder();
} else {
tagService = null;
}
oParcel.recycle();
int nfca_idx = -1;
int mc_idx = -1;
short oSak = 0;
short nSak = 0;
for (int idx = 0; idx < sTechList.length; idx++) {
if (sTechList[idx].equals(NfcA.class.getName())) {
if (nfca_idx == -1) {
nfca_idx = idx;
if (oTechExtras[idx] != null
&& oTechExtras[idx].containsKey("sak")) {
oSak = oTechExtras[idx].getShort("sak");
nSak = oSak;
}
} else {
if (oTechExtras[idx] != null
&& oTechExtras[idx].containsKey("sak")) {
nSak = (short) (nSak | oTechExtras[idx].getShort("sak"));
}
}
} else if (sTechList[idx].equals(MifareClassic.class.getName())) {
mc_idx = idx;
}
}
boolean modified = false;
if (oSak != nSak) {
oTechExtras[nfca_idx].putShort("sak", nSak);
modified = true;
}
if (nfca_idx != -1 && mc_idx != -1 && oTechExtras[mc_idx] == null) {
oTechExtras[mc_idx] = oTechExtras[nfca_idx];
modified = true;
}
if (!modified) {
return oTag;
}
Parcel nParcel = Parcel.obtain();
nParcel.writeInt(id.length);
nParcel.writeByteArray(id);
nParcel.writeInt(oTechList.length);
nParcel.writeIntArray(oTechList);
nParcel.writeTypedArray(oTechExtras, 0);
nParcel.writeInt(serviceHandle);
nParcel.writeInt(isMock);
if (isMock == 0) {
nParcel.writeStrongBinder(tagService);
}
nParcel.setDataPosition(0);
Tag nTag = Tag.CREATOR.createFromParcel(nParcel);
nParcel.recycle();
return nTag;
}
The SAK value is not a magic value that you could use to distinguish different NFC tags. Instead it is a bit masked value that defines some capabilities of the RF protocol.
Unfortunately the google Android code uses the SAK for mifare card identification as you can see in this code here: MifareClassic.java
What happens in your Xperia Z3 is probably that the NFC controller and NFC stack correctly detect the tag as Mifare compatible and report it as such. Once you try to use the tag you run into the problems you've mentioned.
The Nexus S is likely running a fixed version of the MifareClassic.java code and avoids the problem.
What can you do about it: From an application perspective nothing really. It's a bug in the Android OS. If you have root access you could do it the hard way and patch the member function on the fly.
I am writing a "race box" in C that runs on an Intel Edison. It can send or receive bluetooth data with an Android app based on Bluetooth Chat. Everything works fine. I can send and receive. I can lose the connection and reacquire and the connection comes back and data flows from the C program to the Android app. All is good except once I reconnect I can no longer send data from C to Android. I have traced this to the read statement and I assume it never returns a value because it never exits the while loop. Specifically, this line:
while(bluetooth_up == 1 && (read(client, &aa, 1) == -1) ){
Will not exit even when I know bluetooth_up == 0 (another thread fprints bluetooth_up and it is 0 when bluetooth is down). My conclusion was that read was blocking so I attempted to fix that with the line
fcntl(s, F_SETFL,sock_flags|O_NONBLOCK);
The bluetooth connection is in the bluetooth write thread. But like I said, everything works except that this while loop will not exit when bluetooth_up is 0.
All I can figure out is that the read is blocking and what I cannot figure out is how to make it not blocking so it will return the -1 and the while loop can see that bluetooth_up == 0 and exit.
Here is the global definition of bluetooth_up
volatile int bluetooth_up = 0;
I would appreciate help on this as it needs to be robust and I don't want to require people to power cycle the race box to get bluetooth working again, although that does work.
void *blueRead(void *arg){
blue_read_up = 1;
char aa;
char buffer[500];
int idx = 0;
printf("\nBlue Read started\n");
fcntl(s, F_SETFL,sock_flags|O_NONBLOCK);
while(bluetooth_up == 1){
if (new_blue_read_sentence == 0 && bluetooth_up == 1){
while(bluetooth_up == 1 && (read(client, &aa, 1) == -1) ){
if(bluetooth_up == 0){
printf("\nExiting blue read\n");
blue_read_up = 0;
return NULL;
}
}
printf("%i",aa);
if(aa != '\n')
{
buffer[idx++] = aa;
}
else
{
buffer[idx] = '\n';
buffer[idx + 1] = '\0';
idx = 0;
strcpy( blue_read_buffer, buffer);
new_blue_read_sentence = 1;
}
}
}
printf("\nExiting blue read 2\n");
blue_read_up = 0;
return NULL;
}
I think the bluetooth connection code is pretty standard but here it is
// allocate socket
s = socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
printf("\nsocket = %i\n", s);
// bind socket to port 1 of the first available local bluetooth adapter
loc_addr.rc_family = AF_BLUETOOTH;
loc_addr.rc_bdaddr = *BDADDR_ANY;
loc_addr.rc_channel = (uint8_t)1;
retval = bind(s, (struct sockaddr*)&loc_addr, sizeof(loc_addr));
printf("\nbind = %i\n", retval);
// put socket into listening mode
//listen(s, 1);
retval = listen(s, 1);
printf("\nlisten = %i\n", retval);
// accept one connection
client = accept(s, (struct sockaddr*)&rem_addr, &opt);
sock_flags = fcntl(s,F_GETFL,0);
fcntl(s, F_SETFL,sock_flags|O_NONBLOCK);
printf("\n1 - client connect = %i socket %i\n", client, s);
You are setting O_NONBLOCK on the listening socket (s). Try instead on the accept socket (client) which is the one that is actually being read from.
I am working in an app for Android that uses BLE. I want to write inside a characteristic of the device Service that I am connected to.
My function is this:
public void writeCharacteristic(BluetoothGattCharacteristic characteristic,
boolean enabled, String text) {
if (mBluetoothAdapter == null || mBluetoothGatt == null) {
Log.w(TAG, "BluetoothAdapter not initialized");
return;
}
characteristic.setValue("7");
boolean status = mBluetoothGatt.writeCharacteristic(characteristic);
}
I do not why the value is not written inside the characteristic.
I followed the steps in this link:
write with BLE
anyone knows why my code does not work?
Thank you very much.
Regards
P.D. apologies for my English.
Maybe your characteristic accepts a byte[] value. Try setting the characteristic value with byte array by converting String parameter into byte[]. Your method should be like this:
public void writeCharacteristic(BluetoothGattCharacteristic characteristic,
String text) {
if (mBluetoothAdapter == null || mBluetoothGatt == null) {
Log.w(TAG, "BluetoothAdapter not initialized");
return;
}
byte[] data = hexStringToByteArray(text);
characteristic.setValue(data);
boolean status = mBluetoothGatt.writeCharacteristic(characteristic);
}
private byte[] hexStringToByteArray(String s) {
int len = s.length();
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;
}
Also note that, status variable returns true, if the write operation was initiated successfully. So, in order to get write operation result status use onCharacteristicWrite callback of BluetoothGattCallback and check the status in it.
After spending all morning at the computer trying different functions and forms, I found the solution thanks to a friend from work.
We have to convert the text to byte, then put that byte into a byte array and send. Fixed.
byte pepe = (byte) Integer.parseInt(text);
byte[] charLetra = new byte[1];
charLetra[0] = pepe;
LumChar.setValue(charLetra);
boolean status = mBluetoothGatt.writeCharacteristic(LumChar);
Anyway thank you very much for your help.
Regards.
I have problems when I when to send messages via USB from the board to the devicersa.
Hardware:
Arduino ADK 2011
Samsung Galaxy S3, Android 4.1.2
The problem is the read method in the Android app never terminates and makes the thread get stuck:
mFileDescriptor = mUsbManager.openAccessory(accessory);
if (mFileDescriptor != null) {
mAccessory = accessory;
FileDescriptor fd = mFileDescriptor.getFileDescriptor();
Log.d(TAG, "openAccessory(): FileDescriptor instanciated. valid " + fd.valid());
mInputStream = new FileInputStream(fd);
mOutputStream = new FileOutputStream(fd);
new Thread(null, new Runnable() {
#Override
public void run() {
int ret = 0;
byte[] buffer = new byte[255];
while (ret >= 0 && mInputStream != null) {
try {
// never terminates
ret = mInputStream.read(buffer);
} catch (IOException e) {
Log.e(TAG, "openAccessory(): Could not read inputStream: " + e);
e.printStackTrace();
break;
}
} ...
The connection works fine since I use the special USB-library. When I connect the device the app opens automatically very well. But with logs I see it never passes the read command. Also the Arduinio monitor says that:
Device addressed... Requesting device descriptor.
found possible device. swithcing to serial mode
device supports protcol 1 or above
found android acessory device
config desc
interface desc
interface desc
2
4
Sending message...
Done
disconnect
The ADK sends messages, to the device in the loop (once):
sntmsg[0] = COMMAND_TEXT;
sntmsg[1] = TARGET_DEFAULT;
sntmsg[2] = 25;
for (int i = 0; i < 25; i++) {
sntmsg[3 + i] = hello[i];
}
// schreiben (buffer, length)
Serial.println("Sending message...");
acc.write(sntmsg, 3 + 25);
Serial.println("Done");
done = true;
delay(250);
Now I figured out the problem might be the disconnect. Immedeately after running through the first loop in the Arduiino code it prints disconnect to the monitor. The code in the libraries of AndroidAccessory.cpp is:
bool AndroidAccessory::isConnected(void)
{
USB_DEVICE_DESCRIPTOR *devDesc = (USB_DEVICE_DESCRIPTOR *) descBuff;
byte err;
max.Task();
usb.Task();
if (!connected &&
usb.getUsbTaskState() >= USB_STATE_CONFIGURING &&
usb.getUsbTaskState() != USB_STATE_RUNNING) {
Serial.print("\nDevice addressed... ");
Serial.print("Requesting device descriptor.\n");
err = usb.getDevDescr(1, 0, 0x12, (char *) devDesc);
if (err) {
Serial.print("\nDevice descriptor cannot be retrieved. Trying again\n");
return false;
}
if (isAccessoryDevice(devDesc)) {
Serial.print("found android acessory device\n");
connected = configureAndroid();
} else {
Serial.print("found possible device. swithcing to serial mode\n");
switchDevice(1);
}
} else if (usb.getUsbTaskState() == USB_DETACHED_SUBSTATE_WAIT_FOR_DEVICE) {
if (connected)
Serial.println("disconnect\n");
connected = false;
}
return connected;
}
So in the second loop this method returns false, even though the smartphone is still connected via usb. Do you know why it thinks it is dosconnected after the first loop iteration?
Thanks,
FL