My project:
Controlling 3 stepper motors with bluetooth.
I'm using Android Studio for the app and Arduino to receive the bluetooth data and control the Steppers.
My Problem
When my Arduino receives the data it lags or misses some of the data.
Here is my ConnectedThread.java class used to communicate to the Arduino.
package com.example.a3axisrig;
import android.bluetooth.BluetoothSocket;
import android.os.Handler;
import android.os.SystemClock;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import static com.example.a3axisrig.MainActivityKt.MESSAGE_READ;
public class ConnectedThread extends Thread {
private final BluetoothSocket mmSocket;
private final InputStream mmInStream;
private final OutputStream mmOutStream;
private final Handler mHandler;
public ConnectedThread(BluetoothSocket socket, Handler handler) {
mmSocket = socket;
mHandler = handler;
InputStream tmpIn = null;
OutputStream tmpOut = null;
// Get the input and output streams, using temp objects because
// member streams are final
try {
tmpIn = socket.getInputStream();
tmpOut = socket.getOutputStream();
} catch (IOException e) { }
mmInStream = tmpIn;
mmOutStream = tmpOut;
}
#Override
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 = mmInStream.available();
if(bytes != 0) {
buffer = new byte[1024];
SystemClock.sleep(10); //pause and wait for rest of data. Adjust this depending on your sending speed.
bytes = mmInStream.available(); // how many bytes are ready to be read?
bytes = mmInStream.read(buffer, 0, bytes); // record how many bytes we actually read
mHandler.obtainMessage(MESSAGE_READ, bytes, -1, buffer)
.sendToTarget(); // Send the obtained bytes to the UI activity
}
} catch (IOException e) {
e.printStackTrace();
break;
}
}
}
/* Call this from the main activity to send data to the remote device */
public void write(char input) {
//byte[] bytes = input.getBytes(); //converts entered String into bytes
try {
mmOutStream.write(input);
} catch (IOException e) { }
}
/* Call this from the main activity to shutdown the connection */
public void cancel() {
try {
mmSocket.close();
} catch (IOException e) { }
}
}
And here's my Activity class(TimelapseActivity.kt) that inflates the view with a joystick to control two motors and a Left and Right buttons to control a 3rd motor.
package com.example.a3axisrig
import android.R.attr.button
import android.annotation.SuppressLint
import android.content.Intent
import android.graphics.Color
import android.os.Bundle
import android.util.Log
import android.view.MotionEvent
import android.view.View
import android.view.View.OnTouchListener
import android.widget.Button
import androidx.appcompat.app.AppCompatActivity
private lateinit var setButton: Button
private lateinit var doneButton: Button
private lateinit var backButton: Button
private lateinit var point1Button: Button
private lateinit var point2Button: Button
private lateinit var point3Button: Button
private lateinit var rightButton: Button
private lateinit var leftButton:Button
private var points: Int = 0
class TimelapseActivity : AppCompatActivity(), JoystickView.JoystickListener {
#SuppressLint("ClickableViewAccessibility")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_timelapse)
val joystick = JoystickView(this)
window.decorView.setBackgroundColor(Color.argb(255, 212, 212, 212));
setButton = findViewById(R.id.set_button)
doneButton = findViewById(R.id.done_button)
backButton = findViewById(R.id.back_button)
rightButton = findViewById(R.id.right_button)
leftButton = findViewById(R.id.left_button)
point1Button = findViewById(R.id.point1Button)
point2Button = findViewById(R.id.point2Button)
point3Button = findViewById(R.id.point3Button)
point1Button.setBackgroundColor(Color.BLUE)
point2Button.setBackgroundColor(Color.BLUE)
point3Button.setBackgroundColor(Color.BLUE)
setButton.setOnClickListener { view: View ->
points++
updatePoints()
if (mConnectedThread != null) { //First check to make sure thread created
if (points==1) mConnectedThread!!.write('i') else if (points ==2)mConnectedThread!!.write('o')
}
}
doneButton.setOnClickListener { view: View ->
val intent = Intent(this, TimelapseSetupActivity::class.java)
startActivity(intent)
if (mConnectedThread != null) { //First check to make sure thread created
mConnectedThread!!.write('r')
}
}
backButton.setOnClickListener { view: View ->
points=0
updatePoints()
}
leftButton.setOnTouchListener(OnTouchListener { v, event ->
if (event.action == MotionEvent.ACTION_DOWN) {
if (mConnectedThread != null) { //First check to make sure thread created
mConnectedThread!!.write('a')
}
} else if (event.action == MotionEvent.ACTION_UP) {
if (mConnectedThread != null) { //First check to make sure thread created
mConnectedThread!!.write('1')
}
}
true
})
rightButton.setOnTouchListener(OnTouchListener { v, event ->
if (event.action == MotionEvent.ACTION_DOWN) {
if (mConnectedThread != null) { //First check to make sure thread created
mConnectedThread!!.write('9')
}
} else if (event.action == MotionEvent.ACTION_UP) {
if (mConnectedThread != null) { //First check to make sure thread created
mConnectedThread!!.write('1')
}
}
true
})
}
override fun onJoystickMoved(xPercent: Float, yPercent: Float, id: Int) {
Log.d("Joystick", "X percent: $xPercent Y percent: $yPercent")
if (mConnectedThread != null) { //First check to make sure thread created
if (xPercent > 0.1 && yPercent >0.1) mConnectedThread!!.write('1') //Pan Right & Tilt Up
else if (xPercent > 0.1 && yPercent< -0.1) mConnectedThread!!.write('2') //Pan Right & Tilt Down
else if (xPercent < -0.1 && yPercent > 0.1) mConnectedThread!!.write('3') //Pan Left & Tilt Up
else if (xPercent < -0.1 && yPercent < -0.1) mConnectedThread!!.write('4') //Pan Left & Tilt Down
else if (xPercent > 0.1) mConnectedThread!!.write('5') //Pan Right
else if (xPercent < -0.1) mConnectedThread!!.write('6') //Pan Left
else if (yPercent > 0.1) mConnectedThread!!.write('7') //Tilt Up
else if (yPercent < -0.1) mConnectedThread!!.write('8') //Tilt Down
else mConnectedThread!!.write('9')
}
}
}
private fun updatePoints(){
if(points ==1){
point1Button.setBackgroundColor(Color.GREEN)
}else if (points ==2){
point2Button.setBackgroundColor(Color.GREEN)
}else if (points >=3){
point3Button.setBackgroundColor(Color.GREEN)
}else{
point1Button.setBackgroundColor(Color.BLUE)
point2Button.setBackgroundColor(Color.BLUE)
point3Button.setBackgroundColor(Color.BLUE)
}
}
And here's my arduino code
#include <AccelStepper.h>
#include <MultiStepper.h>
#include <SPI.h>
#include <Wire.h>
// -----------------------------------BLUETOOTH-----------------------------------
#include <SoftwareSerial.h> // use the software uart
SoftwareSerial bluetooth(0 , 1); // RX, TX
// -----------------------------------MENU-----------------------------------
#include <Adafruit_SSD1306.h>
#include <Adafruit_GFX.h>
//#include <Adafruit_PCD8544.h>
#include <ClickEncoder.h>
#include <TimerOne.h>
int contrast = 60;
#define OLED_RESET 4
Adafruit_SSD1306 display(OLED_RESET);
int menuitem = 1;
int frame = 1;
int page = 0;
int mainMenuItem = 1;
int subMenuItem1 = 1;
int subMenuItem2 = 1;
int subMenuItem3 = 1;
int subMenuItem4 = 1;
String menuItem1 = "Setup";
String menuItem2 = "Free Control";
String menuItem3 = "Saved";
String menuItem4 = "Settings";
String setupItem1 = "Timelapse";
String setupItem2 = "Video";
String setupItem3 = "Back";
boolean up = false;
boolean down = false;
boolean middle = false;
bool sliderLengthSet = false;
// ------------------------------------------------------------------------------------
#define JoyX A0
#define JoyY A1
#define JoySwitch 10 // Joystick switch connected
// Rotary Encoder
#define CLK 8
#define DT 9
#define SW 12
int counter = 0;
int currentStateCLK;
int lastStateCLK;
String currentDir = "";
unsigned long lastButtonPress = 0;
ClickEncoder *encoder;
int16_t last, value;
//Opto Trigger
#define opto 13
//limitSwitch
#define limitSwitch 11
AccelStepper tiltStepper(1, 2, 3);
AccelStepper panStepper(1, 4, 5);
AccelStepper sliderStepper(1, 6, 7);
MultiStepper StepperControl;
int JoyXPos = 0;
int JoyYPos = 0;
int tiltSpeed = 60;
int sliderSpeed = 1500;
int panSpeed = 10;
int inOutSpeed = 0;
int panInPoint = 0;
int tiltInPoint = 0;
int sliderInPoint = 0;
int panOutPoint = 0;
int tiltOutPoint = 0;
int sliderOutPoint = 0;
int sliderLength = 43; //in cm (725steps = 1cm)
int sliderLengthInSteps = (sliderLength * 725) - 100; //725steps = 1cm && 100 steps as safety
long gotoposition[3]; // An array to store the In or Out position for each stepper motor
//Rotary Encoder
int clickCount = 0;
bool rotaryEncoderMenuState = true; //true when in Menu mode, false when in slider mode
//Timer
long duration = 3000; //ms
//Intervalometer
int shotDuration = 100; //in ms
int interval = 3000; //in ms
int numberOfShots = 0;
char lastReading;
char bt ;
// ------------------------------------------------------------------ SETUP -------------------------------------------------------------------
void setup() {
//Bluetooth
bluetooth.begin(9600); // start the bluetooth uart at 9600 which is its default
//delay(3000); // wait for settings to take affect.
//Set initial speed values for the steppers
tiltStepper.setMaxSpeed(6000);
tiltStepper.setSpeed(0);
tiltStepper.setAcceleration(10);
panStepper.setMaxSpeed(6000);
panStepper.setSpeed(0);
panStepper.setAcceleration(5);
sliderStepper.setMaxSpeed(6000);
sliderStepper.setSpeed(0);
sliderStepper.setAcceleration(10);
StepperControl.addStepper(panStepper);
StepperControl.addStepper(tiltStepper);
StepperControl.addStepper(sliderStepper);
//limitSwitch
pinMode(limitSwitch, INPUT_PULLUP);
//Opto Trigger
pinMode(opto, OUTPUT);
// //Go to Home
// while (digitalRead(limitSwitch) == 0) {
// sliderStepper.setSpeed(500);
// sliderStepper.runSpeed();
// sliderStepper.setCurrentPosition(0); // When limit switch pressed set position to 0 steps
// }
// delay(20);
// // Move 200 steps back from the limit switch
// while (sliderStepper.currentPosition() != -500) {
// sliderStepper.setSpeed(-1500);
// sliderStepper.run();
// }
}
// ------------------------------------------------------------------ LOOP -------------------------------------------------------------------
void loop() {
//
// if (digitalRead(limitSwitch) != 0 || sliderStepper.currentPosition() < sliderLengthInSteps + 3000) {
// sliderStepper.setSpeed(1500);
// sliderStepper.run();
// }
if (bluetooth.available()) {
bt = bluetooth.read();
}
int inOutSpeed = 500; //steps per second
// -----------------------------------BLUETOOTH-----------------------------------
lastReading = bluetooth.read();
// while (lastReading == bluetooth.read()) {
// lastReading = bluetooth.read();
switch (bt) {
case '1':
sliderStepper.setSpeed(0);
tiltStepper.setSpeed(0);
panStepper.setSpeed(0);
break;
case '2':
panStepper.setSpeed(500);
bluetooth.print("Pan Right");
break;
case '3':
panStepper.setSpeed(-500);
bluetooth.print("Pan Left");
break;
case '4':
tiltStepper.setSpeed(-500);
bluetooth.print("Tilt Down");
break;
case '5':
tiltStepper.setSpeed(500);
bluetooth.print("Tilt Up");
break;
case '6':
//sliderStepper.setSpeed(500);
bluetooth.print("Slider Right");
break;
case '7':
//sliderStepper.setSpeed(-500);
bluetooth.print("Slider Left");
break;
case '9':
sliderStepper.setSpeed(500);
break;
case 'a':
sliderStepper.setSpeed(-500);
break;
case 'i':
panInPoint = panStepper.currentPosition();
tiltInPoint = tiltStepper.currentPosition();
sliderInPoint = sliderStepper.currentPosition();
break;
case 'o':
panOutPoint = panStepper.currentPosition();
tiltOutPoint = tiltStepper.currentPosition();
sliderOutPoint = sliderStepper.currentPosition();
gotoposition[0] = panInPoint;
gotoposition[1] = tiltInPoint;
gotoposition[2] = sliderInPoint;
//inOutSpeed = findSpeed();
panStepper.setMaxSpeed(500);
tiltStepper.setMaxSpeed(300);
sliderStepper.setMaxSpeed(500);
StepperControl.moveTo(gotoposition); // Calculates the required speed for all motors
while (panStepper.distanceToGo() != 0 || tiltStepper.distanceToGo() != 0 || sliderStepper.distanceToGo() != 0) {
StepperControl.run(); // Blocks until all are in position
}
delay(200);
bluetooth.println("o called");
break;
case'r':
bluetooth.println("r called");
gotoposition[0] = panOutPoint;
gotoposition[1] = tiltOutPoint;
gotoposition[2] = sliderOutPoint;
inOutSpeed = findSpeed();
bluetooth.println(inOutSpeed);
panStepper.setMaxSpeed(inOutSpeed);
tiltStepper.setMaxSpeed(inOutSpeed);
sliderStepper.setMaxSpeed(inOutSpeed);
StepperControl.moveTo(gotoposition); // Calculates the required speed for all motors
//StepperControl.runSpeedToPosition(); // Blocks until all are in position
long timePassed = millis();
long lastTrigger = millis();
while (panStepper.distanceToGo() != 0 || tiltStepper.distanceToGo() != 0 || sliderStepper.distanceToGo() != 0) {
StepperControl.run();
if ((millis() - lastTrigger) / 1000 == interval / 1000) {
Serial.println(lastTrigger);
digitalWrite(opto, HIGH);
delay(shotDuration); // wait for a shutter speed
digitalWrite(opto, LOW);
//delay(interval+duration);
Serial.println("triggered");
lastTrigger = millis();
}
}
break;
}
sliderStepper.runSpeed();
tiltStepper.runSpeed();
panStepper.runSpeed();
}
int findSpeed() {
numberOfShots = duration / (interval + shotDuration);
if (abs(panInPoint - panOutPoint) > abs(tiltInPoint - tiltOutPoint) && abs(panInPoint - panOutPoint) > abs(sliderInPoint - sliderOutPoint)) {
return (abs(panInPoint - panOutPoint) / ((duration - (shotDuration * numberOfShots)) / 1000));
} else if (abs(tiltInPoint - tiltOutPoint) > abs(panInPoint - panOutPoint) && abs(tiltInPoint - tiltOutPoint) > abs(sliderInPoint - sliderOutPoint)) {
return (abs(tiltInPoint - tiltOutPoint) / ((duration - (shotDuration * numberOfShots)) / 1000));
} else {
return (abs(sliderInPoint - sliderOutPoint) / ((duration - (shotDuration * numberOfShots)) / 1000));
}
}
//----------------------------------------------------- DRAW MENU -----------------------------------------------------
void drawMenu()
{
//Setup->Timelapse->Next
panInPoint = panStepper.currentPosition();
tiltInPoint = tiltStepper.currentPosition();
sliderInPoint = sliderStepper.currentPosition();
//Save Out Point
int inOutSpeed = 0;
panOutPoint = panStepper.currentPosition();
tiltOutPoint = tiltStepper.currentPosition();
sliderOutPoint = sliderStepper.currentPosition();
Serial.println("out");
Serial.println(panOutPoint);
Serial.println(tiltOutPoint);
Serial.println(sliderOutPoint);
//go to Start Point
gotoposition[0] = panInPoint;
gotoposition[1] = tiltInPoint;
gotoposition[2] = sliderInPoint;
Serial.println("in");
Serial.println(gotoposition[0]);
Serial.println(gotoposition[1]);
Serial.println(gotoposition[2]);
//inOutSpeed = findSpeed();
panStepper.setMaxSpeed(500);
tiltStepper.setMaxSpeed(300);
sliderStepper.setMaxSpeed(1000);
StepperControl.moveTo(gotoposition); // Calculates the required speed for all motors
StepperControl.runSpeedToPosition(); // Blocks until all are in position
delay(200);
//Setup->Timelapse->Next->Next-> Start
// Execute Move
gotoposition[0] = panOutPoint;
gotoposition[1] = tiltOutPoint;
gotoposition[2] = sliderOutPoint;
inOutSpeed = findSpeed();
panStepper.setMaxSpeed(inOutSpeed);
tiltStepper.setMaxSpeed(inOutSpeed);
sliderStepper.setMaxSpeed(inOutSpeed);
StepperControl.moveTo(gotoposition); // Calculates the required speed for all motors
//StepperControl.runSpeedToPosition(); // Blocks until all are in position
long timePassed = millis();
long lastTrigger = millis();
while (panStepper.distanceToGo() != 0 || tiltStepper.distanceToGo() != 0 || sliderStepper.distanceToGo() != 0) {
StepperControl.run();
if ((millis() - lastTrigger) / 1000 == interval / 1000) {
Serial.println(lastTrigger);
digitalWrite(opto, HIGH);
delay(shotDuration); // wait for a shutter speed
digitalWrite(opto, LOW);
//delay(interval+duration);
Serial.println("triggered");
lastTrigger = millis();
}
}
}
I'm receiving bluetooth data to my Arduino and the motors are turning, it's just not very accurate and misses some button presses.
Please could you help me! :)
Related
I am trying to use MediaCodec in async mode. My files are aac encoded and I'm using c2.android.aac.decoder (OMX.google.aac.decoder has the same problem). The format is ENCODING_PCM_16BIT.
The ByteBuffers returned are in LittleEndian format. If I use getShort to extract the sample data then the first use gives me the correct value, but the second call gives me a byte reversed value (256 instead of 1, 512 instead of 2, etc.), the third call is correct, the fourth byte reversed.
I got around this by writing my own conversion routines from a byte sequence to a short, but this is inelegant. Is there anyway to use the ByteBuffer as it is supposed to be used?
package info.upadouble.audiotest;
import android.content.Context;
import android.media.AudioFormat;
import android.media.MediaCodec;
import android.media.MediaCodecInfo;
import android.media.MediaCodecList;
import android.media.MediaExtractor;
import android.media.MediaFormat;
import android.os.Environment;
import android.os.Looper;
import android.util.Log;
import java.io.File;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import androidx.annotation.NonNull;
public class AudioTest {
File audioFile;
Context context;
MediaExtractor me;
MediaCodec codec;
int channels;
int sampleFormat;
int samplesPerSec;
boolean endOfStream, outputEnd;
int audioTrack;
long seekToSample;
boolean bufferAvailable;
Thread readThread;
int waitingBufferId;
int waitingBufferSize;
int waitingBufferOffset;
long waitingBufferSampleStart;
int activeBufferPos=0;
int activeBufferSize=0;
short [] activeBuffer;
AudioTest(Context context, File audioFile ) {
//this.audioFile = audioFile;
this.audioFile = new File( Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MUSIC),"Sixtest-aac.m4a");
seekToSample = 0;
readThread = new Thread() {
#Override
public void run() {
Looper.prepare();
readThreadBody();
Looper.loop();
Log.i("readThread","read Thread done!");
readThread = null;
}
};
readThread.setName("readThread");
readThread.start();
WavFileWriter wavOutput = new WavFileWriter(new File(context.getExternalFilesDir(Environment.DIRECTORY_MUSIC), "output.wav"));
short[] sample = new short[2];
int scnt = 0;
while ( getNextSample(sample )) {
try {
wavOutput.addStereoSample(sample);
} catch (IOException e) {
}
++scnt;
if ( scnt%44100 == 0 )
Log.i( "Seconds: ", ""+ (scnt/44100));
}
try {
wavOutput.setWavHeader(2, samplesPerSec);
wavOutput.close();
} catch (IOException e) {
}
if ( me!=null )
me.release();
if ( codec!=null )
codec.release();
}
void readThreadBody() {
me = new MediaExtractor();
try {
me.setDataSource(audioFile.toString());
audioTrack = -1;
for ( int i=me.getTrackCount()-1; i>=0 ; --i ) {
String mime = me.getTrackFormat(i).getString(MediaFormat.KEY_MIME);
if (mime.startsWith("audio/")) {
audioTrack = i;
me.selectTrack(i);
break;
}
}
if ( audioTrack==-1 ) {
me.release();
me = null;
return;
}
MediaFormat mf = me.getTrackFormat(audioTrack);
MediaCodecList mcl = new MediaCodecList(MediaCodecList.REGULAR_CODECS);
String codecName = mcl.findDecoderForFormat(mf);
codec = MediaCodec.createByCodecName(codecName);
outputEnd = false;
endOfStream = false;
codec.setCallback(new MediaCodec.Callback() {
#Override
public void onInputBufferAvailable(#NonNull MediaCodec mediaCodec, int bufferId) {
if ( endOfStream )
return;
ByteBuffer inputBuffer = mediaCodec.getInputBuffer(bufferId);
if ( seekToSample!= -1 ) {
Log.i("Seeking","Seeking");
me.seekTo(seekToSample*1000000/samplesPerSec,
MediaExtractor.SEEK_TO_PREVIOUS_SYNC);
seekToSample = -1;
}
int size = me.readSampleData(inputBuffer, 0);
if ( size>0 ) {
mediaCodec.queueInputBuffer(bufferId, 0, size, me.getSampleTime(), me.getSampleFlags());
} else {
mediaCodec.queueInputBuffer(bufferId, 0, 0, me.getSampleTime(), MediaCodec.BUFFER_FLAG_END_OF_STREAM);
endOfStream = true;
}
me.advance();
}
#Override
public void onOutputBufferAvailable(#NonNull MediaCodec mediaCodec, int bufferId,
#NonNull MediaCodec.BufferInfo bufferInfo) {
if ( ( bufferInfo.flags&android.media.MediaCodec.BUFFER_FLAG_END_OF_STREAM)!=0 )
outputEnd = true;
synchronized ( readThread ) {
while ( bufferAvailable ) {
try {
readThread.wait();
} catch (InterruptedException e) {
return;
}
}
if ( bufferInfo.size==0 && !outputEnd ) {
//Log.i("zero data release:", "Zero data: " + bufferId);
codec.releaseOutputBuffer(bufferId,false);
} else {
waitingBufferId = bufferId;
waitingBufferSize = bufferInfo.size;
waitingBufferOffset = bufferInfo.offset;
waitingBufferSampleStart = (bufferInfo.presentationTimeUs * samplesPerSec + 500000) / 1000000;
//Log.i("Out Buf Id","Buf Id "+ bufferId);
//Log.i("Out Time","Time: "+ track.waitingBufferSampleStart + " mSec: " + bufferInfo.presentationTimeUs);
// the +500000 is to round off the division instead of truncating it
bufferAvailable = true;
readThread.notifyAll();
}
if ( outputEnd )
Looper.myLooper().quitSafely();
}
}
#Override
public void onError(#NonNull MediaCodec mediaCodec, #NonNull MediaCodec.CodecException e) {
outputEnd = true;
Looper.myLooper().quitSafely();
}
#Override
public void onOutputFormatChanged(#NonNull MediaCodec mediaCodec, #NonNull MediaFormat mediaFormat) {
// outputEnd = true;
// Looper.myLooper().quitSafely();
/* Hmm. This seems to get called without the output format changing */
}
});
codec.configure(mf,null,null,0);
MediaFormat mediaFormat = codec.getOutputFormat();
channels = mediaFormat.getInteger(MediaFormat.KEY_CHANNEL_COUNT);
// As usual, android docs don't say what the default encoding is when this optional value
// is absent (and it is always absent in my tests so far). I'm guessing 16 bit.
// 16 bit is said to be "always supported", most of the others are not guaranteed to be supported,
// float has no text saying whether supported or not
if ( mediaFormat.containsKey(MediaFormat.KEY_PCM_ENCODING))
sampleFormat = mediaFormat.getInteger(MediaFormat.KEY_PCM_ENCODING);
else
sampleFormat = AudioFormat.ENCODING_PCM_16BIT;
if ( sampleFormat!=AudioFormat.ENCODING_PCM_16BIT && sampleFormat!=AudioFormat.ENCODING_PCM_FLOAT ) {
Log.e("Unexpected track format","Unexpected track sample format (must be short or float)");
throw new IOException();
}
samplesPerSec = mediaFormat.getInteger(MediaFormat.KEY_SAMPLE_RATE);
codec.start();
} catch ( IOException e ) {
Log.e("Decoding error","Decoding Error", e);
if ( me!=null )
me.release();
me = null;
if ( codec!=null )
codec.release();
codec=null;
}
}
boolean getNextSample(short [] sample) {
int activeBufferId;
int activeOffset;
int activeSize;
long activeSampleStart;
while (activeBufferPos >= activeBufferSize) {
if ( outputEnd && !bufferAvailable )
return( false); // End of File
if ( readThread==null )
return( false ); // Something went wrong
synchronized (readThread) {
while (!bufferAvailable) {
try {
readThread.wait();
} catch (InterruptedException e) {
sample[0] = 0;
sample[1] = 0;
return (false);
}
}
activeBufferId = waitingBufferId;
activeOffset = waitingBufferOffset;
activeSize = waitingBufferSize;
activeSampleStart = waitingBufferSampleStart;
waitingBufferId = 0;
bufferAvailable = false;
readThread.notifyAll();
if ( activeSize==0 && outputEnd )
return( false ); // End of file
}
ByteBuffer activeBuf = codec.getOutputBuffer(activeBufferId);
activeBufferSize = activeSize; // Length in bytes
if (sampleFormat == AudioFormat.ENCODING_PCM_16BIT) {
activeBufferSize /= 2;
activeOffset /= 2;
} else if (sampleFormat == AudioFormat.ENCODING_PCM_FLOAT) {
activeBufferSize /= 4;
activeOffset /= 4;
}
// activeBufferSampleStart = activeSampleStart;
if (activeBuffer == null || activeBuffer.length 1) val = 1;
else if (val 1) {
sample[1] = activeBuffer[activeBufferPos++];
activeBufferPos += channels - 2;
} else
sample[1] = sample[0];
return (true);
}
}
I am looking at things on a sample basis rather than just passing the ByteBuffer to AudioPlayer because I need to be able to slow the speed at which the audio plays and do my own mixing.
I used AudioRecord to record audio, following is my code:
#include<stdio.h>
#include<stdlib.h>
#include <media/AudioRecord.h>
using namespace android;
//==============================================
// Audio Record Defination
//==============================================
static pthread_t g_AudioRecordThread;
static pthread_t * g_AudioRecordThreadPtr = NULL;
volatile bool g_bQuitAudioRecordThread = false;
volatile int g_iInSampleTime = 0;
int g_iNotificationPeriodInFrames = 8000/10;
// g_iNotificationPeriodInFrames should be change when sample rate changes.
static void * AudioRecordThread( void *inArg );
void AudioRecordCallback(int event, void* user, void *info)
{
if(event == android::AudioRecord::EVENT_NEW_POS)
{
g_iInSampleTime += g_iNotificationPeriodInFrames;
//if(g_iInSampleTime > g_iNotificationPeriodInFrames*100)
// g_bQuitAudioRecordThread = true;
}
else if (event == android::AudioRecord::EVENT_MORE_DATA)
{
android::AudioRecord::Buffer* pBuff = (android::AudioRecord::Buffer*)info;
pBuff->size = 0;
}
else if (event == android::AudioRecord::EVENT_OVERRUN)
{
//LOGE(" EVENT_OVERRUN \n");
printf("[%d%s]EVENT_OVERRUN \n",__LINE__,__FUNCTION__);
}
}
static void * AudioRecordThread( void *inArg )
{
uint64_t inHostTime = 0;
void * inBuffer = NULL;
audio_source_t inputSource = AUDIO_SOURCE_MIC;
audio_format_t audioFormat = AUDIO_FORMAT_PCM_16_BIT;
audio_channel_mask_t channelConfig = AUDIO_CHANNEL_IN_MONO; //AUDIO_CHANNEL_IN_STEREO;
int bufferSizeInBytes = 1600;
int sampleRateInHz = 8000;
android::AudioRecord * pAudioRecord = NULL;
FILE * g_pAudioRecordFile = NULL;
//char strAudioFile[] = "/mnt/sdcard/external_sd/AudioRecordFile.pcm";
char strAudioFile[] = "./AudioRecordFile.pcm";
int iNbChannels = 1; // 1 channel for mono, 2 channel for streo
int iBytesPerSample = 2; // 16bits pcm, 2Bytes
int frameSize = 0; // frameSize = iNbChannels * iBytesPerSample
//int minFrameCount = 0; // get from AudroRecord object
size_t minFrameCount = 0; // get from AudroRecord object
int iWriteDataCount = 0; // how many data are there write to file
printf("[%d%s]thread enter ok!\n",__LINE__,__FUNCTION__);
String16 pack_name("wang_test");
printf("[%d%s]thread enter ok!\n",__LINE__,__FUNCTION__);
#if 1
// log the thread id for debug info
//LOGD("%s Thread ID = %d \n", __FUNCTION__, pthread_self());
printf("[%d%s] Thread ID = %d \n", __LINE__,__FUNCTION__, pthread_self());
g_iInSampleTime = 0;
g_pAudioRecordFile = fopen(strAudioFile, "wb+");
if(g_pAudioRecordFile == NULL)
{
printf("open file erro !\n");
}
iNbChannels = (channelConfig == AUDIO_CHANNEL_IN_STEREO) ? 2 : 1;
frameSize = iNbChannels * iBytesPerSample;
android::status_t status = android::AudioRecord::getMinFrameCount(
&minFrameCount, sampleRateInHz, audioFormat, channelConfig);
if(status != android::NO_ERROR)
{
//LOGE("%s AudioRecord.getMinFrameCount fail \n", __FUNCTION__);
printf("[%d%s]AudioRecord.getMinFrameCount fail \n",__LINE__,__FUNCTION__);
goto exit ;
}
//LOGE("sampleRateInHz = %d minFrameCount = %d iNbChannels = %d frameSize = %d ",
// sampleRateInHz, minFrameCount, iNbChannels, frameSize);
printf("[%d%s]sampleRateInHz = %d minFrameCount = %d iNbChannels = %d frameSize = %d \n",
__LINE__,__FUNCTION__,sampleRateInHz, minFrameCount, iNbChannels, frameSize);
bufferSizeInBytes = minFrameCount * frameSize;
inBuffer = malloc(bufferSizeInBytes);
if(inBuffer == NULL)
{
//LOGE("%s alloc mem failed \n", __FUNCTION__);
printf("[%d%s] alloc mem failed \n",__LINE__, __FUNCTION__);
goto exit ;
}
g_iNotificationPeriodInFrames = sampleRateInHz/10;
pAudioRecord = new android::AudioRecord(pack_name);
if(NULL == pAudioRecord)
{
//LOGE(" create native AudioRecord failed! ");
printf(" [%d%s] create native AudioRecord failed! \n",__LINE__,__FUNCTION__);
goto exit;
}
pAudioRecord->set( inputSource,
sampleRateInHz,
audioFormat,
channelConfig,
0,
AudioRecordCallback,
NULL,
0,
true);
if(pAudioRecord->initCheck() != android::NO_ERROR)
{
//LOGE("AudioTrack initCheck error!");
printf("[%d%s]AudioTrack initCheck error!\n",__LINE__,__FUNCTION__);
goto exit;
}
if(pAudioRecord->setPositionUpdatePeriod(g_iNotificationPeriodInFrames) != android::NO_ERROR)
{
//LOGE("AudioTrack setPositionUpdatePeriod error!");
printf("[%d%s]AudioTrack setPositionUpdatePeriod error!\n",__LINE__,__FUNCTION__);
goto exit;
}
if(pAudioRecord->start()!= android::NO_ERROR)
{
//LOGE("AudioTrack start error!");
printf("[%d%s]AudioTrack start error!\n",__LINE__,__FUNCTION__);
goto exit;
}
while (!g_bQuitAudioRecordThread)
{
//inHostTime = UpTicks();
int readLen = pAudioRecord->read(inBuffer, bufferSizeInBytes);
int writeResult = -1;
if(readLen > 0)
{
iWriteDataCount += readLen;
if(NULL != g_pAudioRecordFile)
{
writeResult = fwrite(inBuffer, 1, readLen, g_pAudioRecordFile);
if(writeResult < readLen)
{
//LOGE("Write Audio Record Stream error");
printf("[%d%s]Write Audio Record Stream error\n",__LINE__,__FUNCTION__);
}
}
// write PCM data to file or other stream,implement it yourself
//writeResult = WriteAudioData(
// g_iInSampleTime,
// inHostTime,
// inBuffer,
// readLen);
//LOGD("readLen = %d writeResult = %d iWriteDataCount = %d", readLen, writeResult, iWriteDataCount);
}
else
{
//LOGE("pAudioRecord->read readLen = 0");
printf("[%d%s]pAudioRecord->read readLen = 0\n",__LINE__,__FUNCTION__);
}
}
exit:
if(NULL != g_pAudioRecordFile)
{
fflush(g_pAudioRecordFile);
fclose(g_pAudioRecordFile);
g_pAudioRecordFile = NULL;
}
if(pAudioRecord)
{
pAudioRecord->stop();
//delete pAudioRecord;
pAudioRecord == NULL;
}
if(inBuffer)
{
free(inBuffer);
inBuffer = NULL;
}
#endif
//LOGD("%s Thread ID = %d quit\n", __FUNCTION__, pthread_self());
printf("[%d%s] Thread ID = %d quit\n", __LINE__,__FUNCTION__, pthread_self());
return NULL;
}
int main()
{
printf("hello world! \n");
pthread_t record_pid ;
if(pthread_create(&record_pid,NULL,AudioRecordThread,NULL)<0)
{
printf("%d%s pthread create erro !\n",__LINE__,__FUNCTION__);
}
while(1)
{
}
return 0;
}
I pushed the executable file under /data directory. After running it, i get the pcm file. I used Cool Pro Edit software to play it, however i couldn't hear anything.
I am using Raspberry pi3 and DHT11 sensor for temperature monitoring project.
I have following pin positions
VCC to pin no : 2
Ground to pin no : 6
Output to GPIO : BCM22 i.e pin no 15
Code that I have used:
public class WeatherStationActivity extends Activity {
private Handler mHandler = new Handler();
private TextView mTxtStatus;
private PeripheralManagerService service = new PeripheralManagerService();
private Gpio tempGpio;
private int i = 0;
int[] dht11_dat = {0, 0, 0, 0, 0};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.d("Weather station", "Started Weather Station");
setContentView(R.layout.activity_main);
mTxtStatus = (TextView) findViewById(R.id.txtStatus);
try {
tempGpio = service.openGpio("BCM22");
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
if (i == 10) {
handler.removeCallbacks(this);
} else {
getTemp();
handler.postDelayed(this, 5000);
}
i++;
}
}, 5000);
} catch (Exception e) {
e.printStackTrace();
}
}
private void getTemp() {
boolean laststate = false;
try {
laststate = tempGpio.getValue();
} catch (IOException e) {
e.printStackTrace();
}
int j = 0;
final int MAXTIMINGS = 85;
dht11_dat[0] = dht11_dat[1] = dht11_dat[2] = dht11_dat[3] = dht11_dat[4] = 0;
try {
tempGpio.setDirection(Gpio.DIRECTION_OUT_INITIALLY_LOW);
// tempGpio.setActiveType(Gpio.ACTIVE_LOW);
tempGpio.setValue(false);
// Thread.sleep(18);
TimeUnit.MILLISECONDS.sleep(18);
// tempGpio.setActiveType(Gpio.ACTIVE_HIGH);
// tempGpio.setActiveType(Gpio.ACTIVE_HIGH);
tempGpio.setValue(true);
TimeUnit.MICROSECONDS.sleep(40);
tempGpio.setDirection(Gpio.DIRECTION_IN);
/* tempGpio.setActiveType(Gpio.ACTIVE_HIGH);
tempGpio.setValue(true);*/
// tempGpio.setValue(true);
StringBuilder value = new StringBuilder();
for (int i = 0; i < MAXTIMINGS; i++) {
int counter = 0;
while (tempGpio.getValue() == laststate) {
counter++;
TimeUnit.MICROSECONDS.sleep(1);
if (counter == 255) {
break;
}
}
laststate = tempGpio.getValue();
mTxtStatus.append("\nLast State of Sensor " + laststate);
if (counter == 255) {
break;
}
//* ignore first 3 transitions *//*
if ((i >= 4) && (i % 2 == 0)) {
//* shove each bit into the storage bytes *//*
dht11_dat[j / 8] <<= 1;
if (counter > 16) {
dht11_dat[j / 8] |= 1;
}
j++;
}
}
// check we read 40 bits (8bit x 5 ) + verify checksum in the last
// byte
if ((j >= 40) && checkParity()) {
value.append(dht11_dat[2]).append(".").append(dht11_dat[3]);
Log.i("Logger", "temperature value readed: " + value.toString());
mTxtStatus.append("\nTemp " + value.toString());
} else {
mTxtStatus.append("\nNothing is working ");
Log.i("Logger", "Nothing is working ");
}
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (Exception ex) {
ex.printStackTrace();
}
}
private boolean checkParity() {
return dht11_dat[4] == (dht11_dat[0] + dht11_dat[1] + dht11_dat[2] + dht11_dat[3] & 0xFF);
}
}
Above code is giving me "Nothing is working" as output.
Any suggestion where I might be doing wrong?
You can't read data from DHT11 using Raspberry Pi 3 with Android Things because duration of DHT11 response pulses is from 26-28 us to 70 us, but max frequency of RP3 with AT GPIO is around 3kHz, which means around 300 us pulse duration. Take a look at answers to this question.
I have RK3288 Hardware Board and I am trying to use software decoder on it..
I have already integrated my software decoder with the android stage-fright player..
It is perfectly integrated and video is also running completely..
But now the problem is when I pause or seek video ,pop up window says
"Can't Play this video"
When I click on pause button it again calls awesomeplayer's constructor(I checked this out with the printf).
So please Can anybody point where i am missing in my code? or is there any other changes required?
My Onqueuefilled Function(which is similar to SoftAVC.cpp)
void IntdecHEVC::onQueueFilled(OMX_U32 portIndex) {
UNUSED(portIndex);
if (checkp) {
return;
}
IAccessUnit pic_val;
DisplayPic Display_val;
int32_t got_frame;
int32_t timeDelay, timeTaken;
unsigned int p;
if (mSignalledError) {
return;
}
if (mOutputPortSettingsChange != NONE) {
return;
}
List<BufferInfo *> &inQueue = getPortQueue(kInputPortIndex);
List<BufferInfo *> &outQueue = getPortQueue(kOutputPortIndex);
while (!outQueue.empty()) {
BufferInfo *inInfo;
OMX_BUFFERHEADERTYPE *inHeader = NULL;
BufferInfo *outInfo;
OMX_BUFFERHEADERTYPE *outHeader = NULL;
uint8_t *pBuf;
inInfo = NULL;
inHeader = NULL;
Display_val.eosFlag = false;
if (!mIsInFlush) {
if (!inQueue.empty()) {
inInfo = *inQueue.begin();
inHeader = inInfo->mHeader;
} else {
break;
}
}
outInfo = *outQueue.begin();
outHeader = outInfo->mHeader;
outHeader->nFlags = 0;
outHeader->nTimeStamp = 0;
outHeader->nOffset = 0;
if (inHeader != NULL && (inHeader->nFlags & OMX_BUFFERFLAG_EOS)) {
mReceivedEOS = true;
Display_val.eosFlag = true;
if (inHeader->nFilledLen == 0) {
inQueue.erase(inQueue.begin());
inInfo->mOwnedByUs = false;
notifyEmptyBufferDone(inHeader);
inHeader = NULL;
setFlushMode();
}
}
if (inHeader != NULL) {
pic_val.bufferData = inHeader->pBuffer + inHeader->nOffset;
pic_val.bufferLength = inHeader->nFilledLen;
pic_val.pts = inHeader->nTimeStamp;
}
if (outHeader)
pBuf = outHeader->pBuffer;
Display_val.pobLumaSl = pBuf;
Display_val.pobCromaCb = pBuf + (mWidth * mHeight);
Display_val.pobCromaCr = //pBuf + (mWidth*mHeight) + (m_lOriginalWidthUV*m_lHeightUV);
Display_val.pobCromaCb +(m_lOriginalWidthUV*m_lHeightUV);
GETTIME(&mTimeStart, NULL);
/* Compute time elapsed between end of previous decode()
* to start of current decode() */
TIME_DIFF(mTimeEnd, mTimeStart, timeDelay);
// set the height and width of the picture */
pic_val.width = mWidth;
pic_val.height = mHeight;
mInterface.api_inte265Decode(&pic_val); //decoding data
handlePortSettingChangeEvent(&pic_val);
GETTIME(&mTimeEnd, NULL);
/* Compute time taken for decode() */
TIME_DIFF(mTimeStart, mTimeEnd, timeTaken);
got_frame = mInterface.api_inte265GetPic(&Display_val);
if (got_frame) {
FormatIYUV(&Display_val); //copy data to outputbuffer 1-4
/* added to check decoded data by pooja*/
if (1) {
unsigned int i;
unsigned int MAX_SIZE = Display_val.width * Display_val.height;
for (i = 0; i < MAX_SIZE; i++) {
fwrite(&Display_val.pobLumaSl[i], sizeof(uint8_t), 1, fb);
}
MAX_SIZE = (Display_val.width >> 1) * (Display_val.height >> 1);
for (i = 0; i < MAX_SIZE; i++) {
fwrite(&Display_val.pobCromaCb[i], sizeof(uint8_t), 1, fb);
}
for (i = 0; i < MAX_SIZE; i++) {
fwrite(&Display_val.pobCromaCr[i], sizeof(uint8_t), 1, fb);
}
}
if (outHeader != NULL) {
outHeader->nFilledLen = (Display_val.width * Display_val.height * 3) / 2;
outHeader->nTimeStamp = Display_val.pts;
outInfo->mOwnedByUs = false;
outQueue.erase(outQueue.begin());
outInfo = NULL;
notifyFillBufferDone(outHeader);
outHeader = NULL;
}
} else if (mIsInFlush) {
/* If in flush mode and no output is returned by the codec,
* then come out of flush mode */
mIsInFlush = false;
/* If EOS was recieved on input port and there is no output
* from the codec, then signal EOS on output port */
if (mReceivedEOS) {
if (outHeader != NULL) {
outHeader->nFilledLen = 0;
outHeader->nFlags |= OMX_BUFFERFLAG_EOS; // 12-4-2016
outInfo->mOwnedByUs = false;
outQueue.erase(outQueue.begin());
outInfo = NULL;
notifyFillBufferDone(outHeader);
outHeader = NULL;
resetPlugin();
resetDecoder(); // added
checkp = true; //15-4-2016
// break; //13-4-2016
return; //14-4-2016
}
}
}
/* If input EOS is seen and decoder is not in flush mode,
* set the decoder in flush mode.
* There can be a case where EOS is sent along with last picture data
* In that case, only after decoding that input data, decoder has to be
* put in flush. This case is handled here */
if (mReceivedEOS && !mIsInFlush) {
setFlushMode();
}
/* Notify to client that empty buffer is done - pooja*/
if (inHeader != NULL) {
//inHeader->nFilledLen = 0;
inInfo->mOwnedByUs = false;
inQueue.erase(inQueue.begin());
inInfo = NULL;
notifyEmptyBufferDone(inHeader);
inHeader = NULL;
}
} // end !outQueue.empty()) loop
}
I am developing an application to receive data on an Android device from an Arduino. It displays values only up to 255 when I convert it to integer, but I want those values which are sent by the Arduino board. I have tried converting them to strings but that didn't work either.
How can I solve this problem?
Here's the code running on the Android device:
package pkg.MultipleDataReceiveFromArduinoArray;
import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import pkg.MultipleDataReceiveFromArduino.R;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
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.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
import com.android.future.usb.UsbAccessory;
import com.android.future.usb.UsbManager;
public class MultipleDataReceiveFromArduinoActivity extends
Activity implements Runnable {
private TextView txtReceivedBytes;
private TextView txtWaterLitres;
private TextView txtSensor1;
private TextView txtSensor2;
private TextView txtSensor3;
private EditText etCallibrationValue;
private Button btnSetCallibrationValue;
private static final String ACTION_USB_PERMISSION =
"com.google.android.DemoKit.action.USB_PERMISSION";
private UsbManager mUsbManager;
private PendingIntent mPermissionIntent;
private boolean mPermissionRequestPending;
private UsbAccessory mAccessory;
private ParcelFileDescriptor mFileDescriptor;
private FileInputStream mInputStream;
private FileOutputStream mOutputStream;
int countWaterVol = 0;
private int intCallibrationValue = 270;
private static final int MESSAGE_TEMPERATURE = 1;
private static final int MESSAGE_HUMIDITY = 2;
private static final int MESSAGE_WATERLEVEL = 3;
private static final byte COMMAND_OPEN_DOOR = 0x01;
private static final byte COMMAND_CLOSE_DOOR = 0x02;
protected class TelemetryPacket {
private int value;
public TelemetryPacket(int value) {
this.value = value;
}
public int getValue() {
return value;
}
}
private int composeInt(byte hi, byte lo) {
int val = (int) hi & 0xff;
val *= 256;
val += (int) lo & 0xff;
return val;
}
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
txtReceivedBytes=(TextView)findViewById(R.id.txtReceivedBytes);
txtWaterLitres =(TextView)findViewById(R.id.txtWaterLitres);
txtSensor1 = (TextView) findViewById(R.id.txtSensor1);
txtSensor2 =(TextView)findViewById(R.id.txtSensor2);
txtSensor3 =(TextView)findViewById(R.id.txtSensor3);
etCallibrationValue = (EditText)findViewById(R.id.etCallibrationValue);
btnSetCallibrationValue =
(Button)findViewById(R.id.btnSetCallibrationValue);
setupAccessory();
btnSetCallibrationValue.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
intCallibrationValue =
Integer.parseInt(etCallibrationValue.getText().toString());
Toast.makeText(getApplicationContext(),
"Callibration Value:" + intCallibrationValue,
Toast.LENGTH_SHORT).show();
}
});
}
#Override
public Object onRetainNonConfigurationInstance() {
if (mAccessory != null) {
return mAccessory;
} else {
return super.onRetainNonConfigurationInstance();
}
}
#Override
public void onResume() {
super.onResume();
if (mInputStream != null && mOutputStream != null) {
// streams were not null");
return;
}
// streams were null");
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 {
// null accessory
}
}
#Override
public void onPause() {
super.onPause();
}
#Override
public void onDestroy() {
unregisterReceiver(mUsbReceiver);
super.onDestroy();
}
Handler mHandler = new Handler() {
#Override
public void handleMessage(Message msg) {
//TelemetryPacket p = (TelemetryPacket) msg.obj;
ValueMsg t = (ValueMsg) msg.obj;
txtReceivedBytes.setText("Received Bytes: "+t.getRet());
if (t.getReading4()==1) {
countWaterVol = countWaterVol+1;
txtWaterLitres.setText("Water Produced in Litres:"+
(countWaterVol+"\n"+"Interrupt Signal"+t.getReading3());
} else {
}
txtSensor1.setText("S 1: "+t.getReading1()+","+
"Reading 2: "+t.getReading2());
txtSensor2.setText("S 3: "+t.getReading3()+","+
"Reading 4: "+t.getReading4());
txtSensor3.setText("S 5: "+t.getReading5()+","+
"Reading 6: "+t.getReading6());
Alets alerts = new Alets();
}
};
private void setupAccessory() {
mUsbManager = UsbManager.getInstance(this);
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);
registerReceiver(mUsbReceiver, filter);
if (getLastNonConfigurationInstance() != null) {
mAccessory = (UsbAccessory) getLastNonConfigurationInstance();
openAccessory(mAccessory);
}
}
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, "OpenAccessoryTest");
thread.start();
// Accessory opened
} else {
// failed to open accessory
}
}
private void closeAccessory() {
try {
if (mFileDescriptor != null) {
mFileDescriptor.close();
}
} catch (IOException e) {
} finally {
mFileDescriptor = null;
mAccessory = null;
}
}
public void run() {
int ret = 0;
//byte[] buffer = new byte[16384];
byte[] buffer = new byte[65536];
int i;
while (true) { // read data
try {
ret = mInputStream.read(buffer);
//ret= ret/3;
} catch (IOException e) {
break;
}
i = 0;
while (i < ret) {
int len = ret - i;
// if (len >= 1) {
int value = (int) buffer[0];
Message m = Message.obtain(mHandler);
m.obj = new ValueMsg('f',value,ret,buffer[1],buffer[2],
buffer[3],buffer[4],buffer[5]);
mHandler.sendMessage(m);
i += 1;
}
}
}
public static final long unsignedIntToLong(byte[] b)
{
long l = 0;
l |= b[0] & 0xFF;
l <<= 8;
l |= b[1] & 0xFF;
l <<= 8;
l |= b[2] & 0xFF;
l <<= 8;
l |= b[3] & 0xFF;
return l;
}
public static int unsignedByteToInt(byte b) {
return (int) b & 0x10;
}
private final BroadcastReceiver mUsbReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (ACTION_USB_PERMISSION.equals(action)) {
synchronized (this) {
UsbAccessory accessory = UsbManager.getAccessory(intent);
if (intent.getBooleanExtra(
UsbManager.EXTRA_PERMISSION_GRANTED, false)) {
openAccessory(accessory);
} else {
// USB permission denied
}
}
} else if (UsbManager.ACTION_USB_ACCESSORY_DETACHED.equals(action)) {
UsbAccessory accessory = UsbManager.getAccessory(intent);
if (accessory != null && accessory.equals(mAccessory)) {
// accessory detached
closeAccessory();
}
}
}
};
}
And here's the Arduino code (sketch):
#include <Usb.h>
#include <adk.h>
uint8_t b;
USB Usb;
ADK adk(&Usb,
"Ashok Kateshiya", // Manufacturer Name
"analog TEST", // Model Name
"TDS test ", // Description (user-visible string)
"0.1", // Version
"http://www.ashokkateshiya.co.cc",
"123456789"); // Serial Number (optional)
#define tds_pin A15
#define flow_pin 22
#define LLS_pin 49
float avg[10];
float value = 0;
int count;
int pin_state = 0, pin_old_state = 0;
int pulse_counter = 0;
int LLS_state;
int LLS_flag = 0;
int sensor_flag = 0;
int timer_flag = 0;
uint8_t msg[7] = { 0x00 };
uint16_t len = sizeof(msg);
uint8_t rcode;
void setup()
{
Serial.begin(115200);
Serial.print("\r\nADK demo start");
if (Usb.Init() == -1)
{
Serial.print("\r\nOSCOKIRQ failed to assert");
while(1); // halt
}
pinMode(tds_pin, INPUT);
pinMode(flow_pin, INPUT);
pinMode(LLS_pin, INPUT);
digitalWrite(LLS_pin, HIGH);
digitalWrite(flow_pin, HIGH);
TIMSK1 = 0x01;
TCCR1A = 0x00;
TCNT1 = 0x85EF;
TCCR1B = 0x05;
}
void loop()
{
Usb.Task();
if (adk.isReady() == false)
{
return;
}
TDS();
flow();
LLS();
}
void TDS()
{
for (count = 0; count < 10; count++)
{
avg[count] = analogRead(tds_pin);
}
for (count = 0; count < 10; count ++)
{
if (count == 0)
{
value = avg[count];
}
else
{
value = value + avg[count];
}
}
if (len > 0)
{
msg[0] = 0x1;
msg[1] = value/10;
rcode = adk.SndData (6, msg );
Serial.print("TDS 0 : ");
Serial.println(msg[0]);
Serial.print("TDS 1 : ");
Serial.println(msg[1]);
delay(10);
}
if (rcode && rcode != hrNAK)
USBTRACE2("DATA rcv :", rcode);
}
void flow()
{
pin_state = digitalRead(flow_pin);
if (pin_state == LOW)
{
pin_old_state = pin_state;
}
if ((pin_state == HIGH) && (pin_old_state == LOW))
{
pin_old_state = pin_state;
pulse_counter = (pulse_counter + 1);
sensor_flag = 1;
}
if ((pulse_counter / 25 == 1) && (sensor_flag == 1))
{
pulse_counter = 0;
sensor_flag = 0;
msg[2] = 0x2;
msg[3] = 1;
rcode = adk.SndData (6, msg );
Serial.print("value :");
Serial.println(msg[3]);
if (rcode && rcode != hrNAK)
{
USBTRACE2 ("USB DATA : ", rcode);
}
}
else
{
msg[2] = 0x2;
msg[3] = 0;
rcode = adk.SndData (6, msg );
Serial.print("value :");
Serial.println(msg[3]);
if (rcode && rcode != hrNAK)
{
USBTRACE2 ("USB DATA : ", rcode);
}
}
delay(10);
}
void LLS()
{
LLS_state = digitalRead(LLS_pin);
if (LLS_state != 0)
{
if (len > 0)
{
msg[4] = 0x3;
msg[5] = 0x0;
rcode = adk.SndData (6, msg );
Serial.print("LLS 4 : ");
Serial.println(msg[4]);
Serial.print("LLS 5 : ");
Serial.println(msg[5]);
}
}
else
{
msg[4] = 0x3;
msg[5] = 0x1;
rcode = adk.SndData (6, msg );
Serial.print("LLS 0 : ");
Serial.println(msg[4]);
Serial.print("LLS 2 : ");
Serial.println(msg[5]);
}
if (rcode && rcode != hrNAK)
USBTRACE2("DATA rcv :", rcode);
delay(10);
}
/****** timer overflow *******/
ISR(TIMER1_OVF_vect)
{
TCNT1 = 0x85EF;
if (pin_state == pin_old_state )
{
timer_flag = 1;
}
}
It looks like the problem is in the Arduino sketch. The msg array contains (unsigned) bytes which have a maximum value of 255.
The line:
msg[1] = value/10
implicitly truncates value/10 (which is an integer between 0 and 1023 - see http://arduino.cc/en/Reference/analogRead) to a maximum of 255.
To send value/10 you'll need to split it over 2 bytes. For example:
msg[1] = (uint8_t) (i & 0xFF);
msg[2] = (uint8_t) ((i >> 8) & 0xFF);
And msg will have to be one byte longer to accomodate.
On the Android (Java) side you'll need to do something like:
int value = (int) buffer[0];
// ...
int tds = buffer[1] + (buffer[2] << 8);
m.obj = new ValueMsg('f', value, ret, tds,
buffer[3], buffer[4], buffer[5], buffer[6]);
which will require a change to the definition of ValueMsg to accomodate.
Also, there may be a problem with the calls to SndData (assuming the library being used here is the USB_Host_Shield_2.0) as they always send 6 bytes even though in the first time through loop all 6 bytes of msg won't have been initialized.