public void discoveryCompleted(Vector activeNodes) { // we loop over the discovered nodes (hopefully, at least a node's showed up!) Node curr = null; for (int j = 0; j < activeNodes.size(); j++) { curr = (Node) activeNodes.elementAt(j); // we print for each node its details (nodeID, sensors and functions provided) System.out.println(curr); // for each node, we look for specific services for (int i = 0; i < curr.getSensorsList().size(); i++) { byte sensor = ((Sensor) curr.getSensorsList().elementAt(i)).getCode(); // if the current node has an accelerometer, then... if (sensor == SPINESensorConstants.ACC_SENSOR) { // ... we first setup that sensor, specifying its sampling time and time scale; then ... SpineSetupSensor sss = new SpineSetupSensor(); sss.setSensor(sensor); sss.setTimeScale(SPINESensorConstants.MILLISEC); sss.setSamplingTime(SAMPLING_TIME); manager.setup(curr, sss); // ... we can setup a specific function (in this case a Feature) on that sensor; then ... FeatureSpineSetupFunction ssf = new FeatureSpineSetupFunction(); ssf.setSensor(sensor); ssf.setWindowSize(WINDOW_SIZE); ssf.setShiftSize(SHIFT_SIZE); manager.setup(curr, ssf); // ... we can activate that function with function specific parameters // (for Feature they are the desired feature extractors); we can also ... FeatureSpineFunctionReq sfr = new FeatureSpineFunctionReq(); sfr.setSensor(sensor); sfr.add( new Feature( SPINEFunctionConstants.MODE, ((Sensor) curr.getSensorsList().elementAt(i)).getChannelBitmask())); sfr.add( new Feature( SPINEFunctionConstants.MEDIAN, ((Sensor) curr.getSensorsList().elementAt(i)).getChannelBitmask())); sfr.add( new Feature( SPINEFunctionConstants.MAX, ((Sensor) curr.getSensorsList().elementAt(i)).getChannelBitmask())); sfr.add( new Feature( SPINEFunctionConstants.MIN, ((Sensor) curr.getSensorsList().elementAt(i)).getChannelBitmask())); manager.activate(curr, sfr); // ... split a more complex activation in multiple activations // (if the specific function implementation in the node side allows that); of course we // always can ... sfr = new FeatureSpineFunctionReq(); sfr.setSensor(sensor); sfr.add( new Feature( SPINEFunctionConstants.MEAN, ((Sensor) curr.getSensorsList().elementAt(i)).getChannelBitmask())); sfr.add( new Feature( SPINEFunctionConstants.AMPLITUDE, ((Sensor) curr.getSensorsList().elementAt(i)).getChannelBitmask())); manager.activate(curr, sfr); // SetUp Alarm Engine // Window and Shift may be set to value different from the feature engine ones. // here we use the same values for debigging proposes AlarmSpineSetupFunction ssf2 = new AlarmSpineSetupFunction(); ssf2.setSensor(sensor); ssf2.setWindowSize(WINDOW_SIZE); ssf2.setShiftSize(SHIFT_SIZE); manager.setup(curr, ssf2); // Activate alarm on MAX value (one of the features computed above) on CH1 // alarm sent when MAX > upperThresold AlarmSpineFunctionReq sfr2 = new AlarmSpineFunctionReq(); int lowerThreshold = 20; int upperThreshold = 40; sfr2.setDataType(SPINEFunctionConstants.MAX); sfr2.setSensor(SPINESensorConstants.ACC_SENSOR); sfr2.setValueType((SPINESensorConstants.CH1_ONLY)); sfr2.setLowerThreshold(lowerThreshold); sfr2.setUpperThreshold(upperThreshold); sfr2.setAlarmType(SPINEFunctionConstants.ABOVE_THRESHOLD); manager.activate(curr, sfr2); // Activate alarm on AMPLITUDE value (one of the features computed above) on CH2 // alarm sent when AMPLITUDE < lowerThreshold lowerThreshold = 2000; upperThreshold = 1000; sfr2.setDataType(SPINEFunctionConstants.AMPLITUDE); sfr2.setSensor(SPINESensorConstants.ACC_SENSOR); sfr2.setValueType((SPINESensorConstants.CH2_ONLY)); sfr2.setLowerThreshold(lowerThreshold); sfr2.setUpperThreshold(upperThreshold); sfr2.setAlarmType(SPINEFunctionConstants.BELOW_THRESHOLD); manager.activate(curr, sfr2); } // repeat this process for other desired sensors; after that we can finally ... else if (sensor == SPINESensorConstants.INTERNAL_TEMPERATURE_SENSOR) { SpineSetupSensor sss = new SpineSetupSensor(); sss.setSensor(sensor); sss.setTimeScale(SPINESensorConstants.MILLISEC); sss.setSamplingTime(OTHER_SAMPLING_TIME); manager.setup(curr, sss); FeatureSpineSetupFunction ssf = new FeatureSpineSetupFunction(); ssf.setSensor(sensor); ssf.setWindowSize(OTHER_WINDOW_SIZE); ssf.setShiftSize(OTHER_SHIFT_SIZE); manager.setup(curr, ssf); FeatureSpineFunctionReq sfr = new FeatureSpineFunctionReq(); sfr.setSensor(sensor); sfr.add( new Feature( SPINEFunctionConstants.MODE, ((Sensor) curr.getSensorsList().elementAt(i)).getChannelBitmask())); sfr.add( new Feature( SPINEFunctionConstants.MEDIAN, ((Sensor) curr.getSensorsList().elementAt(i)).getChannelBitmask())); sfr.add( new Feature( SPINEFunctionConstants.MAX, ((Sensor) curr.getSensorsList().elementAt(i)).getChannelBitmask())); sfr.add( new Feature( SPINEFunctionConstants.MIN, ((Sensor) curr.getSensorsList().elementAt(i)).getChannelBitmask())); manager.activate(curr, sfr); // SetUp Alarm Engine // Same Window and Shift as before AlarmSpineSetupFunction ssf3 = new AlarmSpineSetupFunction(); ssf3.setSensor(sensor); ssf3.setWindowSize(WINDOW_SIZE); ssf3.setShiftSize(SHIFT_SIZE); manager.setup(curr, ssf3); // Activate alarm on MIN value (one of the features computed above)on CH1 // alarm sent when lowerThreshold < MIN < upperThreshold AlarmSpineFunctionReq sfr3 = new AlarmSpineFunctionReq(); int lowerThreshold = 1000; int upperThreshold = 3000; sfr3.setDataType(SPINEFunctionConstants.MIN); sfr3.setSensor(sensor); sfr3.setValueType((SPINESensorConstants.CH1_ONLY)); sfr3.setLowerThreshold(lowerThreshold); sfr3.setUpperThreshold(upperThreshold); sfr3.setAlarmType(SPINEFunctionConstants.IN_BETWEEN_THRESHOLDS); manager.activate(curr, sfr3); } } } // ... start the sensor network sensing and computing our aforeactivated services. if (activeNodes.size() > 0) manager.startWsn( true, true); // we can tune a few node parameters at run-time for reducing the power consumption // and the packets drop. }
public void received(Data data) { // the specific application logic behaves w.r.t. the type of data received System.out.println(data); switch (data.getFunctionCode()) { case SPINEFunctionConstants.FEATURE: { features = ((FeatureData) data).getFeatures(); counter++; // even this simple application shows us up some nice SPINE properties; in fact ... if (counter == 5) { // it's possible to deactivate functions computation at runtime (even when the radio on // the node works in low-power mode) FeatureSpineFunctionReq sfr = new FeatureSpineFunctionReq(); sfr.setSensor(features[0].getSensorCode()); sfr.remove(new Feature(features[0].getFeatureCode(), SPINESensorConstants.ALL)); manager.deactivate(data.getNode(), sfr); } if (counter == 10) { // and, of course, we can activate new functions at runtime FeatureSpineFunctionReq sfr = new FeatureSpineFunctionReq(); sfr.setSensor(features[0].getSensorCode()); sfr.add(new Feature(SPINEFunctionConstants.RANGE, SPINESensorConstants.CH1_ONLY)); manager.activate(data.getNode(), sfr); } if (counter == 20) { // when we are set, we can decide to ... // stop the WSN, forcing a 'software' reset of the nodes /* manager.resetWsn(); */ // or just deregister ourself to further SPINE events. // manager.deregisterListener(this); } break; } case SPINEFunctionConstants.ONE_SHOT: // OneShotData oneShot = (OneShotData)data; // if needed 'data' can be casted to // spine.datamodel.OneShotData break; case SPINEFunctionConstants.ALARM: // AlarmData alarm = (AlarmData)data; // if needed 'data' can be casted to // spine.datamodel.AlarmData counter_alarm++; if (counter_alarm == 20) { AlarmSpineFunctionReq sfr2 = new AlarmSpineFunctionReq(); sfr2.setSensor(SPINESensorConstants.ACC_SENSOR); sfr2.setAlarmType(SPINEFunctionConstants.ABOVE_THRESHOLD); sfr2.setDataType(SPINEFunctionConstants.MAX); sfr2.setValueType((SPINESensorConstants.CH1_ONLY)); manager.deactivate(data.getNode(), sfr2); } break; } }