I have an Android app that is communicating with and arduino board via bluetooth
All the commands are going backward and forwards fine, until I wanted to send a comand of the type
"aT?bb"
from the android app, however when I print it in ardunio I am getting
"aT%3F"
I am logging the command in android and it is formed correctly My quesion is does c++/Arduino handle '?' differently then normal chars?
here is my arduino code->
while(bluetooth.available())
{
char toSend = (char)bluetooth.read();
if(toSend != '\0'){
if (toSend == 'a'){ i=0 ;}
inMsg[i] = toSend;
i++;
}
}
if(i == 5 )
{
// mock sending queries
if(inMsg[2] == '?'){
if(inMsg[1] == 'T'){
bluetooth.write("ty1");Serial.println("");
}else if(inMsg[1] == 'x'){ //normal cycle
bluetooth.write("xx1");
}else if(inMsg[1] == 'X'){ Serial.println(""); //booter
bluetooth.write("XX0");
}else if(inMsg[1] == 'N'){Serial.println(""); //On time
bluetooth.write("on1");
}else if(inMsg[1] == 'F'){ Serial.println(""); //Off time
bluetooth.write("of30");
}else if(inMsg[1] == 'S'){ Serial.println(""); //Speed percent
bluetooth.write("sp30");
}
}
// write to console
for(int j = 0; j < 5; j++){
Serial.write(inMsg[j]);
}
// new line
if(i == 5){Serial.println("");}
i = 0; // reset buffer
}
aT%3F <- this is mal formed
aS133 <- all the other are as I sent them from android
aN169
aF192
aS200
aXXXX
aYYYY
ayYYY
axXXX
my Android Code
...
command = "aT?bb";
writeCommand(command);
...
private void writeCommand(String command)
{
for (BluetoothGattCharacteristic characteristic : characteristics)
{
if ((characteristic.getProperties() & BluetoothGattCharacteristic.PROPERTY_WRITE_NO_RESPONSE) >0)
{
try {
characteristic.setValue(URLEncoder.encode(command, "utf-8"));
gatt.writeCharacteristic(characteristic);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
}
}
As pointed out in the comments above it was the URLEncoder that was changing the String. I have now changed this method to
private void writeCommand(String command)
{
for (BluetoothGattCharacteristic characteristic : characteristics)
{
if ((characteristic.getProperties() & BluetoothGattCharacteristic.PROPERTY_WRITE_NO_RESPONSE) >0)
{
characteristic.setValue(command);
gatt.writeCharacteristic(characteristic);
}else{
Log.i(TAG,"non write able");
}
}
}
Related
The goal I'm looking to achieve is to send/receive data to/from an Android device from a Linux server. I feel like I've tried all the examples I could find on the Internet as well as reading the libusb APIs, which don't talk at my level of a total noob. Here's what I've got so far:
I've written a program that runs on a Ubuntu server (ARMx64), from examples, I have the following code:
//Error handling removed for brevity
#define BULK_EP_IN 0x08
main(int argc, char* argv) {
libusb_context* libusb_ctxt;
int status;
bool libusb_err = false;
libusb_device** libusb_dvcs = NULL;
bool error = false;
unsigned vid = 0, pid = 0;
unsigned busnum = 0, devaddr = 0, _busnum, _devaddr;
struct libusb_device_descriptor desc;
status = libusb_init(&libusb_ctxt);
if (status < 0) {
libusb_err = true;
}
if (libusb_get_device_list(NULL, &libusb_dvcs) < 0) {
error = true;
} else {
libusb_device *dev = NULL;
for (uint16_t idx = 0; (dev = libusb_dvcs[idx]) != NULL; idx++) {
_busnum = libusb_get_bus_number(dev);
_devaddr = libusb_get_device_address(dev);
status = libusb_get_device_descriptor(dev, &desc);
if (status >= 0) {
if (desc.idVendor == vid_arg && desc.idProduct == pid_arg) {
vid = desc.idVendor;
pid = desc.idProduct;
busnum = _busnum;
devaddr = _devaddr;
fnd_dev = dev;
break;
}
}
}
if (fnd_dev == NULL) {
error = true;
} else {
libusb_device_handle* dev_hnd = NULL;
//Connect to device and write data to it.
dev_hnd = libusb_open_device_with_vid_pid(NULL, vid, pid);
if (dev_hnd) {
char str1[64], str2[64];
int e = 0,config2;
char my_string[64];
int length = 0;
int transferred = 0;
e = libusb_get_string_descriptor_ascii(dev_hnd, desc.iManufacturer, (unsigned char*)str1, sizeof(str1));
if (e < 0) {
break;
}
e = libusb_get_string_descriptor_ascii(dev_hnd, desc.iProduct, (unsigned char*)str2, sizeof(str2));
if(e < 0) {
break;
}
e = libusb_get_configuration(dev_hnd, &config2);
if (e == 0) {
if (config2 != 1)
{
libusb_set_configuration(dev_hnd, 1);
if (e!=0) {
libusb_err = true;
}
}
if (!libusb_err) {
if (libusb_kernel_driver_active(dev_hnd, 0) == 1) {
if (libusb_detach_kernel_driver(dev_hnd, 0) == 1) {
libusb_err = true;
}
}
if (!libusb_err) {
e = libusb_claim_interface(dev_hnd, 0);
if (e < 0) {
libusb_err = true;
}
if (!libusb_err) {
active_config(dev, dev_hnd);
memset(my_string, '\0', 64);
strcpy(my_string, "hello sally");
length = strlen(my_string);
e = libusb_bulk_transfer(dev_hnd, BULK_EP_IN | LIBUSB_ENDPOINT_IN, (unsigned char*)my_string, length, &transferred, 0);
if (e == 0 && transferred == length) {
child_log("Write successful!");
child_log("Sent %d bytes with string: %s", transferred, my_string);
}
else {
child_log("Error in write! e = %d and transferred = %d, error desc: %s", e, transferred, libusb_error_name(e));
}
}
}
}
}
e = libusb_release_interface(dev_hnd, 0);
libusb_close(dev_hnd);
}
}
if (libusb_dvcs != NULL) {
libusb_free_device_list(libusb_dvcs, 1);
}
}
if (!libusb_err) {
libusb_exit(libusb_ctxt);
}
}
Everything works, at least doesn't report an error, until I get to the libusb_bulk_transfer call, which it returns a -1, which translates to a LIBUSB_ERROR_IO.
The USB device I'm connecting to is a Samsung Z-Fold3 mobile phone. I'm using the phone as a test OS as I don't have access to the Android tablet that will be used in the final application.
Here's my questions:
How do I know which interface to connect to?
a) I'll have an application running on the Android device that will be using the same library, hopefully, that will receive the data sent from the Ubuntu server.
How do I know which configuration to use?
Am I doing everything correctly?
Does anyone have any code that can run on the Android to read the data that I'm sending from this code? My goal was to write a program in C that pretty much runs like the one that runs on the Ubuntu server, but reads the data. Once I have that, my next step will be to write data from the Android device to the Ubuntu server using libusb again.
Any help, advice, alternative APIs is very much appreciated.
Thank you!
I wrote an Android Phone app in Android Studio that connects to a UbloX NINA B1 to send and receive data on the SPS Service.
I'm having issues with the incoming data from the NINA B1 (Peripheral). I'm not sure if I connected correctly and turned the notifications on correctly.
Below is the code where I do the connection to the SPS Service. (Hardcoded to select Group 3 and child 0)
#RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
// Clicked on a Caracteristic (eg. FIFO or Credits)
public boolean enableNotification() {
// Hardcode for SPS service on NINA B112, can only use this service, other services will not be used
// This groupPosition and childPosition was determined from A_05 code, The selectable list gave these values when selecting SPS service
int groupPosition = 3;
int childPosition = 0;
BluetoothGattCharacteristic characteristic;
characteristic = characteristics_HashMapList.get(services_ArrayList.get(groupPosition).getUuid().toString()).get(childPosition);
// Todo find a better way to do below two lines. This is a temp way to pass characteristic & mBTLE_Service to static variables to use in HomeFragment for sending data
//Copy characteristics of SPS service to static act_characteristic for use by HomeFragment
this.act_characteristic = characteristic;
//Copy mBTLE_Service of SPS service to static act_service for use by HomeFragment
this.act_service = mBTLE_Service;
if (Utils.hasWriteProperty(characteristic.getProperties()) != 0) {
String uuid = characteristic.getUuid().toString();
//act_characteristic.setTitle(uuid);
//act_characteristic.setService(mBTLE_Service);
//act_characteristic.setCharacteristic(characteristic);
//dialog_btle_characteristic.show(getFragmentManager(), "Dialog_BTLE_Characteristic");
} if (Utils.hasReadProperty(characteristic.getProperties()) != 0) {
if (mBTLE_Service != null) {
mBTLE_Service.readCharacteristic(characteristic);
}
} if (Utils.hasNotifyProperty(characteristic.getProperties()) != 0) {
if (mBTLE_Service != null) {
mBTLE_Service.setCharacteristicNotification(characteristic, true);
}
}
return false;
}
Here is where I set the notifications ON, this part I'm not so confident about.
#RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
public void setCharacteristicNotification(BluetoothGattCharacteristic characteristic, boolean enabled) {
if (mBluetoothAdapter == null || mBluetoothGatt == null) {
Log.w(TAG, "BluetoothAdapter not initialized");
return;
}
mBluetoothGatt.setCharacteristicNotification(characteristic, enabled);
BluetoothGattDescriptor descriptor = characteristic.getDescriptor(UUID.fromString(getString(R.string.CLIENT_CHARACTERISTIC_CONFIG)));
// Todo: if the indications and notifications is to be used, then mode the indications part back into setCharacteristicNotification() and add a check for Indications, then change below code to set both indication and notify
if (enabled) {
// Enable INDICATION & NOTIFICATION
final byte[] ENABLE_INDICATION_NOTIFICATION = {0x03, 0x00};
descriptor.setValue(ENABLE_INDICATION_NOTIFICATION);
}
else {
descriptor.setValue(BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE);
}
//ToDo Shorten the delay time so that the Notifications Enable still works
// Delay in milli seconds
int m_sec = 200;
Delay.delay(m_sec, new Delay.DelayCallback() {
#Override
public void afterDelay() {
// Enable Notifications after 200 m_sec Delay
mBluetoothGatt.writeDescriptor(descriptor);
}
});
}
This is where I handle the incoming Bytes, I send a Modbus message from the Phone to NINA B1, then NINA B1 replies with a Modbus message. The Incoming byte count is always < 20 bytes. And I fill the RxBuff until the correct amount of bytes are received AND the Slave Address is correct, then I decode the received message.
#RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
private void broadcastUpdate(final String action, final BluetoothGattCharacteristic characteristic) {
final Intent intent = new Intent(action);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
intent.putExtra(EXTRA_UUID, characteristic.getUuid().toString());
}
// For all other profiles, writes the data formatted in HEX.
// Only Pack 20 bytes at a time coming from BLE server into data[]
final byte[] rx_Data;
int tempSlavAdr;
rx_Data = characteristic.getValue();
if (rx_Data != null && rx_Data.length > 0) {
// Only handle message if request came from ReadInput_Thread
if (this.request_flag) {
// ToDO: See if other non Modbus data arrives between packets
// Populate RxBuff
for (int i = 0; i < rx_Data.length; i++) {
this.RxBuff[this.WrPtr++] = rx_Data[i];
}
Log.d(TAG,"QTY Bytes in rx_Data = " + (Integer)rx_Data.length);
// Start Decode message only after all expected bytes are received && first message is Slave Address
// Prevent Negative numbers in Slave Address: tempSlavAdr is used in the the next if statement
tempSlavAdr = (byte) this.RxBuff[0];
if (tempSlavAdr < 0) tempSlavAdr += 256;
if ((this.WrPtr == FragmentHome.ExpectedCount_sent) && (tempSlavAdr == slaveAddr)) {
// Copy RxBuff over to Dec_RxBuff
int Dec_RxBuff[] = new int[255];
for (int i = 0; i < this.WrPtr; i++) {
Dec_RxBuff[i] = (this.RxBuff[i]);
Dec_RxBuff[i] += 256;
Dec_RxBuff[i] = Dec_RxBuff[i] & 0xFF;
}
// Clear flag indicating that Thread Send a Request
this.request_flag = false;
message_rx = false;
// Decode ModbusMessage and message Good
if (modbusHandler.DecodeModbusMessage(Dec_RxBuff)){
message_rx = true;
}
// Decode ModbusMessage and message Bad
else{
message_rx = false;
}
// Clear buffers
WrPtr = 0;
Arrays.fill(rx_Data, (byte) 0);
Arrays.fill(RxBuff, (byte) 0);
// Todo What if WrPtr stop short of Expected counter? Do some protection
// WrPtr > ExpectedCount Clear Buffers
} else if (WrPtr > FragmentHome.ExpectedCount_sent) {
// Clear buffers
// HomeFragment.set_Actual(false);
Log.d(TAG,"RX Count to big expected " + FragmentHome.ExpectedCount_sent + " got " + WrPtr);
WrPtr = 0;
Arrays.fill(rx_Data, (byte) 0);
Arrays.fill(RxBuff, (byte) 0);
}
// Todo Use this intent to pass data to a service to Decode Modbus Data (Service not written yet)
// intent.putExtra(EXTRA_DATA, new String(data) + "\n" + Utils.hexToString(data));
}
}
else {
//intent.putExtra(EXTRA_DATA, "0");
}
//sendBroadcast(intent);
}
I still get some data loss, and not sure how to handle this. Phone and NINA B1 is next to one another so distance is not a problem.
Can I get some help on how to set the indications correctly? And why I might lose bytes.
Marinus
This issue is troubling me until 1 week. I want to take picture like bracketing but in Sony Camera API its not support. so I coded it like continuously take 5 pictures with different value (0,+2,-2,-4,+4) using loop. (using button for it, and when press the button it should take picture 5 times) U can see the code in below:
This code for set Shutter Speed on camera
This code for taking picture:
private void takePicture() {
if (mLiveviewSurface == null || !mLiveviewSurface.isStarted()) {
DisplayHelper.toast(getApplicationContext(), R.string.msg_error_take_picture);
return;
}
new Thread() {
#Override
public void run() {
try {
JSONObject replyJson = mRemoteApi.actTakePicture();
JSONArray resultsObj = replyJson.getJSONArray("result");
JSONArray imageUrlsObj = resultsObj.getJSONArray(0);
String postImageUrl = null;
if (1 <= imageUrlsObj.length()) {
postImageUrl = imageUrlsObj.getString(0); continousShottingWithDifferentShutterValue();
}
if (postImageUrl == null) {
Log.w(TAG, "takePicture: post image URL is null.");
DisplayHelper.toast(getApplicationContext(), //
R.string.msg_error_take_picture);
return;
}
// Show progress indicator
DisplayHelper.setProgressIndicator(SonyCameraActivity.this, false);
} catch (Exception e) {
e.printStackTrace();
}
}
}.start();
}
and this is for loop:
int val, posVal = 0;
int currentShutterSpeed = 0;
private void continousShottingWithDifferentShutterValue() {
if (val == 0) {
currentShutterSpeed = -5;
setShutterSpeed(currentShutterSpeed);
val++;
} else if (val == 1) {
currentShutterSpeed = 5;
setShutterSpeed(currentShutterSpeed);
val++;
} else if (val == 2) {
currentShutterSpeed = -10;
setShutterSpeed(currentShutterSpeed);
val++;
} else if (val == 3) {
currentShutterSpeed = 10;
setShutterSpeed(currentShutterSpeed);
val++;
} else if (val == 4) {
setShutterSpeedVal0(0);
posVal++;
}
if (posVal == 3) {
posVal = 0;
val = 0;
}
}
But when I take picture sometimes shutterSpeed or takePicture is getting error and loop is stop.
Error types are: setShutterSpeed IOExeption error: 500; or setShutterSpeed is not set. Someone works with Sonycamera remote API and has any idea how to fix it or take picture 5 times with different value. will thankful for any idea. Thanks
I solved the problem. it was a shutter speed value error. As u know in Sony Camera Api there is not have the value of shutter speed and I wrote it as in camera settings. and JSON request and response is not match so its shows error 500. If someone wants to use shutter speed value: here it is:
String shutterValue[] = {"30\"", "25\"", "20\"", "15\"", "13\"", "10\"", "8\"", "6\"",
"5\"", "4\"", "3.2\"", "2.5\"", "2\"", "1.6\"", "1.3\"", "1\"", "0.8\"", "0.6\"", "0.5\"",
"0.4\"", "1/3", "1/4", "1/5", "1/6", "1/8", "1/10", "1/13", "1/15", "1/20", "1/25", "1/30",
"1/40", "1/50", "1/60", "1/80", "1/100", "1/125", "1/160", "1/200", "1/250", "1/320", "1/400",
"1/500", "1/640", "1/800", "1/1000", "1/1250", "1/1600", "1/2000", "1/2500", "1/3200", "1/4000"};
Currently I am working on my app which is going to run some code after receiving a specific type of data
So when I push on button, my arduino is going to send the following:
for button 1
ble_write(0x0A);
ble_write(0x01);
ble_write(0x00);
for button 2:
ble_write(0x0A);
ble_write(0x02);
ble_write(0x00);
The data is received by my phone but the problem is, it would only put out the code 1 toast and not code 2 when i press button 2. here is the code for my app.
for (int i = 0; i < data.length; i += 3) {
if (data[i] == 0x0A) {
if (data[i + 1] == 0x01)
Toast.makeText(getApplicationContext(), "CODE 1", Toast.LENGTH_SHORT).show();
} else if (data[i] == 0x02) {
Toast.makeText(getApplicationContext(), "CODE 2", Toast.LENGTH_SHORT).show();
}
}
I feel like because of the for loop it will just take one byte and always see it as code 1.
The code is based on: https://github.com/RedBearLab/Android/blob/master/Examples/Android%20Studio%20Examples/SimpleControls/src/com/redbear/simplecontrols/SimpleControls.java
I am kinda stuck dealing with the problem, any help would be great.
Just move the curly braces ?
for (int i = 0; i < data.length; i += 3) {
if (data[i] == 0x0A) {
if (data[i + 1] == 0x01) { // <- added {
Toast.makeText(getApplicationContext(), "CODE 1", Toast.LENGTH_SHORT).show();
} else if (data[i + 1] == 0x02) { // added '+ 1'
Toast.makeText(getApplicationContext(), "CODE 2", Toast.LENGTH_SHORT).show();
}
} //<- added }
}
Or did I miss something?
In the end I decided to change the received data (byte[]) to a string format via a standard character set. (UTF_8)
I have an Android app to which I am trying to add DNS SRV record detection. I know it is possible, based on the existence of apps such as DNS Lookup, which I have installed, and it works just fine.
I am using dnsjava and this code runs fine as a stand-alone Java application on my machine, but when I run it on my Android device, I just get the "Error!" message:
Lookup lookup = new Lookup(serviceName, Type.SRV, DClass.IN);
Resolver resolver = new SimpleResolver();
lookup.setResolver(resolver);
lookup.setCache(null);
Record[] records = lookup.run();
if (lookup.getResult() == Lookup.SUCCESSFUL) {
String responseMessage = null;
String listingType = null;
for (int i=0; i < records.length; i++) {
if (records[i] instanceof SRVRecord) {
listingType = ((SRVRecord) records[i]).toString()
}
}
System.out.println("Found!");
System.out.println("Response Message: "+responseMessage);
System.out.println("Listing type: "+listingType);
} else if (lookup.getResult() == Lookup.HOST_NOT_FOUND) {
System.out.println("Not found.");
} else {
System.out.println("Error!");
}
Any ideas why this isn't working?
Using a very different setup for SRV lookup in Android; I found they always failed with a 'not found', unless I add the following to my Android Manifest:
<uses-permission android:name="android.permission.INTERNET" />
I am not allowed to comment -- otherwise I would.
Make more else if statements, for example:
else if (lookup.getResult() == Lookup.HOST_NOT_FOUND) {
System.out.println("Not found.");
} else if (lookup.getResult() == Lookup.TRY_AGAIN) {
System.out.println("Error!1");
} else if (lookup.getResult() == Lookup.TYPE_NOT_FOUND) {
System.out.println("Error!2");
} else if (lookup.getResult() == Lookup.UNRECOVERABLE) {
System.out.println("Error!3");
}
Also, try changing: DClass.IN to DClass.ANY