All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jpac.Decimal Maven / Gradle / Ivy

Go to download

Open-source runtime system for component-based implementation of automation solutions with Java

The newest version!
/**
 * PROJECT   : Elbfisch - java process automation controller (jPac)
 * MODULE    : Decimal.java
 * VERSION   : -
 * DATE      : -
 * PURPOSE   : 
 * AUTHOR    : Bernd Schuster, MSK Gesellschaft fuer Automatisierung mbH, Schenefeld
 * REMARKS   : -
 * CHANGES   : CH#n   
 *
 * This file is part of the jPac process automation controller.
 * jPac 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.
 *
 * jPac 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 the jPac If not, see .
 */

package org.jpac;

import java.net.URI;
import java.net.URISyntaxException;
import java.util.function.Supplier;

import org.jpac.vioss.IoDecimal;

/**
 * represents a decimal signal
 */
public class Decimal extends Signal{
    protected boolean        rangeChecked;
    protected double         minValue;
    protected double         maxValue;
    protected DecimalMapper  mapper;
    protected DecimalMapper  newMapper;
    protected String         unit;
    private   DecimalValue   wrapperValue;
    
    /**
     * constructs a decimal signal with intrinsic range check
     * @param containingModule: module this signal is contained in
     * @param identifier: identifier of the signal
     * @param minValue: minimum value signalValid for this decimal
     * @param maxValue: maximum value signalValid for this decimal
     * @param intrinsicFunction: intrinsic function which will be applied in every cycle to calculate the actual value
     * @param ioDirection: defines the signal as being either an INPUT or OUTPUT signal. (Relevant in distributed applications)
     * @throws org.jpac.SignalAlreadyExistsException
     */
    public Decimal(AbstractModule containingModule, String identifier, double minValue, double maxValue, Supplier intrinsicFunction, IoDirection ioDirection) throws SignalAlreadyExistsException{
    	super(containingModule, identifier, intrinsicFunction, ioDirection);
        this.wrapperValue       = new DecimalValue();
        this.minValue           = minValue;
        this.maxValue           = maxValue;
        this.rangeChecked       = true;//activate range check
        this.mapper             = null;
        this.unit               = null;
    }

    /**
     * constructs a decimal signal with intrinsic range check
     * @param containingModule: module this signal is contained in
     * @param identifier: identifier of the signal
     * @param minValue: minimum value signalValid for this decimal
     * @param maxValue: maximum value signalValid for this decimal
     * @param intrinsicFunction: intrinsic function which will be applied in every cycle to calculate the actual value
     * @throws org.jpac.SignalAlreadyExistsException
     */
    public Decimal(AbstractModule containingModule, String identifier, double minValue, double maxValue, Supplier intrinsicFunction) throws SignalAlreadyExistsException{
    	super(containingModule, identifier, intrinsicFunction, IoDirection.UNDEFINED);
        this.wrapperValue       = new DecimalValue();
        this.minValue           = minValue;
        this.maxValue           = maxValue;
        this.rangeChecked       = true;//activate range check
        this.mapper             = null;
        this.unit               = null;
    }

    /**
     * constructs a decimal signal with intrinsic range check
     * @param containingModule: module this signal is contained in
     * @param identifier: identifier of the signal
     * @param minValue: minimum value signalValid for this decimal
     * @param maxValue: maximum value signalValid for this decimal
     * @param ioDirection: defines the signal as being either an INPUT or OUTPUT signal. (Relevant in distributed applications)
     * @throws org.jpac.SignalAlreadyExistsException
     */
    public Decimal(AbstractModule containingModule, String identifier, double minValue, double maxValue, IoDirection ioDirection) throws SignalAlreadyExistsException{
    	this(containingModule, identifier, minValue, maxValue, null, ioDirection);
    }
    
    /**
     * constructs a decimal signal with intrinsic range check
     * @param containingModule: module this signal is contained in
     * @param identifier: identifier of the signal
     * @param minValue: minimum value signalValid for this decimal
     * @param maxValue: maximum value signalValid for this decimal
     * @throws org.jpac.SignalAlreadyExistsException
     */
    public Decimal(AbstractModule containingModule, String identifier, double minValue, double maxValue) throws SignalAlreadyExistsException{
    	this(containingModule, identifier, minValue, maxValue, IoDirection.UNDEFINED);
    }

    /**
     * constructs a decimal signal without range check.
     * @param containingModule: module this signal is contained in
     * @param identifier: identifier of the signal
     * @param ioDirection: defines the signal as being either an INPUT or OUTPUT signal. (Relevant in distributed applications)
     * @throws org.jpac.SignalAlreadyExistsException
     */
    public Decimal(AbstractModule containingModule, String identifier, IoDirection ioDirection) throws SignalAlreadyExistsException{
        this(containingModule, identifier, 0.0, 0.0, ioDirection);
        this.rangeChecked      = false;
    }    

    /**
     * constructs a decimal signal without range check.
     * @param containingModule: module this signal is contained in
     * @param identifier: identifier of the signal
     * @throws org.jpac.SignalAlreadyExistsException
     */
    public Decimal(AbstractModule containingModule, String identifier) throws SignalAlreadyExistsException{
        this(containingModule, identifier, 0.0, 0.0);
        this.rangeChecked      = false;
    }    

    /**
     * constructs a decimal signal without range check.
     * @param containingModule: module this signal is contained in
     * @param identifier: identifier of the signal
     * @param intrinsicFunction: intrinsic function which will be applied in every cycle to calculate the actual value
     * @param ioDirection: defines the signal as being either an INPUT or OUTPUT signal. (Relevant in distributed applications)
     * @throws org.jpac.SignalAlreadyExistsException
     */
    public Decimal(AbstractModule containingModule, String identifier, Supplier intrinsicFunction, IoDirection ioDirection) throws SignalAlreadyExistsException{
    	this(containingModule, identifier, 0.0, 0.0, intrinsicFunction, ioDirection);
        this.rangeChecked      = false;
    }    

    /**
     * constructs a decimal signal without range check.
     * @param containingModule: module this signal is contained in
     * @param identifier: identifier of the signal
     * @param intrinsicFunction: intrinsic function which will be applied in every cycle to calculate the actual value
     * @throws org.jpac.SignalAlreadyExistsException
     */
    public Decimal(AbstractModule containingModule, String identifier, Supplier intrinsicFunction) throws SignalAlreadyExistsException{
    	this(containingModule, identifier, 0.0, 0.0, intrinsicFunction);
        this.rangeChecked      = false;
    }    

    /**
     * constructs a decimal signal with a given default value and without range check.
     * @param containingModule: module this signal is contained in
     * @param identifier: identifier of the signal
     * @param defaultValue: default value of the signal
     * @param ioDirection: defines the signal as being either an INPUT or OUTPUT signal. (Relevant in distributed applications)
     * @throws org.jpac.SignalAlreadyExistsException
     */
    public Decimal(AbstractModule containingModule, String identifier, double defaultValue, IoDirection ioDirection) throws SignalAlreadyExistsException{
    	this(containingModule, identifier, ioDirection);
        this.rangeChecked      = false;
        this.initializing      = true;//prevent signal access assertion
        try{set(defaultValue);}catch(SignalAccessException exc){/*cannot happen*/}catch(NumberOutOfRangeException exc){/*cannot happen*/};
        this.initializing      = false;
    }
    
    /**
     * constructs a decimal signal with a given default value and without range check.
     * @param containingModule: module this signal is contained in
     * @param identifier: identifier of the signal
     * @param defaultValue: default value of the signal
     * @throws org.jpac.SignalAlreadyExistsException
     */
    public Decimal(AbstractModule containingModule, String identifier, double defaultValue) throws SignalAlreadyExistsException{
    	this(containingModule, identifier);
        this.rangeChecked      = false;
        this.initializing      = true;//prevent signal access assertion
        try{set(defaultValue);}catch(SignalAccessException exc){/*cannot happen*/}catch(NumberOutOfRangeException exc){/*cannot happen*/};
        this.initializing      = false;
    }

    /**
     * constructs a decimal signal with a given default value and intrinsic range check
     * @param containingModule: module this signal is contained in
     * @param identifier: identifier of the signal
     * @param minValue: minimum value signalValid for this decimal
     * @param maxValue: maximum value signalValid for this decimal
     * @param defaultValue: default value of the decimal
     * @param ioDirection: defines the signal as being either an INPUT or OUTPUT signal. (Relevant in distributed applications)
     * @throws NumberOutOfRangeException
     * @throws org.jpac.SignalAlreadyExistsException
     */
    public Decimal(AbstractModule containingModule, String identifier, double minValue, double maxValue, double defaultValue, IoDirection ioDirection) throws NumberOutOfRangeException, SignalAlreadyExistsException{
    	this(containingModule, identifier, minValue, minValue, ioDirection);
        this.initializing      = true;//prevent signal access assertion
        try{set(defaultValue);}catch(SignalAccessException exc){/*cannot happen*/};
        this.initializing      = false;
    }

    /**
     * constructs a decimal signal with a given default value and intrinsic range check
     * @param containingModule: module this signal is contained in
     * @param identifier: identifier of the signal
     * @param minValue: minimum value signalValid for this decimal
     * @param maxValue: maximum value signalValid for this decimal
     * @param defaultValue: default value of the decimal
     * @throws NumberOutOfRangeException
     * @throws org.jpac.SignalAlreadyExistsException
     */
    public Decimal(AbstractModule containingModule, String identifier, double minValue, double maxValue, double defaultValue) throws NumberOutOfRangeException, SignalAlreadyExistsException{
    	this(containingModule, identifier, minValue, minValue);
        this.initializing      = true;//prevent signal access assertion
        try{set(defaultValue);}catch(SignalAccessException exc){/*cannot happen*/};
        this.initializing      = false;
    }
    
    /**
     * used to set the decimal to the given value
     * @param value: value, the decimal is set to
     * @throws org.jpac.NumberOutOfRangeException
     * @throws org.jpac.SignalAccessException
     */
    public void set(double value) throws NumberOutOfRangeException, SignalAccessException{
        synchronized(this){
            assertRange(value);
            wrapperValue.set(value);
            wrapperValue.setValid(true);
            setValue(wrapperValue);
        }
    }
    
    /**
     * used to set the Decimal from any thread, which is not a module and not the jPac thread
     * The value is changed synchronized to the jPac cycle
     * @param value: value, the decimal is set to
     */
    public void setDeferred(double value){
        DecimalValue localWrapperValue = new DecimalValue();
        localWrapperValue.set(value);
        localWrapperValue.setValid(true);
        setValueDeferred(localWrapperValue);
    }
    

    /**
     * returns the value of the decimal. If the calling module is the containing module the value of this signal is returned.
     * If the calling module is a foreign module the propagated signal is returned.
     * @return see above
     * @throws org.jpac.SignalInvalidException
     */
    public double get() throws SignalInvalidException{
        return ((DecimalValue)getValidatedValue()).get();
    }
    
    /**
     * used to set the intrinsic function of this signal.
     * @param intrinsicFunction 
     */
    public void setIntrinsicFunction(Supplier intrinsicFunction){
        setIntrinsicFct(intrinsicFunction);
    }

    /**
     * returns a process event (DecimalExceeds), which is fired, if the decimal exceeds the given threshold
     * @param threshold: threshold to be supervised
     */
    public DecimalExceeds exceeds(double threshold){
        return new DecimalExceeds(this, threshold);
    }

    /**
     * returns a process event (DecimalFallsBelow), which is fired, if the decimal falls below the given threshold
     * @param threshold: threshold to be supervised
     */
    public DecimalFallsBelow fallsBelow(double threshold){
        return new DecimalFallsBelow(this, threshold);
    }

    /**
     * returns a process event (DecimalChanges), which is fired, if the decimal changes above the given threshold in relation to the given baseValue
     * @param baseValue
     * @param threshold: threshold to be supervised
     */
    public DecimalChanges changes(double baseValue, double threshold){
        return new DecimalChanges(this, baseValue, threshold);
    }

    /**
     * returns a process event (DecimalChanges), which is fired, whenever the decimal changes.
     * CAUTION: may be fired unintentionally due to noise in the last decimal places
     */
    public DecimalChanges changes(){
        return new DecimalChanges(this, 0.0, 0.0);
    }

    private void assertRange(double newValue) throws NumberOutOfRangeException{
        if (isRangeChecked()){
            if (newValue > getMaxValue() || newValue < getMinValue()){
                setValid(false);
                throw new NumberOutOfRangeException(newValue,getMinValue(), getMaxValue());
            }
        }
    }

    /**
     * used to connect this decimal to another decimal. One decimal can be connected
     * to multiple decimals.
     * The connection is unidirectional: Changes of the connecting signal (sourceSignal) will be
     * propagated to the signals it is connected to (targetSignal): sourceSignal.connect(targetSignal).
     * @param targetSignal
     */
    public void connect(Decimal targetSignal) throws SignalAlreadyConnectedException{
        synchronized(this){
            targetSignal.setNewMapper(null);
            super.connect(targetSignal);
        }
    }

    /**
     * used to connect this decimal to another decimal. One decimal can be connected
     * to multiple decimals.
     * The connection is unidirectional: Changes of the connecting signal (sourceSignal) will be
     * propagated to the signals it is connected to (targetSignal): sourceSignal.connect(targetSignal).
     * @param targetSignal
     * @param decimalMapper
     * @throws org.jpac.SignalAlreadyConnectedException
     * @throws org.jpac.SignalAccessException
     *
     */
    public void connect(Decimal targetSignal, DecimalMapper decimalMapper) throws SignalAlreadyConnectedException, SignalAccessException{
        synchronized(this){
            //the target is responsible for correct value mapping
            targetSignal.setNewMapper(decimalMapper);
            super.connect(targetSignal);
        }
    }

    /**
     * used to connect this decimal to another decimal. One decimal can be connected
     * to multiple decimals.
     * The connection is unidirectional: Changes of the connecting signal (sourceSignal) will be
     * propagated to the signals it is connected to (targetSignal): sourceSignal.connect(targetSignal).
     * @param targetSignal
     * @throws org.jpac.SignalAlreadyConnectedException
     */
    public void connect(SignedInteger targetSignal) throws SignalAlreadyConnectedException{
        synchronized(this){
            targetSignal.setNewMapper(new SignedIntegerMapper(Integer.MIN_VALUE, Integer.MAX_VALUE,Integer.MIN_VALUE, Integer.MAX_VALUE));        
            super.connect(targetSignal);
        }
    }

    /**
     * used to connect this decimal to another decimal. One decimal can be connected
     * to multiple decimals.
     * The connection is unidirectional: Changes of the connecting signal (sourceSignal) will be
     * propagated to the signals it is connected to (targetSignal): sourceSignal.connect(targetSignal).
     * @param targetSignal
     * @param signedIntegerMapper
     * @throws org.jpac.SignalAlreadyConnectedException
     * @throws org.jpac.SignalAccessException
     *
     */
    public void connect(SignedInteger targetSignal, SignedIntegerMapper signedIntegerMapper) throws SignalAlreadyConnectedException, SignalAccessException{
        synchronized(this){
            //the target is responsible for correct value mapping
            targetSignal.setNewMapper(signedIntegerMapper);
            super.connect(targetSignal);
        }
    }
    
    @Override
    protected void deferredConnect(Signal targetSignal) throws SignalAlreadyConnectedException{
        //first install mapper
        if (targetSignal instanceof Decimal){
            ((Decimal)targetSignal).setMapper(((Decimal)targetSignal).getNewMapper());
            ((Decimal)targetSignal).setNewMapper(null);
        } else if (targetSignal instanceof SignedInteger){
            ((SignedInteger)targetSignal).setMapper(((SignedInteger)targetSignal).getNewMapper());
            ((SignedInteger)targetSignal).setNewMapper(null);
        } 
        super.deferredConnect(targetSignal);
    }
    
    @Override
    protected void deferredDisconnect(Signal targetSignal){
        //first remove mapper
        if (targetSignal instanceof Decimal){
            ((Decimal)targetSignal).setMapper(null);
        } else if (targetSignal instanceof SignedInteger){
            ((SignedInteger)targetSignal).setMapper(null);
        } 
        super.deferredDisconnect(targetSignal);
    }
          
    /**
     * @return the rangeChecked
     */
    public boolean isRangeChecked() {
        return rangeChecked;
    }

    /**
     * @param rangeChecked the rangeChecked to set
     * @throws org.jpac.SignalAccessException
     */
    protected void setRangeChecked(boolean rangeChecked) throws SignalAccessException {
        assertContainingModule();
        this.rangeChecked = rangeChecked;
    }

    /**
     * @return the minValue
     */
    public double getMinValue() {
        return minValue;
    }

    /**
     * @param minValue the minValue to set
     * @throws org.jpac.SignalAccessException
     */
    protected void setMinValue(double minValue) throws SignalAccessException{
        assertContainingModule();
        this.minValue = minValue;
        setRangeChecked(this.minValue > Double.MIN_VALUE || this.maxValue < Double.MAX_VALUE);
    }

    /**
     * @return the maxValue
     */
    public double getMaxValue() {
        return maxValue;
    }

    /**
     * @param maxValue the maxValue to set
     * @throws org.jpac.SignalAccessException
     */
    protected void setMaxValue(double maxValue) throws SignalAccessException{
        assertContainingModule();
        this.maxValue = maxValue;
        setRangeChecked(this.minValue > Double.MIN_VALUE || this.maxValue < Double.MAX_VALUE);
    }

    /**
     * @return the maxValue
     */
    public String getUnit() {
        return this.unit;
    }

    /**
     * @param unit: string representation of the unit
     * @throws org.jpac.SignalAccessException
     */
    protected void setUnit(String unit) throws SignalAccessException{
        assertContainingModule();
        this.unit = unit;
    }
 
    /**
     * @return the mapper
     */
    public DecimalMapper getMapper() {
        return mapper;
    }

    /**
     * @param decimalMapper
     */
    protected void setMapper(DecimalMapper decimalMapper){   
        this.mapper = decimalMapper;
    }

    /**
     * @return the mapper
     */
    public DecimalMapper getNewMapper() {
        return newMapper;
    }

    /**
     * @param decimalMapper
     */
    protected void setNewMapper(DecimalMapper decimalMapper){   
        this.newMapper = decimalMapper;
    }

    @Override
    protected boolean isCompatibleSignal(Signal signal) {
        return signal instanceof Decimal;
    }

    @Override
    protected void propagateSignalInternally() {
        //physically copy the value to the propagated value
        ((DecimalValue)getPropagatedValue()).copy((DecimalValue)getValue());
    }

    @Override
    protected void updateValue(Object o, Object arg) throws SignalAccessException {
        try{
            if (o instanceof Decimal){
                if (getMapper() != null){
                    set(getMapper().map(((Decimal)o).get()));
                }
                else{
                    set(((Decimal)o).get());
                }
            }
            if (o instanceof SignedInteger){
                //this instance must supply a mapper
                set(getMapper().map(((SignedInteger)o).get()));
            }
        }
        catch(Exception exc){
        	if (Log.isDebugEnabled()) Log.error(this + " : " + exc.getMessage());
        	invalidate();
        }
    }

    @Override
    protected void applyTypedIntrinsicFunction() throws Exception {
        if (intrinsicFunction != null){
           set((Double)intrinsicFunction.get()); 
        }
    }

    @Override
    protected Value getTypedValue() {
  	  return new DecimalValue();
    }

    @Override
    protected Signal getTypedProxyIoSignal(URI remoteElbfischInstance, IoDirection ioDirection) {
  		Signal signal = null;
  		
  		try{
  	    	String sigIdentifier = getIdentifier() + PROXYQUALIFIER;
  			URI  sigUri = new URI(remoteElbfischInstance + "/" + getQualifiedIdentifier());
  			signal = new IoDecimal(containingModule, sigIdentifier, sigUri, ioDirection);
  		} catch(URISyntaxException exc) {
  			throw new RuntimeException("failed to instantiate proxy signal: ", exc);
  		}
  		return signal;
    }
    
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy