Today, I’d like to show how to exchange data between USB device and ADK-capable Android phone. I will be using CueCat barcode scanner as source device; the data will be received by the phone and displayed on a screen using Arduino Terminal Android application.
A phone is USB device, too, and since two USB devices are unable to communicate to each other directly, I’m using Arduino board equipped with USB Host shield to relay data between devices. The sketch which runs on Arduino is a mix of two other pieces of code, one from ADK terminal emulator article and another one from an article explaining interfacing with a barcode scanner. Refer to these articles if you have questions about a specific piece.
Below is a full text of an Arduino sketch. It can be pasted from this page in Arduino IDE, compiled, and loaded into the board. It is also included in the examples section of USB Host library rev.2.0 distribution on gitHub. The library itself shall be installed in Arduino IDE tree as well.
To receive data from Arduino you’ll need Arduino Terminal application installed on your phone. The source code of application is also available – it is released under GPL2, if you make modifications to the code, please make them available for other people!
Finally, we will need some hardware – an Arduino board, USB Host shield, a USB hub, “declawed” CueCat or any other HID boot barcode scanner, as well as ADK-compatible Android phone. We will also need a 5V power supply capable of providing ~700ma of electrical current. I will show arrangement of all necessary pieces after explaining the sketch code.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 | /**/ /* A sketch demonstrating data exchange between two USB devices - a HID barcode scanner and ADK-compatible Android phone */ /**/ #include <avrpins.h> #include <max3421e.h> #include <usbhost.h> #include <usb_ch9.h> #include <Usb.h> #include <usbhub.h> #include <avr/pgmspace.h> #include <address.h> #include <adk.h> #include <hidboot.h> USB Usb; USBHub Hub1(&Usb); USBHub Hub2(&Usb); HIDBoot<HID_PROTOCOL_KEYBOARD> Keyboard(&Usb); ADK adk(&Usb,"Circuits@Home, ltd.", "USB Host Shield", "Arduino Terminal for Android", "1.0", "http://www.circuitsathome.com", "0000000000000001"); class KbdRptParser : public KeyboardReportParser { protected: virtual void OnKeyDown (uint8_t mod, uint8_t key); virtual void OnKeyPressed(uint8_t key); }; void KbdRptParser::OnKeyDown(uint8_t mod, uint8_t key) { uint8_t c = OemToAscii(mod, key); if (c) OnKeyPressed(c); } /* what to do when symbol arrives */ void KbdRptParser::OnKeyPressed(uint8_t key) { const char* new_line = "\n"; uint8_t rcode; uint8_t keylcl; if( adk.isReady() == false ) { return; } keylcl = key; if( keylcl == 0x13 ) { rcode = adk.SndData( strlen( new_line ), (uint8_t *)new_line ); } else { rcode = adk.SndData( 1, &keylcl ); } Serial.print( keylcl ); Serial.print(" : "); Serial.println( keylcl, HEX ); }; KbdRptParser Prs; void setup() { Serial.begin(115200); Serial.println("\r\nADK demo start"); if (Usb.Init() == -1) { Serial.println("OSCOKIRQ failed to assert"); while(1); //halt }//if (Usb.Init() == -1... Keyboard.SetReportParser(0, (HIDReportParser*)&Prs); delay( 200 ); } void loop() { Usb.Task(); } |
The main functionality of this sketch is contained in
OnKeyPressed()
callback – when a “key” is pressed, i.e., symbol arrives from the scanner, this symbol is sent out as-is to the phone or, if a special “end-of-barcode” character is received, it is substituted with newline character. Certain lines of this sketch deserve some explanation:
- Line 17. An instance of
USB
object is declared. All USB devices refer to it. - Lines 18-19.Two instances of USB hub are declared. I need two because 7-port hub I’m using consists of two cascaded 4-port hubs and I need to support both.
- Line 20.An instance of HID boot device is declared.
- Line 22.An instance of ADK device is declared.
- Lines 30-69.Redefining of HID methods.
- Lines 38-44.This method is called when a new keycode appears in input report. The code is translated into ASCII and the main
OnKeyPressed()
callback is called. - Lines 46-69.The main callback.
- Lines 53-55.It returns immediately if ADK device is not ready.
- Lines 59-61.Here I test if “end-of-barcode” symbol has been received and replace it with a newline.
- Lines 62-64.Otherwise, the symbol simply gets sent to the phone.
- Lines 66-68.These lines print received symbol to serial terminal.
The setup()
and loop()
functions at the end of the sketch don’t do anything exciting. The former initializes serial port, Usb subsystem and keyboard report parser. The latter calls Usb.Task()
periodically; the callbacks described above are in fact called from here. If you want to modify this code to use in your project and if your application is going to do anything inside loop()
make sure not to block Usb.Task()
for too long.
A picture above shows all the hardware necessary to run this sketch, neatly arranged for your viewing pleasure. A 1000mah LiPo battery is connected to MintyBoost and 5V from MintyBoost is connected to USB port of Arduino via standard USB cable. The Android phone draws 500ma until fully charged, CueCat needs another 100ma when active and Arduino/USB Host duo needs some milliamps as well; tiny MintyBoost provides that much power while staying cool.
The USB Host shield sits on top of Arduino and connects to USB hub uplink port with ordinary USB cable. CueCat and Nexus S are connected to USB hub downlink ports. If everything is working, CueCat shall start emitting red light from its nose and Android phone shall auto-start Arduino Terminal application. Now just tap “clear” in the terminal, scan the barcode and see it appear on the screen. Pretty easy, huh?
Oleg.
Hi,
I am very, very new to all of this. I apologize for simplistic questions, and thank you in advance for patiently reading this.
I would like to use your usb host shield to write text from a usb keyboard to a usb flash drive.
Like this:
keyboard -> usb shield -> usb flash drive
or rather, the keyboard and the usb flash drive would both need to be connected to a usb hub (as there is only 1 usb host port) like the android and the cuecat are connected to a usb hub.
I think with the code you provided for the usb host shield + usb keyboard demo, I can collect the keystroke data. But instead of writing to an lcd display, I want to write to a text file on the usb flash drive. Is this hard to do?
Thank you for your generous work here!
I don’t have code to support USB mass storage devices AKA flash drives yet. The work on it is planned next after HID is finalized but it will still take some time.
There are very cheap ($1 shipped) octopus-type USB hubs on eBay, it can be reduced to a small PCB and soldered directly to the shield.
I’m glad to hear that USB mass storage will be coming. I’m sure others are as well. I can’t wait!
I downloaded both beta versions of Arduino Terminal into my phone, but get an “error parsing” message when I try to run them. Any ideas?
What is the make/model of your phone? OS version?
Hi Oleg,
I followed your examples, and it works very well by itself, the problem occurs after I added the blink code in the loop
void loop()
{
//digitalWrite(13, HIGH);
Usb.Task();
//digitalWrite(13, LOW);
//delay(100);
}
then it seems the blink code interfers with the scanner input, I can only get the first character scaned with scanner. if I comment the digitalWrite ,the scanner scans fine. I am using Nexus S (with ICS 4.04).
found a workaround, get rid of the delay and use another methods to control the blink period. Thanks for your library, it made my life eaiser:-). I have the scanner working and also can use the arduino to control the step motor .
This is correct. You don’t want the loop() time to be very long.
I followed your example but when i try to run this keyboard arduino sample into my firmware(Arduino board with USB host shield) The USB.Init() is getting failed .
can you tell me what are all the situation the USB initialization will get failed?
Please reply this………
Thank,
Mahi
What is the error message?
“OSCOKIRQ failed to assert” This is the error message when i run this program.
Doupt: My Usb Host Shield(Spark fun) sitting on the Arduino UNO(AtMega328p) .When i connect my phone to the Usb Host shield my phone is getting charged but the phone is not detecting the accessory.
How to confirm whether the host shield is working properly or not?
Note:Currently i am using USB_Host_Shield_2.0 for my arduino ADK development.
Please clear my problem if you know or if you are interested
Thanks,
Mahi
Hi, im very new to this and I thought if I can use my USB keyboard with my android phone using maybe ths technology ? .. Because I would want to make something instead of buying a small keyboard for phones 🙂
This project will work – you just need to replace a barcode scanner with a keyboard.
Hi, I have an Arduino Board, A USB and an UltraSonic Maxbotix Sensor (Distance Finder), caould you please you tell me how can I exchange Data between an Android Application and the Arduino Board via USB?? Is it Possible? how can I program the application ?I need help !
Hi,
Check out this example sketch I wrote: https://github.com/felis/USB_Host_Shield_2.0/blob/master/examples/adk/ArduinoBlinkLED/ArduinoBlinkLED.ino the link to the Android source code can be found there as well.
All you need to do is upload the program to your Arduino plug in your phone and it will prompt you to install the application.
I got a lot of inspiration from this excellent blog post: http://allaboutee.com/2011/12/31/arduino-adk-board-blink-an-led-with-your-phone-code-and-explanation/ where you will also find information on how to send data from the board to your Android device.
hanks a lot Lauszus for your help!! I just have one more question, can you tell me if it possible to connect the Arduino Board to the Android Emulator on PC? not on an android mobile phone or any other device? thanks a lot 🙂
thanks a lot Lauszus for your help!! I just have one more question, can you tell me if it possible to connect the Arduino Board to the Android Emulator on PC? not on an android mobile phone or any other device? thanks a lot 🙂
No that is not possible 🙂
Thanks a lot for your help 🙂
Sorry for offtopic, but I don`t found more suitable place for my question.
If I have Android tablet PC with usb host mode support, can I use this device for connect with arduino mega 2560 board directly, without USB Host shield? And if this is possible, tell me how do it. Thanks a lot.
Vitalij.
You need to compile the kernel modules for your device. You can read more about it here: http://android.serverbox.ch/?p=285.
Thank you for your advice. I`ll try check, how it work in my case.
I now this is a old comment, but you should check out the following Android library: https://github.com/ksksue/PhysicaloidLibrary. I have used it to upload code directly to the Balandino: http://www.kickstarter.com/projects/tkjelectronics/balanduino-balancing-robot-kit and it works great!
HI,
I have android tab with usb host mode,can I use this device for connect with arduino mega 2560 board directly?
is it possible. if yes how it is possible to communicate with each other, if there are any drivers please send me. goliajay15@gmail.com
please help me
Yes. You could for instance parse serial data. See this Android library for more information: https://github.com/ksksue/PhysicaloidLibrary.
Hi,
I have a android machine 2.3.7, and I want to pick data from its USB port throwed by weighing machine and I don’t know how to do that please tell me how could I do this ?
Is that a host or a peripheral?
I installed Arduino Terminal from link above for my Ainol Jelly Bean Android Tablet but when i ran it, suddenly force closed so i can not use it until now. can you suggest or give me advice so this app run on my Android tablet? thanks.
Hi all,
I am using the Circuit@Home’s USB Host library with an Arduino DUE to make some experiments with Android-based smartphones and tablets and ADK; I am using the library included with Arduino v1.5.5.
I noted that ADK applications behave differently on different versions of Android; if I use an accessory and the paired app with on smartphones with Android v4.1.2 (Galaxy S2 and Galaxy Pocket Neo), accessories and phones communicate bidirectionally as I expect; if I try to use the same accessory/app with Android v4.3 (Galaxy Note 3), the communication works only from accessory to phone but not vice-versa (that is the smartphone doesn’t receive the data sent by the accessory but it sends data to the accessory which receives it).
Enabling the tracing mode in the USB Host library, I observed that the Galaxy Note 3 doesn’t acknowledge the write operations when it switches in accessory mode.
This is the tracing of USB transactions between the accessory and the Galaxy Note 3:
+ USB_DETACHED_SUBSTATE_INITIALIZE
+ USB_ATTACHED_SUBSTATE_SETTLE
+ USB_ATTACHED_SUBSTATE_RESET_DEVICE
+ USB_DETACHED_SUBSTATE_INITIALIZE
+ USB_ATTACHED_SUBSTATE_SETTLE
+ USB_ATTACHED_SUBSTATE_RESET_DEVICE
+ USB_ATTACHED_SUBSTATE_WAIT_RESET_COMPLETE
+ USB_ATTACHED_SUBSTATE_WAIT_SOF
+ USB_STATE_CONFIGURING
ADK::Init
=> ctrlReq
=> SetAddress deviceEP=0 configued as hostPIPE=0 sending to address=0
=> dispatchPkt token=0 pipe=0 nak_limit=65535
=> ctrlData IN
=> dispatchPkt token=256 pipe=0 nak_limit=65535
– Received data: 0x12, 0x01, 0x10, 0x02, 0x00, 0x00, 0x00, 0x40, 0xe8, 0x04, 0x60, 0x68, 0x00, 0x04, 0x01, 0x02, 0x03, 0x01,
=> dispatchPkt token=512 pipe=0 nak_limit=65535
=> USBHost::setAddr
=> ctrlReq
=> SetAddress deviceEP=0 configued as hostPIPE=0 sending to address=0
=> dispatchPkt token=0 pipe=0 nak_limit=0
=> dispatchPkt token=256 pipe=0 nak_limit=0
ADK::Init : device address is now 1
=> ctrlReq
=> SetAddress deviceEP=0 configued as hostPIPE=0 sending to address=1
=> dispatchPkt token=0 pipe=0 nak_limit=65535
=> ctrlData IN
=> dispatchPkt token=256 pipe=0 nak_limit=65535
– Received data: 0x02, 0x00,
=> dispatchPkt token=512 pipe=0 nak_limit=65535
ADK::Init : DK protocol rev. 2
=> ctrlReq
=> SetAddress deviceEP=0 configued as hostPIPE=0 sending to address=1
=> dispatchPkt token=0 pipe=0 nak_limit=65535
=> ctrlData OUT
=> dispatchPkt token=512 pipe=0 nak_limit=65535
– Wrote data: 0x41, 0x2e, 0x53, 0x2e, 0x44, 0x2e, 0x20, 0x4d, 0x6f, 0x6e, 0x6f, 0x70, 0x6f, 0x6c, 0x69, 0x20, 0x4e, 0x75, 0x6f, 0x74, 0x6f, 0x00,
=> dispatchPkt token=256 pipe=0 nak_limit=65535
=> ctrlReq
=> SetAddress deviceEP=0 configued as hostPIPE=0 sending to address=1
=> dispatchPkt token=0 pipe=0 nak_limit=65535
=> ctrlData OUT
=> dispatchPkt token=512 pipe=0 nak_limit=65535
– Wrote data: 0x43, 0x48, 0x52, 0x4f, 0x4e, 0x4f, 0x4c, 0x4f, 0x47, 0x47, 0x45, 0x52, 0x00,
=> dispatchPkt token=256 pipe=0 nak_limit=65535
=> ctrlReq
=> SetAddress deviceEP=0 configued as hostPIPE=0 sending to address=1
=> dispatchPkt token=0 pipe=0 nak_limit=65535
=> ctrlData OUT
=> dispatchPkt token=512 pipe=0 nak_limit=65535
– Wrote data: 0x43, 0x68, 0x72, 0x6f, 0x6e, 0x6f, 0x4c, 0x6f, 0x67, 0x67, 0x65, 0x72, 0x00,
=> dispatchPkt token=256 pipe=0 nak_limit=65535
=> ctrlReq
=> SetAddress deviceEP=0 configued as hostPIPE=0 sending to address=1
=> dispatchPkt token=0 pipe=0 nak_limit=65535
=> ctrlData OUT
=> dispatchPkt token=512 pipe=0 nak_limit=65535
– Wrote data: 0x31, 0x2e, 0x30, 0x00,
=> dispatchPkt token=256 pipe=0 nak_limit=65535
=> ctrlReq
=> SetAddress deviceEP=0 configued as hostPIPE=0 sending to address=1
=> dispatchPkt token=0 pipe=0 nak_limit=65535
=> ctrlData OUT
=> dispatchPkt token=512 pipe=0 nak_limit=65535
– Wrote data: 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x64, 0x72, 0x69, 0x76, 0x65, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x66, 0x6f, 0x6c, 0x64, 0x65, 0x72, 0x76, 0x69, 0x65, 0x77, 0x3f, 0x69, 0x64, 0x3d, 0x30, 0x42, 0x5f, 0x4d, 0x44, 0x6d, 0x35, 0x61, 0x48, 0x49, 0x5a, 0x52, 0x30, 0x55, 0x30, 0x64, 0x59, 0x63, 0x6d, 0x74, 0x43, 0x57, 0x47, 0x70, 0x78,
=> dispatchPkt token=512 pipe=0 nak_limit=65535
– Wrote data: 0x4e, 0x33, 0x4d, 0x26, 0x75, 0x73, 0x70, 0x3d, 0x73, 0x68, 0x61, 0x72, 0x69, 0x6e, 0x67, 0x2f, 0x63, 0x68, 0x72, 0x6f, 0x6e, 0x6f, 0x6c, 0x6f, 0x67, 0x67, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x6b, 0x00,
=> dispatchPkt token=256 pipe=0 nak_limit=65535
=> ctrlReq
=> SetAddress deviceEP=0 configued as hostPIPE=0 sending to address=1
=> dispatchPkt token=0 pipe=0 nak_limit=65535
=> ctrlData OUT
=> dispatchPkt token=512 pipe=0 nak_limit=65535
– Wrote data: 0x31, 0x00,
=> dispatchPkt token=256 pipe=0 nak_limit=65535
=> ctrlReq
=> SetAddress deviceEP=0 configued as hostPIPE=0 sending to address=1
=> dispatchPkt token=0 pipe=0 nak_limit=65535
=> dispatchPkt token=256 pipe=0 nak_limit=65535
ADK::Init Accessory mode switch attempt : error code: 4294967295
/!\ USBHost::Task : USB_STATE_CONFIGURING failed with code: 4294967295
+ USB_DETACHED_SUBSTATE_INITIALIZE
+ USB_ATTACHED_SUBSTATE_SETTLE
+ USB_ATTACHED_SUBSTATE_RESET_DEVICE
+ USB_ATTACHED_SUBSTATE_WAIT_RESET_COMPLETE
+ USB_ATTACHED_SUBSTATE_WAIT_SOF
+ USB_STATE_CONFIGURING
ADK::Init
=> ctrlReq
=> SetAddress deviceEP=0 configued as hostPIPE=0 sending to address=0
=> dispatchPkt token=0 pipe=0 nak_limit=65535
=> ctrlData IN
=> dispatchPkt token=256 pipe=0 nak_limit=65535
– Received data: 0x12, 0x01, 0x10, 0x02, 0x00, 0x00, 0x00, 0x40, 0xd1, 0x18, 0x01, 0x2d, 0x32, 0x02, 0x01, 0x02, 0x03, 0x01,
=> dispatchPkt token=512 pipe=0 nak_limit=65535
=> USBHost::setAddr
=> ctrlReq
=> SetAddress deviceEP=0 configued as hostPIPE=0 sending to address=0
=> dispatchPkt token=0 pipe=0 nak_limit=0
=> dispatchPkt token=256 pipe=0 nak_limit=0
ADK::Init : device address is now 1
ADK::Init : Accessory mode device detected
ADK::Init : number of configuration is 1
=> ctrlReq
=> SetAddress deviceEP=0 configued as hostPIPE=0 sending to address=1
=> dispatchPkt token=0 pipe=0 nak_limit=65535
=> ctrlData IN
=> dispatchPkt token=256 pipe=0 nak_limit=65535
– Received data: 0x09, 0x02, 0x37, 0x00, 0x02, 0x01, 0x00, 0xc0,
=> dispatchPkt token=512 pipe=0 nak_limit=65535
=> ctrlReq
=> SetAddress deviceEP=0 configued as hostPIPE=0 sending to address=1
=> dispatchPkt token=0 pipe=0 nak_limit=65535
=> ctrlData IN
=> dispatchPkt token=256 pipe=0 nak_limit=65535
– Received data: 0x09, 0x02, 0x37, 0x00, 0x02, 0x01, 0x00, 0xc0, 0x30, 0x09, 0x04, 0x00, 0x00, 0x02, 0xff, 0xff, 0x00, 0x05, 0x07, 0x05, 0x81, 0x02, 0x00, 0x02, 0x00, 0x07, 0x05, 0x02, 0x02, 0x00, 0x02, 0x00, 0x09, 0x04, 0x01, 0x00, 0x02, 0xff, 0x42, 0x01, 0x00, 0x07, 0x05, 0x82, 0x02, 0x00, 0x02, 0x00, 0x07, 0x05, 0x03, 0x02, 0x00, 0x02, 0x00, 0xff, 0x4f, 0x0d, 0x00, 0x00, 0x38, 0x7f, 0x08, 0x20,
ADK::EndpointXtract : Found new endpoint
ADK::EndpointXtract : deviceEpNum: 1
ADK::EndpointXtract : maxPktSize: 512
ADK::EndpointXtract : index: 1
ADK::EndpointXtract : Found new endpoint
ADK::EndpointXtract : deviceEpNum: 2
ADK::EndpointXtract : maxPktSize: 512
ADK::EndpointXtract : index: 2
=> dispatchPkt token=512 pipe=0 nak_limit=65535
=> ctrlReq
=> SetAddress deviceEP=0 configued as hostPIPE=0 sending to address=1
=> dispatchPkt token=0 pipe=0 nak_limit=65535
=> dispatchPkt token=256 pipe=0 nak_limit=65535
ADK::Init : ADK device configured successfully
USBHost::Configuring : found device class!
+ USB_STATE_RUNNING
=> SetAddress deviceEP=2 configued as hostPIPE=2 sending to address=1
=> dispatchPkt token=512 pipe=2 nak_limit=1
=> dispatchPkt: NAK limit reached!
– Wrote data: 0x01,
=> SetAddress deviceEP=2 configued as hostPIPE=2 sending to address=1
=> dispatchPkt token=512 pipe=2 nak_limit=1
=> dispatchPkt: NAK limit reached!
– Wrote data: 0x02,
=> SetAddress deviceEP=2 configued as hostPIPE=2 sending to address=1
=> dispatchPkt token=512 pipe=2 nak_limit=1
=> dispatchPkt: NAK limit reached!
– Wrote data: 0x04,
I slighty modified the usb.cpp source code adding some additional tracing info to the log.
My accessory is very simple: it sends out a byte every time anyone of three pushbuttons is pressed, coding the pressed button on different bits of the byte sent (in the previous log the lines following the +USB_STATE_RUNNING are the result of activation of different pushbuttons.
I also noted that only when I connect the Arduino DUE running the accessory sketch to the Galaxy Note 3 the USB Host library generates the following error:
ADK::Init Accessory mode switch attempt : error code: 4294967295
/!\ USBHost::Task : USB_STATE_CONFIGURING failed with code: 4294967295
The behaviour is the same also with other ADK applications, that is the Galaxy Note sends correctly the data out but doesn’t read the data sent by the external accessory.
I spent many hours looking for a solution but until now I was unable to find where the problem is; I don’t have another smartphone with Android 4.3 to verify if the problem is with this version of Android.
I would like to know if someone else has experimented difficulties with the USB Host library and Android 4.3.
Any hint will be appreciated.
The library used by the Due is a very old version of the USB Host library which the Arduino team ported when the Due was first released, so that is not something we are going to fix for now. Btw the source code is available here: https://github.com/arduino/Arduino/tree/ide-1.5.x/libraries/USBHost.
If you still want to use the Due and got a USB Host shield, then please see the following issue: https://github.com/felis/USB_Host_Shield_2.0/issues/76.
Dear Lauszus,
thank you for your answer!
For my application I need to use a Due board because I need more resources and processing power than that available on the UNO; so I will continue my investigations to try to find where the problem is or buy a USB Shield as you suggest.
Thanks againg for your great work and willingness!