Sunday, July 13, 2014

Socket Server to transfer Accelerometer Sensor data to PC

Hi Guys,

Recently, I have been trying to get the accelerometer data on PC in real time. Here is how to make it work.

The idea basically is to create a socket server in the Android device and a socket client in local PC to transfer data over wifi. Now lets create a socket server in the Android device which transmits the linear acceleration data.

Create an android Project in Eclipse:
package com.example.myserver;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import android.app.Activity;
import android.content.Context;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.widget.TextView;

public class MainActivity extends Activity implements SensorEventListener {
    String mClientMsg = "";
    Thread myCommsThread = null;
    public static final String TAG = "SocketServer";
    private CommsThread commsThread = null;
    TextView tv;
    PrintWriter out;
    private float ax, ay, az;
    private long timenow = 0, timeprev = 0, timestamp =0 ;

    private SensorManager sm;
    private Sensor sensor;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        tv = (TextView) findViewById(R.id.textView1);
        sm = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
        sensor = sm.getSensorList(Sensor.TYPE_LINEAR_ACCELERATION).get(0);
    }

    @Override
    protected void onResume() {
        // TODO Auto-generated method stub
        super.onResume();
        sm.registerListener(this, sensor, SensorManager.SENSOR_DELAY_UI);
        this.commsThread = new CommsThread();
        this.myCommsThread = new Thread(this.commsThread);
        this.myCommsThread.start();
    }

    @Override
    protected void onPause() {
        // TODO Auto-generated method stub
        super.onPause();
        sm.unregisterListener(this);
        if (commsThread != null) {
            commsThread.stopComms();
        }
    }    

    Handler myHandler = new Handler(){
        public void handleMessage(Message msg){
            TextView status = (TextView) findViewById(R.id.textView3);
            status.setText("Status: Streaming Now!");
        }
    };

    class CommsThread implements Runnable {
        private volatile boolean stopFlag = false;
        private ServerSocket ss = null;
        private static final int SERVERPORT = 6000;
        public void run() {
            Socket s = null;
            try {
                ss = new ServerSocket(SERVERPORT);
            } catch (IOException e) {
                e.printStackTrace();
            }
            
            try {
                s = ss.accept();
            } catch (IOException e1) {
                // TODO Auto-generated catch block
                e1.printStackTrace();
            }
            myHandler.sendEmptyMessage(0);
            
            while(!stopFlag){
                try {
                    out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(s.getOutputStream())), true);
                    out.printf("*#%3.2f#%3.2f#%3.2f#%2d#*\n",ax,ay,az,(int)timestamp );
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }

        public void stopComms() {
            // TODO Auto-generated method stub
            this.stopFlag = true;
            if(ss != null){
                try {
                    ss.close();
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }         
        }
    }

    @Override
    public void onAccuracyChanged(Sensor arg0, int arg1) {
        // TODO Auto-generated method stub       
    }

    @Override
    public void onSensorChanged(SensorEvent event) {
        // TODO Auto-generated method stub
        ax = event.values[0];
        ay = event.values[1];
        az = event.values[2];
        timenow = event.timestamp;
        timestamp = (timenow - timeprev)/1000000;
        refreshDisplay();
    }

    private void refreshDisplay() {
        // TODO Auto-generated method stub
        String output = String.format("time: %d -- x:%03.2f | Y:%03.2f | Z:%03.2f", timestamp, ax,ay,az);
        timeprev = timenow;
        tv.setText(output);
    }
}


In the AndroidManifest.xml add the following lines:
    <uses-permission android:maxSdkVersion="19" android:name="android.permission.INTERNET"/>
    <uses-permission android:maxSdkVersion="19" android:name="android.permission.ACCESS_NETWORK_STATE"/>

Now install the socket server on the Android device and launch the program. The server is up and running. It now waits for the client to connect and then transmit the real-time linear acceleration data to the client.

Now lets write a simple client to read the data on Ubuntu PC.

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h> 

void error(const char *msg)
{
    perror(msg);
    exit(0);
}

int main(int argc, char *argv[])
{
    int sockfd, portno, n;
    struct sockaddr_in serv_addr;
    struct hostent *server;

    char buffer[256] = "\0";
    if (argc < 3) {
       fprintf(stderr,"usage %s hostname port\n", argv[0]);
       exit(0);
    }

    portno = atoi(argv[2]);
    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd < 0) 
        error("ERROR opening socket");
    server = gethostbyname(argv[1]);

    if (server == NULL) {
        fprintf(stderr,"ERROR, no such host\n");
        exit(0);
    }

    bzero((char *) &serv_addr, sizeof(serv_addr));
    serv_addr.sin_family = AF_INET;
    bcopy((char *)server->h_addr, 
         (char *)&serv_addr.sin_addr.s_addr,
         server->h_length);
    serv_addr.sin_port = htons(portno);
    if (connect(sockfd,(struct sockaddr *) &serv_addr,sizeof(serv_addr)) < 0) 
        error("ERROR connecting");

    //printf("Please enter the message: ");
    bzero(buffer,256);

    //fgets(buffer,255,stdin);
    n = write(sockfd,buffer,strlen(buffer));
    if (n < 0) 
         error("ERROR writing to socket");
    while(1){
        bzero(buffer,256);
        n = read(sockfd,buffer,255);
        if (n < 0) 
            error("ERROR reading from socket");
        printf("%s\n",buffer);
    }
    close(sockfd);
    return 0;
}



compile the above code using
gcc -o socketclient client.c
To connect to the server over wifi network:
./socketclient 192.168.1.2 6000
to connect to the server via USB cable:
adb forward tcp:1234 tcp:6000
./socketclient localhost 1234
Now the data will be streaming on the Ubuntu PC. I'll try to plot this data in my next blog.

References:
C socket programming:
1. http://www.linuxhowtos.org/C_C++/socket.htm 
USB port forwarding:
2. http://www.anothem.net/archives/2010/02/15/communicating-over-the-usb-cable/
Android Socket Programming:
3. http://thinkandroid.wordpress.com/2010/03/27/incorporating-socket-programming-into-your-applications/
4. http://www.edumobile.org/android/android-development/socket-programming/ 

Sunday, July 6, 2014

adb port forwarding via USB



Here is a way to create a socket connection between Android phone and Ubuntu 14.04 desktop.

Pre-requites:
1. Android Terminal Emulator App (On Android Device)
2. Android SDK installed on host computer

create a socket on the device using nc command:
jai@jai-server:~$ adb shell
shell@mako:/ $ nc -l -p 1234
---//
The above command could be executed on the terminal Emulator as follows:



On the host machine:
jai@jai-server:~$ adb forward tcp:1235 tcp:1234
jai@jai-server:~$ nc localhost 1235
--//
Connection is established and you are good to go. Start writing on any of the device. It should be reflected on other device.

Reference: http://bharathisubramanian.wordpress.com/2012/03/10/android-socket-communication-thru-adb/