What would be analog to hid_get_feature_report in Android USB Library?
I need to get relays state from usb relays device on Android.
I found example on C (for Linux/Windows): https://github.com/darrylb123/usbrelay/blob/master/libusbrelay.c
static int get_board_features(relay_board *board, hid_device *handle)
{
unsigned char buf[9];
//Get the features of the device
buf[0] = 0x01;
int ret = hid_get_feature_report(handle, buf, sizeof(buf));
if (ret == -1)
{
perror("hid_get_feature_report\n");
}
//Set the serial number (0x0 for termination)
memset(board->serial, 0x0, sizeof(board->serial));
memcpy(board->serial, buf, Serial_Length);
//Byte 7 in the response contains the target_state of the relays
board->state = buf[7];
return ret;
}
On Android it returns only one end point Log.i(TAG, "endpointCount ${usbInterface.endpointCount}
I am making an android app + arduino that will receive ir code from arduino and sending the results.value (ir decode) to android through bluetooth. on the android side I have receive the code as a String that results into (for example) 92c0 then made a test button that will send it back to arduino and trigger it to send ir code to a device by irsend.sendNEC(0x92c0, 32) problem is when receiving the codes back from the android app is I have to receive it by char data, how do I use data which is a char and use it as a substitute for 0x92c0 in irsend.sendN My sketch down below:
#include <IRremote.h>
#include <SoftwareSerial.h>
SoftwareSerial bluetoothPort(4,5);
const int RECV_PIN = 12;
char data = "0";
const int SEND_PIN = 13;
IRsend irsend;
IRrecv irrecv(RECV_PIN);
decode_results results;
int BTval;
int IRval;
void setup()
{
bluetoothPort.begin(9600);
Serial.begin(9600);
irrecv.enableIRIn();
}
void loop()
{
if(bluetoothPort.available() > 0)
{
data = bluetoothPort.read();
Serial.print(data);
irsend.sendNEC(operator[data],32);
irrecv.resume();
}
if(irrecv.decode(&results))
{
Serial.println(results.value);
int set = results.value;
bluetoothPort.println(results.value, HEX);
irrecv.resume();
}
}
The problem here is that you CAN'T transfer 0x92c0 as a char (or byte). Just because it is not a byte, but two.
Now, I'm not much into android, so I need to see the android code to make a real solution You can handle this in three ways:
Binary transfer the data (2 bytes)
Transfer the data as a string (5 bytes)
Index the possible replies in an array and transfer the index (only applicable for a small quantity of codes).
I'm showing you the last 2, because the 1st is the most effective but I don't think you have the proper knowledge to send and receive data in binary format from android (and surely I don't have it).
So, if the data is transferred in string format (the same way you are uploading it) you will receive more bytes:
1 to 4 hexadecimal digits
1 carriage return
The code just stores the bytes you receive in a variable and then sends it when you receive a CR or LF:
// Outside the loop function
uint16_t receivedData;
// Inside the loop function
if(bluetoothPort.available() > 0)
{
data = bluetoothPort.read();
if ((data >= '0') && (data <= '9'))
{ // If it is a digit between 0 and 9 (in ascii)
receivedData = (receivedData << 4) | (data - '0');
}
else if ((data >= 'A') && (data <= 'F'))
{ // If it is a digit between A and F (in ascii)
receivedData = (receivedData << 4) | (data - 'A' + 10);
}
else if ((data >= 'a') && (data <= 'f'))
{ // Lowercase case
receivedData = (receivedData << 4) | (data - 'a' + 10);
}
else if (((data == '\r') || (data == '\n')) && (receivedData > 0))
{ // I tend to consider both CR and LF, because windows always screws this
Serial.print(receivedData, HEX);
irsend.sendNEC(receivedData,32); // Not sure about the 32 here...
irrecv.resume();
receivedData = 0;
}
else
receivedData = 0; // Something went wrong, just reset the variable
}
If you just have to send a few codes, you can store them and then transfer only the proper index. For instance:
// Outside the loop function
uint16_t possibleCodes[] = { 0x92c0, 0x8238, 0x5555 };
// Inside the loop function
if(bluetoothPort.available() > 0)
{
data = bluetoothPort.read();
// If you are using string transmission, use the following
// line to get the correct value
// data = bluetoothPort.read() - '0';
if (data < sizeof(possibleCodes) / sizeof(possibleCodes[0]))
{
Serial.print(possibleCodes[data], HEX);
irsend.sendNEC(possibleCodes[data],32); // Not sure about the 32 here...
irrecv.resume();
}
}
For instance in this case to send 0x92c0 you will have to send from android the value 0.
I have android device and windows drivers for it.
I have to communicate using my own binary protocol in accessory mode.
Is it possible to send data to this device without writing custom USB driver?
USB is a complex protocol because it is 'universal' and can handle a large variety of devices (mass storage, cameras,...). So on your android device has to be implemented a basic USB structure to use standard libraries like libusb or something like that.
You can assume that this is the case, because android is in most cases used on processors with USB port.
See http://www.beyondlogic.org/usbnutshell/usb1.shtml.
You can get more information about the USB device classes, interfaces, configurations, endpoints ur android device impmenets by using libusb -v
Then if you know what the USB structure on your android device looks like you can use libusb or another library to write data to specific endpoints in the usb structure by e.g. libusb_bulk_transfer(), libusb_control_transfer()
http://libusb.sourceforge.net/api-1.0/io.html
If you want to program in java you can use usb4java however this is a bit flaky http://usb4java.org/quickstart/libusb.html
The general USB structure is device -> (configuration) -> interface -> endpoint
So the way to write data to an endpoint is:
libusb_init(NULL);
libusb_open_device_with_vid_pid(NULL, vendor_id, product_id);
libusb_claim_interface(devh, 0);
libusb_bulk_transfer(dev_handle, (2 | LIBUSB_ENDPOINT), data,
4, &p, 0); //example
... release interface...
...
libusb_close(devh);
libusb_exit(NULL);
Here is C++ example copied from http://www.dreamincode.net/forums/topic/148707-introduction-to-using-libusb-10/
#include <iostream>
#include <libusb.h>
using namespace std;
int main() {
libusb_device **devs; //pointer to pointer of device, used to
retrieve a list of devices
libusb_device_handle *dev_handle; //a device handle
libusb_context *ctx = NULL; //a libusb session
int r; //for return values
ssize_t cnt; //holding number of devices in list
r = libusb_init(&ctx); //initialize the library for the session we
just declared
if(r < 0) {
cout<<"Init Error "<<r<<endl; //there was an error
return 1;
}
libusb_set_debug(ctx, 3); //set verbosity level to 3, as suggested in
the documentation
cnt = libusb_get_device_list(ctx, &devs); //get the list of devices
if(cnt < 0) {
cout<<"Get Device Error"<<endl; //there was an error
return 1;
}
cout<<cnt<<" Devices in list."<<endl;
dev_handle = libusb_open_device_with_vid_pid(ctx, 5118, 7424);
//these are vendorID and productID I found for my usb device
if(dev_handle == NULL)
cout<<"Cannot open device"<<endl;
else
cout<<"Device Opened"<<endl;
libusb_free_device_list(devs, 1); //free the list, unref the devices
in it
unsigned char *data = new unsigned char[4]; //data to write
data[0]='a';data[1]='b';data[2]='c';data[3]='d'; //some dummy values
int actual; //used to find out how many bytes were written
if(libusb_kernel_driver_active(dev_handle, 0) == 1) { //find out if
kernel driver is attached
cout<<"Kernel Driver Active"<<endl;
if(libusb_detach_kernel_driver(dev_handle, 0) == 0) //detach it
cout<<"Kernel Driver Detached!"<<endl;
}
r = libusb_claim_interface(dev_handle, 0); //claim interface 0 (the
first) of device (mine had jsut 1)
if(r < 0) {
cout<<"Cannot Claim Interface"<<endl;
return 1;
}
cout<<"Claimed Interface"<<endl;
cout<<"Data->"<<data<<"<-"<<endl; //just to see the data we want to
write : abcd
cout<<"Writing Data..."<<endl;
r = libusb_bulk_transfer(dev_handle, (2 | LIBUSB_ENDPOINT_OUT), data,
4, &actual, 0); //my device's out endpoint was 2, found with trial-
the device had 2 endpoints: 2 and 129
if(r == 0 && actual == 4) //we wrote the 4 bytes successfully
cout<<"Writing Successful!"<<endl;
else
cout<<"Write Error"<<endl;
r = libusb_release_interface(dev_handle, 0); //release the claimed
interface
if(r!=0) {
cout<<"Cannot Release Interface"<<endl;
return 1;
}
cout<<"Released Interface"<<endl;
libusb_close(dev_handle); //close the device we opened
libusb_exit(ctx); //needs to be called to end the
delete[] data; //delete the allocated memory for data
return 0;
}
So as your device runs android it has a USB structure/functionality. To investigate the USB functionality of your device (device class like mass storage, RNDIS,...) use libusb -v and the see the code above to write custom data to one of the endpoints on the device.
I have a USB sound card that has the following setup and allows for stereo recording with 48000hz 2 channels 16 bit, so I'm trying to set it up that way:
UsbConfiguration[mId=1,mName=null, mAttributes=160, mMaxPower=50,
mInterfaces=[
UsbInterface[mId=0,mAlternateSetting=0,mName=null,mClass=1,mSubclass=1,mProtocol=0,
mEndpoints=[]
UsbInterface[mId=1,mAlternateSetting=0,mName=null,mClass=1,mSubclass=2,mProtocol=0,
mEndpoints=[]
UsbInterface[mId=1,mAlternateSetting=1,mName=null,mClass=1,mSubclass=2,mProtocol=0,
mEndpoints=[UsbEndpoint[mAddress=4,mAttributes=9,mMaxPacketSize=384,mInterval=1]]
UsbInterface[mId=1,mAlternateSetting=2,mName=null,mClass=1,mSubclass=2,mProtocol=0,
mEndpoints=[UsbEndpoint[mAddress=4,mAttributes=9,mMaxPacketSize=576,mInterval=1]]
UsbInterface[mId=1,mAlternateSetting=3,mName=null,mClass=1,mSubclass=2,mProtocol=0,
mEndpoints=[UsbEndpoint[mAddress=4,mAttributes=9,mMaxPacketSize=192,mInterval=1]]
UsbInterface[mId=2,mAlternateSetting=0,mName=null,mClass=1,mSubclass=2,mProtocol=0,
mEndpoints=[]
UsbInterface[mId=2,mAlternateSetting=1,mName=null,mClass=1,mSubclass=2,mProtocol=0,
mEndpoints=[UsbEndpoint[mAddress=138,mAttributes=5,mMaxPacketSize=196,mInterval=1]]
UsbInterface[mId=2,mAlternateSetting=2,mName=null,mClass=1,mSubclass=2,mProtocol=0,
mEndpoints=[UsbEndpoint[mAddress=138,mAttributes=5,mMaxPacketSize=294,mInterval=1]]
UsbInterface[mId=2,mAlternateSetting=3,mName=null,mClass=1,mSubclass=2,mProtocol=0,
mEndpoints=[UsbEndpoint[mAddress=138,mAttributes=5,mMaxPacketSize=388,mInterval=1]]
UsbInterface[mId=2,mAlternateSetting=4,mName=null,mClass=1,mSubclass=2,mProtocol=0,
mEndpoints=[UsbEndpoint[mAddress=138,mAttributes=5,mMaxPacketSize=582,mInterval=1]]
UsbInterface[mId=3,mAlternateSetting=0,mName=null,mClass=3,mSubclass=0,mProtocol=0,
mEndpoints=[UsbEndpoint[mAddress=130,mAttributes=3,mMaxPacketSize=16,mInterval=16]
]
]
I'm trying to select and use the incoming interface with the alternate setting for stereo input and do the same thing with the interface for the stereo output.
For the input, I've tried to do it natively with the following code:
int AndroidUSBAudioIO_start(int sampleRate, int bufferSize, void *callback, void *clientData) {
int rc = -1;
if (androidUSBAudioIO == NULL) {
androidUSBAudioIO = (AndroidUSBAudioIOInternals *) malloc(sizeof(AndroidUSBAudioIOInternals));
}
androidUSBAudioIO->samplerate = sampleRate;
androidUSBAudioIO->buffersize = bufferSize;
androidUSBAudioIO->callback = (audioUSBProcessingCallback *) callback;
androidUSBAudioIO->clientData = clientData;
androidUSBAudioIO->maruStream = 0;
androidUSBAudioIO->isSetup = 0;
androidUSBAudioIO->isPlaying = 0;
rc = libusb_init(NULL);
if (rc < 0) {
}
androidUSBAudioIO->deviceHandle = libusb_open_device_with_vid_pid(NULL, VID, PID);
if (!androidUSBAudioIO->deviceHandle) {
rc = -1;
goto out;
}
rc = libusb_reset_device(androidUSBAudioIO->deviceHandle);
if (rc < 0) {
goto out;
}
rc = libusb_set_configuration(androidUSBAudioIO->deviceHandle, 1);
if (rc < 0) {
}
rc = libusb_kernel_driver_active(androidUSBAudioIO->deviceHandle, IFACE_NUM);
if (rc == 1) {
rc = libusb_detach_kernel_driver(androidUSBAudioIO->deviceHandle, IFACE_NUM);
if (rc < 0) {
goto out;
}
}
rc = libusb_claim_interface(androidUSBAudioIO->deviceHandle, IFACE_NUM);
if (rc < 0) {
goto out;
}
rc = libusb_set_interface_alt_setting(androidUSBAudioIO->deviceHandle, 1, 2);
if (rc < 0) {
printf("libusb_claim_interface: %s.\n", libusb_error_name(rc));
goto out;
}
...
I'm getting the following error at when setting the alternate interface:
Fatal signal 11 (SIGSEGV) at 0x0000001d (code=1), thread 10303
and also tried to do it from java with the following code upon receiving the permission to use the device:
UsbDeviceConnection mUsbDevConn = mUsbManager.openDevice(mAudioDevice);
int mReqType = 0x01; //
int mRequest = 0x0B; // SET_INTERFACE USB SPEC CONSTANT
int mValue = 0x02; // alt settings
int mIndex = 0x01; // interface nr
byte[] mBuffer = null;
int mLength = 0;
int mTimout = 1000;
mUsbDevConn.controlTransfer(UsbConstants.USB_DIR_OUT | mReqType, mRequest, mValue, mIndex, mBuffer, mLength, mTimout);
I'm getting the following error:
Error (status 6: **UNKNOWN**)
What am I missing?
I think it would be highly unusual for the libusb_set_interface_alt_setting call itself to cause the SIGSEGV. I would expect that either a prior call would cause this, or the SIGSEGV is an indirect effect of the call. That is, this call changes the alternate setting, which effectively starts the transfer of audio data. If the buffers, other data structures or the callback are not setup correctly a SIGSEGV may result.
In your situation, I would put more debug messages in the code, including in the library and your callback to try to narrow down the last thing before the crash.
If the code was working for a "mono" device, have a look at what has changed in the move to "Stereo". Perhaps the data-packet size (buffers) needs to be larger.
As far as the Java version is concerned, the error 6 may be related to the fact that you don't seem to be detaching any kernel drivers or claiming the interface before trying to change the alternate setting.
In the past I found it necessary to detach kernel drivers from each and every interface including HID interfaces to free up the allocated bus bandwidth before starting the audio.
Finally, if the free version of usbEffects (Android App) works with this device, you can connect adb to the phone via Wi-Fi and run the app with the device connected to see the debug messages that will tell if the requestType, request etc parameters are correct for this hardware.
I've hit a bit of a roadblock with my project. I've tried for hours and can't seem to find out what is causing my problem.
I'm trying to create a box that, when it's closed I can use bluetooth commands and arduino will play a response.
When you open the box, it will play a unique audio clip.
The problem is, the LDR works fine as in the unique clip plays whenever I open the box, however when the box is closed, the bluetooth responses don't play as expected, they just play a tiny snippet of the unique response from when it's open?
So once I open the box, the unique clip plays and the bluetooth responses work as expected.
I've tried using switch cases and for loops but to no avail.
Your help will be much appreciated!
//Coded By: Angelo Casimiro (4/27/14)
//Voice Activated Arduino (Bluetooth + Android)
//Feel free to modify it but remember to give credit
//PCM library used to turn voice file into a string of text for the speaker.
//Credit to HighTechLowTech
#include <SD.h> // need to include the SD library
//#define SD_ChipSelectPin 53 //example uses hardware SS pin 53 on Mega2560
#define SD_ChipSelectPin 4 //using digital pin 4 on arduino nano 328, can use other pins
#include <TMRpcm.h> // also need to include this library...
#include <SPI.h>
TMRpcm tmrpcm; // create an object for use in this sketch
int ldrPin = A2; //declared LDR on analog pin 2
int ldrValue = 0; //reading different values from the LDR
//declare voice as a string of data
String voice;
void setup() {
//Speaker pin
tmrpcm.speakerPin = 9;
Serial.begin(9600);
if (!SD.begin(SD_ChipSelectPin)) { // see if the card is present and can be initialized:
Serial.println("SD fail");
return; // don't do anything more if not
}
}
//-----------------------------------------------------------------------//
void loop() {
while (Serial.available()){ //Check if there is an available byte to read
delay(50); //Delay added to make thing stable
char c = Serial.read(); //Conduct a serial read
if (c == '#') {break;} //Exit the loop when the # is detected after the word
voice += c; //Shorthand for voice = voice + c
}
if (voice.length() > 0) {
Serial.println(voice);
}
//LDR variable defined from analog pin 2
ldrValue = analogRead(ldrPin);
//define LDR value ranges and map them to cases
//if voice string is "marco" then playback the sample array
if(voice == "*marco") {tmrpcm.play("Polo!.wav");}
else if(voice == "*hello") {tmrpcm.play("Hello!.wav");}
else if(voice == "*where") {tmrpcm.play("here.wav");}
else if(voice == "*who") {tmrpcm.play("Scott.wav");}
else if(voice == "*knock knock") {tmrpcm.play("Who.wav");}
else if(ldrValue > 500) {tmrpcm.play("Burp.wav");}
voice="";
delay(1);
}
It might be easier to see in this sketch using switch cases.
Basically, when the box is closed i can see in the serial monitor that case 2 is active which is what I want.
When the box is open, case 1 is active, but it's not playing 'Burp.wav' until I close it again and it switches back to case 2
//Coded By: Angelo Casimiro (4/27/14)
#include <SD.h> // need to include the SD library
//#define SD_ChipSelectPin 53 //example uses hardware SS pin 53 on Mega2560
#define SD_ChipSelectPin 4 //using digital pin 4 on arduino nano 328, can use other pins
#include <TMRpcm.h> // also need to include this library...
#include <SPI.h>
TMRpcm tmrpcm; // create an object for use in this sketch
//declare voice as a string of data
String voice;
//LDR value Range
const int sensorMin = 100;
const int sensorMax = 480;
void setup()
{
//Speaker pin
tmrpcm.speakerPin = 9;
Serial.begin(9600);
if (!SD.begin(SD_ChipSelectPin))
{
// see if the card is present and can be initialized:
Serial.println("SD fail");
return; // don't do anything more if not
}
}
//-----------------------------------------------------------------------//
void loop()
{
while (Serial.available())
{
//Check if there is an available byte to read
delay(50); //Delay added to make thing stable
char c = Serial.read(); //Conduct a serial read
if (c == '#')
{
break; //Exit the loop when the # is detected after the word
}
voice += c; //Shorthand for voice = voice + c
}
if (voice.length() > 0)
{
Serial.println(voice);
}
//LDR variable defined from analog pin 2
int sensorReading = analogRead(A2);
Serial.println(sensorReading);
//define LDR value ranges and map them to cases
int range = map(sensorReading, sensorMin, sensorMax, 1, 2);
Serial.println(range);
switch (range)
{
case 1:
{
tmrpcm.play("Burp.wav");
}
break;
case 2:
//if voice string is "marco" then playback the sample array
if (voice == "*marco")
{
tmrpcm.play("Polo!.wav");
}
else if (voice == "*hello")
{
tmrpcm.play("Hello!.wav");
}
else if (voice == "*where")
{
tmrpcm.play("here.wav");
}
else if (voice == "*who")
{
tmrpcm.play("Scott.wav");
}
else if (voice == "*knock knock")
{
tmrpcm.play("Who.wav");
}
voice = "";
break;
}
delay(50);
Serial.println();
}