001package jmri.jmrix.powerline.dmx512;
002
003import org.slf4j.Logger;
004import org.slf4j.LoggerFactory;
005import jmri.jmrix.powerline.SerialTrafficController;
006
007/**
008 * Implementation of the Light class for DMX based subclasses.
009 * <p>
010 * DMX maps the value of 0.0 to 1.0 to values of 0 to 255.
011 *
012 * @author Dave Duchamp Copyright (C) 2004
013 * @author Bob Jacobsen Copyright (C) 2006, 2007, 2008, 2009, 2010
014 * @author Ken Cameron Copyright (C) 2009, 2010 Converted to multiple connection
015 * @author kcameron Copyright (C) 2023
016 */
017public class SpecificDmxLight extends jmri.jmrix.powerline.SerialLight {
018
019    /**
020     * Create a Light object, with only system name.
021     * <p>
022     * 'systemName' was previously validated in SerialLightManager
023     * @param systemName system name
024     * @param tc traffic controller
025     */
026    public SpecificDmxLight(String systemName, SerialTrafficController tc) {
027        super(systemName, tc);
028        this.tc = tc;
029        maxDimStep = tc.getNumberOfIntensitySteps();
030    }
031
032    /**
033     * Create a Light object, with both system and user names.
034     * <p>
035     * 'systemName' was previously validated in SerialLightManager
036     * @param systemName system name
037     * @param tc traffic controller
038     * @param userName user name
039     */
040    public SpecificDmxLight(String systemName, SerialTrafficController tc, String userName) {
041        super(systemName, tc, userName);
042        this.tc = tc;
043        maxDimStep = tc.getNumberOfIntensitySteps();
044    }
045
046    SerialTrafficController tc = null;
047    protected int maxDimStep = 0;
048
049    /**
050     * Set the intensity for the DMX hardware to reach a specific
051     * intensity. Acts immediately, and changes no general state.
052     */
053    @Override
054    protected void sendIntensity(double intensity) {
055        // correct for out of range value
056        if ((intensity < mMinIntensity) || (intensity > mMaxIntensity)) {
057            log.debug("correcting out of range intensity: {}", intensity);
058            if (intensity < mMinIntensity) {
059                intensity = mMinIntensity;
060            }
061            if (intensity > mMaxIntensity) {
062                intensity = mMaxIntensity;
063            }
064        }
065        // test current too, if the change is out of range...
066        if ((mCurrentIntensity < mMinIntensity) || (mCurrentIntensity > mMaxIntensity)) {
067            log.debug("correcting out of range current intensity: {}", mCurrentIntensity);
068            if (mCurrentIntensity < mMinIntensity) {
069                mCurrentIntensity = mMinIntensity;
070            }
071            if (mCurrentIntensity > mMaxIntensity) {
072                mCurrentIntensity = mMaxIntensity;
073            }
074        }
075        
076        if (log.isDebugEnabled()) {
077            log.debug("sendIntensity({}) maxDimStep: {}", intensity, maxDimStep);
078        }
079
080        // find the new correct dim count
081        int newStep = (int) Math.round(intensity * maxDimStep);  // maxDimStep is full on, 0 is full off, etc
082
083        // check for errors
084        if ((newStep < 0) || (newStep > maxDimStep)) {
085            log.error("newStep wrong: {} intensity: {} mCurrentIntensity {}", newStep, intensity, mCurrentIntensity);
086            return;
087        }
088
089        // update dmxArray
090        tc.sendDmxSequence(this.unitid, (byte) newStep);
091    }
092
093    /**
094     * Number of steps from dim to bright is maintained in specific
095     * SerialTrafficController implementation
096     */
097    @Override
098    protected int getNumberOfSteps() {
099        return tc.getNumberOfIntensitySteps();
100    }
101
102    /**
103     * Send a On/Off Command to the hardware
104     */
105    @Override
106    protected void sendOnOffCommand(int newState) {
107        if (log.isDebugEnabled()) {
108            log.debug("sendOnOff({}) Current: {}", newState, mState);
109        }
110
111        // figure out command 
112        byte newDim;
113        if (newState == ON) {
114            newDim = (byte) maxDimStep;
115            // set new intensity, skip stepping
116            mCurrentIntensity = 1;
117            mTransitionTargetIntensity = 1;
118        } else if (newState == OFF) {
119            newDim = 0;
120            // set new intensity, skip stepping
121            mCurrentIntensity = 0;
122            mTransitionTargetIntensity = 0;
123        } else {
124            log.warn("illegal state requested for Light: {}", getSystemName());
125            return;
126        }
127
128        log.debug("set state {} unitid {} value {}", newState, unitid, newDim);
129        
130        // send value to array
131        tc.sendDmxSequence(this.unitid, newDim);
132
133        if (log.isDebugEnabled()) {
134            log.debug("sendOnOff() unit {} state {} value {} ", this.unitid, newState, newDim);
135        }
136    }
137
138    private final static Logger log = LoggerFactory.getLogger(SpecificDmxLight.class);
139}
140
141