Arduino programming - android

I am working on a project for college and I am using android and arduino. The project I am trying to build is a quad copter flight controller in arduino. I have all the necessary equipment for the project but, I've hit a road block with the code I am using. The idea is to have the an android phone control the quad copter and I have a HTTP server on the arduino that can communicate with my phone. The only problem is when I create the required servo motors in the arduino sketch and assign them pins the http server will not run in the setup of the arduino sketch. I have not idea why this is happening and would appreciate any help necessary. Thanks in advance. A copy of my code will be displayed below.
/***************************************************
Adafruit CC3000 Breakout/Shield Simple HTTP Server
This is a simple implementation of a bare bones
HTTP server that can respond to very simple requests.
Note that this server is not meant to handle high
load, concurrent connections, SSL, etc. A 16mhz Arduino
with 2K of memory can only handle so much complexity!
This server example is best for very simple status messages
or REST APIs.
See the CC3000 tutorial on Adafruit's learning system
for more information on setting up and using the
CC3000:
http://learn.adafruit.com/adafruit-cc3000-wifi
Requirements:
This sketch requires the Adafruit CC3000 library. You can
download the library from:
https://github.com/adafruit/Adafruit_CC3000_Library
For information on installing libraries in the Arduino IDE
see this page:
http://arduino.cc/en/Guide/Libraries
Usage:
Update the SSID and, if necessary, the CC3000 hardware pin
information below, then run the sketch and check the
output of the serial port. After connecting to the
wireless network successfully the sketch will output
the IP address of the server and start listening for
connections. Once listening for connections, connect
to the server IP from a web browser. For example if your
server is listening on IP 192.168.1.130 you would access
http://192.168.1.130/ from your web browser.
Created by Tony DiCola and adapted from HTTP server code created by Eric Friedrich.
This code was adapted from Adafruit CC3000 library example
code which has the following license:
Designed specifically to work with the Adafruit WiFi products:
----> https://www.adafruit.com/products/1469
Adafruit invests time and resources providing this open source code,
please support Adafruit and open-source hardware by purchasing
products from Adafruit!
Written by Limor Fried & Kevin Townsend for Adafruit Industries.
BSD license, all text above must be included in any redistribution
****************************************************/
#include <Adafruit_CC3000.h>
#include <Adafruit_VC0706.h>
#include <SoftwareSerial.h>
#include <SPI.h>
#include "utility/debug.h"
#include "utility/socket.h"
#include <Servo.h>
// These are the interrupt and control pins
#define ADAFRUIT_CC3000_IRQ 3 // MUST be an interrupt pin!
// These can be any two pins
#define ADAFRUIT_CC3000_VBAT 5
#define ADAFRUIT_CC3000_CS 10
// Use hardware SPI for the remaining pins
// On an UNO, SCK = 13, MISO = 12, and MOSI = 11
Adafruit_CC3000 cc3000 = Adafruit_CC3000(ADAFRUIT_CC3000_CS, ADAFRUIT_CC3000_IRQ, ADAFRUIT_CC3000_VBAT,
SPI_CLOCK_DIVIDER); // you can change this clock speed
#define WLAN_SSID "AndroidAP" // cannot be longer than 32 characters!
#define WLAN_PASS "tyhv5688"
// Security can be WLAN_SEC_UNSEC, WLAN_SEC_WEP, WLAN_SEC_WPA or WLAN_SEC_WPA2
#define WLAN_SECURITY WLAN_SEC_WPA2
#define LISTEN_PORT 80 // What TCP port to listen on for connections.
// The HTTP protocol uses port 80 by default.
#define MAX_ACTION 10 // Maximum length of the HTTP action that can be parsed.
#define MAX_PATH 64 // Maximum length of the HTTP request path that can be parsed.
// There isn't much memory available so keep this short!
#define BUFFER_SIZE MAX_ACTION + MAX_PATH + 20 // Size of buffer for incoming request data.
// Since only the first line is parsed this
// needs to be as large as the maximum action
// and path plus a little for whitespace and
// HTTP version.
#define TIMEOUT_MS 500 // Amount of time in milliseconds to wait for
// an incoming request to finish. Don't set this
// too high or your server could be slow to respond.
Adafruit_CC3000_Server httpServer(LISTEN_PORT);
Servo m1, m2, m3, m4;
uint8_t buffer[BUFFER_SIZE+1];
int bufindex = 0;
char action[MAX_ACTION+1];
char path[MAX_PATH+1];
int speed = 0;
void setup(void)
{
// Give name to robot
Serial.begin(9600);
Serial.println(F("\nHello, CC3000!\n"));
Serial.print("Free RAM: "); Serial.println(getFreeRam(), DEC);
// Initialise the module
Serial.println(F("\nInitializing..."));
m1.attach(5);
m2.attach(9);
m3.attach(10);
m4.attach(11);
if (!cc3000.begin())
{
Serial.println(F("Couldn't begin()! Check your wiring?"));
while(1);
}
Serial.print(F("\nAttempting to connect to ")); Serial.println(WLAN_SSID);
if (!cc3000.connectToAP(WLAN_SSID, WLAN_PASS, WLAN_SECURITY)) {
Serial.println(F("Failed!"));
while(1);
}
Serial.println(F("Connected!"));
Serial.println(F("Request DHCP"));
while (!cc3000.checkDHCP())
{
delay(100); // ToDo: Insert a DHCP timeout!
}
// Display the IP address DNS, Gateway, etc.
while (! displayConnectionDetails()) {
delay(1000);
}
// Start listening for connections
httpServer.begin();
Serial.println(F("Listening for connections..."));
}
void loop(void)
{
// Try to get a client which is connected.
Adafruit_CC3000_ClientRef client = httpServer.available();
if (client) {
Serial.println(F("Client connected."));
// Process this request until it completes or times out.
// Note that this is explicitly limited to handling one request at a time!
// Clear the incoming data buffer and point to the beginning of it.
bufindex = 0;
memset(&buffer, 0, sizeof(buffer));
// Clear action and path strings.
memset(&action, 0, sizeof(action));
memset(&path, 0, sizeof(path));
// Set a timeout for reading all the incoming data.
unsigned long endtime = millis() + TIMEOUT_MS;
// Read all the incoming data until it can be parsed or the timeout expires.
bool parsed = false;
while (!parsed && (millis() < endtime) && (bufindex < BUFFER_SIZE)) {
if (client.available()) {
buffer[bufindex++] = client.read();
}
parsed = parseRequest(buffer, bufindex, action, path);
}
// Handle the request if it was parsed.
if (parsed) {
Serial.println(F("Processing request"));
Serial.print(F("Action: ")); Serial.println(action);
Serial.print(F("Path: ")); Serial.println(path);
// Check the action to see if it was a GET request.
if (strcmp(action, "GET") == 0) {
// Respond with the path that was accessed.
// First send the success response code.
client.fastrprintln(F("HTTP/1.1 200 OK"));
// Then send a few headers to identify the type of data returned and that
// the connection will not be held open.
client.fastrprintln(F("Content-Type: text/plain"));
client.fastrprintln(F("Connection: close"));
client.fastrprintln(F("Server: Adafruit CC3000"));
// Send an empty line to signal start of body.
client.fastrprintln(F(""));
// Now send the response data.
client.fastrprintln(F("Connected"));
}
else if (strcmp(action, "POST") == 0) {
bool start = true;
startMotors(start);
client.fastrprintln(F("HTTP/1.1 200 OK"));
// Then send a few headers to identify the type of data returned and that
// the connection will not be held open.
client.fastrprintln(F("Content-Type: text/plain"));
client.fastrprintln(F("Connection: close"));
client.fastrprintln(F("Server: Adafruit CC3000"));
// Send an empty line to signal start of body.
client.fastrprintln(F(""));
// Now send the response data.
client.fastrprintln(F("Motors are starting"));
}
else {
// Unsupported action, respond with an HTTP 405 method not allowed error.
client.fastrprintln(F("HTTP/1.1 405 Method Not Allowed"));
}
}
// Wait a short period to make sure the response had time to send before
// the connection is closed (the CC3000 sends data asyncronously).
delay(100);
}
client.close();
}
void startMotors(bool start)
{
if(start == true)
{
for (speed = 0; speed<60; speed++)
{
m1.write(speed);
m2.write(speed);
m3.write(speed);
m4.write(speed);
}
}
}
// Return true if the buffer contains an HTTP request. Also returns the request
// path and action strings if the request was parsed. This does not attempt to
// parse any HTTP headers because there really isn't enough memory to process
// them all.
// HTTP request looks like:
// [method] [path] [version] \r\n
// Header_key_1: Header_value_1 \r\n
// ...
// Header_key_n: Header_value_n \r\n
// \r\n
bool parseRequest(uint8_t* buf, int bufSize, char* action, char* path) {
// Check if the request ends with \r\n to signal end of first line.
if (bufSize < 2)
return false;
if (buf[bufSize-2] == '\r' && buf[bufSize-1] == '\n') {
parseFirstLine((char*)buf, action, path);
return true;
}
return false;
}
// Parse the action and path from the first line of an HTTP request.
void parseFirstLine(char* line, char* action, char* path) {
// Parse first word up to whitespace as action.
char* lineaction = strtok(line, " ");
if (lineaction != NULL)
strncpy(action, lineaction, MAX_ACTION);
// Parse second word up to whitespace as path.
char* linepath = strtok(NULL, " ");
if (linepath != NULL)
strncpy(path, linepath, MAX_PATH);
}
// Tries to read the IP address and other connection details
bool displayConnectionDetails(void)
{
uint32_t ipAddress, netmask, gateway, dhcpserv, dnsserv;
if(!cc3000.getIPAddress(&ipAddress, &netmask, &gateway, &dhcpserv, &dnsserv))
{
Serial.println(F("Unable to retrieve the IP Address!\r\n"));
return false;
}
else
{
Serial.print(F("\nIP Addr: ")); cc3000.printIPdotsRev(ipAddress);
Serial.print(F("\nNetmask: ")); cc3000.printIPdotsRev(netmask);
Serial.print(F("\nGateway: ")); cc3000.printIPdotsRev(gateway);
Serial.print(F("\nDHCPsrv: ")); cc3000.printIPdotsRev(dhcpserv);
Serial.print(F("\nDNSserv: ")); cc3000.printIPdotsRev(dnsserv);
Serial.println();
return true;
}
}

I 'm not sure of this, but it would seem that you are trying to use pins 5 and 10 both in the motor drivers and the CC3000 shield. You should try to use separate pins for each (e.g. drive the motors with pins 7,8,9,11).

Related

ESP32 BLE and Android phone(s) - presence detection

Is there a possibility how to "overcome" BLE MAC address randomization and detect presence of my own Android phone(s)?
I'm looking for a solution how to detect presence of my phone in close-range to ESP32 without installing something like iBeacon app which would drain my battery.
I've started with example for BLE sniffer which works nice but with MAC randomization on Android it is useless.
Then I moved to the solution using emulation of a HID keyboard. After pairing it, it is nicely reconnecting when the phone comes into the range. Once it is connected I can trigger needed action and then I can turn ESP32 Bluetooth off not to be connected whole time. When I need check the phone again I just can turn the server back on. It would be neat solution but... I need to check more (at least two) phones. I've tried to duplicate BLEServers to swith between or run two simoutinasly but without success - either it is not possible or it is exceeding my knowladge about this BLE advertising/pairing/connecting magic.
Third solution would be to have separate ESP for each phone - doable but only as a last resort
Has somebody solved such task somehow already?
For the keyboard solution I'm using this code found online:
#include <Arduino.h>
#include <BLEDevice.h>
#include <BLEUtils.h>
#include <BLEServer.h>
#include "BLE2902.h"
#include "BLEHIDDevice.h"
#include "HIDTypes.h"
#include "HIDKeyboardTypes.h"
#include <driver/adc.h>
BLEHIDDevice* hid;
BLECharacteristic* input;
BLECharacteristic* output;
BLEAdvertising *pAdvertising;
BLEServer *pServer;
bool connected = false;
bool restart = false;
class MyCallbacks : public BLEServerCallbacks {
void onConnect(BLEServer* pServer){
connected = true;
Serial.println("Connected");
BLE2902* desc = (BLE2902*)input->getDescriptorByUUID(BLEUUID((uint16_t)0x2902));
desc->setNotifications(true);
// NEEDED ACTIONS
}
void onDisconnect(BLEServer* pServer){
connected = false;
Serial.println("DisConnected");
BLE2902* desc = (BLE2902*)input->getDescriptorByUUID(BLEUUID((uint16_t)0x2902));
desc->setNotifications(false);
restart = true;
}
};
void setup() {
Serial.begin(115200);
Serial.println("Starting BLE work!");
BLEDevice::init("Backpack-MeowMeow");
pServer = BLEDevice::createServer();
pServer->setCallbacks(new MyCallbacks());
pServer->getPeerDevices(true);
hid = new BLEHIDDevice(pServer);
input = hid->inputReport(1); // <-- input REPORTID from report map
output = hid->outputReport(1); // <-- output REPORTID from report map
std::string name = "ElectronicCats";
hid->manufacturer()->setValue(name);
hid->pnp(0x02, 0xe502, 0xa111, 0x0210);
hid->hidInfo(0x00,0x02);
BLESecurity *pSecurity = new BLESecurity();
// pSecurity->setKeySize();
pSecurity->setAuthenticationMode(ESP_LE_AUTH_BOND);
hid->startServices();
pAdvertising = pServer->getAdvertising();
pAdvertising->setAppearance(HID_BARCODE);
pAdvertising->addServiceUUID(hid->hidService()->getUUID());
pAdvertising->start();
hid->setBatteryLevel(7);
//ESP_LOGD(LOG_TAG, "Advertising started!");
//delay(portMAX_DELAY);
}
void loop() {
if(connected){
delay(10);
}
if (restart) {
restart = false;
pAdvertising->start();
}
delay(50);
}

TCP client for Android: text is not received in full

I am converting a Java desktop project to Android. Part of it includes a TCP connection to a server and parsing a long text from the server to the client (the Android application). This is the code that I have for the desktop project that I also try to use in Android:
// Method is called when a button is tapped
public void tapButton() {
// Create a message to the server that requests for the Departure navdata
String messageToServer = someMethodToMakeHandshakeMessage();
// Connect to the server
if (!messageToServer.equals("")) {
String finalMessageToServer = messageToServer;
new Thread(() -> {
String navdata = connectClient(finalMessageToServer);
getActivity().runOnUiThread(() -> messageReceived(navdata));
// I am also using messageReceived(navdata) without runOnUiThread with the same result
}).start();
}
}
public String connectClient(String messageOut) {
Socket socket = null;
DataInputStream input = null;
DataOutputStream output = null;
BufferedReader br = null;
// Final message from the server
String data = "";
// Message from the server that should terminate TCP connection
String terminator = "END_DATA";
try {
// Create socket and streams
socket = new Socket(someIPAddress, somePort);
input = new DataInputStream(socket.getInputStream());
output = new DataOutputStream(socket.getOutputStream());
//Send message to the server
output.writeBytes(messageOut);
//Read Response
br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
StringBuilder sb = new StringBuilder();
String s = "";
int value = 0;
// Process the message from the server and add to the StringBuilder
while((value = br.read()) != -1) {
// converts int to character
char c = (char)value;
sb.append(c);
if(sb.toString().contains(terminator)) {
break;
}
}
// Create the final string
data = sb.toString();
}
catch (UnknownHostException e) {
// Dealing with exception
}
catch (EOFException e) {
// Dealing with exception
}
catch (IOException e) {
// Dealing with exception
}
finally {
try {
if(socket!=null) { socket.close();}
if(input != null) { input.close();}
if(output != null) { output.close();}
if(br != null) { br.close();}
}
catch (IOException ex) {
// Dealing with exception
}
socket = null;
input = null;
output = null;
br = null;
}
return data;
}
public void messageReceived(String message) {
// Method to deal with received data
}
Whereas the code works fine in the desktop Java application, I have problems with Android (using an emulator). The text is not sent in full length and is cut somewhere in the middle (only 20-50% received by the client; the number of parsed characters differs all the time). Besides, I have noticed that it is taking too long to connect to the server, but, I guess, this is due to working with an emulator.
Should a TCP client receiving long texts from the server be implemented in Android somewhat differently?
EDIT: Implemented the following code using a suggestion by #blackapps:
String line = br.readLine();
while (line != null) {
sb.append(line);
line = br.readLine();
if (line.trim().isEmpty()) {
Log.i("EMPTY LINE>>>>>>>>>>>>>>>>>",line);
}
if(line.equals(terminator)) {
break;
}
}
// Create the final string
data = sb.toString();
}
Two issues. I would like to keep the empty lines in the received text. The terminator is not detected. I think, it is separated from the main text with two empty lines. However, after the first empty line, it goes to indefinite loop and connection never terminated.
EDIT #2.
After having spent several hours trying to figure out what is going on, making changes to the server, and comparing the number of bytes sent and received, I have noticed that this is not the problem with the code. It appears that the client receives the full text. The problem is with how the text is written in the console using the Log.i(String, String) method. I have added the good old System.out.println() in the code, and the whole text was shown in the console. However, the text from Log.i() was cut off in the middle. As this is my first experience with Android Studio, what the heck is going on?
Thanks a lot!
Let talk about TCP socket first.
When talking about TCP socket, it's a stream of data.
TCP views data as an unstructured, but ordered, stream of bytes. It's different from the kinds of socket.io.
From time to time, TCP will grab chunks of data from the send buffer and pass the data to the network layer. The maximum amount of data that can be grabbed and placed in a segment is limited by the maximum segment size (MSS). The MSS is typically set by first determining the length of the largest link-layer frame.
So it depends on the device.
For example, you have two messages, each of them has 1000 bytes data, and you call:
-------------- client side ----------------
client.send(theFirstMessage) // 1000 bytes
client.send(theSecondMessage) // 1000 bytes
-------------- server side -----------------
socket.onReceived(data => {
// process(data)
})
With above pseudocode you should note that:
The data which received and called on onReceived block couldn't be 1000 bytes of theFirstMessage.
It could be first 400 bytes, then on other event you receive 400 bytes, then more 400 bytes (200 of the first one and 200 of the second one).
It could be 1200 bytes (1000 of the first one and 200 of the second one).
TCP views data as an unstructured, but ordered, stream of bytes. Socket.io is a wrapper, when it uses TCP socket, it collect and combine/split the data for you, so that you received the events with exactly the data was sent from other side.
When you work with TCP, you have to do it your self, you have to define the application protocol to do it.
There're two common ways to send/receive TCP requests:
Splitter, you choose a splitter. For example, we choose 32 bits AABBCCDD as the splitter (same as you choose END_DATA string), but keep in mind it's binary data. Then you have to ensure that the data in request doesn't contains the splitter. To do that, you have to encode the request. For example we can encode request as base64, then use the character which isn't included in base64 table as the splitter.
Prefix length, the above method has its overhead as we have to encode request data. The prefix length method is a better choice.
We can prefix the length of request before.
The pseudocode:
// use Int32, 4 bytes to indicate the length of message after it
-------------- client side ----------------
client.send(theFirstMessage.length) // Int32
client.send(theFirstMessage) // 1000 bytes
client.send(theSecondMessage.length)
client.send(theSecondMessage) // 1000 bytes
-------------- server side -----------------
var buffer = Buffer()
socket.onReceived(data => {
buffer.append(data)
let length = Int32(buffer[0...3])
if (buffer.length >= length + 4) {
let theRequest = buffer[4 ... 4 + length - 1]
process(theRequest)
buffer = buffer.dropFirst(4 + length)
}
})
One more thing, when working with TCP socket, it's just stream of bytes, so the endianness is important https://en.wikipedia.org/wiki/Endianness
For example, an android device is little endian and server side (or other android device) is big endian. Then 4 bytes of Int32 from the android device, when received on server side, it will be decoded wrongly if you don't care about it.
So, the prefix length should be encoded by specific endianness.

How to detect if a device get my phone bluetooth name?

I'm using a bluetooth modul (HC-05) to detect if an android phone is in the modul's range.
I tried to connect with HC-05 (as master) and a PIC16f887 to the phone, but I can't. Searched many pages on net how to use HC-05 as master, but no solution.
So, finally I could do this by modul get my phone's BT name. If it could, my phone is in range.
But now I want my phone to detect this "remote name query" and play some sound then.
Sorry for my poor english :)
Im guessing you want something like this: VIDEO
Lets start with the basics:
The typical default factory settings for a new Bluetooth HC-05 module are:
Default Bluetooth Name: “HC-05”
Default Password: 1234 or 0000
Default Communication: Slave Device
Default Mode: Data Mode
Default Data Mode Baud Rate: 9600, 8, N, 1
Default Command Mode Baud Rate: 38400, 8, N, 1
Default firmware: LINVOR
1. To TEST Bluetooth connections from your android device use id suggest you use this APK
2. Connect the HC-05 BT module as shown in the diagram
3. Initialize the UART receiver at the microcontroller end (side)
(code includes 2 leds for pin 33 and pin 34)
/*
* LAB Number: 17
* LAB Name: Bluetooth Module HC-05 Interfacing (Smartphone -> MCU)
* Author: Khaled Magdy
* For More Information Visit My Website # DeepBlueMbedded.com
*
*/
#include <xc.h>
#include <stdint.h>
#include "config.h"
#define _XTAL_FREQ 4000000
//--[ Control Data ]--
#define Blue_LED_ON 49
#define Blue_LED_OFF 50
#define Yellow_Toggle 51
//--------------------------------
// Functions Declarations
void UART_RX_Init(void);
// Globals
uint8_t UART_Buffer = 0;
//--------------------------------
// Main Routine
void main(void)
{
//--[ Peripherals & IO Configurations ]--
UART_RX_Init(); // Initialize The UART in Master Mode # 9600bps
TRISB0 = 0; // Blue LED (Switch)
TRISB1 = 0; // Yellow LED (Toggle)
RB0 = 0; // Initially OFF
RB1 = 0; // Initially OFF
//---------------------------
while(1)
{
}
return;
}
//--------------------------------
// Functions Definitions
void UART_RX_Init()
{
BRGH = 1; // Set For High-Speed Baud Rate
SPBRG = 25; // Set The Baud Rate To Be 9600 bps
// Enable The Ascynchronous Serial Port
SYNC = 0;
SPEN = 1;
// Set The RX-TX Pins to be in UART mode (not io)
TRISC6 = 1; // As stated in the datasheet
TRISC7 = 1; // As stated in the datasheet
//--[ Enable UART Receiving Interrupts ]--
RCIE = 1; // UART Receving Interrupt Enable Bit
PEIE = 1; // Peripherals Interrupt Enable Bit
GIE = 1; // Global Interrupt Enable Bit
//------------------
CREN = 1; // Enable Data Continous Reception
}
void interrupt ISR (void)
{
if (RCIF == 1)
{
UART_Buffer = RCREG; // Read The Received Data Buffer
// This could have been done within the main loop. Since it's not
// Excessive processing, so it's OK to do it here below
if(UART_Buffer == Blue_LED_ON)
RB0 = 1; // Blue LED ON
if(UART_Buffer == Blue_LED_OFF)
RB0 = 0; // Blue LED OFF
if(UART_Buffer == Yellow_Toggle)
RB1 = ~RB1; // Toggle Yellow LED
RCIF = 0; // Clear The Interrupt Flag
}
}
NOTE The Data Bytes (49, 50, and 51) are the ASCII equivalents for the numeric characters (1, 2, and 3 respectively).
4. Download this apk to send commands to your HC05: APK
For more info follow Reference: LINK

Arduino Mega ADK strange acc.write() behavior (huge delay) NAK issue seemd to be confirmed. Android generates NAK's as a result of acc.write

I'm trying to communicate between Arduino Mega Adk (ADK 2011) and android device.
Something goes ok, but something goes completely wrong.
Transfer data from Android to Arduino via acc.read from Arduino side works fine.
But when i try to send some bytes from Arduino to Android - something strange happens.
First of all here is Arduino sketch:
#include <Max3421e_constants.h>
#include <Max3421e.h>
#include <Usb.h>
#include <AndroidAccessory.h>
#define COMMAND_LED 0x2
#define TARGET_PIN_18 0x12
#define TARGET_PIN_19 0x13
#define V_ON 0x1
#define V_OFF 0x0
#define PIN_18 18
#define PIN_19 19
#define INPUT_PIN 30
AndroidAccessory acc("Google, Inc.",
"DemoKit",
"Ololo device board",
"1.0",
"http://www.android.com",
"0000000012345678");
byte rcvmsg[3];
byte sndmsg[3];
int buttonState = 0;
void setup();
void loop();
void led_setup(){
pinMode(PIN_18, OUTPUT);
pinMode(PIN_19, OUTPUT);
pinMode(INPUT_PIN, INPUT);
}
void setup()
{
Serial.begin(115200);
Serial.print("\r\nStart");
led_setup();
acc.powerOn();
}
void loop()
{
if (acc.isConnected()) {
buttonState = digitalRead(INPUT_PIN);
if (buttonState == 1){
sndmsg[0] = 0x2;
sndmsg[1] = 0x1;
sndmsg[2] = 0x1;
int len = acc.write(sndmsg, 3);
digitalWrite(PIN_19, HIGH);
}
else {
//Nothing here for test
}
}
//usefull test for button
buttonState = digitalRead(INPUT_PIN);
if (buttonState == 1){
digitalWrite(PIN_19, HIGH);
}
else {
digitalWrite(PIN_19, LOW);
}
}
Ok. When acc.write() is executed it takes up to ~1 second to transfer data to android. And this time doesn't depend on number of bytes in sndmsg. Only if i execute acc.write(sndmsg,0) (sending 0 bytes) - everything goes fast.
That is a little bit disturbing. I've tried to change board to another one but have got the same result.
Any advices? may be that is a common bug, but there is no such much information in web.
UPD:
Wrote some very simple code, that only sends 3 bytes via acc.write.
here it is:
#include <Max3421e_constants.h>
#include <Max3421e.h>
#include <Usb.h>
#include <AndroidAccessory.h>
AndroidAccessory acc("Google, Inc.",
"DemoKit",
"Demokit board",
"1.0",
"http://www.android.com",
"0000000012345678");
byte msg[3];
unsigned long time;
void setup();
void loop();
void led_setup(){
}
void setup()
{
Serial.begin(115200);
Serial.print("\r\nStart");
acc.powerOn();
}
void loop()
{
if (acc.isConnected()) {
Serial.print("\r\nis Connected");
msg[0] = 0x1;
msg[1] = 0x1;
msg[2] = 0x1;
//Serial.print("\r\nSending");
time = millis();
Serial.print ("\r\nBefore write\r\n");
Serial.print (time);
acc.write(msg, 3);
time = millis();
Serial.print("\r\nAfter write: \r\n");
Serial.print (time);
//delay(500);
}
}
And it's debug output is:
is Connected
Before write
6983
After write:
10958
is Connected
Before write
10958
After write:
14491
is Connected
and so on. So on some reasons acc.write takes a lot of time and there is no data in the android app.
New UPD (19.01.2015):
Today i've performed some experiments. Here are results.
First, i've looked into AndroidAccessory.cpp and found write function:
int AndroidAccessory::write(void *buff, int len)
{
usb.outTransfer(1, out, len, (char *)buff);
return len;
}
Ok, then i looked into usb host shield library and found there usb.cpp with outTransfer fucntion, that returns error code if ouccured and 0x00 if everything is ok.
So i modified write function to return an error code instead of lenght, like this:
int AndroidAccessory::write(void *buff, int len)
{
byte rcode;
rcode = usb.outTransfer(1, out, len, (char *)buff);
return int(rcode);
}
and recived "4" as result.
According to MAX3421Econstants.h it is hrNAK (0x04) error code.
Any ideas? Looks like accessory does not recive NAKs from Android and write fails as a result.
Situation update:
Did some research. There is a hell of NAK's when accessory is connected. Here is dump from usb connector:
i found the solution. And it is very simple - i didn't setup communication with accessory correctly.
This is not an Arduino problem. Arduino works fine.
It is just how android interacts with android accessory.
So, results:
When AndroidAccessory is plugged to Android and Android haven't setup
communication with the accessory yet, Android OS will send a lot of
USB NAKs to the accessory and this is normal.
You must be careful
during setuping communication with the accessory. If you make some
mistakes, you can receive same situation: Probably possible to write
to the accessory, but accessory isn't possible to write to the
android.
If UsbManager opens accessory correctly, it stops sending
NAKs and starts recieve data from arduino.
It is a little bit strange for me, because it was really hard to found a problem: i have an application, written according to this manual: http://developer.android.com/guide/topics/connectivity/usb/accessory.html But, because i'm not very familiar with android, it seems that i've done some mistakes and receive strange behavior:
i was able to write to arduino
i was able to retrive information about arduino as android accessory
it was possible to ask for permissions
but when arduino tries to write to android, it recievs a lot of NAKs
So i decided to rewrite program in more simple way, just with one function and tried to do it in right way. And after some debugging it finally started to work as i want.
So thank everyone, who spend time for reading this.
Bonus: dump of normal packet, ended with EOP not NAK
UPD 26.01.2015:
I found problem and it was in my android code.
here is explanation:
Android developer's manual said that function, which set up communication with accessory must start it's own thread in which all communications with input and output streams are held. Smth like this:
private void openAccessory() {
Log.d(TAG, "openAccessory: " + accessory);
mFileDescriptor = mUsbManager.openAccessory(mAccessory);
if (mFileDescriptor != null) {
FileDescriptor fd = mFileDescriptor.getFileDescriptor();
mInputStream = new FileInputStream(fd);
mOutputStream = new FileOutputStream(fd);
Thread thread = new Thread(null, this, "AccessoryThread");
thread.start();
}
}
I really messed this thing up. Forgot about creating new thread in openAccessory function and tried to do it in different place. And recieve a hell of NAK's. Then i've changed my code and add some debug-like run() function like this:
public void run() {
final byte[] buffer = new byte[16384];
int ret = 0;
int i = 0;
while (i<50) {
try {
ret = mInputStream.read(buffer);
i++;
Thread.sleep(500);
} catch (IOException e) {
break;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
And until this run method exists (while i < 50) android reads arduino correctly. And when thread ends up (i > 50) - Arduino starts to readout Error Code 4 (NAK) from Android.
That's all folks.

control a servo with android and arduino

I'm trying to control a servo with an android phone and an arduino via bluetooth but the data in the arduino is received as a char, and the arduino doesn't know when all the data is received and the servo don't move properly. The arduino code is this:
#include
Servo myservo;
char val; // variable to receive data from the serial port
int ledpin = 13; // LED connected to pin 48 (on-board LED)
void setup() {
pinMode(ledpin, OUTPUT); // pin 48 (on-board LED) as OUTPUT
Serial.begin(9600); // start serial communication at 9600bps
myservo.attach(9);
}
void loop() {
if( Serial.available() ) // if data is available to read
{
val = Serial.read(); // read it and store it in 'val'
}
if( val - 0 >= 0 && val - 0 <= 180){
}
// Serial.print("Recibido");
delay(100); // wait 100ms for next reading
}
What can I do to get the correct value from "val" to control the servo?
You can send multiple chars if you need them. Simple store each new char into an array and program your android program to send a specific byte that indicates the ending of the val reading.
Checking this "ending" byte each time you perform a read from serial will tell you if this char is to store or to convert the previous stored chars into an integer or whatever data type you need it.
Than simply converting that array will tell you the correct val.

Categories

Resources