/*
* Copyright 2011-16 Fraunhofer ISE
*
* This file is part of OpenMUC.
* For more information visit http://www.openmuc.org
*
* OpenMUC is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* OpenMUC is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenMUC. If not, see <http://www.gnu.org/licenses/>.
*
*/
package org.openmuc.framework.dataaccess;
import java.io.IOException;
import java.util.List;
import org.openmuc.framework.data.Flag;
import org.openmuc.framework.data.Record;
import org.openmuc.framework.data.Value;
import org.openmuc.framework.data.ValueType;
/**
* The <code>Channel</code> class is used to access a single data field of a communication device. A desired channel can
* be obtained using the <code>DataAccessService</code>. A channel instance can be used to
* <ul>
* <li>Access the latest record. That is the latest data record that the framework either sampled or received by
* listening or an application set using <code>setLatestRecord</code>.</li>
* <li>Directly read/write data from/to the corresponding communication device.</li>
* <li>Access historical data that was stored by a data logger such as SlotsDB.</li>
* <li>Get configuration information about this channel such as its unit.</li>
* </ul>
* <p>
* Note that only the call of the read or write functions will actually result in a corresponding read or write request
* being sent to the communication device.
*/
public interface Channel {
/**
* Returns the ID of this channel. The ID is usually a meaningful string. It is used to get Channel objects using
* the <code>DataAccessService</code>.
*
* @return the ID of this channel.
*/
String getId();
/**
* Returns the address of this channel. Returns the empty string if not configured.
*
* @return the address of this channel.
*/
String getChannelAddress();
/**
* Returns the description of this channel. Returns the empty string if not configured.
*
* @return the description of this channel.
*/
String getDescription();
/**
* Returns the unit of this channel. Returns the empty string if not configured. The unit is used for informational
* purposes only. Neither the framework nor any driver does value conversions based on the configured unit.
*
* @return the unit of this channel.
*/
String getUnit();
/**
* Returns the value type of this channel. The value type specifies how the value of the latest record of a channel
* is stored. A data logger is encouraged to store values using the configured value type if it supports that value
* type.
* <p>
* Usually an application does not need to know the value type of the channel because it can use the value type of
* its choice by using the corresponding function of {@link Value} (e.g. {@link Value#asDouble()}). Necessary
* conversions will be done transparently.
* <p>
* If no value type was configured, the default {@link ValueType#DOUBLE} is used.
*
* @return the value type of this channel.
*/
ValueType getValueType();
/**
* Returns the scaling factor. Returns 1.0 if the scaling factor is not configured.
* <p>
* The scaling factor is applied in the following cases:
* <ul>
* <li>Values received by this channel's driver or from apps through {@link #setLatestRecord(Record)} are multiplied
* with the scaling factor before they are stored in the latest record.</li>
* <li>Values written (e.g. using {@link #write(Value)}) are divided by the scaling factor before they are handed to
* the driver for transmission.</li>
* </ul>
*
* @return the scaling factor
*/
double getScalingFactor();
/**
* Returns the channel's configured sampling interval in milliseconds. Returns -1 if not configured.
*
* @return the channel's configured sampling interval in milliseconds.
*/
int getSamplingInterval();
/**
* Returns the channel's configured sampling time offset in milliseconds. Returns the default of 0 if not
* configured.
*
* @return the channel's configured sampling time offset in milliseconds.
*/
int getSamplingTimeOffset();
/**
* Returns the channel's configured logging interval in milliseconds. Returns -1 if not configured.
*
* @return the channel's configured logging interval in milliseconds.
*/
int getLoggingInterval();
/**
* Returns the channel's configured logging time offset in milliseconds. Returns the default of 0 if not configured.
*
* @return the channel's configured logging time offset in milliseconds.
*/
int getLoggingTimeOffset();
/**
* Returns the unique name of the communication driver that is used by this channel to read/write data.
*
* @return the unique name of the communication driver that is used by this channel to read/write data.
*/
String getDriverName();
/**
* Returns the channel's device address.
*
* @return the channel's device address.
*/
String getDeviceAddress();
/**
* Returns the name of the communication device that this channel belongs to. The empty string if not configured.
*
* @return the name of the communication device that this channel belongs to.
*/
String getDeviceName();
/**
* Returns the description of the communication device that this channel belongs to. The empty string if not
* configured.
*
* @return the description of the communication device that this channel belongs to.
*/
String getDeviceDescription();
/**
* Returns the current channel state.
*
* @return the current channel state.
*/
ChannelState getChannelState();
/**
* Returns the current state of the communication device that this channel belongs to.
*
* @return the current state of the communication device that this channel belongs to.
*/
DeviceState getDeviceState();
/**
* Adds a listener that is notified of new records received by sampling or listening.
*
* @param listener
* the record listener that is notified of new records.
*/
void addListener(RecordListener listener);
/**
* Removes a record listener.
*
* @param listener
* the listener shall be removed.
*/
void removeListener(RecordListener listener);
/**
* Returns <code>true</code> if a connection to the channel's communication device exist.
*
* @return <code>true</code> if a connection to the channel's communication device exist.
*/
boolean isConnected();
/**
* Returns the latest record of this channel. Every channel holds its latest record in memory. There exist three
* possible source for the latest record:
* <ul>
* <li>It may be provided by a communication driver that was configured to sample or listen on the channel. In this
* case the timestamp of the record represents the moment in time that the value was received by the driver.</li>
* <li>An application may also set the latest record using <code>setLatestRecord</code>.</li>
* <li>Finally values written using <code>write</code> are also stored as the latest record</li>
* </ul>
*
* Note that the latest record is never <code>NULL</code>. When a channel is first created its latest record is
* automatically initialized with a flag that indicates that its value is not valid.
*
* @return the latest record.
*/
Record getLatestRecord();
/**
* Sets the latest record of this channel. This function should only be used with channels that are neither sampling
* nor listening. Using this function it is possible to realize "virtual" channels that get their data not from
* drivers but from applications in the framework.
* <p>
* Note that the framework treats the passed record in exactly the same way as if it had been received from a
* driver. In particular that means:
* <ul>
* <li>If data logging is enabled for this channel the latest record is being logged by the registered loggers.</li>
* <li>Other applications can access the value set by this function using <code>getLatestRecord</code>.</li>
* <li>Applications are notified of the new record if they registered as listeners using <code>addListener</code>.
* <li>If a scaling factor has been configured for this channel then the value passed to this function is scaled.
* </li>
* </ul>
*
* @param record
* the record to be set.
*/
void setLatestRecord(Record record);
/**
* Writes the given value to the channel's corresponding data field in the connected communication device. If an
* error occurs, the returned <code>Flag</code> will indicate this.
*
* @param value
* the value that is to be written
* @return the flag indicating whether the value was successfully written ( <code>Flag.VALID</code>) or not (any
* other flag).
*/
Flag write(Value value);
/**
* Schedules a List<records> with future timestamps as write tasks <br>
* This function will schedule single write tasks to the provided timestamps.<br>
* Once this function is called, previously scheduled write tasks will be erased.<br>
*
* @param records
* each record contains the value that is to be written and the timestamp indicating when it should be
* written. The flag of the record is ignored.
*/
void write(List<Record> records);
/**
* Returns a <code>WriteValueContainer</code> that corresponds to this channel. This container can be passed to the
* write function of <code>DataAccessService</code> to write several values in one transaction.
*
* @return a <code>WriteValueContainer</code> that corresponds to this channel.
*/
WriteValueContainer getWriteContainer();
/**
* Actively reads a value from the channel's corresponding data field in the connected communication device. If an
* error occurs it will be indicated in the returned record's flag.
*
* @return the record containing the value read, the time the value was received and a flag indicating success (
* <code>Flag.VALID</code>) or a an error (any other flag).
*/
Record read();
/**
* Returns a <code>ReadRecordContainer</code> that corresponds to this channel. This container can be passed to the
* <code>read</code> function of <code>DataAccessService</code> to read several values in one transaction.
*
* @return a <code>ReadRecordContainer</code> that corresponds to this channel.
*/
ReadRecordContainer getReadContainer();
/**
* Returns the logged data record whose timestamp equals the given <code>time</code>. Note that it is the data
* logger's choice whether it stores values using the timestamp that the driver recorded when it received it or the
* timestamp at which the value is to be logged. If the former is the case then this function is not useful because
* it is impossible for an application to know the exact time at which a value was received. In this case use
* <code>getLoggedRecords</code> instead.
*
* @param time
* the time in milliseconds since midnight, January 1, 1970 UTC.
* @return the record that has been stored by the framework's data logger at the given <code>timestamp</code>.
* Returns <code>null</code> if no record exists for this point in time.
* @throws DataLoggerNotAvailableException
* if no data logger is installed and therefore no logged data can be accessed.
* @throws IOException
* if any kind of error occurs accessing the logged data.
*/
Record getLoggedRecord(long time) throws DataLoggerNotAvailableException, IOException;
/**
* Returns a list of all logged data records with timestamps from <code>startTime</code> up until now.
*
* @param startTime
* the starting time in milliseconds since midnight, January 1, 1970 UTC. inclusive
* @return a list of all logged data records with timestamps from <code>startTime</code> up until now.
* @throws DataLoggerNotAvailableException
* if no data logger is installed and therefore no logged data can be accessed.
* @throws IOException
* if any kind of error occurs accessing the logged data.
*/
List<Record> getLoggedRecords(long startTime) throws DataLoggerNotAvailableException, IOException;
/**
* Returns a list of all logged data records with timestamps from <code>startTime</code> to <code>endTime</code>
* inclusive.
*
* @param startTime
* the starting time in milliseconds since midnight, January 1, 1970 UTC. inclusive
* @param endTime
* the ending time in milliseconds since midnight, January 1, 1970 UTC. inclusive
* @return a list of all logged data records with timestamps from <code>startTime</code> to <code>endTime</code>
* inclusive.
* @throws DataLoggerNotAvailableException
* if no data logger is installed and therefore no logged data can be accessed.
* @throws IOException
* if any kind of error occurs accessing the logged data.
*/
List<Record> getLoggedRecords(long startTime, long endTime) throws DataLoggerNotAvailableException, IOException;
}