Posts

Exchanging data between USB devices and Android phone using Arduino and USB Host shield

CueCat connected to Android phone

CueCat connected to Android phone

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();
}

Connecting CueCat to Android phone - a full setup

Connecting CueCat to Android phone - a full setup


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.

31 comments to Exchanging data between USB devices and Android phone using Arduino and USB Host shield

  • 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.

  • david

    I’m glad to hear that USB mass storage will be coming. I’m sure others are as well. I can’t wait!

  • Bill Thrush

    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?

  • James

    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).

  • James

    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 .

  • mahi

    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

  • mahi

    “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

  • Hans

    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 🙂

  • lila

    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 !

  • lila

    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 🙂

  • Vitaliz

    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.

  • nitesh

    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 ?

  • Mohamad Dani

    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.

  • fradaxx

    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.