saranicole
saranicole

Reputation: 2483

ADK AndroidAccessory Read Function on Arduino should be getting something, per DemoKit sketch?

I'm using a Freeduino (Arduino Uno compatible) with a Samsung Galaxy Tab 10.1 running ICS (4) and I have succeeded in writing from the Arduino to the Android, but I have not been able to read from the Android in the Arduino sketch.

Here's the Android class for the USB Accessory:

package com.kegui.test;

import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.StringWriter;
import java.io.Writer;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.util.ArrayList;

import org.apache.http.NameValuePair;
import org.apache.http.message.BasicNameValuePair;

import com.kegui.test.Scripto;

import android.app.Activity;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.hardware.usb.UsbAccessory;
import android.hardware.usb.UsbManager;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.os.ParcelFileDescriptor;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;

public class USBAccess extends Activity implements Runnable, OnClickListener {
    private static final String ACTION_USB_PERMISSION = "com.google.android.DemoKit.action.USB_PERMISSION";

    protected static final String TAG = "KegUI";

    private UsbManager mUsbManager;
    private PendingIntent mPermissionIntent;
    private boolean mPermissionRequestPending;

    private TextView debugtext = null;
        private Button button1 = null;
        private Button button2 = null;
        private boolean button2visible = false;



    UsbAccessory mAccessory;
    ParcelFileDescriptor mFileDescriptor;
    FileInputStream mInputStream;
    FileOutputStream mOutputStream;

    private static final int MESSAGE_BUTTON_PRESSED = 1;


    private final BroadcastReceiver mUsbReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
            Log.i("KegApp", "***********************Received*************************");
            if (ACTION_USB_PERMISSION.equals(action)) {
                synchronized (this) {
                    UsbAccessory accessory = (UsbAccessory) intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY);
                    if (intent.getBooleanExtra(
                            UsbManager.EXTRA_PERMISSION_GRANTED, false)) {
                        openAccessory(accessory);
                    } else {
                        Log.d(TAG, "permission denied for accessory "
                                + accessory);
                    }
                    mPermissionRequestPending = false;
                }
            } else if (UsbManager.ACTION_USB_ACCESSORY_DETACHED.equals(action)) {
                UsbAccessory accessory = (UsbAccessory) intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY);
                if (accessory != null && accessory.equals(mAccessory)) {
                    closeAccessory();
                }
            }
        }
    };


    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        mUsbManager = (UsbManager) getSystemService(Context.USB_SERVICE);
        mPermissionIntent = PendingIntent.getBroadcast(this, 0, new Intent(
                    ACTION_USB_PERMISSION), 0);
        IntentFilter filter = new IntentFilter(ACTION_USB_PERMISSION);
        filter.addAction(UsbManager.ACTION_USB_ACCESSORY_DETACHED);

        setContentView(R.layout.main);
        final Button button = (Button) findViewById(R.id.button1);
        button.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {
                // Perform action on click

                new TempUpdateTask().execute("testing");
            }
        });
        registerReceiver(mUsbReceiver, filter);

        Log.d(TAG,"on Create'd");
    }

    @Override
    public void onResume() {
        super.onResume();

        if (mInputStream != null && mOutputStream != null) {
            return;
        }

        UsbAccessory[] accessories = mUsbManager.getAccessoryList();
        UsbAccessory accessory = (accessories == null ? null : accessories[0]);
        if (accessory != null) {
            if (mUsbManager.hasPermission(accessory)) {
                openAccessory(accessory);
            } else {
                synchronized (mUsbReceiver) {
                    if (!mPermissionRequestPending) {
                        mUsbManager.requestPermission(accessory,
                                mPermissionIntent);
                        mPermissionRequestPending = true;
                    }
                }
            }
        } else {
            Log.d(TAG, "mAccessory is null");
        }
    }

    @Override
    public void onPause() {
        super.onPause();
        closeAccessory();
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        unregisterReceiver(mUsbReceiver);

    }

    private void openAccessory(UsbAccessory accessory) {
        mFileDescriptor = mUsbManager.openAccessory(accessory);
        if (mFileDescriptor != null) {
            mAccessory = accessory;
            FileDescriptor fd = mFileDescriptor.getFileDescriptor();
            mInputStream = new FileInputStream(fd);
            mOutputStream = new FileOutputStream(fd);
            Thread thread = new Thread(null, this, "KegApp");
            thread.start();




            //enableControls(true);
        } else {
            Log.d(TAG, "accessory open fail");
        }
    }


    public void run() { 
        int ret = 0;
        byte[] buffer = new byte[16384];
        int i;
        Log.i("KegApp", "***********************in run*************************");
        while (ret >= 0) {
            try {
                ret = mInputStream.read(buffer); // this will be always positive, as long as the stream is not closed
            } catch (IOException e) {
                break;
            }

            i = 0;
            while (i < ret) {
                Message m = Message.obtain(messageHandler, MESSAGE_BUTTON_PRESSED);
                m.obj = buffer[i];
                messageHandler.sendMessage(m);
                i++;
            }

        }

    }



    private void closeAccessory() {
        //enableControls(false);

        try {
            if (mFileDescriptor != null) {
                mFileDescriptor.close();
            }
        } catch (IOException e) {
        } finally {
            mFileDescriptor = null;
            mAccessory = null;
        }
    }

    public void sendCommand(FileOutputStream mStream) { 
        BufferedOutputStream bo = new BufferedOutputStream(mStream);

    //  if (mStream != null && message.length > 0) {
            try {
                Log.i("KegApp", "***********************sending command now*************************");
                bo.write(1); //message, 0, 3);
            } catch (IOException e) {
                Log.e(TAG, "write failed", e);
            }
    //  }
    }

    @Override
    public void onClick(View v) {
        // Send some message to Arduino board, e.g. "13"
        Log.e(TAG, "write failed");
    }

    // Instantiating the Handler associated with the main thread.
      private Handler messageHandler = new Handler() {

          @Override
          public void handleMessage(Message msg) { 
              Log.i("KegApp", "***********************message handler before " + msg.what +  "************************");
                try {  
                    String load = msg.obj.toString();
                    Log.i("KegApp", "***********************in message handler*************************");
                    /*
                    if (button2visible==false) {
                        debugtext.setText("Received message: "+String.valueOf(load));
                        button2.setVisibility(View.VISIBLE);
                        button2visible = true;
                    } else {
                        debugtext.setText("");
                        button2.setVisibility(View.GONE);
                        button2visible = false;
                    }
                    */
                    new TempUpdateTask().execute(load);

                } catch (Exception e) {
                    Log.e(TAG, "message failed", e);
                }
          }

      };

// UpdateData Asynchronously sends the value received from ADK Main Board.
// This is triggered by onReceive()
class TempUpdateTask extends AsyncTask<String, String, String> {

    // Called to initiate the background activity
    protected String doInBackground(String... sensorValue) {
            try {
                Log.i("KegApp", "***********************calling sendcommand*********************");
                sendCommand(mOutputStream);

                Log.i("KegApp", "*********************incoming-sensorValue*********************" );
                ArduinoMessage arduinoMessage = new ArduinoMessage(sensorValue[0]);


            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (Exception e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            String returnString = String.valueOf(sensorValue[0]);//String.valueOf(sensorValue[0]) + " F";
            publishProgress(String.valueOf(sensorValue[0]));
            return (returnString); // This goes to result

    }

    // Called when there's a status to be updated
    @Override
    protected void onProgressUpdate(String... values) {
        // Init TextView Widget to display ADC sensor value in numeric.
        TextView tvAdcvalue = (TextView) findViewById(R.id.tvTemp);
        tvAdcvalue.setText(String.valueOf(values[0]));

        // Not used in this case
    }

    // Called once the background activity has completed
    @Override
    protected void onPostExecute(String result) {
        super.onPostExecute(result);
        closeAccessory();
    }

}
}

Here's my Arduino Sketch:

#include <FHB.h>
#include <Max3421e.h>
#include <Max3421e_constants.h>
#include <Max_LCD.h>
#include <Usb.h>


//FREEDUINO ONLY------------------------------------

//END FREEDUINO ONLY------------------------------------
int pin_light_sensor_1=A0;
int pin_output_sensor=9;
int currLightLevel=0;
//int prevLightLevel=0;
//int lightStableRange=90;
int delayTime=3000;
int loopCtr=0;
char cSTX=char(2);
char cSOH=char(1);
char cEOT=char(4);
char cGS=char(29);
char cRS=char(30);
char cCR=char(13);
char cLF=char(10);

//FREEDUINO ONLY------------------------------------
AndroidAccessory acc("Company Inc.",
             "Kegbot5K datawriter",
             "Kegbot 5000 data writer",
             "1.0",
             "http://companyinc.com",
             "0000000012345678");
//END FREEDUINO ONLY------------------------------------
void setup()
{
  pinMode(pin_light_sensor_1, INPUT);
  pinMode(pin_output_sensor, OUTPUT);
  Serial.begin(57600);
//FREEDUINO ONLY------------------------------------  
  Serial.println("pre-power");
  acc.powerOn();
  Serial.println("post-power");
//END FREEDUINO ONLY------------------------------------
}

void loop()
{
byte msg[3];
if (acc.isConnected()) {
  currLightLevel = analogRead(pin_light_sensor_1);

     //sysPrint(delayTime*loopCtr);
     //sysPrint(",");
     //sysPrint(currLightLevel);
     writeDataMessage("LGH01", currLightLevel);

 }

 delay(1000);
 if (acc.isConnected()) {
    int len = acc.read(msg, sizeof(msg), 1);
    Serial.println(len);
      if (len > 0){
     for (int index=0; index < len; index++){
        digitalWrite(pin_output_sensor, 1);
                delay(500);
        digitalWrite(pin_output_sensor, 0);
     }
      }
 }
  loopCtr++;
  delay(delayTime);
}

void writeHeader(String msgType)
{
  sysPrint(cSTX);
  sysPrint(cSTX);
  sysPrint(cSOH);
  sysPrint(msgType);
  sysPrint(cGS);
}

void writeFooter()
  {
  sysPrint(cEOT);
  sysPrintLn(cEOT);
  }

void writeDataMessage(String sensorID, int value)
  {
  writeHeader("DATA");
  sysPrint(sensorID);
  sysPrint(cRS);
  sysPrint(value);
  writeFooter();
  }

void writeAlarmMessage(String sensorID, String message)
//Do we need to enforce the 5 char sensorID here? I don't think so...
  {
  writeHeader("ALRM");
  sysPrint(sensorID);
  sysPrint(cRS);
  sysPrint(message);
  writeFooter();
  }

void sysPrint(String whatToWrite)
  {
    int len=whatToWrite.length();
  char str[len];
  whatToWrite.toCharArray(str, len);
  acc.write((void *)str, len);
 // acc.write(&whatToWrite, whatToWrite.length());
  }
void sysPrint(char whatToWrite)
  {
  acc.write((void *)whatToWrite, 1);
 // acc.write(&whatToWrite, 1);
  }
void sysPrint(int whatToWrite)
  {
  acc.write((void *)&whatToWrite, 1);
//  acc.write(&whatToWrite, 1);
  }

void sysPrintLn(String whatToWrite)
  {
  int len=whatToWrite.length();
  char str[len];
  whatToWrite.toCharArray(str, len);
  acc.write((void *)str, len);
  acc.write((void *)&cCR, 1);
  acc.write((void *)&cLF, 1);
 // acc.write(&whatToWrite, whatToWrite.length());
 // acc.write(&cCR, 1);
 // acc.write(&cLF, 1);
  }

void sysPrintLn(char whatToWrite)
  {
  acc.write((void *)whatToWrite, 1);
   acc.write((void *)&cCR, 1);
  acc.write((void *)&cLF, 1);
 // acc.write(&whatToWrite, 1);
 // acc.write(&cCR, 1);
 // acc.write(&cLF, 1);
  }

The sendCommand function in the Android is logging that it was sent. The acc.read function is printing length to Serial output as -1, as in no input. Speaking of which, the Android logs do not show errors, so I'm thinking this might be an Arduino thing.

My Manifest has an Intent filter that's registering the device, although permissions might have something to do with it.

 <intent-filter>
        <action android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED" />
    </intent-filter>

    <meta-data android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED"
        android:resource="@xml/accessory_filter" />
        </activity>

Thanks in advance for any thoughts, Sara

Upvotes: 0

Views: 2498

Answers (2)

Qurashi
Qurashi

Reputation: 1467

I have developed an RC helicopter that can be controlled using android by sending messages from the android to the arduino located on top of the Helicopter using Bluetooth Stick, i did not use usb yet for any project but when you are sending messages to the arduino you are using serial communication weather connected threw USB or Bluetooth i suggest to simply use Serial.read and every message you send to arduino end it with some symbol '#' for example just to separate messages and get the message character by character this is the code to read the full message ended with '#' from the Serial port:

    String getMessage()
    {
      String msg=""; //the message starts empty
      byte ch; // the character that you use to construct the Message 
      byte d='#';// the separating symbol 

      if(Serial.available())// checks if there is a new message;
      {
        while(Serial.available() && Serial.peek()!=d)// while the message did not finish
        {
          ch=Serial.read();// get the character
          msg+=(char)ch;//add the character to the message
          delay(1);//wait for the next character
        }
      ch=Serial.read();// pop the '#' from the buffer
      if(ch==d) // id finished
      return msg;
      else
      return "NA";
      }
    else
    return "NA"; // return "NA" if no message;
}

this function checks if there any message in the buffer if not it returns "NA". if that did not help please inform.

Upvotes: 1

saranicole
saranicole

Reputation: 2483

Figured out what's going wrong - sendCommand is executing from the asynchronous TempTask so it doesn't get passed a valid reference to the FileOutputStream. I can execute sendCommand onClick from the main thread and receive on the Arduino just fine.

Upvotes: 0

Related Questions