Sending Arduino ADC Data to Android Tablet via USB Serial - android

I'm trying to send Arduino ADC data to android tablet using USB serial Communication. I'm using Serial.println() at arduino side. My Issue is that I'm not able to Decode the data received at the android end.
For Eg. Suppose I send Serial.println(768) from arduino, I check my android receive buffer and it Shows (55,54,56,13,10).
How can i decode this data back to 768 value?

Looking into an ASCII table you'll find that
55,54,56,13,10
represents
"768\n\r"
Most programming languages provide means for conversion between byte values and characters/strings with their string libraries. So you don't have to implement the decoding yourself.
Refer to https://howtodoinjava.com/array/convert-byte-array-string-vice-versa/
or UTF-8 byte[] to String
or anything else you find online for "byte to string Android"

String rawdata = " " ;
String finaldata = " ";
UsbSerialInterface.UsbReadCallback mCallback = new UsbSerialInterface.UsbReadCallback() { //Defining a Callback which triggers whenever data is read.
#Override
public void onReceivedData(byte[] arg0) {
byte[] buffer = arg0;
for (i =0;i <=(buffer.length-1);i++) {
if(buffer[i]!= 13) {
if(buffer[i]== 10){
finaldata = rawdata;
rawdata = "";
}else {
chdata = (char) buffer[i];
rawdata += chdata;
}
}
}
data = Integer.parseInt(finaldata);
}

Related

BLE sends junk data on onLeScan

Working on Bluetooth communication using https://github.com/GitGarage/BLEMingleDroid
While receiving data I am getting some junk Char appended to my real message, below is my code for sending and receiving message
AdvertiseData
byte[] data = message.getBytes();
ParcelUuid pu = ParcelUuid.fromString("0000" + asHex(message.substring(0,2).getBytes()) + "-0000-1000-8000-00805F9B34FB");
AdvertiseData.Builder builder = new AdvertiseData.Builder();
builder.addServiceData(pu, data);
builder.addServiceUuid(pu);
Receive Data
#Override
public void onLeScan(final BluetoothDevice newDevice, final int newRssi,
final byte[] newScanRecord) {
String message = new String(newScanRecord);
TextView textViewToChange = (TextView) findViewById(R.id.textView);
String oldText = textViewToChange.getText().toString();
String device = newDevice.getAddress();
String rssi = "" + newRssi;
}
I am not sure for what reason this junk appended to my real message, any idea?
That's not junk data. The scanRecord is an array of bytes, so you can't just convert it to a String.
void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord)
The scanRecord often contains strings, like the advertised device name, but it also contains service uuids, and other data that needs to be parsed. You need to manually parse this data. The scanRecord will have a byte indicating the length, a byte indicating the data type, then the data. Additional length, type, value bytes can follow the first one. The type codes are listed in the Generic Access Profile documentation.

IOException with Host based card emulation

I have been using HCE and have been facing an IOException on
isoDep.connect();
on a specific Android reader device cr100 simcent.
HCE works perfectly fine when I enable the reader mode in NFC with the below flags.
public static int READER_FLAGS =
NfcAdapter.FLAG_READER_NFC_A | NfcAdapter.FLAG_READER_SKIP_NDEF_CHECK;
But with that I am not able to read NDEF tags. Though the same code works perfectly fine on Nexus 7 (2012) Tablet.
The complete code is attached
CardReaderFragment
public class CardReaderFragment extends Fragment implements LoyaltyCardReader.AccountCallback {
public static final String TAG = "CardReaderFragment";
// Recommend NfcAdapter flags for reading from other Android devices. Indicates that this
// activity is interested in NFC-A devices (including other Android devices), and that the
// system should not check for the presence of NDEF-formatted data (e.g. Android Beam).
public static int READER_FLAGS =
NfcAdapter.FLAG_READER_NFC_A | NfcAdapter.FLAG_READER_SKIP_NDEF_CHECK;
public LoyaltyCardReader mLoyaltyCardReader;
private TextView mAccountField;
/** Called when sample is created. Displays generic UI with welcome text. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View v = inflater.inflate(R.layout.main_fragment, container, false);
if (v != null) {
mAccountField = (TextView) v.findViewById(R.id.card_account_field);
mAccountField.setText("Waiting...");
mLoyaltyCardReader = new LoyaltyCardReader(this);
// Disable Android Beam and register our card reader callback
enableReaderMode();
}
return v;
}
#Override
public void onPause() {
super.onPause();
disableReaderMode();
}
#Override
public void onResume() {
super.onResume();
enableReaderMode();
}
private void enableReaderMode() {
Log.i(TAG, "Enabling reader mode");
Activity activity = getActivity();
NfcAdapter nfc = NfcAdapter.getDefaultAdapter(activity);
if (nfc != null) {
nfc.enableReaderMode(activity, mLoyaltyCardReader, READER_FLAGS, null);
}
}
private void disableReaderMode() {
Log.i(TAG, "Disabling reader mode");
Activity activity = getActivity();
NfcAdapter nfc = NfcAdapter.getDefaultAdapter(activity);
if (nfc != null) {
nfc.disableReaderMode(activity);
}
}
#Override
public void onAccountReceived(final String account) {
// This callback is run on a background thread, but updates to UI elements must be performed
// on the UI thread.
getActivity().runOnUiThread(new Runnable() {
#Override
public void run() {
mAccountField.setText(account);
}
});
}
}
LoyaltyCardReader
public class LoyaltyCardReader implements NfcAdapter.ReaderCallback {
private static final String TAG = "LoyaltyCardReader";
// AID for our loyalty card service.
private static final String SAMPLE_LOYALTY_CARD_AID = "F222222222";
// ISO-DEP command HEADER for selecting an AID.
// Format: [Class | Instruction | Parameter 1 | Parameter 2]
private static final String SELECT_APDU_HEADER = "00A40400";
// "OK" status word sent in response to SELECT AID command (0x9000)
private static final byte[] SELECT_OK_SW = {(byte) 0x90, (byte) 0x00};
// Weak reference to prevent retain loop. mAccountCallback is responsible for exiting
// foreground mode before it becomes invalid (e.g. during onPause() or onStop()).
private WeakReference<AccountCallback> mAccountCallback;
public interface AccountCallback {
public void onAccountReceived(String account);
}
public LoyaltyCardReader(AccountCallback accountCallback) {
mAccountCallback = new WeakReference<AccountCallback>(accountCallback);
}
/**
* Callback when a new tag is discovered by the system.
* <p>
* <p>Communication with the card should take place here.
*
* #param tag Discovered tag
*/
#Override
public void onTagDiscovered(Tag tag) {
Log.i(TAG, "New tag discovered");
// Android's Host-based Card Emulation (HCE) feature implements the ISO-DEP (ISO 14443-4)
// protocol.
//
// In order to communicate with a device using HCE, the discovered tag should be processed
// using the IsoDep class.
IsoDep isoDep = IsoDep.get(tag);
if (isoDep != null) {
try {
// Connect to the remote NFC device
isoDep.connect();
// Build SELECT AID command for our loyalty card service.
// This command tells the remote device which service we wish to communicate with.
Log.i(TAG, "Requesting remote AID: " + SAMPLE_LOYALTY_CARD_AID);
byte[] command = BuildSelectApdu(SAMPLE_LOYALTY_CARD_AID);
// Send command to remote device
Log.i(TAG, "Sending: " + ByteArrayToHexString(command));
byte[] result = isoDep.transceive(command);
// If AID is successfully selected, 0x9000 is returned as the status word (last 2
// bytes of the result) by convention. Everything before the status word is
// optional payload, which is used here to hold the account number.
int resultLength = result.length;
byte[] statusWord = {result[resultLength - 2], result[resultLength - 1]};
byte[] payload = Arrays.copyOf(result, resultLength - 2);
if (Arrays.equals(SELECT_OK_SW, statusWord)) {
// The remote NFC device will immediately respond with its stored account number
String accountNumber = new String(payload, "UTF-8");
Log.i(TAG, "Received: " + accountNumber);
// Inform CardReaderFragment of received account number
mAccountCallback.get().onAccountReceived(accountNumber);
}
} catch (IOException e) {
Log.e(TAG, "Error communicating with card: " + e.toString());
}
} else {
Ndef ndef = Ndef.get(tag);
if (ndef == null) {
// NDEF is not supported by this Tag.
Log.d("NFCCardTagNDEF", "even this is null");
// return;
}
NdefMessage ndefMessage = ndef.getCachedNdefMessage();
if (ndefMessage == null) {
Log.d("NFCCardTagNDEF", "ndef message is null");
// return;
}
NdefRecord[] records = ndefMessage.getRecords();
String text = ndefRecordToString(records[0]);
Log.d("NFCCardTagNFC", "old" + text);
mAccountCallback.get().onAccountReceived(text);
}
}
public String ndefRecordToString(NdefRecord record) {
byte[] payload = record.getPayload();
return new String(payload);
}
/**
* Build APDU for SELECT AID command. This command indicates which service a reader is
* interested in communicating with. See ISO 7816-4.
*
* #param aid Application ID (AID) to select
* #return APDU for SELECT AID command
*/
public static byte[] BuildSelectApdu(String aid) {
// Format: [CLASS | INSTRUCTION | PARAMETER 1 | PARAMETER 2 | LENGTH | DATA]
return HexStringToByteArray(SELECT_APDU_HEADER + String.format("%02X", aid.length() / 2) + aid);
}
/**
* Utility class to convert a byte array to a hexadecimal string.
*
* #param bytes Bytes to convert
* #return String, containing hexadecimal representation.
*/
public static String ByteArrayToHexString(byte[] bytes) {
final char[] hexArray = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
char[] hexChars = new char[bytes.length * 2];
int v;
for (int j = 0; j < bytes.length; j++) {
v = bytes[j] & 0xFF;
hexChars[j * 2] = hexArray[v >>> 4];
hexChars[j * 2 + 1] = hexArray[v & 0x0F];
}
return new String(hexChars);
}
/**
* Utility class to convert a hexadecimal string to a byte string.
* <p>
* <p>Behavior with input strings containing non-hexadecimal characters is undefined.
*
* #param s String containing hexadecimal characters to convert
* #return Byte array generated from input
*/
public static 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;
}
}
Any help would be appreciated
Typically, there is not much you could do about this error. An IOException (or the more specific TagLostException) upon IsoDep.connect() indicates that the reading phone could not initiate communication with the HCE device. This is often due to connectivity issues caused by bad coupling (e.g. badly matching antenna dimensions, poor antenna design, antennas partially covered by the device battery without proper antenna design, etc.) or long power-up times (typically only with passive cards and not with HCE). So usually this error is not caused by logical problems with the communication protocol (which you could possibly fix through software) but by problem with the physical characteristics of the devices (which usually require hardware modifications).
Unfortunately, there's not much you can do about this. Possible work-arounds could be:
Try to better place the two phones together (so that the reader device antenna and the HCE device antenna) align to each other and that metal parts of the device case or the device battery does not cover the other device's antenna. In case of significanly different antenna sizes, try to align the other borders of the antennas to each other so that the smaller one is inside the larger one.
On some(!) devices it may help to increase the transceive timeout before calling connect():
isoDep.setTimeout(10000);
However, it seems that this timeout does not have any effect before connect was called on most devices.
There exist antenna "boosters" for NFC which either detune the HF resonance frequency to get better matching, that mitigate coupling issues do to adapting antenna shape around batteries, or that replace the original antenna altogether. I don't have much experience with this and can't quote any source for such boosters.
EDIT
After re-reading your question, it seems that communication between the cr100 and the HCE device works if you set the flag NfcAdapter.FLAG_READER_SKIP_NDEF_CHECK on the reader device. If that's the case, the IOException might indeed be caused by a logical error. In that case, it could be that the cr100 has a broken NFC discovery implementation that breaks if an ISO-DEP card (e.g. HCE device) does not implement the NDEF tag specification. While I would consider this highly unlikely, you could easily test this by implementing the Type 4 Tag application in your HCE application. See my answer here and the source code here for an example on how to do this.

How do you synchronize android clients with a python server?

I have a python server and about 10 android clients, using sockets. It is really important that when the server sends a message, all clients receive it at the same time (say 1/10th of a second of difference).
But the connection is over Wifi, and some devices get the message later than others, which gives a very messy result. I don't want to get the latency of every device because this is a very unreliable approach. I want something as accurate as possible.
For example, in FPS games, it is common to have a countdown at the start of the round, and every player can start playing at the same time. What kind of logic lies behind this?
As for what my code currently looks like:
I use a BufferedReader in android to read every line sent by the server. The server is a console application in which you can type a message, and when you press enter, every listed client receives it with a new thread for every client.
java method receiving messages:
private void readMessage() throws IOException {
String data;
while ((data = mBufferedReader.readLine()) != null) {
data = data.toUpperCase();
if (data.startsWith("POSITION")) {
String[] splitData = data.split("/");
Log.d(Constants.TAG, splitData[1]);
mMainActivity.setDevicePosition(Integer.parseInt(splitData[1]));
} else {
String message = data.substring(data.indexOf('/') + 1, data.length());
int devices = Integer.parseInt(data.substring(0, data.indexOf('/')));
if (message.length() >= devices) {
message += " ";
} else {
int difference = devices - message.length();
for (int i = 0; i < difference; i++) {
message += " ";
}
}
mMainActivity.printMessage(message);
}
}
}
python line :
for cl in clients_list:
start_new_thread(send_message_thread, (cl, message,))

Problems when sending a continuous stream of data over BLE

I'm wondering if anybody can help me figure out what is causing the data I am sending to become corrupt.
My setup is currently an Arduino pro mini with a HM-10 bluetooth module connected (I have also tried HM-11 Module too) and an Android application to receive the bluetooth data.
Module setup: http://letsmakerobots.com/node/38009
If I send data with big enough intervals then the data is fine, but if I send the data continuously I see messages getting mixed up and lost. To test this I send "$0.1,0.2,0.3,0.4,0.5" to the Android application from the Arduino, sometimes the stream of data appears to send fine but other times it is really quite scrambled. Please see the below graphs that demonstrate this:
Good case:
Bad case:
Arduino code:
String inputString = ""; //Hold the incoming data.
boolean stringComplete = false; //Determines if the string is complete.
boolean realtime = false;
void setup()
{
Serial.begin(9600);
delay(500);
Serial.print("AT+START");
delay(500);
}
void loop()
{
if(stringComplete)
{
if(inputString.equals("rStart"))
{
Serial.println("$startACK");
realtime = true;
}
else if(inputString.equals("stop"))
{
Serial.println("$stopACK");
realtime = false;
}
else{
Serial.print(inputString);
}
inputString = "";
stringComplete = false;
}
if(realtime)
{
Serial.println("$0.1,0.2,0.3,0.4,0.5,0.6");
delay(10);
}
}
void serialEvent() {
while (Serial.available())
{
// get the new byte:
char inChar = (char)Serial.read();
if (inChar == '\n')
{
stringComplete = true;
}
else
{
inputString += inChar;
}
}
}
The Android side just receives the data and then parses it in an IntentService:
#Override
protected void onHandleIntent(Intent intent) {
//Incoming command.
String rawData = intent.getStringExtra(DataProcessingIntentService.REQUEST);
//Append our new data to our data helper.
Log.i(this.getClass().getName(), "Previous Raw: (" + DataProcessingHelper.getInstance().getData() + ")");
DataProcessingHelper.getInstance().appendData(rawData);
Log.i(this.getClass().getName(), "New Raw: (" + DataProcessingHelper.getInstance().getData() + ")");
commandStartIndex = DataProcessingHelper.getInstance().getData().indexOf("$");
commandEndIndex = DataProcessingHelper.getInstance().getData().indexOf("\n");
//Set this as the data starting point.
if(commandStartIndex != -1){
DataProcessingHelper.getInstance().offsetData(commandStartIndex);
}
//Ensure that a command has been found and that the end index is after the starting index.
if(commandStartIndex != -1 && commandEndIndex > commandStartIndex){
//Remove the command structure from the command.
command = DataProcessingHelper.getInstance().getData().substring(commandStartIndex+1, commandEndIndex-1); //Remove the \r\n end command.
DataProcessingHelper.getInstance().offsetData(commandEndIndex+1);
if(command.length() > 1){
//Split the data out of the comand.
splitData = command.split(",");
Log.i(this.getClass().getName(), "Broadcasting the processed data. (" + command + ")");
//Broadcast data.
Intent broadcastIntent = new Intent();
broadcastIntent.setAction(DataProcessingIntentService.RESPONSE);
broadcastIntent.addCategory(Intent.CATEGORY_DEFAULT);
broadcastIntent.putExtra(DataProcessingIntentService.RESPONSE, splitData);
sendBroadcast(broadcastIntent);
}else{
Log.e(this.getClass().getName(), "Command is less than 1 character long!");
}
}
}
Thank you for any help!
I have now figured out what was causing this problem. It appears that BLE only supports a maximum of 20 bytes per a transaction. The time between these transactions is different depending on what you are using. I'm currently using notifications which means that I can send 20 bytes every 7.5 milliseconds maximum. I have opted for 10 milliseconds to be safe. I will now need to look into breaking up packets into 20 bytes maximum to ensure no data corruption.

android client socket is not receiving data

I have a tcp server which is not in java also its a hardware device , I need to send and receve the data ,
I am connecting with server and sending some configuration data using following code
this.clientSocket=new Socket("198.168.1.17",9999);
this.os=new DataOutputStream(this.clientSocket.getOutputStream());
this.in=new DataInputStream(this.clientSocket.getInputStream());
System.out.println("Conncted");
char data[]={0x03,0x03,0x00};
byte b[]=new byte[data.length];
for (int i = 0; i < b.length; i++) {
b[i] = (byte) data[i];
}
try {
os.write(b);
Device receives data correctly , now in my tcp client i am not able to receive data , though i write following code just after above code
int size =in.available();
byte data1[]=new byte[size];
// in.read(data1);
String str=new String(data1);
System.out.println("Reading data:"+str);
It only shows reading data , and string has not data
also i tried about code in thread
public void run(){
try{
while(true){
int size =in.available();
byte data[]=new byte[size];
in.read(data);
String str=new String(data);
System.out.println("Reading data:"+str);
}
in thread it only shows reading data ,
Please help how can i get data from the server also please note server is built in i can not change the server code
what available() method do in code "int size =in.available();"????????
Solution may be:
available() method return 0 so you are not able to receive data.
use this code for receiving data from socket. write this code before onCreate.
private EditText mInputMessageView;
private Emitter.Listener onNewMessage = new Emitter.Listener() {
#Override
public void call(final Object... args) {
MainActivity.this.runOnUiThread(new Runnable() {
#Override
public void run() {
JSONObject data = (JSONObject) args[0];
String username;
String message;
try {
username = data.getString("username");
message = data.getString("message");
} catch (JSONException e) {
return;
}
// add the message to view
addMessage(username, message);
}
});
}
};

Categories

Resources