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

org.ogema.channelmapperv2.impl.ChannelController Maven / Gradle / Ivy

The newest version!
/**
 * Copyright 2011-2018 Fraunhofer-Gesellschaft zur Förderung der angewandten Wissenschaften e.V.
 *
 * 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 org.ogema.channelmapperv2.impl;

import java.util.Collections;
import java.util.List;
import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;

import org.ogema.channelmapperv2.config.ChannelMapperConfigPattern;
import org.ogema.core.channelmanager.ChannelAccess;
import org.ogema.core.channelmanager.ChannelAccessException;
import org.ogema.core.channelmanager.ChannelConfiguration;
import org.ogema.core.channelmanager.ChannelEventListener;
import org.ogema.core.channelmanager.EventType;
import org.ogema.core.channelmanager.ChannelConfiguration.Direction;
import org.ogema.core.channelmanager.driverspi.ChannelLocator;
import org.ogema.core.channelmanager.driverspi.SampledValueContainer;
import org.ogema.core.channelmanager.measurements.BooleanValue;
import org.ogema.core.channelmanager.measurements.FloatValue;
import org.ogema.core.channelmanager.measurements.IntegerValue;
import org.ogema.core.channelmanager.measurements.LongValue;
import org.ogema.core.channelmanager.measurements.Value;
import org.ogema.core.model.ValueResource;
import org.ogema.core.model.simple.BooleanResource;
import org.ogema.core.model.simple.FloatResource;
import org.ogema.core.model.simple.IntegerResource;
import org.ogema.core.model.simple.SingleValueResource;
import org.ogema.core.model.simple.TimeResource;
import org.ogema.core.resourcemanager.ResourceValueListener;
import org.ogema.tools.resource.util.ValueResourceUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class ChannelController implements ResourceValueListener, ChannelEventListener, Runnable {

	private final static long MAX_DELAY = 900000; // 15min
	final ChannelMapperConfigPattern pattern;
	private volatile ChannelConfiguration channelConfiguration;
	private final Logger logger;
	private final ChannelAccess ca;
	final ChannelLocator channelLocator;
	private final ChannelMapperImpl mapper;
	private volatile ScheduledExecutorService t;
	private volatile ScheduledFuture openTask;
	private volatile long delay = 5000;
	
	public ChannelController(ChannelMapperConfigPattern pattern, ChannelAccess ca, ChannelMapperImpl mapper) {
		this.pattern = pattern;
		this.ca = ca;
		this.logger = mapper.logger;
		this.mapper = mapper;
		this.channelLocator = ChannelMapperUtil.getChannelLocator(pattern.channelLocator);
		this.run();
	}
	
	@Override
	public void run() {
		if (!pattern.model.isActive())
			return;
		try {
			Direction direction = Direction.valueOf(pattern.direction.getValue()); // potentially throws an exception
			long samplingPeriod;
			if (pattern.samplingInterval.isActive())
				samplingPeriod = pattern.samplingInterval.getValue();
			else
				samplingPeriod = 60000;
			channelConfiguration = ca.addChannel(channelLocator, direction, samplingPeriod);
			if (direction == Direction.DIRECTION_OUTPUT || direction == Direction.DIRECTION_INOUT)  {
				pattern.target.addValueListener(this);
			}
			if (direction == Direction.DIRECTION_INPUT || direction == Direction.DIRECTION_INOUT)
				ca.registerUpdateListener(Collections.singletonList(channelConfiguration), this);
			pattern.registrationSuccessful. create().setValue(true);
			pattern.registrationSuccessful.activate(false);
			t = null;
			openTask = null;
		} catch (ChannelAccessException cae) {
			if (!pattern.model.isActive())
				return;
			if (delay < MAX_DELAY) {
				delay = delay * 2;
				if (delay > MAX_DELAY)
					delay = MAX_DELAY;
			}
			logger.warn("Channel registration failed: {}. Trying again in {}s.", channelLocator, (delay / 1000), cae);
			pattern.registrationSuccessful. create().setValue(false);
			pattern.registrationSuccessful.activate(false);
			if (channelConfiguration != null) {
				ca.deleteChannel(channelConfiguration);
			}
			if (t == null) 
				t = mapper.getTimer();
			try {
				openTask = t.schedule(this, delay, TimeUnit.MILLISECONDS);
			} catch (RejectedExecutionException e) { // if task has been canceled
				t = null;
				openTask = null;
			}
		}
	}
	
	
	@Override
	public void resourceChanged(SingleValueResource resource) {
		float factor = 1;
		float offset = 0;
		if (pattern.scalingFactor.isActive())
			factor = pattern.scalingFactor.getValue();
		if (pattern.valueOffset.isActive())
			offset = pattern.valueOffset.getValue();
		try {
			ca.setChannelValue(channelConfiguration, transformBack(resource, factor, offset));
		} catch (ChannelAccessException e) {
			logger.error("Could not set new value for channel " + channelConfiguration + ", resource " + resource,e);
		}
	}
	
	@Override
	public void channelEvent(EventType type, List channels) {
		logger.trace("Channel event for {}", pattern.target);
		for (SampledValueContainer container: channels) {
			if (container.getChannelLocator().equals(channelConfiguration.getChannelLocator())) {
				float factor = 1;
				float offset = 0;
				if (pattern.scalingFactor.isActive())
					factor = pattern.scalingFactor.getValue();
				if (pattern.valueOffset.isActive())
					offset = pattern.valueOffset.getValue();
				Value value = transform(container.getSampledValue().getValue(), factor, offset);
				ValueResourceUtils.setValue(pattern.target, value);
				pattern.target.activate(false);
			}
		}
	}
	
	void close() {
		try{ 
			pattern.target.removeValueListener(this);
		} catch (Exception e) {
			LoggerFactory.getLogger(ChannelMapperImpl.class).warn("Error closing channel controller",e);
		}
		if (channelConfiguration != null) {
			try{ 
				ca.unregisterUpdateListener(Collections.singletonList(channelConfiguration), this);
			} catch (Exception e) {
				LoggerFactory.getLogger(ChannelMapperImpl.class).warn("Error closing channel controller",e);
			}
			try {
				ca.deleteChannel(channelConfiguration);
			} catch (Exception e) {
				LoggerFactory.getLogger(ChannelMapperImpl.class).warn("Error closing channel controller",e);
			}
		}
		ScheduledFuture openTask = this.openTask;
		if (openTask != null)
			openTask.cancel(true);
		this.openTask = null;
		t = null;
	}
	
	// from channel value to resource
	private static Value transform(Value in, float factor, float offset) {
		if (in instanceof FloatValue)
			return new FloatValue(in.getFloatValue() * factor + offset);
		else if (in instanceof IntegerValue)
			return new IntegerValue(in.getIntegerValue() * ((int) factor) + (int) offset); // problematic...
		else if (in instanceof LongValue)
			return new LongValue(in.getLongValue() * ((long) factor) + (long) offset);// problematic...
		else if (in instanceof BooleanValue)
			return new BooleanValue(in.getBooleanValue() && (factor >= 0));
		else
			return in;
	}
	
	// from resource value to channel value
	private static Value transformBack(SingleValueResource in, float factor, float offset) {
		final Object value = ValueResourceUtils.getValue((ValueResource) in);
		if (in instanceof FloatResource)
			return new FloatValue(((float) value - offset) / factor);
		else if (in instanceof IntegerResource)
			return new IntegerValue(((int) value - (int) offset) / ((int) factor));
		else if (in instanceof TimeResource)
			return new LongValue(((long) value - (long) offset) / ((long) factor));
		else if (in instanceof BooleanResource)
			return new BooleanValue((boolean) value && (factor >= 0));
		else
			throw new IllegalArgumentException("Unsupported resource type " + in.getResourceType().getName());
	}

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy