1

I want to make a project/android app that can transfer command to arduino and receives response from it via USB-OTG. The specifications are as follows :

  1. android app sends a command (in array of bytes) to arduino,
  2. arduino receives, and the command prompts the arduino to send a response (also in array of bytes) to the app,
  3. App receives the response, which prompts it to send another command,
  4. Do this repeatedly until arduino sends the final response, which has the data I want the android app to display (e.g. balance, amount of transaction, etc.)

This whole process needs to be done automatically after one push of a button (on the app) by the user.

This project is basically a smart card reader simulator (It's a simulator because the APDU response is hard-coded into the arduino code, so the whole system does not require an actual smart card and card reader).

The description of the problem is written below, followed by the questions. It's quite long, so please bear with me.

The java code that I modified was :

 UsbSerialInterface.UsbReadCallback mCallback = new UsbSerialInterface.UsbReadCallback() { //Defining a Callback which triggers whenever data is read.
    @Override
    public void onReceivedData(byte[] arg0) {

        //the part that I modified :
        String balance = "";
        try{
            if ((arg0[0] == (byte) 0x50) && (arg0[1] == (byte) 0x33)) {
                byte[] CMD2 = {0x00,(byte)0xA2,0x00,0x00,0x05,0x41,0x00};
                serialPort.write(CMD2);
            }
            else if ((arg0[0] == (byte) 0x50) && (arg0[1] == (byte) 0x44)) {
                byte[] CMD3 = {0x00,(byte)0xA2,0x00,0x00,0x05,0x41,0x11};
                serialPort.write(CMD3);
            }
            else if ((arg0[0] == (byte) 0x50) && (arg0[1] == (byte) 0x1C)) {
                byte[] CMD4 = {0x00,(byte)0xD1,0x00,0x00,0x10};
                serialPort.write(CMD4);
            }
            else if (arg0[0] == (byte) 0xC5) {

                byte[] bufferData = PickData(arg0, 8);
                balanceData = bytesToLong(bufferData);
                balance = Long.toString(balanceData);
                balanceView.setText(balance);
            }
            else{
                balanceView.setText("Balance Check Failed! Click Refresh");
            }
        }catch (Exception e) {
            e.printStackTrace();}


    }

};
/* The part that I added */
//Picks the balance data from the final response.
public static byte[] PickData(byte[] bytes, int lengthb) {
    byte[] buffer= new byte [lengthb];
    for (int i = 0; i < lengthb; i++) {
        if((bytes[i+1]==0xB0)||(bytes[i+1]==0x90))
            buffer[i] = 0;
        else
            buffer[i] = bytes[1+i];
    }
    return buffer;
}


//converts array of byte into long. 
public static long bytesToLong(byte[] Data) {
    long value=0;
    for (int i = 0; i < Data.length; i++)
    {
        value = (value << 8) + (Data[i] & 0xff);
    }
    return value;
}

And this is the arduino code :

#include <SoftwareSerial.h>
#define RX 3
#define TX 5
int c;
SoftwareSerial usbdevice=SoftwareSerial(RX,TX);
byte command[11];

//Hard-coded responses
byte response1[] = {0x50,0x33,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
byte response2[] = {0x50,0x44,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
byte response3[] = {0x50,0x1C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
//0x2710 is the balance data. It will be translated to long then to string, which is 10000.
byte response4[] = {0xC5,0x00,0x00,0x00,0x00,0x00,0x00,0x27,0x10,0x90,0x00}; 

String str; //only for serial monitor viewing
byte response[11];  // to be printed on Serial Monitor

void setup() {
  pinMode(RX,INPUT);
  pinMode(TX,OUTPUT);
  Serial.begin(115200);
  usbdevice.begin(9600);
  Serial.println("Arduino Reader Simulation Start: ");
}

void loop() 
{
  //Reads the command from android
  if(usbdevice.available()>0)
  {
    c=0;
    delay(15);
    while(1)
    {
      if(usbdevice.available()>0)
      {
        command[c] = usbdevice.read();
        c++;
      }
      else
        break;
    }
 //Checks the command byte-per-byte then sends the response 
 for(c=0;c<11;c++)
    {
      if((command[0] == 0x00)&&(command[1] == 0xA2)&&(command[2] == 0x00)&&(command[3] == 0x00)&&(command[4] == 0x05)&&(command[5] == 0x4e)&&(command[6] == 0x00)){
        usbdevice.write(response1[c]);
        response[c] = response1[c];
      }
      else if((command[0] == 0x00)&&(command[1] == 0xA2)&&(command[2] == 0x00)&&(command[3] == 0x00)&&(command[4] == 0x05)&&(command[5] == 0x41)&&(command[6] == 0x00)){
        usbdevice.write(response2[c]);
        response[c] = response2[c];
      }
      else if ((command[0] == 0x00)&&(command[1] == 0xA2)&&(command[2] == 0x00)&&(command[3] == 0x00)&&(command[4] == 0x05)&&(command[5] == 0x41)&&(command[6] == 0x11)){
        usbdevice.write(response3[c]);
        response[c] = response3[c];
      }
      else if((command[0] == 0x00)&&(command[1] == 0xD1)&&(command[2] == 0x00)&&(command[3] == 0x00)&&(command[4] == 0x10)){
        usbdevice.write(response4[c]);
        response[c] = response4[c];
      }
    }
    //Prints each command and it's response.
    printAll();
  }
}

During the testing of these codes, I encountered some problems :

  1. At first I didn't use try-catch. When tested, the app would always crash whenever I tried to send the first command. When I tried to use try-catch, the app no longer crashes but the second problem appears (I have never used try-catch so I don't know it's purpose and how to use it correctly).
  2. Sometimes the app successfully displayed the balance, but most of the time it failed. The successful process :

        Command: 
    0 a2 0 0 5 4e 0 0 0 0 0 
    Response: 
    50 33 0 0 0 0 0 0 0 0 0 
    Command: 
    0 a2 0 0 5 41 0 0 0 0 0 
    Response: 
    50 44 0 0 0 0 0 0 0 0 0 
    Command: 
    0 a2 0 0 5 41 11 0 0 0 0 
    Response: 
    50 1c 0 0 0 0 0 0 0 0 0 
    Command: 
    0 d1 0 0 10 41 11 0 0 0 0 
    Response: 
    c5 0 0 0 0 0 0 27 10 90 0 
    

    While the failed process :

    //First attempt
    Command: 
    0 a2 0 0 5 4e 0 0 0 0 0 
    Response: 
    50 33 0 0 0 0 0 0 0 0 0 
    Command: 
    48 10 50 e0 5 4e 0 0 0 0 0 
    Response: 
    50 33 0 0 0 0 0 0 0 0 0 
    
    //Second attempt
    Command: 
    0 a2 0 0 5 4e 0 0 0 0 0 
    Response: 
    50 33 0 0 0 0 0 0 0 0 0 
    Command: 
    0 a2 0 0 5 41 0 0 0 0 0 
    Response: 
    50 44 0 0 0 0 0 0 0 0 0 
    Command: 
    0 a2 0 0 5 41 11 0 0 0 0 
    Response: 
    50 1c 0 0 0 0 0 0 0 0 0 
    Command: 
    0 d1 0 20 5 41 11 0 0 0 0 
    Response: 
    50 1c 0 0 0 0 0 0 0 0 0 
    

As can be seen in the failed process, the command bytes which were sent from android to arduino were different from the hard-coded bytes in the java code. Somehow the android would randomly send random bytes as a command, thus stopping the process and the 'failed' message would be displayed. I have no idea why this could happen. What I understand is that this might be the cause of the crash had I not use try-catch.

Based on the details of my problem above, my questions are :

1. How do I fix the crash problem, and the 'randomly changing command data' problem?

2. Is there any other way to transfer data sequentially like this but actually works?

Thank you in advance.

P.S. I suspect that one of the problems is caused by the function PickData in the java code, because when I disabled it, the app almost never failed to display something, though it would always display some random numbers (if I'm lucky, the app might displayed the balance data). This randomly changing byte data is what I'm very confused about.

I'm using this tutorial as a reference : https://www.allaboutcircuits.com/projects/communicate-with-your-arduino-through-android/

I also use USB Serial Library (as used in the tutorial above) by Github user felHR85. Link : https://github.com/felHR85/UsbSerial/

0 Answers0