I'm new in developing with ACR or NFC Reader, especially for Android. And recently I need to use an ACR35 and I've got the SDK and the example from this acs official website. And It works just fine as an example.
And now I need to create an activity that will always be ready to check whether nfc card is tapped. But the problem is I don't know how to detect when the nfc card is tapped and I don't know what to do next, and I can't find the way out from the example as it detects nfc card when I touch the 'transmit' button, it doesn't do it automatically.
Please give me with example code.
Thanks for your answer.
A bit late, but it might help someone.
I have found following project on the git hub. It shows how to read tag id from the acr35
here
.
I have been using acr35 for some time to read the tag id. From my experience is a buggy device on Android. I tested around 10 devices and it worked only on 3...
I read from it every second. It returns results from the last card even though it is not present there anymore. Therefore; I have to reset it twice per every successful read and it takes around 6 seconds to get the device in reading state again... Also be very careful with multithreading.
My implementation based on mentioned project - added simple locking to stop querying the card after successfull reading + full device reset, filternig same uuid which was read in very short time after it was read previously:
ACR3x class
import com.acs.audiojack.AudioJackReader;
import android.media.AudioManager;
import sk.tido.util.ByteHex;
import java.util.Date;
/**
* This class allows control of the ACR35 reader sleep state and PICC commands
*/
public class Acr3x {
private Acr3xTransmitter transmitter;
private AudioManager mAudioManager;
private AudioJackReader mReader;
private boolean firstReset = true; /** Is this the first reset of the reader? */
/** APDU command for reading a card's UID */
private final byte[] apdu = { (byte) 0xFF, (byte) 0xCA, (byte) 0x00, (byte) 0x00, (byte) 0x00 };
/** Timeout for APDU response (in <b>seconds</b>) */
private final int timeout = 1;
private int acr3xCardType = AudioJackReader.PICC_CARD_TYPE_ISO14443_TYPE_A
| AudioJackReader.PICC_CARD_TYPE_ISO14443_TYPE_B
| AudioJackReader.PICC_CARD_TYPE_FELICA_212KBPS
| AudioJackReader.PICC_CARD_TYPE_FELICA_424KBPS
| AudioJackReader.PICC_CARD_TYPE_AUTO_RATS;
private int acr3xStartAudioLevel = 0;
private Object locking = new Object();
private String lastUuid = "";
private Date lastUuidDate = new Date();
public Acr3x(AudioManager mAudioManager){
this.mAudioManager = mAudioManager;
}
public void start(final Acr3xNotifListener listener){
Runnable r = new Runnable(){
#Override
public void run() {
if(mReader == null){
mReader = new AudioJackReader(mAudioManager);
}
System.out.println("ACR35 reader start");
acr3xStartAudioLevel = mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC);
System.out.println("acr3x start audio stream level: " + acr3xStartAudioLevel);
mAudioManager.setStreamVolume(AudioManager.STREAM_MUSIC,
mAudioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC), 0);
System.out.println("acr3x set audio stream level: " + mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC));
mReader.start();
mReader.setSleepTimeout(30);
mReader.setOnFirmwareVersionAvailableListener(new AudioJackReader.OnFirmwareVersionAvailableListener() {
#Override
public void onFirmwareVersionAvailable(AudioJackReader reader,
String firmwareVersion) {
System.out.println("acr3x firmware version: " + firmwareVersion);
if(listener != null){
listener.onFirmwareVersionAvailable(firmwareVersion);
}
Acr3x.this.read(listener);
}
});
mReader.reset(new AudioJackReader.OnResetCompleteListener(){
#Override
public void onResetComplete(AudioJackReader arg0) {
mReader.getFirmwareVersion();
}
});
}
};
Thread t = new Thread(r, "Acr3xInitThread");
t.start();
}
/**
* Sets the ACR35 reader to continuously poll for the presence of a card. If a card is found,
* the UID will be returned to the Apache Cordova application
*
* #param callbackContext: the callback context provided by Cordova
* #param cardType: the integer representing card type
*/
public void read(final Acr3xNotifListener callbackContext){
System.out.println("acr3x setting up for reading...");
firstReset = true;
/* Set the PICC response APDU callback */
mReader.setOnPiccResponseApduAvailableListener
(new AudioJackReader.OnPiccResponseApduAvailableListener() {
#Override
public void onPiccResponseApduAvailable(AudioJackReader reader,
byte[] responseApdu) {
/* Update the connection status of the transmitter */
transmitter.updateStatus(true);
/* Print out the UID */
String uuid = ByteHex.bytesToHex(responseApdu);
if(uuid.equalsIgnoreCase("0x9000")){
return;
}
if(uuid.endsWith("9000")){
uuid = uuid.substring(0, uuid.length() - 4);
}
if(uuid.equals(lastUuid)){ // na odfiltrovanie opakujucich sa uuid z citacky z predchadzajuceho citania
if(new Date().getTime() - lastUuidDate.getTime() < 3000){
return;
}
}
lastUuid = uuid;
lastUuidDate = new Date();
synchronized(locking){
System.out.println("acr3x uuid: " + uuid);
if(callbackContext != null){
callbackContext.onUUIDAavailable(uuid);
}
System.out.println("acr3x restarting reader");
transmitter.kill();
try {
locking.wait(2000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
read(callbackContext);
}
});
/* Set the reset complete callback */
mReader.setOnResetCompleteListener(new AudioJackReader.OnResetCompleteListener() {
#Override
public void onResetComplete(AudioJackReader reader) {
System.out.println("acr3x reset complete");
/* If this is the first reset, the ACR35 reader must be turned off and back on again
to work reliably... */
Thread t = null;
if(firstReset){ //firstReset
t = new Thread(new Runnable() {
public void run() {
try{
/* Set the reader asleep */
mReader.sleep();
/* Wait one second */
Thread.sleep(500);
/* Reset the reader */
mReader.reset();
firstReset = false;
} catch (InterruptedException e) {
e.printStackTrace();
// TODO: add exception handling
}
}
});
} else {
/* Create a new transmitter for the UID read command */
transmitter = new Acr3xTransmitter(mReader, mAudioManager, timeout,
apdu, acr3xCardType, locking);
t = new Thread(transmitter);
}
t.start();
}
});
mReader.start();
mReader.reset();
System.out.println("acr3x setup complete");
}
public void stop(){
if(transmitter != null){
transmitter.kill();
}
System.out.println("acr3x restoring audio level: " + acr3xStartAudioLevel);
mAudioManager.setStreamVolume(AudioManager.STREAM_MUSIC,acr3xStartAudioLevel, 0);
System.out.println("acr3x set audio stream level: " + mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC));
if(mReader != null){
mReader.stop();
}
}
}
Transmitter class
import com.acs.audiojack.AudioJackReader;
import android.media.AudioManager;
/**
* This class sets up an independent thread for card polling, and is linked to the
* <code>setOnPiccResponseApduAvailableListener</code> callback function
*/
public class Acr3xTransmitter implements Runnable {
private AudioJackReader mReader;
private AudioManager mAudioManager;
//private CallbackContext mContext;
private boolean killMe = false; /** Stop the polling thread? */
private int itersWithoutResponse = 0; /** The number of iterations that have passed with no
response from the reader */
private boolean readerConnected = true; /** Is the reader currently connected? */
private int cardType;
private int timeout;
private byte[] apdu;
private Object locking;
/**
* #param mReader: AudioJack reader service
* #param mAudioManager: system audio service
* #param mContext: context for plugin results
* #param timeout: time in <b>seconds</b> to wait for commands to complete
* #param apdu: byte array containing the command to be sent
* #param cardType: the integer representing card type
*/
public Acr3xTransmitter(AudioJackReader mReader, AudioManager mAudioManager,
int timeout, byte[] apdu, int cardType, Object locking){
this.mReader = mReader;
this.mAudioManager = mAudioManager;
this.timeout = timeout;
this.apdu = apdu;
this.cardType = cardType;
this.locking = locking;
}
/**
* Stops the polling thread
*/
public void kill(){
killMe = true;
}
/**
* Updates the connection status of the reader (links to APDU response callback)
*/
public void updateStatus(boolean status){
readerConnected = status;
}
/**
* Sends the APDU command for reading a card UID every second
*/
#Override
public void run() {
try {
/* Wait one second for stability */
Thread.sleep(1000);
while (!killMe) {
synchronized(locking){
if(killMe){
continue;
}
/* If the reader is not connected, increment no. of iterations without response */
if(!readerConnected){
itersWithoutResponse++;
}
/* Else, reset the number of iterations without a response */
else{
itersWithoutResponse = 0;
}
/* Reset the connection state */
readerConnected = false;
if(itersWithoutResponse == 4) {
/* Communicate to the Cordova application that the reader is disconnected */
System.out.println("acr3x disconnected");
/* Kill this thread */
kill();
} else if(!mAudioManager.isWiredHeadsetOn()) {
System.out.println("acr3x not connected");
/* Kill this thread */
kill();
} else{
System.out.println("acr3x reading...");
/* Power on the PICC */
mReader.piccPowerOn(timeout, cardType);
/* Transmit the APDU */
mReader.piccTransmit(timeout, apdu);
}
}
/* Repeat every second */
Thread.sleep(1000);
}
/* Power off the PICC */
mReader.piccPowerOff();
/* Set the reader asleep */
mReader.sleep();
/* Stop the reader service */
mReader.stop();
synchronized(locking){
locking.notifyAll();
}
} catch (InterruptedException e) {
e.printStackTrace();
// TODO: add exception handling
}
}
}
listener interface:
public interface Acr3xNotifListener {
public void onUUIDAavailable(String uuid);
public void onFirmwareVersionAvailable(String firmwareVersion);
}
First you call the Reset command to activate the device. As the device will fall asleep (after 4 seconds by default)* the trick is to keeping it alive.
You can achieve that by relaunching a new PowerOn command every time the previous PowerOn timedOut. Something like that
void powerOn () {
if (!mReader.piccPowerOn(mPiccTimeout, mPiccCardType)) {
powerOn();
} else {
askNfcForItsId();
}
Don't forget to call powerOn after you read the nfc otherwise it will fall asleep after the 1st nfc card.
*the reset timeout can be set between 4 and 20 seconds
Related
I am recently working on a project. The idea is to make a Bluetooth speaker which has playback controls like pause,play, next song on the speaker itself. The speaker is to be connected to the mobile phone via Bluetooth. Ultimately i wanted to achieve the button control(on speaker) of songs I play on mobile which is connected to speaker via Bluetooth.
I was able to make the speaker connected via Bluetooth to the phone and could play songs but the biggest challenge is i couldn't pause or forward the playlist on phone from speaker side. What i understood is that the speaker is able to receive signals from phone to play songs but how do i send a command(like next song via physical button) from the speaker to the phone(via a micro controller like arduino). I hope I stated my situation well. I came across idea like having multiple bluetooth pairing, custom programming of the BT module that i'll be using, etc.
I am open to all kinds of way this can be done and I really appreciate if anyone could recommend me the proper BT modules and micro-controller to be used.
About the BT module, I suggest you to use an HC-05. For the MCU, Arduino cannot be used to play music... so you should optain for Rasberry, but I am not sure. Also I never used it...
If you need some code similar, I mede an app for a greenhouse which displays temperature, humidity and light inside it.
If you wanna read these class in order: gitHub.
But I have to post the code, too: maybe I could delete the repo a day
BLTSocket class:
public class BLTSocket extends Service {
private static final UUID uuid = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
private static boolean isBtConnected = false;
private static BluetoothAdapter adapter = null;
private static BluetoothSocket socket = null;
private static InputStream is = null;
private static OutputStream os = null;
public BLTSocket(){
}
/**
* Constructor called when a bluetooth device has been clicked in the layout
* If the phone's bluetooth socket has not already connected , it tries to initialize
* the new connection with the one clicked.
* Get the stream and set #isBtConnected as true
*
* #param address - MAC address of the bluetooth device
*/
public BLTSocket(String address){
if (!isBtConnected || !socket.isConnected()) {
try {
adapter = BluetoothAdapter.getDefaultAdapter();
BluetoothDevice device = adapter.getRemoteDevice(address);
socket = device.createInsecureRfcommSocketToServiceRecord(uuid);
socket.connect();
is = socket.getInputStream();
os = socket.getOutputStream();
isBtConnected = true;
} catch (IOException e) {
e.printStackTrace();
}
}
}
#Override
public void onCreate() {
HandlerThread handlerThread = new HandlerThread("SURVEYS_SERVICE", Process.THREAD_PRIORITY_BACKGROUND);
handlerThread.start();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
survey();
return START_STICKY;
}
/**
* This handler keeps updating the three surveys reading their current value
* from the bluetooth module's input stream.
* Set the the circular progress bar and the own text view below as the relative value
*/
Handler handler = new Handler();
Runnable runnable;
private void survey() {
runnable = new Runnable() {
#RequiresApi(api = Build.VERSION_CODES.O)
#Override
public void run() {
byte[] survey = new byte[12];
try {
/*
Once got the current values of the three surveys,
it sets the relative progress bar and the text view
*/
if(is.read(survey) > 0){
for(int i = 0; i < 3; i++){
MainActivity.getProgressBars()[i].setProgress(survey[i]);
MainActivity.getTextViews()[i].setText(String.valueOf(survey[i]) + (i == 0 ? "°C" : '%'));
}
}
} catch (IOException e) {
e.printStackTrace();
return;
}
handler.postDelayed(this, 2000);
}
};
runnable.run();
}
/**
* Called when the user click on the UPDATE SEED button
* on the popup menu of the ViewSeed layout
*
* Send to the HC-05 the new recommended values
*
* #param values
*/
public void updateSeed(int[] values){
try {
handler.removeCallbacks(runnable);
for(int value : values) {
os.write(value);
}
os.flush();
} catch (IOException e) {
e.printStackTrace();
}finally {
handler.postDelayed(runnable, 2000);
}
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
/**
* Close the socket and set #isBtConnected as false when the app is closed or crashes
*/
#Override
public void onDestroy() {
try {
this.socket.close();
this.isBtConnected = false;
}catch (IOException e) {
e.printStackTrace();
}
}
}
BLTActivity:
public class BluetoothActivity extends AppCompatActivity {
ActivityBluetoothBinding activityBluetoothBinding;
private BluetoothAdapter adapter;
private Set<BluetoothDevice> pairedDevices;
private ListView listBLTDevice;
private TextView bltTV;
private BluetoothDevice deviceSelected;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
activityBluetoothBinding = DataBindingUtil.setContentView(this, R.layout.activity_bluetooth);
activityBluetoothBinding.setSettings(MainActivity.loadSettings);
this.bltTV = findViewById(R.id.bltTV);
this.listBLTDevice = findViewById(R.id.listBLTDevices);
setBlt();
}
public static BLTSocket bltSocket;
private void setBlt(){
this.adapter = BluetoothAdapter.getDefaultAdapter();
//If the adapter is null, the user's phone hasn't a bluetooth radio
if(adapter != null){
if(!adapter.isEnabled()){
//If the bluetooth is disabled, it asks to the user to enable it
startActivityForResult(new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE), 1);
}
//The bonded devices are those ones which have already been compared
pairedDevices = adapter.getBondedDevices();
this.bltTV.setText(pairedDevices.size() + " Devices Found");
if(pairedDevices.size() > 0){
/*
* Create a new list of strings which every one contains the name of one compared
* bluetooth radio. The array list is given to the adapter.
*/
final ArrayList<String> arrayList = new ArrayList<>();
for (BluetoothDevice device : pairedDevices){
arrayList.add(device.getName());
}
final ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, getListViewLayout(), arrayList);
this.listBLTDevice.setAdapter(adapter);
/*
When an item (string that represents a bluetooth radio) has been clicked,
its MAC address is given to the BLTSocket constructor, which will set
the opportune variable, objects and connects our radio with the selected one
*/
this.listBLTDevice.setOnItemClickListener( (parent, v, pos, id) -> {
deviceSelected = (BluetoothDevice) pairedDevices.toArray()[pos];
Toast.makeText(getApplicationContext(), "Device Selected: " + deviceSelected.getName() + "\n" + deviceSelected.getAddress(), Toast.LENGTH_SHORT).show();
bltSocket = new BLTSocket(deviceSelected.getAddress());
startService(new Intent(this, BLTSocket.class));
} );
}
}else{
Toast.makeText(getApplicationContext(), "Seems like your device hasn't any bluetooth adapter...", Toast.LENGTH_SHORT).show();
}
}
/**
* Called when setting the ArrayAdapter to chose list layout with the right color of the text
* If the user has the dark mode enabled, this method returns the white list and vice versa
*
* #return the id of the opportune listview layout
*/
private int getListViewLayout() {
return !MainActivity.loadSettings.isDarkMode() ? R.layout.listview_blacktext_layout : R.layout.listview_whitetext_layout;
}
}
Hello i can send data from android to arduino but i cant send data from arduino to android via Bluetooth on procesing i dont get any Error but I cant see anything on display of android app.. i used for blueToothSerial.print(XXX); for arduino side .. and used text(readMessage , width,heigth); for processing side.
Please check it out . Where is my fault ? . What am I missing ?
Thanks in Advance
** on arduino side**
#include <SoftwareSerial.h>
#include <Stepper.h>
#define RxD 6 // This is the pin that the Bluetooth (BT_TX) will transmit to the Arduino (RxD)
#define TxD 7 // This is the pin that the Bluetooth (BT_RX) will receive from the Arduino (TxD)
#define DEBUG_ENABLED 1
#define RELAY 4
SoftwareSerial blueToothSerial(RxD, TxD);
int led = 9 ;
int in1Pin = 10;
int in2Pin = 12;
int in3Pin = 11;
int in4Pin = 13;
data = 100;
Stepper motor(512, in1Pin, in2Pin, in3Pin, in4Pin);
/*----------------------SETUP----------------------------*/
void setup() {
Serial.begin(9600);//low Serial communication via USB cable to computer (if required)
pinMode(RxD, INPUT); // Setup the Arduino to receive INPUT from the bluetooth shield on Digital Pin 6
pinMode(TxD, OUTPUT); // Setup the Arduino to send data (OUTPUT) to the bluetooth shield on Digital Pin 7
pinMode(13, OUTPUT); // Use onboard LED if required.
pinMode(9,OUTPUT);
motor.setSpeed(30);
pinMode(RELAY,OUTPUT);
setupBlueToothConnection(); //Used to initialise the Bluetooth shield
}
/*----------------------LOOP----------------------------*/
void loop() {
digitalWrite(13, LOW); //Turn off the onboard Arduino LED
char recvChar;
while (1) {
if (blueToothSerial.available()) {//check if there's any data sent from the remote bluetooth shield
recvChar = blueToothSerial.read();
Serial.print(recvChar); // Print the character received to the Serial Monitor (if required)
//If the character received = 'r' , then change the RGB led to display a RED colour
if (recvChar=='r') {
motor.step(300);
digitalWrite(led,HIGH);23
delay(500);
}
//If the character received = 'g' , then change the RGB led to display a GREEN colour
if (recvChar=='g') {
digitalWrite(led,LOW);
motor.step(-300);
}
//If the character received = 'b' , then change the RGB led to display a BLUE colour
if (recvChar=='b') {
digitalWrite(led,HIGH);
digitalWrite(RELAY,HIGH);
}
//If the character received = 'x' , then turn RGB led OFF
if (recvChar=='x') {
digitalWrite(led,LOW);
digitalWrite(RELAY,LOW);
}
}
//You can use the following code to deal with any information coming from the Computer (serial monitor)
if (Serial.available()) {
recvChar = Serial.read();
//This will send value obtained (recvChar) to the phone. The value will be displayed on the phone.
blueToothSerial.print(recvChar);
blueToothSerial.print("burak:");
blueToothSerial.print(data); // data which is defined begin of sketch
}
}
}
//The following code is necessary to setup the bluetooth shield ------copy and paste----------------
void setupBlueToothConnection()
{
blueToothSerial.begin(9600);// BluetoothBee BaudRate to default baud rate 38400
blueToothSerial.print("\r\n+STWMOD=0\r\n"); //set the bluetooth work in slave mode
blueToothSerial.print("\r\n+STNA=HC-05\r\n"); //set the bluetooth name as "SeeedBTSlave"
blueToothSerial.print("\r\n+STOAUT=1\r\n"); // Permit Paired device to connect me
blueToothSerial.print("\r\n+STAUTO=0\r\n"); // Auto-connection should be forbidden here
delay(2000); // This delay is required.
blueToothSerial.print("\r\n+INQ=1\r\n"); //make the slave bluetooth inquirable
Serial.println("The slave bluetooth is inquirable!");
delay(2000); // This delay is required.
blueToothSerial.flush();
}
And i have processing sketch .
*on processing side *
/* BluetoothApp1: Written by ScottC on 25 March 2013 using
Processing version 2.0b8
Tested on a Samsung Galaxy SII, with Android version 2.3.4
Android ADK - API 10 SDK platform
Apwidgets version: r44 */
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.widget.Toast;
import android.view.Gravity;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import java.util.UUID;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.bluetooth.BluetoothServerSocket;
import android.bluetooth.BluetoothSocket;
import apwidgets.*;
public BluetoothSocket scSocket;
//Used for the GUI**************************************
APWidgetContainer widgetContainer;
APButton redButton, greenButton, blueButton, offButton,yeniButton;
String buttonText="";
int buttonWidth=0;
int buttonHeight=0;
int n=4; //number of buttons
int gap=10; //gap between buttons
boolean foundDevice=false; //When true, the screen turns green.
boolean BTisConnected=false; //When true, the screen turns purple.
String serverName = "ArduinoBasicsServer";
// Message types used by the Handler
public static final int MESSAGE_WRITE = 1;
public static final int MESSAGE_READ = 2;
String readMessage="";
//Used to send bytes to the Arduino
SendReceiveBytes sendReceiveBT=null;
//Get the default Bluetooth adapter
BluetoothAdapter bluetooth = BluetoothAdapter.getDefaultAdapter();
/*The startActivityForResult() within setup() launches an
Activity which is used to request the user to turn Bluetooth on.
The following onActivityResult() method is called when this
Activity exits. */
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode==0) {
if (resultCode == RESULT_OK) {
ToastMaster("Bluetooth simdi acildi");
}
else {
ToastMaster("Programi kullanabilmek icin Bluetoot acmalisiniz!!!");
}
}
}
/* Create a BroadcastReceiver that will later be used to
receive the names of Bluetooth devices in range. */
BroadcastReceiver myDiscoverer = new myOwnBroadcastReceiver();
/* Create a BroadcastReceiver that will later be used to
identify if the Bluetooth device is connected */
BroadcastReceiver checkIsConnected = new myOwnBroadcastReceiver();
// The Handler that gets information back from the Socket
private final Handler mHandler = new Handler() {
#Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MESSAGE_WRITE:
//Do something when writing
break;
case MESSAGE_READ:
//Get the bytes from the msg.obj
byte[] readBuf = (byte[]) msg.obj;
// construct a string from the valid bytes in the buffer
readMessage = new String(readBuf, 0, msg.arg1);
break;
}
}
};
void setup() {
orientation(LANDSCAPE);
//Setup GUI********************************
buttonWidth=((width/n)-(n*gap));
buttonHeight=(height/2);
widgetContainer = new APWidgetContainer(this); //create new container for widgets
yeniButton = new APButton(700,600,(buttonWidth/2),(buttonHeight/2),"Yeni buton");
redButton =new APButton(0,0 ,400,400, "PERDE YUKARI"); //Create a RED button
// redButton =new APButton((buttonWidth*(n-4)+(gap*1)), gap, buttonWidth, buttonHeight, "RED"); //Create a RED button
greenButton = new APButton((buttonWidth*(n-3)+(gap*2)), gap, buttonWidth, buttonHeight, "GREEN"); //Create a GREEN button
blueButton = new APButton((buttonWidth*(n-2)+(gap*3)), gap, buttonWidth, buttonHeight, "BLUE"); //Create a BLUE button
offButton = new APButton((buttonWidth*(n-1)+(gap*4)), gap, buttonWidth, buttonHeight, "OFF"); //Create a OFF button
widgetContainer.addWidget(redButton); //place red button in container
widgetContainer.addWidget(greenButton); //place green button in container
widgetContainer.addWidget(blueButton);//place blue button in container
widgetContainer.addWidget(offButton);//place off button in container
widgetContainer.addWidget(yeniButton);
background(0); //Start with a black background
/*IF Bluetooth is NOT enabled, then ask user permission to enable it */
if (!bluetooth.isEnabled()) {
Intent requestBluetooth = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(requestBluetooth, 0);
}
/*If Bluetooth is now enabled, then register a broadcastReceiver to report any
discovered Bluetooth devices, and then start discovering */
if (bluetooth.isEnabled()) {
registerReceiver(myDiscoverer, new IntentFilter(BluetoothDevice.ACTION_FOUND));
registerReceiver(checkIsConnected, new IntentFilter(BluetoothDevice.ACTION_ACL_CONNECTED));
//Start bluetooth discovery if it is not doing so already
if (!bluetooth.isDiscovering()) {
bluetooth.startDiscovery();
}
}
}
void draw() {
//Display a green screen if a device has been found,
//Display a purple screen when a connection is made to the device
if (foundDevice) {
if (BTisConnected) {
background(170, 50, 255); // purple screen
}
else {
background(10, 255, 10); // green screen
}
}
//Change the text based on the button being pressed.
text(buttonText, 10, buttonHeight+(buttonHeight/2));
//Display anything received from Arduino
text(readMessage, 10, buttonHeight+(buttonHeight/2)+30);
}
/* This BroadcastReceiver will display discovered Bluetooth devices */
public class myOwnBroadcastReceiver extends BroadcastReceiver {
ConnectToBluetooth connectBT;
#Override
public void onReceive(Context context, Intent intent) {
String action=intent.getAction();
ToastMaster("Eylem:" + action);
//Notification that BluetoothDevice is FOUND
if (BluetoothDevice.ACTION_FOUND.equals(action)) {
//Display the name of the discovered device
String discoveredDeviceName = intent.getStringExtra(BluetoothDevice.EXTRA_NAME);
ToastMaster("Bulunan Cihaz: " + discoveredDeviceName);
//Display more information about the discovered device
BluetoothDevice discoveredDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
ToastMaster("getAddress() = " + discoveredDevice.getAddress());
ToastMaster("getName() = " + discoveredDevice.getName());
int bondyState=discoveredDevice.getBondState();
ToastMaster("getBondState() = " + bondyState);
String mybondState;
switch(bondyState) {
case 10:
mybondState="BOND_NONE";
break;
case 11:
mybondState="BOND_BONDING";
break;
case 12:
mybondState="BOND_BONDED";
break;
default:
mybondState="INVALID BOND STATE";
break;
}
ToastMaster("getBondState() = " + mybondState);
//Change foundDevice to true which will make the screen turn green
foundDevice=true;
//Connect to the discovered bluetooth device (SeeedBTSlave)
if (discoveredDeviceName.equals("HC-05")) {
ToastMaster("BAGLANIYOR!!");
unregisterReceiver(myDiscoverer);
connectBT = new ConnectToBluetooth(discoveredDevice);
//Connect to the the device in a new thread
new Thread(connectBT).start();
}
}
//Notification if bluetooth device is connected
if (BluetoothDevice.ACTION_ACL_CONNECTED.equals(action)) {
ToastMaster("CIHAZINIZ BAGLANDI");
int counter=0;
while (scSocket==null) {
//do nothing
}
ToastMaster("scSocket" + scSocket);
BTisConnected=true; //turn screen purple
if (scSocket!=null) {
sendReceiveBT = new SendReceiveBytes(scSocket);
new Thread(sendReceiveBT).start();
String red = "r";
byte[] myByte = stringToBytesUTFCustom(red);
sendReceiveBT.write(myByte);
}
}
}
}
public static byte[] stringToBytesUTFCustom(String str) {
char[] buffer = str.toCharArray();
byte[] b = new byte[buffer.length << 1];
for (int i = 0; i < buffer.length; i++) {
int bpos = i << 1;
b[bpos] = (byte) ((buffer[i]&0xFF00)>>8);
b[bpos + 1] = (byte) (buffer[i]&0x00FF);
}
return b;
}
public class ConnectToBluetooth implements Runnable {
private BluetoothDevice btShield;
private BluetoothSocket mySocket = null;
private UUID uuid = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
public ConnectToBluetooth(BluetoothDevice bluetoothShield) {
btShield = bluetoothShield;
try {
mySocket = btShield.createRfcommSocketToServiceRecord(uuid);
}
catch(IOException createSocketException) {
//Problem with creating a socket
Log.e("ConnectToBluetooth", "Error with Socket");
}
}
#Override
public void run() {
/* Cancel discovery on Bluetooth Adapter to prevent slow connection */
bluetooth.cancelDiscovery();
try {
/*Connect to the bluetoothShield through the Socket. This will block
until it succeeds or throws an IOException */
mySocket.connect();
scSocket=mySocket;
}
catch (IOException connectException) {
Log.e("ConnectToBluetooth", "Error with Socket Connection");
try {
mySocket.close(); //try to close the socket
}
catch(IOException closeException) {
}
return;
}
}
// Will allow you to get the socket from this class
public BluetoothSocket getSocket() {
return mySocket;
}
/* Will cancel an in-progress connection, and close the socket */
public void cancel() {
try {
mySocket.close();
}
catch (IOException e) {
}
}
}
private class SendReceiveBytes implements Runnable {
private BluetoothSocket btSocket;
private InputStream btInputStream = null;
;
private OutputStream btOutputStream = null;
String TAG = "SendReceiveBytes";
public SendReceiveBytes(BluetoothSocket socket) {
btSocket = socket;
try {
btInputStream = btSocket.getInputStream();
btOutputStream = btSocket.getOutputStream();
}
catch (IOException streamError) {
Log.e(TAG, "Error when getting input or output Stream");
}
}
public void run() {
byte[] buffer = new byte[1024]; // buffer store for the stream
int bytes; // bytes returned from read()
// Keep listening to the InputStream until an exception occurs
while (true) {
try {
// Read from the InputStream
bytes = btInputStream.read(buffer);
// Send the obtained bytes to the UI activity
mHandler.obtainMessage(MESSAGE_READ, bytes, -1, buffer)
.sendToTarget();
}
catch (IOException e) {
Log.e(TAG, "Error reading from btInputStream");
break;
}
}
}
/* Call this from the main activity to send data to the remote device */
public void write(byte[] bytes) {
try {
btOutputStream.write(bytes);
}
catch (IOException e) {
Log.e(TAG, "Error when writing to btOutputStream");
}
}
/* Call this from the main activity to shutdown the connection */
public void cancel() {
try {
btSocket.close();
}
catch (IOException e) {
Log.e(TAG, "Error when closing the btSocket");
}
}
}
/* My ToastMaster function to display a messageBox on the screen */
void ToastMaster(String textToDisplay) {
Toast myMessage = Toast.makeText(getApplicationContext(),
textToDisplay,
Toast.LENGTH_SHORT);
myMessage.setGravity(Gravity.CENTER, 0, 0);
myMessage.show();
}
//onClickWidget is called when a widget is clicked/touched
void onClickWidget(APWidget widget) {
String sendLetter = "";
//Disable the previous Background colour changers
foundDevice=false;
BTisConnected=false;
if (widget == redButton) { //if the red button was clicked
buttonText="RED";
background(255, 0, 0);
sendLetter = "r";
}
else if (widget == greenButton) { //if the green button was clicked
buttonText="GREEN";
background(0, 255, 0);
sendLetter = "g";
}
else if (widget == blueButton) { //if the blue button was clicked
buttonText="BLUE";
background(0, 0, 255);
sendLetter = "b";
}
else if (widget == offButton) { //if the off button was clicked
buttonText="OFF";
background(0);
sendLetter = "x";
}
else if (widget == yeniButton) { //if the off button was clicked
buttonText="yeni buton";
background(100,100,100);
sendLetter = "y";
}
byte[] myByte = stringToBytesUTFCustom(sendLetter);
sendReceiveBT.write(myByte);
}
you forgot to declare the mode (int ) in data on line 14
SoftwareSerial blueToothSerial(RxD, TxD);
int led = 9 ;
int in1Pin = 10;
int in2Pin = 12;
int in3Pin = 11;
int in4Pin = 13;
int data = 100;
I see a fault on the Arduino code - don't think that 23 should be there.
if (recvChar=='r') {
motor.step(300);
digitalWrite(led,HIGH);23
Also - this code requires that you send data from the serial monitor before any Arduino data is sent through bluetooth . Try to echo back the character received by the arduino on this line
Serial.print(recvChar);
Change it to
blueToothSerial.print(recvChar);
Burak have you solved the problem? I am working with Arduino-Android communication for my project. Try to use blueToothSerial.write("burak:");
Also to test your program run some test program. Make some changes with Rx,Tx and you can test it via Arduino Serial Monitor.
/*
Pinout:
8 --> BT module Tx
9 --> BT module Rx
*/
#include <SoftwareSerial.h>
SoftwareSerial mySerial(8, 9); // RX, TX
void setup()
{
// Open serial communications and wait for port to open:
Serial.begin(9600);
Serial.println("I am ready to send some stuff!");
// set the data rate for the SoftwareSerial port
mySerial.begin(9600);
}
void loop() // run over and over
{
if (mySerial.available())
Serial.write(mySerial.read());
while (Serial.available())
mySerial.write(Serial.read());
}
Also you could try to use ready app from GooglePlay, like "Bluetooth Terminal". If it works with this then look in your code. Please check this for now and later we will be able to continue.
I'am able to connect to device and ask device specifications:
specs:
Model: /dev/bus/usb/001/002
ID: 1002
Class: 0
Protocol: 0
Vendor ID 1155
Product ID: 22352
Interface count: 1
---------------------------------------
***** *****
Interface index: 0
Interface ID: 0
Inteface class: 3 USB_CLASS_HID
Interface protocol: 0
Endpoint count: 2
++++ ++++ ++++
Endpoint index: 0
Attributes: 3
Direction: 128 (device to host)
Number: 1
Interval: 1
Packet size: 64
Type: 3 USB_ENDPOINT_XFER_INT (interrupt endpoint)
++++ ++++ ++++
Endpoint index: 1
Attributes: 3
Direction: 0 (host to device)
Number: 1
Interval: 1
Packet size: 64
Type: 3 USB_ENDPOINT_XFER_INT (interrupt endpoint)
No more devices connected.
I'am also able to send data from host to device, using this method:
int bufferDataLength = mEndpointOut.getMaxPacketSize();
ByteBuffer buffer = ByteBuffer.allocate(bufferDataLength + 1);
UsbRequest request = new UsbRequest();
buffer.put(DataToSend);
request.initialize(mDeviceConnection, mEndpointOut);
request.queue(buffer, bufferDataLength);
try
{
if (request.equals(mDeviceConnection.requestWait()))
{
// Read an analyze the incoming data here
byte[] byteBuffer = new byte[buffer.remaining()];
buffer.get(byteBuffer, 0, buffer.remaining());
return true;
}
}
catch (Exception ex)
{
Log.e(TAG, "Error sending data: " + ex.toString());
}
return false;
But i'am not able to read from device, i've tested several methods without success..
for example this doesn't work:
int bufferDataLength = mEndpointIn.getMaxPacketSize();
ByteBuffer buffer = ByteBuffer.allocate(bufferDataLength + 1);
//Make a request
UsbRequest request = new UsbRequest();
request.initialize(mDeviceConnection, mEndpointIn);
ByteBuffer buffer = ByteBuffer.allocate(bufferDataLength);
//For IN endpoints, data is read into the buffer
request.queue(buffer, bufferDataLength);
//This blocks until the request is successful
//Make sure the request that finished is the one you need
if (mDeviceConnection.requestWait() == request) {
// Read an analyze the incoming data here
byte[] byteBuffer = new byte[buffer.remaining()];
buffer.get(byteBuffer, 0, buffer.remaining());
}
Suggestions?
I resolved my problems using this class, i'm answering to my my question hoping it can help someone else:
/**
* This class is used for talking to hid of the dongle, connecting, disconnencting and enumerating the devices.
* #author gai
*/
#TargetApi(Build.VERSION_CODES.HONEYCOMB_MR1)
public class HidBridge {
private Context _context;
private int _productId;
private int _vendorId;
//private HidBridgeLogSupporter _logSupporter = new HidBridgeLogSupporter();
private static final String ACTION_USB_PERMISSION =
"com.example.company.app.testhid.USB_PERMISSION";
// Locker object that is responsible for locking read/write thread.
private final Object _locker = new Object();
private Thread _readingThread = null;
private boolean _runReadingThread = false;
private String _deviceName;
private UsbManager _usbManager;
private UsbDevice _usbDevice;
// The queue that contains the read data.
private Queue<byte[]> _receivedQueue;
/**
* Creates a hid bridge to the dongle. Should be created once.
* #param context is the UI context of Android.
* #param productId of the device.
* #param vendorId of the device.
*/
public HidBridge(Context context, int productId, int vendorId) {
_context = context;
_productId = productId;
_vendorId = vendorId;
_receivedQueue = new LinkedList<byte[]>();
}
/**
* Searches for the device and opens it if successful
* #return true, if connection was successful
*/
public boolean OpenDevice() {
_usbManager = (UsbManager) _context.getSystemService(Context.USB_SERVICE);
HashMap<String, UsbDevice> deviceList = _usbManager.getDeviceList();
Iterator<UsbDevice> deviceIterator = deviceList.values().iterator();
_usbDevice = null;
// Iterate all the available devices and find ours.
while(deviceIterator.hasNext()){
UsbDevice device = deviceIterator.next();
if (device.getProductId() == _productId && device.getVendorId() == _vendorId) {
_usbDevice = device;
_deviceName = _usbDevice.getDeviceName();
}
}
if (_usbDevice == null) {
Log("Cannot find the device. Did you forgot to plug it?");
Log(String.format("\t I search for VendorId: %s and ProductId: %s", _vendorId, _productId));
return false;
}
// Create and intent and request a permission.
PendingIntent mPermissionIntent = PendingIntent.getBroadcast(_context, 0, new Intent(ACTION_USB_PERMISSION), 0);
IntentFilter filter = new IntentFilter(ACTION_USB_PERMISSION);
_context.registerReceiver(mUsbReceiver, filter);
_usbManager.requestPermission(_usbDevice, mPermissionIntent);
Log("Found the device");
return true;
}
/**
* Closes the reading thread of the device.
*/
public void CloseTheDevice() {
try
{
StopReadingThread();
_context.unregisterReceiver(mUsbReceiver);
}
catch(RuntimeException e)
{
Log("Error happend while closing device. Usb reciver not connected.");
}
}
/**
* Starts the thread that continuously reads the data from the device.
* Should be called in order to be able to talk with the device.
*/
public void StartReadingThread() {
if (_readingThread == null) {
_runReadingThread = true;
_readingThread = new Thread(readerReceiver);
_readingThread.start();
} else {
Log("Reading thread already started");
}
}
/**
* Stops the thread that continuously reads the data from the device.
* If it is stopped - talking to the device would be impossible.
*/
public void StopReadingThread() {
if (_readingThread != null) {
// Just kill the thread. It is better to do that fast if we need that asap.
_runReadingThread = false;
_readingThread = null;
} else {
Log("No reading thread to stop");
}
}
/**
* Write data to the usb hid. Data is written as-is, so calling method is responsible for adding header data.
* #param bytes is the data to be written.
* #return true if succeed.
*/
public boolean WriteData(byte[] bytes) {
try
{
// Lock that is common for read/write methods.
synchronized (_locker) {
UsbInterface writeIntf = _usbDevice.getInterface(0);
UsbEndpoint writeEp = writeIntf.getEndpoint(1);
UsbDeviceConnection writeConnection = _usbManager.openDevice(_usbDevice);
// Lock the usb interface.
writeConnection.claimInterface(writeIntf, true);
// Write the data as a bulk transfer with defined data length.
int r = writeConnection.bulkTransfer(writeEp, bytes, bytes.length, 0);
if (r != -1) {
Log(String.format("Written %s bytes to the dongle. Data written: %s", r, composeString(bytes)));
} else {
Log("Error happened while writing data. No ACK");
}
// Release the usb interface.
writeConnection.releaseInterface(writeIntf);
writeConnection.close();
}
} catch(NullPointerException e)
{
Log("Error happend while writing. Could not connect to the device or interface is busy?");
Log.e("HidBridge", Log.getStackTraceString(e));
return false;
}
return true;
}
/**
* #return true if there are any data in the queue to be read.
*/
public boolean IsThereAnyReceivedData() {
synchronized(_locker) {
return !_receivedQueue.isEmpty();
}
}
/**
* Queue the data from the read queue.
* #return queued data.
*/
public byte[] GetReceivedDataFromQueue() {
synchronized(_locker) {
return _receivedQueue.poll();
}
}
// The thread that continuously receives data from the dongle and put it to the queue.
private Runnable readerReceiver = new Runnable() {
public void run() {
if (_usbDevice == null) {
Log("No device to read from");
return;
}
UsbEndpoint readEp;
UsbDeviceConnection readConnection = null;
UsbInterface readIntf = null;
boolean readerStartedMsgWasShown = false;
// We will continuously ask for the data from the device and store it in the queue.
while (_runReadingThread) {
// Lock that is common for read/write methods.
synchronized (_locker) {
try
{
if (_usbDevice == null) {
OpenDevice();
Log("No device. Recheking in 10 sec...");
Sleep(10000);
continue;
}
readIntf = _usbDevice.getInterface(0);
readEp = readIntf.getEndpoint(0);
if (!_usbManager.getDeviceList().containsKey(_deviceName)) {
Log("Failed to connect to the device. Retrying to acquire it.");
OpenDevice();
if (!_usbManager.getDeviceList().containsKey(_deviceName)) {
Log("No device. Recheking in 10 sec...");
Sleep(10000);
continue;
}
}
try
{
readConnection = _usbManager.openDevice(_usbDevice);
if (readConnection == null) {
Log("Cannot start reader because the user didn't gave me permissions or the device is not present. Retrying in 2 sec...");
Sleep(2000);
continue;
}
// Claim and lock the interface in the android system.
readConnection.claimInterface(readIntf, true);
}
catch (SecurityException e) {
Log("Cannot start reader because the user didn't gave me permissions. Retrying in 2 sec...");
Sleep(2000);
continue;
}
// Show the reader started message once.
if (!readerStartedMsgWasShown) {
Log("!!! Reader was started !!!");
readerStartedMsgWasShown = true;
}
// Read the data as a bulk transfer with the size = MaxPacketSize
int packetSize = readEp.getMaxPacketSize();
byte[] bytes = new byte[packetSize];
int r = readConnection.bulkTransfer(readEp, bytes, packetSize, 50);
if (r >= 0) {
byte[] trancatedBytes = new byte[r - 1]; // Truncate bytes in the honor of r
int i=0;
for (byte b : bytes) {
if (i > 0)
trancatedBytes[i - 1] = b;
i++;
}
_receivedQueue.add(trancatedBytes); // Store received data
Log(String.format("Message received of lengths %s and content: %s", r, composeString(bytes)));
}
// Release the interface lock.
readConnection.releaseInterface(readIntf);
readConnection.close();
}
catch (NullPointerException e) {
Log("Error happened while reading. No device or the connection is busy");
Log.e("HidBridge", Log.getStackTraceString(e));
}
catch (ThreadDeath e) {
if (readConnection != null) {
readConnection.releaseInterface(readIntf);
readConnection.close();
}
throw e;
}
}
// Sleep for 10 ms to pause, so other thread can write data or anything.
// As both read and write data methods lock each other - they cannot be run in parallel.
// Looks like Android is not so smart in planning the threads, so we need to give it a small time
// to switch the thread context.
Sleep(10);
}
}
};
private void Sleep(int milliseconds) {
try {
Thread.sleep(milliseconds);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
private final BroadcastReceiver mUsbReceiver = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (ACTION_USB_PERMISSION.equals(action)) {
synchronized (this) {
UsbDevice device = (UsbDevice)intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) {
if(device != null){
//call method to set up device communication
}
}
else {
Log.d("TAG", "permission denied for the device " + device);
}
}
}
}
};
/**
* Logs the message from HidBridge.
* #param message to log.
*/
private void Log(String message) {
//LogHandler logHandler = LogHandler.getInstance();
//logHandler.WriteMessage("HidBridge: " + message, LogHandler.GetNormalColor());
Log.i("HidBridge: ", message);
}
/**
* Composes a string from byte array.
*/
private String composeString(byte[] bytes) {
StringBuilder builder = new StringBuilder();
for (byte b: bytes) {
builder.append(b);
builder.append(" ");
}
return builder.toString();
}
}
I am having some trouble with controlling a stepper motor using a IOIO board. I started with the HelloIOIOPower example and added my code. The program will run and turn on/off the LED when the toggle button is pressed but if a button is pressed that changes the value of motor_command in the UI thread the motor control signals do not get set and the program appears to hang. It does not crash but the LED control is lost.
I tried using synchronized on the switch statement in the run method to have the entire switch statement evaluated before allowing a change to motor_control in the UI thread.
I believe the correct way to implement this is to bind to the IOIO thread but I have been unsuccessful in getting that to work correctly.
I would like to be able to change the value of "motor_control" to create a control command to the IOIO thread to move the stepper motor. Once the command is executed the IOIO thread sets "motor_control" to zero which is a do noting or hold state.
Running the IOIO in a service would be preferred but is not required.
I plan to have this app running 24/7 with intermittent commands sent to the stepper motor. what is the correct method for controlling a stepper motor via a IOIO when only intermittent commands will be sent to the IOIO?
this is my first attempt at Java/ Android/ IOIO please feel free to point out all errors, I would love to learn where I can improve....
Thanks...
`
package com.medo.testmotor4;
import ioio.lib.api.DigitalOutput;
import ioio.lib.api.IOIO;
import ioio.lib.api.IOIOFactory;
import ioio.lib.api.exception.ConnectionLostException;
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
import android.widget.ToggleButton;
public class TestMotor4 extends Activity {
/** The text displayed at the top of the page. */
private TextView title_;
/** The toggle button used to control the LED. */
private ToggleButton button_;
Button full;
Button half;
Button step16th;
Button cup;
Button dish;
TextView cup_count;
TextView random_num;
int traycount = 0; // try cup position
int motor_command = 0; //motor command index value for switch statement
/** The thread that interacts with the IOIO. */
private IOIOThread ioio_thread_;
/**
* Called when the activity is first created. Here we normally initialize
* our GUI.
*/
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_test_motor4);
title_ = (TextView) findViewById(R.id.title);
button_ = (ToggleButton) findViewById(R.id.button);
// Assign value to Text Views:
cup_count = (TextView)findViewById(R.id.tv_cup_count);
cup_count.setText(Integer.toString(traycount));
random_num = (TextView)findViewById(R.id.tv_random_number);
random_num.setText("no number");
// Set up buttons
dish = (Button) findViewById(R.id.btn_dish);
dish.setOnClickListener(new View.OnClickListener(){
#Override
public void onClick(View arg0) {
// call method that moves motor one full step
motor_command = 4;
Toast.makeText(TestMotor4.this, "Motor_Command Set to: " + motor_command,Toast.LENGTH_SHORT).show();
}
});
full = (Button) findViewById(R.id.btn_fullstep);
full.setOnClickListener(new View.OnClickListener(){
#Override
public void onClick(View arg0) {
// call method that moves motor one full step
motor_command = 1;
Toast.makeText(TestMotor4.this, "Motor_Command Set to: " + motor_command,Toast.LENGTH_SHORT).show();
}
});
cup = (Button) findViewById(R.id.btn_cup);
cup.setOnClickListener(new View.OnClickListener(){
#Override
public void onClick(View arg0) {
// call method that moves motor one full step
traycount ++;
if (traycount % 3 == 0 )
motor_command = 3; // every 3rd tray cup move 54 1/8 steps
// all others move 53 1/8 steps
else motor_command = 2;
Toast.makeText(TestMotor4.this, "Motor_Command Set to: " + motor_command,Toast.LENGTH_SHORT).show();
cup_count.setText(Integer.toString(traycount));
}
});
half = (Button) findViewById(R.id.btnhalfstep);
half.setOnClickListener(new View.OnClickListener(){
#Override
public void onClick(View arg0) {
// call method that moves motor one half step
motor_command = 3;
Toast.makeText(TestMotor4.this, "Motor_Command Set to: " + motor_command,Toast.LENGTH_SHORT).show();
}
});
} //onCreate
/**
* Called when the application is resumed (also when first started). Here is
* where we'll create our IOIO thread.
*/
#Override
protected void onResume() {
super.onResume();
ioio_thread_ = new IOIOThread();
ioio_thread_.start();
}
/**
* Called when the application is paused. We want to disconnect with the
* IOIO at this point, as the user is no longer interacting with our
* application.
*/
#Override
protected void onPause() {
super.onPause();
ioio_thread_.abort();
try {
ioio_thread_.join();
} catch (InterruptedException e) {
}
}
/**
* This is the thread that does the IOIO interaction.
*
* It first creates a IOIO instance and wait for a connection to be
* established. Then it starts doing the main work of opening the LED pin
* and constantly updating it to match the toggle button's state.
*
* Whenever a connection drops, it tries to reconnect, unless this is a
* result of abort().
*/
class IOIOThread extends Thread {
private IOIO ioio_;
private boolean abort_ = false;
DigitalOutput led;
private DigitalOutput dir;
private DigitalOutput stp;
private DigitalOutput slp_,rst_, ms3, ms2, ms1,en_;
private DigitalOutput led_;
private DigitalOutput dish;
private static final int STEP_WAIT = 5;
/** Thread body. */
#Override
public void run() {
super.run();
while (true) {
synchronized (this) {
if (abort_) {
break;
}
ioio_ = IOIOFactory.create();
}
try {
setText(R.string. wait_ioio);
ioio_.waitForConnect();
setText(R.string.ioio_connected);
//IOIO pin setup:
//DigitalOutput led = ioio_.openDigitalOutput(0, true);
rst_ = ioio_.openDigitalOutput(13, true); // /RESET
ms3 = ioio_.openDigitalOutput(14, true); // ms3 set step size L L L full step
ms2 = ioio_.openDigitalOutput(15, true); // ms2
ms1 = ioio_.openDigitalOutput(16, true); // ms1 H H H 1/16 step
en_ = ioio_.openDigitalOutput(17, false); // /enable
dir = ioio_.openDigitalOutput(18, false); // DIRECTION - set initial direction of motor rotation
stp = ioio_.openDigitalOutput(19, false); // STEP
slp_ = ioio_.openDigitalOutput(20, true); // /SLEEP -
led = ioio_.openDigitalOutput(IOIO.LED_PIN);
dish = ioio_.openDigitalOutput(9, false); // Dish - linear actuator activate signal
Log.d ("IOIOLooper setup", "Complete");
int test = 0;
Toast.makeText(TestMotor4.this, "Starting while loop",Toast.LENGTH_SHORT).show();
while (true) {
led.write(!button_.isChecked());
switch(motor_command){
case 0: // hold - do nothing for 5 sec.
this.timeout(100);
break;
case 1: //full step on motor
full();
Log.d("STEPPER-FULL","Complete");
motor_command = 0;
break;
case 2: // move motor 1 cup - (53) 1/8 steps
cup(53);
motor_command = 0;
Log.d("STEPPER-CUP - 53","Complete" );
break;
case 3: // move motor 1 cup (54) 1/8 steps
cup(54);
motor_command = 0;
Log.d("STEPPER-CUP - 54","Complete" );
break;
case 4: // dump scoop dish
dish.write(true);
//Toast.makeText(TestMotor4.this, "Dish set HIGH: ",Toast.LENGTH_SHORT).show();
this.timeout(5000);
dish.write(false);
//Toast.makeText(TestMotor4.this, "Dish set LOW " + motor_command,Toast.LENGTH_SHORT).show();
motor_command = 0;
break;
} // switch
sleep(10);
}
} catch (ConnectionLostException e) {
setText(R.string.connectionLost);
} catch (Exception e) {
Log.e("TestMotor4", "Unexpected exception caught", e);
ioio_.disconnect();
break;
} finally {
if (ioio_ != null) {
try {
ioio_.waitForDisconnect();
} catch (InterruptedException e) {
}
}
synchronized (this) {
ioio_ = null;
}
}
} // while(true)
}// Run
/**
* Abort the connection.
*
* This is a little tricky synchronization-wise: we need to be handle
* the case of abortion happening before the IOIO instance is created or
* during its creation.
*/
synchronized public void abort() {
abort_ = true;
if (ioio_ != null) {
ioio_.disconnect();
}
}// abort
/**
* Set the text line on top of the screen.
*
* #param id
* The string ID of the message to present.
*/
private void setText(final int id) {
runOnUiThread(new Runnable() {
#Override
public void run() {
title_.setText(getString(id));
}
});
} //setText
public void full ()throws ConnectionLostException{
// move motor 1 full step (1.8 degrees)
// requires stp to be LOW before entering method - leaves stp LOW on exit of method
try{
en_.write(false); // enable MC outputs
// configure for full step ( L L L)
ms1.write(false);
ms2.write(false);
ms3.write(false);
Log.d("Set FULL", "L L L");
//send step signal with LOW To HIGH transition
stp.write(true);
timeout(STEP_WAIT);
stp.write(false);
this.timeout(STEP_WAIT);
}catch(ConnectionLostException e) {
//enableUi(false);
Toast.makeText(TestMotor4.this, "IOIO Connection Lost ",Toast.LENGTH_LONG).show();
throw e;
}
} // full
public void cup(int num) throws ConnectionLostException{
try{
// set step size to 1/8 step
ms1.write(true);
ms2.write(true);
ms3.write(false);
Log.d("Set 1/8 step size ", "H H L");
// set up wait for signals to stabilize
this.timeout(STEP_WAIT);
//move motor 53 steps
for (int i = 0; i<num; i++){
stp.write(true);
this.timeout(STEP_WAIT);
stp.write(false);
this.timeout(STEP_WAIT);
}
}catch (ConnectionLostException e){
Toast.makeText(TestMotor4.this, "IOIO Connection Lost ",Toast.LENGTH_LONG).show();
throw e;
}
} //cup
private void timeout(int ms) {
try {
sleep(ms);
} catch (InterruptedException e) {
// Do nothing...
}
}
} //IOIOThread
}`
I need to send file to a computer instead of another android application. I have looked at the bluetooth api, but it only allow connection as client-server. In my case I dont know what UUId would be on the computer. Do I need to look at obex. I haven't used it before. So any help would be benficial.
Try this.
I can send a file using this code.
ContentValues values = new ContentValues();
values.put(BluetoothShare.URI, "file:///sdcard/refresh.txt");
values.put(BluetoothShare.DESTINATION, deviceAddress);
values.put(BluetoothShare.DIRECTION, BluetoothShare.DIRECTION_OUTBOUND);
Long ts = System.currentTimeMillis();
values.put(BluetoothShare.TIMESTAMP, ts);
getContentResolver().insert(BluetoothShare.CONTENT_URI, values);
Code of BluetoothShare.java
import android.provider.BaseColumns;
import android.net.Uri;
/**
* Exposes constants used to interact with the Bluetooth Share manager's content
* provider.
*/
public final class BluetoothShare implements BaseColumns {
private BluetoothShare() {
}
/**
* The permission to access the Bluetooth Share Manager
*/
public static final String PERMISSION_ACCESS = "android.permission.ACCESS_BLUETOOTH_SHARE";
/**
* The content:// URI for the data table in the provider
*/
public static final Uri CONTENT_URI = Uri.parse("content://com.android.bluetooth.opp/btopp");
/**
* Broadcast Action: this is sent by the Bluetooth Share component to
* transfer complete. The request detail could be retrieved by app * as _ID
* is specified in the intent's data.
*/
public static final String TRANSFER_COMPLETED_ACTION = "android.btopp.intent.action.TRANSFER_COMPLETE";
/**
* This is sent by the Bluetooth Share component to indicate there is an
* incoming file need user to confirm.
*/
public static final String INCOMING_FILE_CONFIRMATION_REQUEST_ACTION = "android.btopp.intent.action.INCOMING_FILE_NOTIFICATION";
/**
* This is sent by the Bluetooth Share component to indicate there is an
* incoming file request timeout and need update UI.
*/
public static final String USER_CONFIRMATION_TIMEOUT_ACTION = "android.btopp.intent.action.USER_CONFIRMATION_TIMEOUT";
/**
* The name of the column containing the URI of the file being
* sent/received.
*/
public static final String URI = "uri";
/**
* The name of the column containing the filename that the incoming file
* request recommends. When possible, the Bluetooth Share manager will
* attempt to use this filename, or a variation, as the actual name for the
* file.
*/
public static final String FILENAME_HINT = "hint";
/**
* The name of the column containing the filename where the shared file was
* actually stored.
*/
public static final String _DATA = "_data";
/**
* The name of the column containing the MIME type of the shared file.
*/
public static final String MIMETYPE = "mimetype";
/**
* The name of the column containing the direction (Inbound/Outbound) of the
* transfer. See the DIRECTION_* constants for a list of legal values.
*/
public static final String DIRECTION = "direction";
/**
* The name of the column containing Bluetooth Device Address that the
* transfer is associated with.
*/
public static final String DESTINATION = "destination";
/**
* The name of the column containing the flags that controls whether the
* transfer is displayed by the UI. See the VISIBILITY_* constants for a
* list of legal values.
*/
public static final String VISIBILITY = "visibility";
/**
* The name of the column containing the current user confirmation state of
* the transfer. Applications can write to this to confirm the transfer. the
* USER_CONFIRMATION_* constants for a list of legal values.
*/
public static final String USER_CONFIRMATION = "confirm";
/**
* The name of the column containing the current status of the transfer.
* Applications can read this to follow the progress of each download. See
* the STATUS_* constants for a list of legal values.
*/
public static final String STATUS = "status";
/**
* The name of the column containing the total size of the file being
* transferred.
*/
public static final String TOTAL_BYTES = "total_bytes";
/**
* The name of the column containing the size of the part of the file that
* has been transferred so far.
*/
public static final String CURRENT_BYTES = "current_bytes";
/**
* The name of the column containing the timestamp when the transfer is
* initialized.
*/
public static final String TIMESTAMP = "timestamp";
/**
* This transfer is outbound, e.g. share file to other device.
*/
public static final int DIRECTION_OUTBOUND = 0;
/**
* This transfer is inbound, e.g. receive file from other device.
*/
public static final int DIRECTION_INBOUND = 1;
/**
* This transfer is waiting for user confirmation.
*/
public static final int USER_CONFIRMATION_PENDING = 0;
/**
* This transfer is confirmed by user.
*/
public static final int USER_CONFIRMATION_CONFIRMED = 1;
/**
* This transfer is auto-confirmed per previous user confirmation.
*/
public static final int USER_CONFIRMATION_AUTO_CONFIRMED = 2;
/**
* This transfer is denied by user.
*/
public static final int USER_CONFIRMATION_DENIED = 3;
/**
* This transfer is timeout before user action.
*/
public static final int USER_CONFIRMATION_TIMEOUT = 4;
/**
* This transfer is visible and shows in the notifications while in progress
* and after completion.
*/
public static final int VISIBILITY_VISIBLE = 0;
/**
* This transfer doesn't show in the notifications.
*/
public static final int VISIBILITY_HIDDEN = 1;
/**
* Returns whether the status is informational (i.e. 1xx).
*/
public static boolean isStatusInformational(int status) {
return (status >= 100 && status < 200);
}
/**
* Returns whether the transfer is suspended. (i.e. whether the transfer
* won't complete without some action from outside the transfer manager).
*/
public static boolean isStatusSuspended(int status) {
return (status == STATUS_PENDING);
}
/**
* Returns whether the status is a success (i.e. 2xx).
*/
public static boolean isStatusSuccess(int status) {
return (status >= 200 && status < 300);
}
/**
* Returns whether the status is an error (i.e. 4xx or 5xx).
*/
public static boolean isStatusError(int status) {
return (status >= 400 && status < 600);
}
/**
* Returns whether the status is a client error (i.e. 4xx).
*/
public static boolean isStatusClientError(int status) {
return (status >= 400 && status < 500);
}
/**
* Returns whether the status is a server error (i.e. 5xx).
*/
public static boolean isStatusServerError(int status) {
return (status >= 500 && status < 600);
}
/**
* Returns whether the transfer has completed (either with success or
* error).
*/
public static boolean isStatusCompleted(int status) {
return (status >= 200 && status < 300) || (status >= 400 && status < 600);
}
/**
* This transfer hasn't stated yet
*/
public static final int STATUS_PENDING = 190;
/**
* This transfer has started
*/
public static final int STATUS_RUNNING = 192;
/**
* This transfer has successfully completed. Warning: there might be other
* status values that indicate success in the future. Use isSucccess() to
* capture the entire category.
*/
public static final int STATUS_SUCCESS = 200;
/**
* This request couldn't be parsed. This is also used when processing
* requests with unknown/unsupported URI schemes.
*/
public static final int STATUS_BAD_REQUEST = 400;
/**
* This transfer is forbidden by target device.
*/
public static final int STATUS_FORBIDDEN = 403;
/**
* This transfer can't be performed because the content cannot be handled.
*/
public static final int STATUS_NOT_ACCEPTABLE = 406;
/**
* This transfer cannot be performed because the length cannot be determined
* accurately. This is the code for the HTTP error "Length Required", which
* is typically used when making requests that require a content length but
* don't have one, and it is also used in the client when a response is
* received whose length cannot be determined accurately (therefore making
* it impossible to know when a transfer completes).
*/
public static final int STATUS_LENGTH_REQUIRED = 411;
/**
* This transfer was interrupted and cannot be resumed. This is the code for
* the OBEX error "Precondition Failed", and it is also used in situations
* where the client doesn't have an ETag at all.
*/
public static final int STATUS_PRECONDITION_FAILED = 412;
/**
* This transfer was canceled
*/
public static final int STATUS_CANCELED = 490;
/**
* This transfer has completed with an error. Warning: there will be other
* status values that indicate errors in the future. Use isStatusError() to
* capture the entire category.
*/
public static final int STATUS_UNKNOWN_ERROR = 491;
/**
* This transfer couldn't be completed because of a storage issue.
* Typically, that's because the file system is missing or full.
*/
public static final int STATUS_FILE_ERROR = 492;
/**
* This transfer couldn't be completed because of no sdcard.
*/
public static final int STATUS_ERROR_NO_SDCARD = 493;
/**
* This transfer couldn't be completed because of sdcard full.
*/
public static final int STATUS_ERROR_SDCARD_FULL = 494;
/**
* This transfer couldn't be completed because of an unspecified un-handled
* OBEX code.
*/
public static final int STATUS_UNHANDLED_OBEX_CODE = 495;
/**
* This transfer couldn't be completed because of an error receiving or
* processing data at the OBEX level.
*/
public static final int STATUS_OBEX_DATA_ERROR = 496;
/**
* This transfer couldn't be completed because of an error when establishing
* connection.
*/
public static final int STATUS_CONNECTION_ERROR = 497;
}
For Ice Cream Sandwich this code is not working so you have to use this code
int currentapiVersion = android.os.Build.VERSION.SDK_INT;
if (currentapiVersion >= android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
Intent sharingIntent = new Intent(
android.content.Intent.ACTION_SEND);
sharingIntent.setType("image/jpeg");
sharingIntent
.setComponent(new ComponentName(
"com.android.bluetooth",
"com.android.bluetooth.opp.BluetoothOppLauncherActivity"));
sharingIntent.putExtra(Intent.EXTRA_STREAM, uri);
startActivity(sharingIntent);
} else {
ContentValues values = new ContentValues();
values.put(BluetoothShare.URI, uri.toString());
Toast.makeText(getBaseContext(), "URi : " + uri,
Toast.LENGTH_LONG).show();
values.put(BluetoothShare.DESTINATION, deviceAddress);
values.put(BluetoothShare.DIRECTION,
BluetoothShare.DIRECTION_OUTBOUND);
Long ts = System.currentTimeMillis();
values.put(BluetoothShare.TIMESTAMP, ts);
getContentResolver().insert(BluetoothShare.CONTENT_URI,
values);
}
You can use the obex library. It seemed that android didn't provide the obex library, but I solved the problem and the solution is posted here.
Further Explanation (please start reading from here if you're busy)
I was trying to create an android phone remote controller (and something similar to telnet server) which helps controlling the phone remotely with my old feature phone.
Main content :Bluetooth FTP client
My first plan was to make the app check the list of files of my feature phone's directory.
But I didn't know how to connect to my feature phone's ftp server.
I googled a lot about how to connect to a ftp server via bluetooth but I could only find that Bluetoorh FTP server used the OBEX Protocol.
I found a useful material (PDF file) in a SO thread and studied about OBEX connect requests, put and get operations.
So I finally wrote some codes that tries to connect to the Bluetooth FTP server. I want to show them to you, but I lost it :( The codes were like just directly writting byte sequences to the output stream.
I also had difficult time finding out what UUID makes the app connect as FTP client. But I tried every UUIDs retrieved using the code below.
String parcels="";
ParcelUuid[] uuids=mBtDevice.getUuids();
int i=0;
for (ParcelUuid p:uuids)
{
parcels += "UUID UUID" + new Integer(i).toString() + "=UUID.fromString((\"" + p.getUuid().toString() + "\"));\n\n";
++i;
}
Nothing seemed to bring me to the answer I wanted. So I googled more and found out that I not only should I use UUID 00001106-0000-1000-8000-00805f9b34fb to connect to OBEX FTP server, but also shold I transmit target header ** with UUID **F9EC7BC4-953C-11D2-984E-525400DC9E09 when sending OBEX connect request.
The code below shows how to connect to a bluetooth FTP server as a client.
try
{
mBtSocket = mBtDevice.createInsecureRfcommSocketToServiceRecord(UUID.fromString(" 00001106-0000-1000-8000-00805f9b34fb"));
}
catch (Exception e)
{
//e.printStackTrace();
}
Thread thread=new Thread(new Runnable() {
public void run()
{
UUID uuid=UUID.fromString("F9EC7BC4-953C-11D2-984E-525400DC9E09");
ByteBuffer bb = ByteBuffer.wrap(new byte[16]);
bb.putLong(uuid.getMostSignificantBits());
bb.putLong(uuid.getLeastSignificantBits());
byte [] bytes=bb.array();
Operation putOperation=null;
Operation getOperation=null;
try
{
// connect the socket
mBtSocket.connect();
//I will explain below
mSession = new ClientSession((ObexTransport)(mTransport = new BluetoothObexTransport(mBtSocket)));
HeaderSet headerset = new HeaderSet();
headerset.setHeader(HeaderSet.TARGET, bytes);
headerset = mSession.connect(headerset);
if (headerset.getResponseCode() == ResponseCodes.OBEX_HTTP_OK)
{
mConnected = true;
}
else
{
mSession.disconnect(headerset);
}
...
Then you are now connected as FTP client and are ready to use OBEX operations to send files, request for files, list directories, etc.
However I didn't want to wait an hour to send my command to my android phone. (And it would be inefficient if I increase frequency of polling, as every polling methods are.)
Start reading from here if you are busy
Main content: OBEX OPP
For the reason I mentioned above, I greedly searched for ways to manipulate OPP which I discovered from the OBEX documentation.
You may want to transfer files via bluetooth normally (without defining your protocol and building a new desktop application just for it) to your computer, right? Then sending to OBEX OPP inbox service that is running natively on your desktop windows computer is the best solution. So how can we connect to the OPP (Obex Object Push) inbox service?
Setup OBEX library
Add import javax.obex; to your source code.
If your compiler doesn't support OBEX library, download sources and add to your project from here.
Implement ObexTransport
You should provide a class that implements ObexTransport to the library when you use it. It defines how the library should send data (like by RFCOMM, TCP,...). A sample implementation is here. This can cause some runtime or compilation errors such as there's no method. But you can partially fix those by replacing the method calls to constants like return 4096 instead of return mSocket.getMaxTransmitPacketSize();, outcommenting the if statements of public int getMaxTransmitPacketSize(). Or you can try using reflection to get those methods runtime.
Get BluetoothSocket
Get a bluetooth socket using mBtDevice.createInsecureRfcommSocketToServiceRecord(UUID.fromString(" 00001105-0000-1000-8000-00805f9b34fb" )); And call connect().
Create ClientSession
Create a instance of your ObexTransport implementation, and create a new ClientSession like mSession = new ClientSession((ObexTransport)(mTransport = new BluetoothObexTransport(mBtSocket)));.
Send OBEX connect request to your computer OPP inbox service.
HeaderSet headerset = new HeaderSet();
// headerset.setHeader(HeaderSet.COUNT,n);
headerset = mSession.connect(null);
if (headerset.getResponseCode() == ResponseCodes.OBEX_HTTP_OK)
{
mConnected = true;
}
Send OBEX put requests using the ClientSession.
protected boolean Put(ClientSession session, byte[] bytes, String as, String type)
{
// TODO: Implement this method
//byte [] bytes;
String filename=as;
boolean retry=true;
int times=0;
while (retry && times < 4)
{
Operation putOperation=null;
OutputStream mOutput = null;
//ClientSession mSession = null;
//ArrayUtils.reverse(bytes);
try
{
// Send a file with meta data to the server
final HeaderSet hs = new HeaderSet();
hs.setHeader(HeaderSet.NAME, filename);
hs.setHeader(HeaderSet.TYPE, type);
hs.setHeader(HeaderSet.LENGTH, new Long((long)bytes.length));
Log.v(TAG,filename);
//Log.v(TAG,type);
Log.v(TAG,bytes.toString());
putOperation = session.put(hs);
mOutput = putOperation.openOutputStream();
mOutput.write(bytes);
mOutput.close();
putOperation.close();
}
catch (Exception e)
{
Log.e(TAG, "put failed", e);
retry = true;
times++;
continue;
//e.printStackTrace();
}
finally
{
try
{
if(mOutput!=null)
mOutput.close();
if(putOperation!=null)
putOperation.close();
}
catch (Exception e)
{
Log.e(TAG, "put finally" , e);
retry = true;
times++;
continue;
}
//updateStatus("[CLIENT] Connection Closed");
}
retry = false;
return true;
}
return false;
}
Finally, disconnect.
private void FinishBatch(ClientSession mSession) throws IOException
{
mSession.disconnect(null);
try
{
Thread.sleep((long)500);
}
catch (InterruptedException e)
{}
mBtSocket.close();
}
Then here is a wrapper class.
import android.bluetooth.*;
import android.util.*;
import java.io.*;
import java.util.*;
import javax.obex.*;
public class BluetoothOPPHelper
{
String address;
BluetoothAdapter mBtadapter;
BluetoothDevice device;
ClientSession session;
BluetoothSocket mBtSocket;
protected final UUID OPPUUID=UUID.fromString(("00001105-0000-1000-8000-00805f9b34fb"));
private String TAG="BluetoothOPPHelper";
public BluetoothOPPHelper(String address)
{
mBtadapter=BluetoothAdapter.getDefaultAdapter();
device=mBtadapter.getRemoteDevice(address);
try
{
mBtSocket = device.createRfcommSocketToServiceRecord(OPPUUID);
}
catch (IOException e)
{
throw new RuntimeException(e);
}
}
public ClientSession StartBatch(int n)
{
ClientSession mSession = null;
// TODO: Implement this method
boolean retry=true;
int times=0;
while (retry && times < 4)
{
//BluetoothConnector.BluetoothSocketWrapper bttmp=null;
try
{
mBtSocket.connect();
//bttmp = (new BluetoothConnector(device,false,BluetoothAdapter.getDefaultAdapter(),Arrays.asList(new UUID[]{OPPUUID,OPPUUID, OPPUUID}))).connect();//*/ device.createInsecureRfcommSocketToServiceRecord(OPPUUID);
/*if(mBtSocket.isConnected())
{
mBtSocket.close();
}*/
}
catch (Exception e)
{
Log.e(TAG, "opp fail sock " + e.getMessage());
retry = true;
times++;
continue;
}
try
{
//mBtSocket=bttmp.getUnderlyingSocket();
// mBtSocket.connect();
BluetoothObexTransport mTransport = null;
mSession = new ClientSession((ObexTransport)(mTransport = new BluetoothObexTransport(mBtSocket)));
HeaderSet headerset = new HeaderSet();
// headerset.setHeader(HeaderSet.COUNT,n);
headerset = mSession.connect(null);
if (headerset.getResponseCode() == ResponseCodes.OBEX_HTTP_OK)
{
boolean mConnected = true;
}
else
{
Log.e(TAG, "SEnd by OPP denied;");
mSession.disconnect(headerset);
times++;
continue;
}
}
catch (Exception e)
{
Log.e(TAG, "opp failed;" , e);
retry = true;
times++;
continue;
//e.rintStackTrace();
}
retry=false;
}
return mSession;
}
protected boolean Put(ClientSession session, byte[] bytes, String as, String type)
{
// TODO: Implement this method
//byte [] bytes;
String filename=as;
boolean retry=true;
int times=0;
while (retry && times < 4)
{
Operation putOperation=null;
OutputStream mOutput = null;
//ClientSession mSession = null;
//ArrayUtils.reverse(bytes);
try
{
// Send a file with meta data to the server
final HeaderSet hs = new HeaderSet();
hs.setHeader(HeaderSet.NAME, filename);
hs.setHeader(HeaderSet.TYPE, type);
hs.setHeader(HeaderSet.LENGTH, new Long((long)bytes.length));
Log.v(TAG,filename);
//Log.v(TAG,type);
Log.v(TAG,bytes.toString());
putOperation = session.put(hs);
mOutput = putOperation.openOutputStream();
mOutput.write(bytes);
mOutput.close();
putOperation.close();
}
catch (Exception e)
{
Log.e(TAG, "put failed", e);
retry = true;
times++;
continue;
//e.printStackTrace();
}
finally
{
try
{
if(mOutput!=null)
mOutput.close();
if(putOperation!=null)
putOperation.close();
}
catch (Exception e)
{
Log.e(TAG, "put finally" , e);
retry = true;
times++;
continue;
}
//updateStatus("[CLIENT] Connection Closed");
}
retry = false;
return true;
}
return false;
}
protected boolean Put(ClientSession s, OPPBatchInfo info)
{
return Put(s,info.data,info.as,info.type);
}
private void FinishBatch(ClientSession mSession) throws IOException
{
mSession.disconnect(null);
try
{
Thread.sleep((long)500);
}
catch (InterruptedException e)
{}
mBtSocket.close();
}
public boolean flush() throws IOException
{
if (sendQueue.isEmpty())
{
return true;
}
try
{
Thread.sleep((long)2000);
}
catch (InterruptedException e)
{}
ClientSession session=StartBatch(sendQueue.size());
if (session == null)
{
return false;
}
while (!sendQueue.isEmpty())
{
if (Put(session, sendQueue.remove()) == false)
{
Log.e(TAG, "Put failed");
}
}
FinishBatch(session);
return true;
}
Queue<OPPBatchInfo> sendQueue;
public boolean AddTransfer(String as,String mimetype,byte[] data)
{
return sendQueue.add(new OPPBatchInfo(as,mimetype,data));
}
class OPPBatchInfo
{
String as;
String type;
byte[] data;
public OPPBatchInfo(String as,String type,byte[] data)
{
this.as=as;
this.data=data;
this.type=type;
}
}
}
You need to implement FTP over OBEX. Once you implement the standard protocol and profile, your Android FTP implementation will inter-operate with virtually any Bluetooth FTP server. You'll also need to implement OPP for maximum inter-operability. The OBEX protocol is not so difficult to implement and the specs is freely available.
I know this question is old, but for anyone having to deal with this still:
With this library you can send files via OBEX and commands via RFCOMM:
https://github.com/ddibiasi/Funker
Once connected to your target device, you can manipulate its filesystem.
The following example sends a file:
val rxOBEX = RxObex(device)
rxOBEX
.putFile("rubberduck.txt", "text/plain", "oh hi mark".toByteArray(), "example/directory") // Name of file, mimetype, bytes of file, directory
.subscribeBy(
onComplete = {
Log.d(TAG, "Succesfully sent a testfile to device")
},
onError = { e ->
Log.e(TAG, "Received error!")
}
)
The library is built on Rx, so all calls are non blocking.