/*
* Dog - Network Driver
*
* Copyright (c) 2012-2014 Dario Bonino and Luigi De Russis
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License
*/
package it.polito.elite.dog.drivers.echelon.ilon100.network;
import it.polito.elite.dog.core.library.util.ElementDescription;
import it.polito.elite.dog.core.library.model.ControllableDevice;
import it.polito.elite.dog.core.library.model.DeviceStatus;
import it.polito.elite.dog.core.library.model.StatefulDevice;
import it.polito.elite.dog.drivers.echelon.ilon100.network.info.CmdNotificationInfo;
import it.polito.elite.dog.drivers.echelon.ilon100.network.info.DataPointInfo;
import it.polito.elite.dog.drivers.echelon.ilon100.network.info.EchelonIlonInfo;
import it.polito.elite.dog.drivers.echelon.ilon100.network.interfaces.EchelonIlon100Network;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
/**
* An abstract class to be extended by device-specific network drivers, allows
* driver developers to avoid dealing with common network operations.
*
* @author <a href="mailto:dario.bonino@polito.it">Dario Bonino</a>
* @see <a href="http://elite.polito.it">http://elite.polito.it</a>
*
*/
public abstract class EchelonIlon100DriverInstance implements StatefulDevice
{
// a reference to the network driver interface to allow network-level access
// for sub-classes
protected EchelonIlon100Network network;
// the state of the device associated to this driver
protected DeviceStatus currentState;
// the device associated to the driver
protected ControllableDevice device;
// the endpoint address associated to this device by means of the gateway
// attribute
protected String endpointAddress;
// the datapoints managed by this driver
protected Set<DataPointInfo> managedDatapoints;
// the datapoint to notifications map
protected Map<DataPointInfo, Set<CmdNotificationInfo>> datapoint2Notification;
// the command2datapoint map
protected Map<CmdNotificationInfo, DataPointInfo> command2Datapoint;
/**
* Notifies a device-specific driver of a new datapoint value coming from
* the underlying iLon100 network connection (either through polling or
* through direct read). The updated value is contained in the given
* {@link DataPointInfo} instance.
*
* @param dataPointInfo
* The {@link DataPointInfo} instance representing the data point
* whose value has changed.
*/
public abstract void newMessageFromHouse(DataPointInfo dataPointInfo);
/**
* The base class constructor, provides common initialization for all the
* needed data structures, must be called by sub-class constructors
*
* @param network
* the network driver to use (as described by the
* {@link EchelonIlon100Network} interface.
* @param device
* the device to which this driver is attached/associated
*/
public EchelonIlon100DriverInstance(EchelonIlon100Network network, ControllableDevice device, String endpointAddress)
{
// store a reference to the network driver
this.network = network;
// store a reference to the associate device
this.device = device;
// store the endpoint address for the attached device
this.endpointAddress = endpointAddress;
// create the map needed to associate datapoints to notifications
this.datapoint2Notification = new ConcurrentHashMap<DataPointInfo, Set<CmdNotificationInfo>>();
// create the map to associate commands and datapoints
this.command2Datapoint = new ConcurrentHashMap<CmdNotificationInfo, DataPointInfo>();
// create the set for storing the managed datapoints
this.managedDatapoints = new HashSet<DataPointInfo>();
// fill the data structures depending on the specific device
// configuration parameters
this.fillConfiguration();
// call the specific configuration method, if needed
this.specificConfiguration();
// associate the device-specific driver to the network driver
for (DataPointInfo dp : this.managedDatapoints)
this.addToNetworkDriver(dp);
}
/**
* Extending classes might implement this method to provide driver-specific
* configurations to be done during the driver creation process, before
* associating the device-specific driver to the network driver
*/
protected abstract void specificConfiguration();
/**
* Adds a device managed by a device-specific driver instance to the
* {@link EchelonIlon100Network} driver. It must be implemented by extending
* classes and it must take care of identifying any additional information
* needed to correctly specify the given datapoint and to associate the
* corresponding {@link DataPointInfo} with the proper
* {@link EchelonIlon100DriverImpl} instance.
*
* @param dp
* the data point to add as a {@link DataPointInfo} instance.
*/
protected abstract void addToNetworkDriver(DataPointInfo dp);
/***
* Fills the inner data structures depending on the specific device
* configuration parameters, extracted from the device instance associated
* to this driver instance
*/
private void fillConfiguration()
{
// gets the properties shared by almost all EchelonDevices, i.e. the
// datapointId and the datapoint unit of measure
// It must be noticed that such informations are specified for each
// command/notification while no common parameters are defined/handled
// get parameters associated to each device command (if any)
Set<ElementDescription> commandsSpecificParameters = this.device.getDeviceDescriptor()
.getCommandSpecificParams();
// get parameters associated to each device notification (if any)
Set<ElementDescription> notificationsSpecificParameters = this.device.getDeviceDescriptor()
.getNotificationSpecificParams();
// --------------- Handle command specific parameters ----------------
for (ElementDescription parameter : commandsSpecificParameters)
{
// get the real command name
String realCommandName = parameter.getElementParams().get(EchelonIlonInfo.COMMAND_NAME);
// get the iLon data point id
String datapointId = parameter.getElementParams().get(EchelonIlonInfo.DATAPOINT_ID);
// get the iLon data point unit of measure
String unitOfMeasure = parameter.getElementParams().get(EchelonIlonInfo.DATAPOINT_UOM);
// get the iLon data point alias
String datapointAlias = parameter.getElementParams().get(EchelonIlonInfo.DATAPOINT_ALIAS);
// if no data point id has been specified, then the command
// cannot be handled
if (datapointId != null)
{
// build the data point info instance to associate to this
// command
DataPointInfo dp = new DataPointInfo(datapointId, datapointAlias, unitOfMeasure, this.endpointAddress);
CmdNotificationInfo cmdInfo = new CmdNotificationInfo(realCommandName, parameter.getElementParams());
// add the command to data point entry
this.command2Datapoint.put(cmdInfo, dp);
// add the datapoint to the set of managed datapoints
this.managedDatapoints.add(dp);
}
}
// --------------- Handle notification specific parameters
// ----------------
for (ElementDescription parameter : notificationsSpecificParameters)
{
// get the real command name
String notificationName = parameter.getElementParams().get(EchelonIlonInfo.NOTIFICATION_NAME);
// get the iLon data point id
String datapointId = parameter.getElementParams().get(EchelonIlonInfo.DATAPOINT_ID);
// get the iLon data point unit of measure
String unitOfMeasure = parameter.getElementParams().get(EchelonIlonInfo.DATAPOINT_UOM);
// get the iLon data point alias
String datapointAlias = parameter.getElementParams().get(EchelonIlonInfo.DATAPOINT_ALIAS);
// if no data point id has been specified, then the notification
// cannot be handled
if (datapointId != null)
{
// build the data point info instance to associate to this
// command
DataPointInfo dp = new DataPointInfo(datapointId, datapointAlias, unitOfMeasure, this.endpointAddress);
// fill the data point to notification map, if the data point
// has
// never been registered create a new entry in the map.
Set<CmdNotificationInfo> notificationNames = this.datapoint2Notification.get(dp);
if (notificationNames == null)
{
notificationNames = new HashSet<CmdNotificationInfo>();
this.datapoint2Notification.put(dp, notificationNames);
}
// add the notification name to the set associated to the dp
// datapoint
CmdNotificationInfo nInfo = new CmdNotificationInfo(notificationName, parameter.getElementParams());
notificationNames.add(nInfo);
// add the datapoint to the set of managed datapoints
this.managedDatapoints.add(dp);
}
}
}
/**
* Provides safe access to the end point address associated to the device
* connected to this driver...
*
* @return the endpointAddress
*/
public String getEndpointAddress()
{
return endpointAddress;
}
/**
* Tries to retrieve the initial state of the device handled by this driver
*/
public void getInitialState()
{
// for each datapoint registered with this driver, call the read command
for (DataPointInfo dp : this.managedDatapoints)
this.network.read(dp);
}
}