package t2.spine.communication.android; import net.tinyos.message.MessageListener; import com.t2.AndroidSpineServerMainActivity; //import com.t2.AndroidSpineServerMainActivity; import com.t2.Constants; import jade.util.Logger; import spine.SPINEManager; import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; import android.os.Bundle; import android.os.Handler; import android.os.IBinder; import android.os.Message; import android.os.Messenger; import android.os.RemoteException; import android.util.Log; /** * This class encapsulates the lowest level of interfacing messaging between * the androidServer and the AndroidBTService (Which acts as a serial forwarder) * @author scott.coleman * */ public class AndroidMessageServer extends BroadcastReceiver { static int msgCount = 0; private static final String TAG = Constants.TAG; // TODO: should share these with service so we know we're using the same labels! public static final String ACTION_STATUS_BROADCAST = "com.t2.biofeedback.service.status.BROADCAST"; public static final String ACTION_SERVER_DATA_BROADCAST = "com.t2.biofeedback.server.data.BROADCAST"; public static final String EXTRA_ADDRESS = "address"; public static final String EXTRA_NAME = "name"; public static final String EXTRA_MESSAGE_TYPE = "messageType"; public static final String EXTRA_MESSAGE_PAYLOAD = "messagePayload"; public static final String EXTRA_MESSAGE_ID = "messageId"; public static final String EXTRA_MESSAGE_VALUE = "messageValue"; public static final String EXTRA_TIMESTAMP = "timestamp"; public static final String EXTRA_MSG_BYTES = "msgBytes"; private static MessageListener androidLocalNodeAdapter; public AndroidMessageServer() { // Bind the the AndroidBTService (serial forwarder) doBindService(); } // The following is legacy code for when we used to send sensor data using // broadcast intents: @Override public void onReceive(Context context, Intent intent) { // This interface code is left in for the off chance we might want to uset the old mechanism // int srcID = 99; // // if(intent.getAction().equals("com.t2.biofeedback.service.spinedata.BROADCAST")) { // if(androidLocalNodeAdapter != null) { // // AndroidMessage tosmsg = null; // // change the intent array to shorts // byte[] bytes = intent.getByteArrayExtra(EXTRA_MSG_BYTES); // tosmsg = AndroidMessage.Construct(bytes); // androidLocalNodeAdapter.messageReceived(srcID, tosmsg); // } // } } /** * Registers a listener for data messages * @param arg Listener to send received messages to */ public void registerListener(MessageListener arg) { if (SPINEManager.getLogger().isLoggable(Logger.INFO)) { StringBuffer str = new StringBuffer(); str.append("registered SocketMessageListener: "); str.append(arg); SPINEManager.getLogger().log(Logger.INFO, str.toString()); } androidLocalNodeAdapter = arg; } /** * Message used for Spine commands * @author scott.coleman * */ public abstract static class BioFeedbackMessage { public String address; public String name; public String messageType; public String messageId; public Double messageValue; } /** * Sends a command (in an AndroidMessage) to a sensor node * @param destNodeID Address of destination node * @param msg Message to send */ public void sendCommand(int destNodeID, AndroidMessage andMsg) { if (SPINEManager.getLogger().isLoggable(Logger.INFO)) { StringBuffer str = new StringBuffer(); str.append("Send cmd: "); str.append(andMsg.toString()); str.append(" to node: "); str.append(destNodeID); SPINEManager.getLogger().log(Logger.INFO, str.toString()); } // Send the command via handlers instead try { short pktType = andMsg.header.getPktType(); Message msg = Message.obtain(null,MSG_SPINE_COMMAND, pktType, 0); // Check to see if there is a payload, of so add it to the message if (andMsg.payloadBuf.length > 0) { Bundle b = new Bundle(); b.putByteArray("EXTRA_MESSAGE_PAYLOAD", andMsg.payloadBuf); msg.setData(b); } mService.send(msg); } catch (RemoteException e) { Log.e(TAG,"Error sending SPINE command to service"); } catch (NullPointerException e) { Log.e(TAG,"Error sending SPINE command to service - NULL POINTER"); } } /** * Command to the service to register a client, receiving callbacks * from the service. The Message's replyTo field must be a Messenger of * the client where callbacks should be sent. */ static final int MSG_REGISTER_CLIENT = 1; /** * Command to the service to unregister a client, ot stop receiving callbacks * from the service. The Message's replyTo field must be a Messenger of * the client as previously given with MSG_REGISTER_CLIENT. */ static final int MSG_UNREGISTER_CLIENT = 2; /** * Command to service to set a new value. This can be sent to the * service to supply a new value, and will be sent by the service to * any registered clients with the new value. */ static final int MSG_SET_VALUE = 3; /** * Command to the service to send a spine command */ static final int MSG_SPINE_COMMAND = 8888; /** Messenger for communicating with service. */ Messenger mService = null; private static final int MSG_SET_ARRAY_VALUE = 5; /** * Handler of incoming messages from service. */ class IncomingHandler extends Handler { @Override public void handleMessage(Message msg) { int srcID = 99; switch (msg.what) { case MSG_SET_ARRAY_VALUE: byte[] bytes = msg.getData().getByteArray("message"); if (bytes != null) { AndroidMessage tosmsg = null; tosmsg = AndroidMessage.Construct(bytes); androidLocalNodeAdapter.messageReceived(srcID, tosmsg); } break; default: super.handleMessage(msg); } } } /** * Target we publish for clients to send messages to IncomingHandler. */ final Messenger mMessenger = new Messenger(new IncomingHandler()); /** * Class for interacting with the main interface of the service. */ private ServiceConnection mConnection = new ServiceConnection() { public void onServiceConnected(ComponentName className,IBinder service) { // This is called when the connection with the service has been // established, giving us the service object we can use to // interact with the service. We are communicating with our // service through an IDL interface, so get a client-side // representation of that from the raw service object. mService = new Messenger(service); AndroidSpineServerMainActivity.getInstance().setmService(mService); // AndroidSpineConnector.getInstance().setmService(mService); Log.i(TAG,"Service Connected"); // We want to monitor the service for as long as we are // connected to it. try { Message msg = Message.obtain(null,MSG_REGISTER_CLIENT); msg.replyTo = mMessenger; mService.send(msg); // Give it some value as an example. // msg = Message.obtain(null,MSG_SET_VALUE, this.hashCode(), 0); // mService.send(msg); } catch (RemoteException e) { Log.e(TAG,"Remove exception " + e.toString()); // In this case the service has crashed before we could even // do anything with it; we can count on soon being // disconnected (and then reconnected if it can be restarted) // so there is no need to do anything here. } } /** * Called when the service is disconnected * @see android.content.ServiceConnection#onServiceDisconnected(android.content.ComponentName) */ public void onServiceDisconnected(ComponentName className) { // This is called when the connection with the service has been // unexpectedly disconnected -- that is, its process crashed. mService = null; AndroidSpineServerMainActivity.getInstance().setmService(mService); // AndroidSpineConnector.getInstance().setmService(mService); Log.i(TAG,"Service Disconnected"); } }; /** * Calls the main activity to bind us to the sdrvice * Note: we have to do this in the main activity so it knows about our connection * so that it can un-bind on destroy time. * This class doesn't know about the destroy event */ void doBindService() { AndroidSpineServerMainActivity.getInstance().doBindService(mConnection); // AndroidSpineConnector.getInstance().doBindService(mConnection); } // The following is legacy code for when we used to send sensor data using // broadcast intents: // public static class BioFeedbackSpineData extends BioFeedbackMessage { // public byte[] msgBytes; // public long currentTimestamp; // // public static BioFeedbackSpineData factory(Intent i) { // BioFeedbackSpineData m = new BioFeedbackSpineData(); // m.address = i.getStringExtra("address"); // m.name = i.getStringExtra("name"); // m.messageType = i.getStringExtra("messageType"); // m.messageId = i.getStringExtra("messageId"); // m.msgBytes = i.getByteArrayExtra("msgBytes"); // m.currentTimestamp = i.getLongExtra("currentTimestamp", 0); // // return m; // } // } }