Java tutorial
/** * Copyright (c) 2016 University of Brescia, Alessandra Flammini, All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package it.unibs.sandroide.lib.item.generalIO; import android.bluetooth.BluetoothClass; import android.bluetooth.BluetoothGatt; import android.bluetooth.BluetoothGattCharacteristic; import android.util.Log; import org.apache.commons.io.HexDump; import org.json.JSONException; import org.json.JSONObject; import java.lang.reflect.Array; import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.concurrent.TimeUnit; import it.unibs.sandroide.lib.communication.BluetoothLeDevice; import it.unibs.sandroide.lib.data.BLEDeviceData; import it.unibs.sandroide.lib.device.DeviceControl; import it.unibs.sandroide.lib.item.BLEItem; import it.unibs.sandroide.lib.item.BLEOnItemInitiatedListener; import it.unibs.sandroide.lib.item.BLEOnItemUpdateListener; import it.unibs.sandroide.lib.item.Bleresource; /** * The class which implements the BLEGeneralIO resources (it's an actuator/sensor/button). */ public class SandroideDevice extends BLEItem { private final static String TAG = "SandroideDevice"; private final static int ANALOG_MAX_VALUE = 1023; protected Map<Integer, SandroidePin> pins = new HashMap<Integer, SandroidePin>(); protected OnDeviceConnectedListener bleOnDeviceConnectedListenerListener; protected OnMessageReceivedListener customOnMessageReceivedListener; private int devDummy = 0; public int getDevDummy() { return devDummy; } public SandroideDevice setDevDummy(int dummy) { this.devDummy = dummy; return this; } /** * Constructor of the {@link SandroideDevice} class. * @param name the name of the device to connect with (the name identifies exactly the * remote device anf the firmware version). * @param bleresource {@link Bleresource} which defines the Item. */ public SandroideDevice(String name, Bleresource bleresource) { super(BLEItem.TYPE_DEVICEIO, name, bleresource); } protected void sendMessage(String msg) { //this.mDeviceControl.writeChar(this.mDeviceControl.); //device //this.run //this.runA // //runAction(msg) } public void customAction(byte[] towrite) { this.runAction(towrite); } //@Override synchronized protected void runAction(byte[] towrite) { List input = new ArrayList<Float>(); for (int i = 0; i < towrite.length; i++) { input.add(new Float(towrite[i])); //input.addAll(new ArrayList<byte>(towrite)); } //input) float //towrite runAction("send_string_value", input); /* DeviceControl deviceControl = this.mDeviceControl; //BluetoothLeDevice mBluetoothLeDevice = deviceControl.mBluetoothLeDevice; //mServices = try { boolean lockGot; do{ lockGot=deviceControl.getLock().tryLock(100, TimeUnit.MILLISECONDS); } while (!lockGot); try{ int delay=0; //BluetoothGatt mBluetoothGatt = mBluetoothLeDevice.getBluetoothGatt(); deviceControl.writeChar("713d0000-503e-4c75-ba94-3148f18d941e","713d0003-503e-4c75-ba94-3148f18d941e",towrite); //BluetoothGattCharacteristic gattCharacteristic = mServices.get(service).get(characteristic); //gattCharacteristic.setValue(command); //boolean a=mBluetoothGatt.writeCharacteristic(gattCharacteristic); //Log.d(TAG, "writing was " + a); //Log.d(TAG, "byteArray was " + Arrays.toString(command)); //Delay(20); } finally { deviceControl.getLock().unlock(); } } catch (InterruptedException e) { e.printStackTrace(); }*/ } public SandroideDevice setCustomOnMessageReceived(OnMessageReceivedListener listener) { this.customOnMessageReceivedListener = listener; return this; } protected void jsonReceived(JSONObject obj) { // TODO: Json handling int pinNo = obj.optInt("pin", -1); SandroidePin pin = pins.containsKey(pinNo) ? (SandroidePin) pins.get(pinNo) : null; if (pin != null) { double val = obj.optDouble("v", -1); if (val >= 0) { pin.receivedValue(val); } } /*String action = obj.optString("action",null); switch(action) { case "config": // TODO break; }*/ } public void msgReceived(String msg) { msgReceived(msg.getBytes()); } private static String hexToAscii(String hexStr) { StringBuilder output = new StringBuilder(""); for (int i = 0; i < hexStr.length(); i += 2) { String str = hexStr.substring(i, i + 2); output.append((char) Integer.parseInt(str, 16)); } return output.toString(); } public void msgReceived(byte[] msg) { String strmsg = new String(msg); // if pin is set then we must pass the message to the right pin, if pin is omitted then this is a device-wide message //String msg2 = "J{\"pin\":2,\"cmd\":\"read\",value:3}"; //Log.d(TAG,"Message arrived"); boolean defaultHandling = true; if (customOnMessageReceivedListener != null) { defaultHandling = customOnMessageReceivedListener.onEvent(msg); } if (defaultHandling) { // default handling is not executed if customMessageReceived says to not process further if (msg.length > 0) { byte cmd = msg[0]; // first byte is the command boolean adafruitworkaround = cmd == 52 || cmd == 53; // workaround to make adafruit work. TOFIX: by fixing adafruit firmware sendMessage function sending byte array instead of newline terminated string if (adafruitworkaround) { // is a '4' or '5' // is written as hex G is 52,55 ..-> 4 7 -> G msg = hexToAscii(strmsg).getBytes(); cmd = msg[0]; // first byte is the command } switch (cmd) { case 'G': // these commands are pin commands, second byte is pin number int i = 1; if (adafruitworkaround) { SandroidePin pin = pins.containsKey((int) msg[i]) ? (SandroidePin) pins.get((int) msg[i]) : null; if (pin != null) { i++; if (strmsg.length() >= 8) pin.receivedValue(Integer.parseInt(strmsg.substring(i * 2, i * 2 + 2 * 2), 16)); } } else { while (i + 2 < msg.length) { SandroidePin pin = pins.containsKey((int) msg[i]) ? (SandroidePin) pins.get((int) msg[i]) : null; if (pin != null) { i++; while (i + 1 < msg.length) { pin.receivedValue(ByteBuffer.wrap(msg).getShort(i) / (float) ANALOG_MAX_VALUE); i += 2; } } i += 3; } } break; // // add more case here to add extra commands // case 'S': case '{': // { means that what follows is a JSON string try { Log.d(TAG, new String(msg)); jsonReceived(new JSONObject(new String(msg))); } catch (JSONException e) { e.printStackTrace(); } break; default: // is a JSON string Log.w(TAG, String.format("Unknown device message: %s", new String(msg))); break; } } } } public SandroidePin getPin(int pinNo) { if (pins.containsKey(pinNo)) return pins.get(pinNo); return null; } public SandroideDevice attachPin(SandroidePin pin) { if (pin == null) throw new RuntimeException("Error calling setPin! Pin object cannot be null!"); if (!this.pins.containsKey(pin.pinNo)) this.pins.put(pin.pinNo, pin); if (pin.getDevice() == null) pin.setDevice(this, pin.pinNo); return this; } public SandroideDevice setOnDeviceConnected(OnDeviceConnectedListener listener) { this.bleOnDeviceConnectedListenerListener = listener; return this; } /** * Overrides the initialization of the {@link it.unibs.sandroide.lib.device.DeviceControl} */ @Override protected void initDeviceControl() { final SandroideDevice self = this; super.initDeviceControl(); if (mDeviceControl != null) { setBleItemListeners(new BLEOnItemUpdateListener() { @Override public void onItemUpdate(BLEDeviceData[] data) { if (isItemInitiated) { // NOT DEFINED HERE: msgReceived is called directly from DeviceControl on ACTION_DATA_AVAILABLE } } }, new BLEOnItemInitiatedListener() { @Override public void onItemInitiated() { for (SandroidePin p : pins.values()) { // this will send pin parameters to device even if they have been set before bluetooth connection p.setMode(); if (p.isOutput()) p.setValue(); p.setSamplingInterval(); p.setDeltaThreshold(); p.setDutyCicle(); p.setPeriodMs(); } if (bleOnDeviceConnectedListenerListener != null) bleOnDeviceConnectedListenerListener.onEvent(self); isItemInitiated = true; } }); initItem(); } } /** * Interface definition for a callback to be invoked when a message is received. */ public interface OnMessageReceivedListener { // return true to allow default handling, false if message has been already handled by user defined callback boolean onEvent(byte[] value); } /** * Interface definition for a callback to be invoked when a message is received. */ public interface OnDeviceConnectedListener { // return true to allow default handling, false if message has been already handled by user defined callback void onEvent(SandroideDevice device); } }