package com.bluekitchen.lescan;

import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.widget.TextView;

import com.bluekitchen.btstack.BD_ADDR;
import com.bluekitchen.btstack.BT_UUID;
import com.bluekitchen.btstack.BTstack;
import com.bluekitchen.btstack.GATTCharacteristic;
import com.bluekitchen.btstack.GATTService;
import com.bluekitchen.btstack.Packet;
import com.bluekitchen.btstack.PacketHandler;
import com.bluekitchen.btstack.Util;
import com.bluekitchen.btstack.event.BTstackEventState;
import com.bluekitchen.btstack.event.GAPEventAdvertisingReport;
import com.bluekitchen.btstack.event.GATTEventCharacteristicQueryResult;
import com.bluekitchen.btstack.event.GATTEventCharacteristicValueQueryResult;
import com.bluekitchen.btstack.event.GATTEventNotification;
import com.bluekitchen.btstack.event.GATTEventQueryComplete;
import com.bluekitchen.btstack.event.GATTEventServiceQueryResult;
import com.bluekitchen.btstack.event.HCIEventCommandComplete;
import com.bluekitchen.btstack.event.HCIEventDisconnectionComplete;
import com.bluekitchen.btstack.event.HCIEventLEConnectionComplete;

public class MainActivity extends Activity implements PacketHandler {

	private static final String BTSTACK_TAG = "BTstack";

	private enum STATE {
		w4_btstack_working, w4_scan_result, w4_connected, w4_services_complete, w4_characteristic_complete, w4_characteristic_read
		, w4_characteristic_write, w4_acc_service_result, w4_acc_enable_characteristic_result, w4_write_acc_enable_result, w4_acc_client_config_characteristic_result, w4_acc_client_config_result,
		w4_acc_data, w4_connected_acc, w4_disconnect, track_rssi, battery_data
	};

	private TextView tv;
	private BTstack btstack;
	private STATE state;
	private int testAddrType;
	private BD_ADDR deviceAddr;
	private int connectionHandle;
	private GATTService testService;
	private GATTCharacteristic testCharacteristic;
	private int service_count = 0;
	private int characteristic_count = 0;
	private int test_run_count = 0;
	private String onScreenMessage = "";
	
	BD_ADDR sensor_tag_addr = new BD_ADDR("1C:BA:8C:20:C7:F6");
	// Accelerometer
	private byte[] acc_service_uuid =           new byte[] {(byte)0xf0, 0, (byte)0xaa, (byte)0x10, 4, (byte)0x51, (byte)0x40, 0, (byte)0xb0, 0, 0, 0, 0, 0, 0, 0};
	private byte[] acc_chr_client_config_uuid = new byte[] {(byte)0xf0, 0, (byte)0xaa, (byte)0x11, 4, (byte)0x51, (byte)0x40, 0, (byte)0xb0, 0, 0, 0, 0, 0, 0, 0};
	private byte[] acc_chr_enable_uuid =        new byte[] {(byte)0xf0, 0, (byte)0xaa, (byte)0x12, 4, (byte)0x51, (byte)0x40, 0, (byte)0xb0, 0, 0, 0, 0, 0, 0, 0};
	private byte[] acc_enable = new byte[] {1};
	private byte acc_notification = 1; 
	private GATTService accService;
	private GATTCharacteristic enableCharacteristic;
	private GATTCharacteristic configCharacteristic;
	
	// Battery 
	private GATTService batteryService;
	private GATTCharacteristic batteryLevelCharacteristic;
	//private byte[] battery_service_uuid =   new byte[] {0, 0, (byte)0x18, (byte)0x0F, 0, 0, (byte)0x10, 0, (byte)0x80, 0, 0, (byte)0x80, (byte)0x5f, (byte)0x9b, (byte)0x34, (byte)0xfb};
	private byte[] battery_level_chr_uuid = new byte[] {0, 0, (byte)0x2a, (byte)0x1b, 0, 0, (byte)0x10, 0, (byte)0x80, 0, 0, (byte)0x80, (byte)0x5f, (byte)0x9b, (byte)0x34, (byte)0xfb}; 
	GATTEventCharacteristicValueQueryResult battery;
	private int batteryLevel = 0;
	private int counter;


	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);

		tv = new TextView(this);
		setContentView(tv);

		test();
	}

	void addMessage(final String message){
		onScreenMessage = onScreenMessage + "\n" + message;
		Log.d(BTSTACK_TAG, message);
		runOnUiThread(new Runnable(){
			public void run(){
				tv.setText(onScreenMessage);
			}
		});
	}
	
	
	void addTempMessage(final String message){
		Log.d(BTSTACK_TAG, message);
		runOnUiThread(new Runnable(){
			public void run(){
				tv.setText(onScreenMessage +"\n" + message);
			}
		});
	}
	
	void clearMessages(){
		onScreenMessage = "";
		runOnUiThread(new Runnable(){
			public void run(){
				tv.setText(onScreenMessage);
			}
		});
	}

	
	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		// Inflate the menu; this adds items to the action bar if it is present.
		getMenuInflater().inflate(R.menu.main, menu);
		return true;
	}

	
	public void testCharacteristics(Packet packet){
		
		switch (state){
		case w4_btstack_working:
			if (packet instanceof BTstackEventState){
				BTstackEventState event = (BTstackEventState) packet;
				if (event.getState() == 2)	{
					addMessage("GAPLEScanStart()");
					state = STATE.w4_scan_result;
					btstack.GAPLEScanStart();
				}
			}
			break;
		case w4_scan_result:
			if (packet instanceof GAPEventAdvertisingReport){
				GAPEventAdvertisingReport report = (GAPEventAdvertisingReport) packet;
				testAddrType = report.getAddressType();
				deviceAddr = report.getAddress();
				addMessage(String.format("Adv: type %d, addr %s", testAddrType, deviceAddr));
				addMessage(String.format("Data: %s", Util.asHexdump(report.getData())));
				addMessage("GAPLEScanStop()");
				btstack.GAPLEScanStop();
				addMessage("GAPLEConnect(...)");
				state = STATE.w4_connected;
				btstack.GAPLEConnect(testAddrType, deviceAddr);
			}
			break;
		case w4_connected:
			if (packet instanceof HCIEventLEConnectionComplete){
				HCIEventLEConnectionComplete event = (HCIEventLEConnectionComplete) packet;
				connectionHandle = event.getConnectionHandle();
				addMessage(String.format("Connection complete, status %d, handle %x", event.getStatus(), connectionHandle));
				state = STATE.w4_services_complete;
				addMessage("GATTDiscoverPrimaryServices(...)");
				btstack.GATTDiscoverPrimaryServices(connectionHandle);
			}
			break;
		case w4_services_complete:
			if (packet instanceof GATTEventServiceQueryResult){
				GATTEventServiceQueryResult event = (GATTEventServiceQueryResult) packet;
				if (testService == null){
					addMessage(String.format("First service UUID %s", event.getService().getUUID()));
					testService = event.getService();
				}
				Log.d(BTSTACK_TAG, "Service: " + event.getService());
				service_count++;
			}
			if (packet instanceof GATTEventQueryComplete){
				addMessage(String.format("Service query complete, total %d services", service_count));
				state = STATE.w4_characteristic_complete;
				btstack.GATTDiscoverCharacteristicsForService(connectionHandle, testService);
			}
			break;

		case w4_characteristic_complete:
			if (packet instanceof GATTEventCharacteristicQueryResult){
				GATTEventCharacteristicQueryResult event = (GATTEventCharacteristicQueryResult) packet;
				if (testCharacteristic == null){
					addMessage(String.format("First characteristic UUID %s", event.getCharacteristic().getUUID()));
					testCharacteristic = event.getCharacteristic();
				}
				Log.d(BTSTACK_TAG, "Characteristic: " + event.getCharacteristic());
				characteristic_count++;
			}
			if (packet instanceof GATTEventQueryComplete){
				addMessage(String.format("Characteristic query complete, total %d characteristics", characteristic_count));
				if (characteristic_count > 0){
					state = STATE.w4_characteristic_read;
					btstack.GATTReadValueOfCharacteristic(connectionHandle, testCharacteristic);
				} else {
					state = STATE.w4_disconnect;
					btstack.GAPDisconnect(connectionHandle);
				}
			}			
			break;

		case w4_characteristic_read:
			if (packet instanceof GATTEventCharacteristicValueQueryResult){
				addMessage("Read complete");
				Log.d(BTSTACK_TAG, packet.toString());
				state = STATE.w4_characteristic_write;
				byte [] data = { 'B', 'T', 's', 't', 'a', 'c', 'k'};
				btstack.GATTWriteValueOfCharacteristic(connectionHandle, testCharacteristic, data.length, data);
			}
			break;
		case w4_characteristic_write:
			if (packet instanceof GATTEventQueryComplete){
				addMessage("Write complete, disconnect now.");
				state = STATE.w4_disconnect;
				// btstack.GAPDisconnect(testHandle);
			}
			break;
		case w4_disconnect:
			if (packet instanceof HCIEventDisconnectionComplete){
				addMessage("Disconnected.");
			}
			break;
		default:
			break;
		}
	}

	public void testAccelerometer(Packet packet){
		switch (state){
		case w4_btstack_working:
			if (packet instanceof BTstackEventState){
				BTstackEventState event = (BTstackEventState) packet;
				if (event.getState() == 2)	{
					addMessage("GAPLEScanStart()");
					state = STATE.w4_scan_result;
					btstack.GAPLEScanStart();
				}
			}
			break;
		case w4_scan_result:
			if (packet instanceof GAPEventAdvertisingReport){
				GAPEventAdvertisingReport report = (GAPEventAdvertisingReport) packet;
				testAddrType = report.getAddressType();
				deviceAddr = report.getAddress();
				if (deviceAddr.toString().equalsIgnoreCase(sensor_tag_addr.toString())){
					addMessage(String.format("Adv: type %d, addr %s", testAddrType, deviceAddr));
					addMessage(String.format("Data: %s", Util.asHexdump(report.getData())));
					addMessage("GAPLEScanStop()");
					btstack.GAPLEScanStop();
					addMessage("GAPLEConnect(...)");
					state = STATE.w4_connected_acc;
					btstack.GAPLEConnect(testAddrType, deviceAddr);
				}
			}
			break;



		case w4_connected_acc:
			if (packet instanceof HCIEventLEConnectionComplete){
				HCIEventLEConnectionComplete event = (HCIEventLEConnectionComplete) packet;
				connectionHandle = event.getConnectionHandle();
				addMessage(String.format("Connection complete, status %d, handle %x", event.getStatus(), connectionHandle));
				addMessage("Search for ACC service");
				state = STATE.w4_acc_service_result;
				byte [] uuid = new byte[16];
				Util.flipX(this.acc_service_uuid, uuid);	
				btstack.GATTDiscoverPrimaryServicesByUUID128(connectionHandle, new BT_UUID(uuid));
			}
			break;

		case w4_acc_service_result:
			clearMessages();
			addMessage(String.format("w4_acc_service_result state"));
			if (packet instanceof GATTEventServiceQueryResult){
				GATTEventServiceQueryResult event = (GATTEventServiceQueryResult) packet;
				addMessage(String.format("ACC service found %s", event.getService().getUUID()));
				accService = event.getService();
				break;
			}
			if (packet instanceof GATTEventQueryComplete){
				if (accService == null) {
					addMessage("No acc service found");
					break;
				}
				addMessage("ACC Service found, searching for acc enable characteristic");
				state = STATE.w4_acc_enable_characteristic_result;
				byte [] uuid = new byte[16];
				Util.flipX(this.acc_chr_enable_uuid, uuid);
				btstack.GATTDiscoverCharacteristicsForServiceByUUID128(connectionHandle, accService, new BT_UUID(uuid));
			}
			break;

		case w4_acc_enable_characteristic_result:
			if (packet instanceof GATTEventCharacteristicQueryResult){
				GATTEventCharacteristicQueryResult event = (GATTEventCharacteristicQueryResult) packet;
				enableCharacteristic = event.getCharacteristic();
				addMessage("Enable ACC Characteristic found ");
			}
			if (packet instanceof GATTEventQueryComplete){
				if (enableCharacteristic == null) {
					addMessage("No acc enable chr found");
					break;
				}
				addMessage("Write enable acc characteristic");
				state = STATE.w4_write_acc_enable_result;
				btstack.GATTWriteValueOfCharacteristic(connectionHandle, enableCharacteristic, 1, this.acc_enable);
			}	
			break;
		case w4_write_acc_enable_result:
			if (packet instanceof GATTEventQueryComplete){
				addMessage("Acc enabled,searching for acc client config characteristic");
				byte [] uuid = new byte[16];
				Util.flipX(this.acc_chr_client_config_uuid, uuid);
				btstack.GATTDiscoverCharacteristicsForServiceByUUID128(connectionHandle, accService, new BT_UUID(uuid));
				state = STATE.w4_acc_client_config_characteristic_result;
			}
			break;

		case w4_acc_client_config_characteristic_result:
			if (packet instanceof GATTEventCharacteristicQueryResult){
				GATTEventCharacteristicQueryResult event = (GATTEventCharacteristicQueryResult) packet;
				configCharacteristic = event.getCharacteristic();
				addMessage("ACC Client Config Characteristic found");
			}
			if (packet instanceof GATTEventQueryComplete){
				if (configCharacteristic == null) {
					addMessage("No acc config chr found");
					break;
				}
				addMessage("Write ACC Client Config Characteristic");
				state = STATE.w4_acc_data;
				btstack.GATTWriteClientCharacteristicConfiguration(connectionHandle, configCharacteristic, this.acc_notification);
			}	
			break;

		case w4_acc_data:
			if (packet instanceof GATTEventQueryComplete){
				addMessage("Acc configured for notification");
				break;
			}

			if (packet instanceof GATTEventNotification){
				addTempMessage("Acc Value");
				Log.d(BTSTACK_TAG, packet.toString());
				//state = STATE.w4_btstack_working;
				//btstack.GAPDisconnect(connectionHandle);
			}
			break;
			
		default:
			break;
		}
	}

	public void testConnectDisconnect(Packet packet){
		if (packet instanceof HCIEventDisconnectionComplete){
			if (state != STATE.w4_disconnect) {
				state = STATE.w4_scan_result;
				btstack.GAPLEScanStart();
				clearMessages();
				HCIEventDisconnectionComplete event = (HCIEventDisconnectionComplete) packet;
				addMessage(String.format("Unexpected disconnect %x. Start scan.", event.getConnectionHandle()));
				return;
			}
		}
		
		switch (state){
		case w4_btstack_working:
			if (packet instanceof BTstackEventState){
				BTstackEventState event = (BTstackEventState) packet;
				if (event.getState() == 2)	{
//					addMessage("GAPLEScanStart()");
//					state = STATE.w4_scan_result;
					// btstack.GAPLEScanStart();
//					runOnUiThread(new Runnable(){
//						public void run(){
							addMessage("BTstack dissconnect.");
							btstack.disconnect();

//					runOnUiThread(new Runnable(){
//						public void run(){
							try {
								Thread.sleep(5000);
							} catch (InterruptedException e) {
								e.printStackTrace();
							}
							btstack.connect();
							addMessage("Power on BTstack.");
							state = STATE.w4_btstack_working;
							test_run_count = 0;
							btstack.BTstackSetPowerMode(1);
//						}
//					});
				}
			}
			break;
		case w4_scan_result:
			if (packet instanceof GAPEventAdvertisingReport){
				BD_ADDR sensor_tag_addr = new BD_ADDR("1C:BA:8C:20:C7:F6");
				//BD_ADDR pts_dongle = new BD_ADDR("00:1B:DC:07:32:EF");

				GAPEventAdvertisingReport report = (GAPEventAdvertisingReport) packet;
				BD_ADDR reportAddr = report.getAddress();
				if (reportAddr.toString().equalsIgnoreCase(sensor_tag_addr.toString())){
					testAddrType = report.getAddressType();
					deviceAddr = report.getAddress();
					addMessage(String.format("Adv: type %d, addr %s", testAddrType, deviceAddr));
					addMessage(String.format("Data: %s", Util.asHexdump(report.getData())));

					addMessage("GAPLEScanStop()");
					btstack.GAPLEScanStop();
					addMessage("GAPLEConnect(...)");
					state = STATE.w4_connected;
					
					btstack.GAPLEConnect(testAddrType, deviceAddr);
				}
			}
			break;
		case w4_connected:
			if (packet instanceof HCIEventLEConnectionComplete){
				HCIEventLEConnectionComplete event = (HCIEventLEConnectionComplete) packet;
				
				connectionHandle = event.getConnectionHandle();
				addMessage(String.format("Connection complete, status %d, handle %x", event.getStatus(), connectionHandle));
				state = STATE.w4_services_complete;
				addMessage("GATTDiscoverPrimaryServices(...)");
				btstack.GATTDiscoverPrimaryServices(connectionHandle);
				
			}
			break;
		case w4_services_complete:
			if (packet instanceof GATTEventServiceQueryResult){
				GATTEventServiceQueryResult event = (GATTEventServiceQueryResult) packet;
				if (testService == null){
					addMessage(String.format("First service UUID %s", event.getService().getUUID()));
					testService = event.getService();
				}
				Log.d(BTSTACK_TAG, "Service: " + event.getService());
				service_count++;
			}
			if (packet instanceof GATTEventQueryComplete){
				addMessage(String.format("Service query complete, total %d services", service_count));
				state = STATE.w4_disconnect;
				test_run_count++;
				btstack.GAPDisconnect(connectionHandle);
			}
			break;
		case w4_disconnect:
			Log.d(BTSTACK_TAG, packet.toString());
			if (packet instanceof HCIEventDisconnectionComplete){
				clearMessages();
				addMessage("BTstack dissconnect.");
				btstack.disconnect();
				try {
					Thread.sleep(15000);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				
				btstack.connect();
				addMessage("Power on BTstack.");
				state = STATE.w4_btstack_working;
				test_run_count = 0;
				btstack.BTstackSetPowerMode(1);
				
				
				/*if (test_run_count%10 == 0){
					addMessage("Power off BTstack.");
					state = STATE.w4_btstack_working;
					btstack.BTstackSetPowerMode(0);
					try {
						Thread.sleep(15000);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
					addMessage("Power on BTstack.");
					btstack.BTstackSetPowerMode(1);
				} else {
					addMessage("GAPLEScanStart()");
					state = STATE.w4_scan_result;
					btstack.GAPLEScanStart();
				}*/
			}
			break;
		default:
			break;
		}
	}

	public void trackRSSI(Packet packet){
		switch (state){
		case w4_btstack_working:
			if (packet instanceof BTstackEventState){
				BTstackEventState event = (BTstackEventState) packet;
				if (event.getState() == 2)	{
					addMessage("GAPLEScanStart()");
					state = STATE.w4_scan_result;
					btstack.GAPLEScanStart();
				}
			}
			break;
		case w4_scan_result:
			if (packet instanceof GAPEventAdvertisingReport){
				clearMessages();
				GAPEventAdvertisingReport report = (GAPEventAdvertisingReport) packet;
				testAddrType = report.getAddressType();
				deviceAddr = report.getAddress();
				addMessage(String.format("Adv: type %d, addr %s", testAddrType, deviceAddr));
				addMessage(String.format("Data: %s", Util.asHexdump(report.getData())));
				addMessage("GAPLEScanStop()");
				btstack.GAPLEScanStop();
				addMessage("GAPLEConnect(...)");
				state = STATE.w4_connected;
				btstack.GAPLEConnect(testAddrType, deviceAddr);
			}
			break;
		case w4_connected:
			if (packet instanceof HCIEventLEConnectionComplete){
				HCIEventLEConnectionComplete event = (HCIEventLEConnectionComplete) packet;
				if (event.getStatus() != 0) {
					addMessage(String.format("Connection didn't succeed, status %d, restart scanning.", event.getStatus()));
					state = STATE.w4_scan_result;
					btstack.GAPLEScanStart();
					break;
				}
				
				state = STATE.track_rssi;
				connectionHandle = event.getConnectionHandle();
				addMessage(String.format("Connection complete, status %d, handle %x. Start RSSI query.", event.getStatus(), connectionHandle));
				counter = 0;
				new Thread(new Runnable(){
					@Override
					public void run() {
						try {
							while(state == STATE.track_rssi){
								Thread.sleep(1000);
								btstack.HCIReadRssi(connectionHandle);
							}
						} catch (InterruptedException e) {}
					}
				}).start();
			}
			break;
		case track_rssi:
			if (packet instanceof HCIEventDisconnectionComplete){
				clearMessages();
				addMessage(String.format("Received dissconnect. Start scannning."));
				state = STATE.w4_scan_result;
				btstack.GAPLEScanStart();
				break;
			}
			
			if (!(packet instanceof HCIEventCommandComplete)) break;
			HCIEventCommandComplete event = (HCIEventCommandComplete) packet;
			int opcode = event.getCommandOpcode();
			if (opcode != 0X1405) break;
			counter = counter + 1;
			byte data[] = event.getReturnParameters();
			addTempMessage(String.format("counter %d, status %d, RSSI: %ddBm", counter, Util.readByte(data, 0), data[3]));
			break;
		
		default:
			break;
		}
	}
	
	public void queryBatteryLevel(Packet packet){
		// Restart scanning on disconnect.
		if (packet instanceof HCIEventDisconnectionComplete){
			clearMessages();
			addMessage(String.format("Received dissconnect. Start scannning."));
			state = STATE.w4_scan_result;
			btstack.GAPLEScanStart();
			return;
		}
		
		switch (state){
		case w4_btstack_working:
			if (packet instanceof BTstackEventState){
				BTstackEventState event = (BTstackEventState) packet;
				if (event.getState() == 2)	{
					addMessage("BTstack working, start scanning.");
					state = STATE.w4_scan_result;
					btstack.GAPLEScanStart();
				}
			}
			break;
		case w4_scan_result:
			if (packet instanceof GAPEventAdvertisingReport){
				// Advertisement received. Connect to the found BT address.
				clearMessages();
				GAPEventAdvertisingReport report = (GAPEventAdvertisingReport) packet;
				testAddrType = report.getAddressType();
				deviceAddr = report.getAddress();
				addMessage(String.format("Adv: type %d, addr %s\ndata: %s \n Stop scan, initiate connect.", testAddrType, deviceAddr, Util.asHexdump(report.getData())));
				btstack.GAPLEScanStop();
				state = STATE.w4_connected;
				btstack.GAPLEConnect(testAddrType, deviceAddr);
			}
			break;
		case w4_connected:
			if (packet instanceof HCIEventLEConnectionComplete){
				HCIEventLEConnectionComplete event = (HCIEventLEConnectionComplete) packet;
				if (event.getStatus() != 0) {
					addMessage(String.format("Connection didn't succeed, status %d, restart scanning.", event.getStatus()));
					state = STATE.w4_scan_result;
					btstack.GAPLEScanStart();
					break;
				}
				
				// Query battery service.
				state = STATE.w4_services_complete;
				connectionHandle = event.getConnectionHandle();
				addMessage(String.format("Connection complete, status %d, handle %x.\nQuery battery service.", event.getStatus(), connectionHandle));
				
				//btstack.GATTDiscoverPrimaryServicesByUUID128(connectionHandle, uuid128(this.battery_service_uuid));
				btstack.GATTDiscoverPrimaryServicesByUUID16(connectionHandle, 0x180f);
			}
			break;
			
		case w4_services_complete:
			if (packet instanceof GATTEventServiceQueryResult){
				// Store battery service. Wait for GATTEventQueryComplete event to send next GATT command.
				GATTEventServiceQueryResult event = (GATTEventServiceQueryResult) packet;
				addMessage(String.format("Battery service found %s", event.getService().getUUID()));
				batteryService = event.getService();
				break;
			}
			if (packet instanceof GATTEventQueryComplete){
				// Check if battery service is found.
				if (batteryService == null) {
					addMessage("No battery service found, restart scanning.");
					state = STATE.w4_scan_result;
					btstack.GAPLEScanStart(); 
					break;
				}
				addMessage("Battery service is found. Query battery level.");
				state = STATE.w4_characteristic_complete;
				btstack.GATTDiscoverCharacteristicsForServiceByUUID128(connectionHandle, batteryService, uuid128(this.battery_level_chr_uuid));	
			}
			break;
		case w4_characteristic_complete:
			if (packet instanceof GATTEventCharacteristicQueryResult){
				// Store battery level characteristic. Wait for GATTEventQueryComplete event to send next GATT command.
				GATTEventCharacteristicQueryResult event = (GATTEventCharacteristicQueryResult) packet;
				batteryLevelCharacteristic = event.getCharacteristic();
				addMessage("Battery level characteristic found.");
				break;
			}
			
			if (!(packet instanceof GATTEventQueryComplete)) break;
			if (batteryLevelCharacteristic == null) {
				addMessage("No battery level characteristic found");
				break;
			}
			clearMessages();
			addMessage("Polling battery.");
			counter = 0;
			state = STATE.battery_data;
			new Thread(new Runnable(){
				@Override
				public void run() {
					try {
						while(state == STATE.battery_data){
							Thread.sleep(5000);
							btstack.GATTReadValueOfCharacteristic(connectionHandle, batteryLevelCharacteristic);
						}
					} catch (InterruptedException e) {}
				}
			}).start();
			break;
			
		case battery_data:
			clearMessages();
			if (packet instanceof GATTEventCharacteristicValueQueryResult){
				GATTEventCharacteristicValueQueryResult battery = (GATTEventCharacteristicValueQueryResult) packet;
				
				if (battery.getValueLength() < 1) break;
				this.batteryLevel = battery.getValue()[0];
				addTempMessage(String.format("Counter %d, battery level: %d", counter, batteryLevel) + "%");
				counter = counter + 1;
				break;
				
			}
			if (packet instanceof GATTEventQueryComplete){
				GATTEventQueryComplete event = (GATTEventQueryComplete) packet;
				addMessage(String.format("Counter %d, battery level: %d", counter, batteryLevel) + "%");
				if (event.getStatus() != 0){
					addMessage("Battery data could not be read - status 0x%02x. Restart scanning." + String.valueOf(event.getStatus()));
					state = STATE.w4_scan_result;
					btstack.GAPLEScanStart(); 
					break;
				}
			}
			
			break;
		default:
			break;
		}
	}

	private BT_UUID uuid128(byte[] att_uuid) {
		byte [] uuid = new byte[16];
		Util.flipX(att_uuid, uuid);	
		return new BT_UUID(uuid);
	}
	
	public void handlePacket(Packet packet){
		// queryBatteryLevel(packet);
		// trackRSSI(packet);
		// testCharacteristics(packet);
		// testAccelerometer(packet);
		testConnectDisconnect(packet);
	}

	void test(){
		counter = 0;
		addMessage("LE Test Application");

		btstack = new BTstack();
		btstack.registerPacketHandler(this);

		boolean ok = btstack.connect();
		if (!ok) {
			addMessage("Failed to connect to BTstack Server");
			return;
		}

		addMessage("BTstackSetPowerMode(1)");

		state = STATE.w4_btstack_working;
		btstack.BTstackSetPowerMode(1);
	}
}
