Android Open Source - 802.11p-Test-App Sonar Activity






From Project

Back to project page 802.11p-Test-App.

License

The source code is released under:

GNU General Public License

If you think the Android project 802.11p-Test-App listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.

Java Source Code

package edu.mit.csail.jasongao.sonar;
/*  w  w w  .  j  a  v  a 2 s  .  c  om*/
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.nio.ByteBuffer;

import android.app.Activity;
import android.content.Context;
import android.location.LocationManager;
import android.net.wifi.WifiManager;
import android.net.wifi.WifiManager.MulticastLock;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.os.PowerManager;
import android.os.StrictMode;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.EditText;
import android.widget.ListView;

public class SonarActivity extends Activity {
  final static private String TAG = "SonarActivity";

  private static final String BINPATH = "/data/local/bin/";
  public static final String TCPDUMP = "tcpdump";
  private static CaptureThread tcpdumpCmd = null;

  // Attributes
  private boolean currentlyRepeating = false;
  private long packetsReceived = 0;
  private long packetsSent = 0;
  private boolean sendConfigPackets = false;
  private boolean sendGetFifoCountPacket = false;

  // UI
  ArrayAdapter<String> receivedMessages, receivedMessages2;

  // Logging to file
  File logFile;
  PrintWriter logWriter;

  // Network
  private NetworkThread netThread;

  // Android components
  PowerManager.WakeLock wakeLock = null;
  LocationManager locManager;
  MulticastLock mcLock = null;

  // Handler message types
  protected final static int LOG = 3;
  protected final static int PACKET_RECV = 4;
  protected final static int CAPTURE_RECV = 5;

  /** Handle messages from various components */
  private final Handler myHandler = new Handler() {
    @Override
    public void handleMessage(Message msg) {
      switch (msg.what) {
      case PACKET_RECV:
        byte[] pingBytes = (byte[]) msg.obj;
        logMsg2(String.format(
            "Received packet %d of size %d, data: %s",
            packetsReceived, pingBytes.length,
            bytesToHex(pingBytes)));
        packetsReceived++;
        break;
      case CAPTURE_RECV:
        String capLine = (String) msg.obj;
        logMsg2(capLine);
        break;
      case LOG: // Write a string to log file and UI log display
        logMsg((String) msg.obj);
        break;
      }
    }
  };

  /** Log message and also display on screen */
  public void logMsg(String line) {
    line = String.format("%d: %s", System.currentTimeMillis(), line);
    Log.i(TAG, line);
    receivedMessages.add((String) line);
    if (logWriter != null) {
      logWriter.println((String) line);
    }
  }

  /** Log message and also display on secondary list */
  public void logMsg2(String line) {
    line = String.format("%d: %s", System.currentTimeMillis(), line);
    Log.i(TAG, line);
    receivedMessages2.add((String) line);
    if (logWriter != null) {
      logWriter.println((String) line);
    }
  }

  /** Periodically repeating packet send */
  private Runnable repeatingPacketR = new Runnable() {
    public void run() {
      myHandler.postDelayed(this, 1);
      for (int i = 0; i < 10; i++) {
        sendData();
      }
    }
  };

  private void repeatingPacketStart() {
    myHandler.post(repeatingPacketR);
  }

  private void repeatingPacketStop() {
    myHandler.removeCallbacks(repeatingPacketR);
  }

  final protected static char[] hexArray = { '0', '1', '2', '3', '4', '5',
      '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };

  public static String bytesToHex(byte[] bytes) {
    char[] hexChars = new char[bytes.length * 2];
    int v;
    for (int j = 0; j < bytes.length; j++) {
      v = bytes[j] & 0xFF;
      hexChars[j * 2] = hexArray[v >>> 4];
      hexChars[j * 2 + 1] = hexArray[v & 0x0F];
    }
    return new String(hexChars);
  }

  private int parseAndLimitRange(String s, int min, int max) {
    int value = Integer.parseInt(s);
    // Restrict rate to be 1 to 7
    value = Math.min(max, Math.max(min, value));
    return value;
  }

  /** Send test data */
  private void sendData() {
    // Get rate and length from GUI
    EditText editTextRate = (EditText) findViewById(R.id.editTextRate);
    EditText editTextLength = (EditText) findViewById(R.id.editTextLength);
    EditText editTextAndroidGain = (EditText) findViewById(R.id.editTextAndroidGain);
    EditText editTextDataPackets = (EditText) findViewById(R.id.editTextDataPackets);
    CheckBox checkBoxUseAndroidGain = (CheckBox) findViewById(R.id.checkBoxUseAndroidGain);
    CheckBox checkBoxSetEnable = (CheckBox) findViewById(R.id.checkBoxSetEnable);

    // Parse and validate values from GUI
    int rate = 1;
    int length = 64;
    int dataPackets = 16;

    boolean useAndroidGain = true;
    boolean setEnable = true;
    int androidGain = 4;
    int androidGainEn = 1;

    try {
      useAndroidGain = checkBoxUseAndroidGain.isChecked();
      setEnable = checkBoxSetEnable.isChecked();

      dataPackets = Integer.parseInt(editTextDataPackets.getText()
          .toString());
      // Restrict length to be between 1 to 1024
      dataPackets = Math.min(1024, Math.max(1, dataPackets));
      editTextDataPackets.setText(Integer.toString(dataPackets));

      length = Integer.parseInt(editTextLength.getText().toString());
      // Restrict length to be between 4 to 4096
      length = Math.min(4096, Math.max(4, length));
      // Restrict length to be a multiple of 4
      // length -= (length % 4);
      editTextLength.setText(Integer.toString(length));

      rate = Integer.parseInt(editTextRate.getText().toString());
      // Restrict rate to be 1 to 7
      rate = Math.min(7, Math.max(1, rate));
      editTextRate.setText(Integer.toString(rate));

      androidGain = Integer.parseInt(editTextAndroidGain.getText()
          .toString());
      // Restrict androidGain to be 0 to 63 (6-bit value)
      androidGain = Math.min(63, Math.max(0, androidGain));
      editTextAndroidGain.setText(Integer.toString(androidGain));
    } catch (NumberFormatException e1) {
      logMsg("INVALID NUMBER FOR LENGTH, RATE, OR GAIN!");
      return;
    }

    // Construct UDP packet containing multiple RRR packets
    ByteArrayOutputStream bos = new ByteArrayOutputStream();
    try {
      if (sendGetFifoCountPacket) {
        // Send several, FPGA Ethernet stack has a min size limitation
        for (int i = 0; i < 7; i++) {
          // Add RRR packet for PacketGen_GetCount
          // (4-byte header 080a8001 and any 4-byte value)
          bos.write(new byte[] { (byte) 0x08, (byte) 0x0a,
              (byte) 0x80, (byte) 0x01, (byte) 0x00, (byte) 0x00,
              (byte) 0x00, (byte) 0x00 });
        }
        sendGetFifoCountPacket = false;
      } else if (sendConfigPackets) {
        // Add RRR packet for PacketGen_SetEnable
        // (4-byte header 08090001 and 1-bit value)
        byte[] setEnable_pkt = new byte[] { (byte) 0x08, (byte) 0x09,
            (byte) 0x00, (byte) 0x01, (byte) 0x00, (byte) 0x00,
            (byte) 0x00, (byte) (setEnable ? 0x01 : 0x00) };
        bos.write(setEnable_pkt);

        // Add RRR packet for PacketGen_SetRate
        // (4-byte header 08080001 and 4-byte value)
        byte[] rate_pkt = new byte[] { (byte) 0x08, (byte) 0x08,
            (byte) 0x00, (byte) 0x01, (byte) 0x00, (byte) 0x00,
            (byte) 0x00, (byte) rate };
        bos.write(rate_pkt);

        androidGainEn = useAndroidGain ? 1 : 0;

        // Add RRR packet to set gaincontrol_AndroidGainEn
        // (4-byte header 08108001 and 1-bit value)
        byte[] androidGainEn_pkt = new byte[] { (byte) 0x08,
            (byte) 0x10, (byte) 0x80, (byte) 0x01, (byte) 0x00,
            (byte) 0x00, (byte) 0x00, (byte) androidGainEn };
        bos.write(androidGainEn_pkt);

        if (useAndroidGain) {
          // Add RRR packet to set gaincontrol_AndroidGain
          // (4-byte header 08100001 and 6-bit value)
          byte[] androidGain_pkt = new byte[] { (byte) 0x08,
              (byte) 0x10, (byte) 0x00, (byte) 0x01, (byte) 0x00,
              (byte) 0x00, (byte) 0x00, (byte) androidGain };
          bos.write(androidGain_pkt);
        }

        sendConfigPackets = false;
      } else {
        // Add RRR packet for PacketGen_SetLength
        // (4-byte header 08088001 and 4-byte value)
        ByteBuffer b = ByteBuffer.allocate(4);
        b.putInt(length);
        byte[] length_bytes = b.array();
        byte[] length_pkt = new byte[] { (byte) 0x08, (byte) 0x08,
            (byte) 0x80, (byte) 0x01, (byte) 0x00, (byte) 0x00,
            length_bytes[2], length_bytes[3] };
        bos.write(length_pkt);

        // Add RRR data packet(s) for PacketGen_SendPacket
        // (4-byte header 080a0001 and 4-byte value)
        for (int i = 0; i < length / 4; i++) {
          byte[] data_pkt = new byte[] { (byte) 0x08, (byte) 0x0A,
              (byte) 0x00, (byte) 0x01, (byte) 0x01, (byte) 0x23,
              (byte) 0x45, (byte) 0x67, };
          bos.write(data_pkt);
        }

        // Add RRR packet for PacketGen_GetCount
        // (4-byte header 080a8001 and any 4-byte value)
        //bos.write(new byte[] { (byte) 0x08, (byte) 0x0a, (byte) 0x80,
        //    (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
        //    (byte) 0x00 });
      }
    } catch (IOException e1) {
      logMsg("Error creating RRR packet.");
      e1.printStackTrace();
    }

    sendPacket(bos.toByteArray());
  }

  /** Send a UDP packet that the FPGA can understand */
  private boolean sendPacket(byte[] packet) {
    // Add 2-byte zero pad to reach a multiple of 4 bytes (b/c eth 14 bytes)
    byte[] padded_packet = new byte[2 + packet.length];
    byte[] zero_pad = new byte[] { (byte) 0x00, (byte) 0x00 };
    System.arraycopy(zero_pad, 0, padded_packet, 0, 2);
    System.arraycopy(packet, 0, padded_packet, 2, packet.length);

    // Send packet
    try {
      netThread.broadcast(padded_packet);
      logMsg(String.format("Sent packet %d of size %d bytes",
          packetsSent, packet.length));
      packetsSent++;
    } catch (IOException e) {
      logMsg(String.format("Error sending packet %d of size %d bytes",
          packetsSent, packet.length));
      e.printStackTrace();
      return false;
    }

    return true;
  }

  /** Called when the activity is first created. */
  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    ((Button) findViewById(R.id.config_button))
        .setOnClickListener(mClicked);

    ((Button) findViewById(R.id.fifo_button)).setOnClickListener(mClicked);

    Button send_button = (Button) findViewById(R.id.data_button);
    send_button.setOnClickListener(mClicked);

    Button repeat_button = (Button) findViewById(R.id.repeat_button);
    repeat_button.setOnClickListener(mClicked);

    receivedMessages = new ArrayAdapter<String>(this, R.layout.message);
    ((ListView) findViewById(R.id.msgList)).setAdapter(receivedMessages);

    receivedMessages2 = new ArrayAdapter<String>(this, R.layout.message);
    ((ListView) findViewById(R.id.msgList2)).setAdapter(receivedMessages2);

    logMsg("*** Application started ***");

    StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
        .permitAll().build());

    // Setup writing to log file on sd card
    String state = Environment.getExternalStorageState();
    if (Environment.MEDIA_MOUNTED.equals(state)) {
      // We can read and write the media
      logFile = new File(Environment.getExternalStorageDirectory(),
          String.format("sonar-%d.txt", System.currentTimeMillis()));
      try {
        logWriter = new PrintWriter(logFile);
        logMsg("*** Opened log file for writing ***");
      } catch (Exception e) {
        logWriter = null;
        logMsg("*** Couldn't open log file for writing ***");
      }
    } else if (Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) {
      // We can only read the media
    } else {
      // One of many other states, but we can neither read nor write
    }

    // Get a wakelock to keep everything running
    PowerManager pm = (PowerManager) getApplicationContext()
        .getSystemService(Context.POWER_SERVICE);
    wakeLock = pm.newWakeLock(PowerManager.FULL_WAKE_LOCK
        | PowerManager.ON_AFTER_RELEASE, TAG);

    // Get a multicast lock???
    WifiManager wifi = (WifiManager) this
        .getSystemService(Context.WIFI_SERVICE);
    mcLock = wifi.createMulticastLock("edu.mit.csail.jasongao.sonar");

    // Location / GPS
    locManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);

    // Extract binaries
    File localTcpdump = getFileStreamPath(TCPDUMP);
    if (localTcpdump.exists()) {
      logMsg("binary already exists at " + getFileStreamPath(TCPDUMP));
    } else {
      extractBinary(R.raw.tcpdump, TCPDUMP);
    }

    // Start the network thread and ensure it's running
    netThread = new NetworkThread(myHandler);
    if (!netThread.socketIsOK()) {
      Log.e(TAG, "Cannot start server: socket not ok.");
      return; // quit out
    }
    netThread.start();
    if (netThread.localAddress == null) {
      Log.e(TAG, "Couldn't get my IP address.");
      return; // quit out
    }

    logMsg("localAddress=" + netThread.localAddress.getHostAddress());
    logMsg("broadcastAddress="
        + netThread.broadcastAddress.getHostAddress());

    startTcpdump();
  }

  /** Always called after onStart, even if activity is not paused. */
  @Override
  protected void onResume() {
    super.onResume();
    wakeLock.acquire();
    mcLock.acquire();
  }

  @Override
  protected void onPause() {
    // stop recurring runnables
    // TODO

    mcLock.release();
    wakeLock.release();
    super.onPause();
  }

  @Override
  public void onDestroy() {
    repeatingPacketStop();
    stopTcpdump();
    netThread.closeSocket();

    logWriter.flush();
    logWriter.close();

    super.onDestroy();
  }

  private void startTcpdump() {
    try {
      tcpdumpCmd = new CaptureThread(getFileStreamPath(TCPDUMP)
          .toString()
          + " -neql -tt -xx -s 256 -i "
          + NetworkThread.IFACE, myHandler);
      tcpdumpCmd.start();
    } catch (IOException e) {
      e.printStackTrace();
      Log.e(TAG, "error starting tcpdump", e);
    }
  }

  private void stopTcpdump() {
    if (tcpdumpCmd != null) {
      tcpdumpCmd.interrupt();
      tcpdumpCmd = null;
      try {
        CaptureThread ec = new CaptureThread("killall " + TCPDUMP);
        ec.start();
        ec.join();
      } catch (IOException e) {
        e.printStackTrace();
        Log.e(TAG, "error killing tcpdump", e);
      } catch (InterruptedException e) {
        // swallow error
      }
    }
  }

  private void extractBinary(int id, String fileName) {
    /*
     * extracts the binary from the apk and makes it executable. If any step
     * fails and the function continues to run everything should be cleaned
     * up
     */
    final InputStream arpBin = getResources().openRawResource(id);
    FileOutputStream out = null;
    boolean success = true;
    final byte[] buff = new byte[4096];
    try {
      out = openFileOutput(fileName, Context.MODE_PRIVATE);
      while (arpBin.read(buff) > 0)
        out.write(buff);
    } catch (FileNotFoundException e) {
      Log.e(TAG, fileName + "wasn't found", e);
      success = false;
    } catch (IOException e) {
      Log.e(TAG, "couldn't extract executable", e);
      success = false;
    } finally {
      try {
        out.close();
      } catch (IOException e) {
        // swallow error
      }
    }
    try {
      CaptureThread ec = new CaptureThread("chmod 770 "
          + getFileStreamPath(fileName).toString());
      ec.start();
      ec.join();
    } catch (IOException e) {
      Log.e(TAG, "error running chmod on local file", e);
      success = false;
    } catch (InterruptedException e) {
      Log.i(TAG, "thread running chmod was interrupted");
      success = false;
    } finally {
      if (!success) {
        getFileStreamPath(fileName).delete();
      } else {
        logMsg("successfully extracted executable to "
            + getFileStreamPath(fileName));
      }
    }
  }

  // Buttons
  private final OnClickListener mClicked = new OnClickListener() {
    public void onClick(View v) {
      switch (v.getId()) {

      case R.id.data_button:
        sendConfigPackets = false;
        sendGetFifoCountPacket = false;
        sendData();
        break;
      case R.id.config_button:
        sendConfigPackets = true;
        sendGetFifoCountPacket = false;
        sendData();
        break;
      case R.id.fifo_button:
        sendConfigPackets = false;
        sendGetFifoCountPacket = true;
        sendData();
        break;
      case R.id.repeat_button:
        if (!currentlyRepeating) {
          currentlyRepeating = true;
          repeatingPacketStart();
          ((Button) findViewById(R.id.repeat_button))
              .setText("STOP loop");
        } else {
          currentlyRepeating = false;
          repeatingPacketStop();
          ((Button) findViewById(R.id.repeat_button))
              .setText("START loop");
        }
      default:
        break;
      }
    }
  };
}




Java Source Code List

edu.mit.csail.jasongao.sonar.CaptureThread.java
edu.mit.csail.jasongao.sonar.NetworkThread.java
edu.mit.csail.jasongao.sonar.SonarActivity.java
edu.mit.csail.jasongao.sonar.SystemHelper.java