001package jmri.jmrix.powerline.simulator;
002
003import jmri.Sensor;
004import jmri.jmrix.powerline.SerialReply;
005import jmri.jmrix.powerline.SerialTrafficController;
006import jmri.jmrix.powerline.X10Sequence;
007import jmri.util.StringUtil;
008import org.slf4j.Logger;
009import org.slf4j.LoggerFactory;
010
011/**
012 * Manage the system-specific Sensor implementation.
013 * <p>
014 * System names are "PSann", where a is the unit id, nn is the unit number
015 * without padding.
016 * <p>
017 * Sensors are numbered from 1.
018 *
019 * @author Bob Jacobsen Copyright (C) 2003, 2006, 2007, 2008, 2009
020 * @author Ken Cameron, (C) 2009, 2010 sensors from poll replies Converted to
021 * multiple connection
022 * @author kcameron Copyright (C) 2011
023 */
024public class SpecificSensorManager extends jmri.jmrix.powerline.SerialSensorManager {
025
026    public SpecificSensorManager(SerialTrafficController tc) {
027        super(tc);
028        this.tc = tc;
029    }
030
031    SerialTrafficController tc = null;
032
033    /**
034     * Process a reply to a poll of Sensors of one node
035     */
036    @Override
037    public synchronized void reply(SerialReply r) {
038        // process for updates
039        processForPollReq(r);
040    }
041
042    private void processForPollReq(SerialReply l) {
043        if ((l.getElement(0) & 0xFF) == Constants.HEAD_STX) {
044            // process the POLL_REQ_X10 and update/create sensors as needed
045            if (((l.getElement(1) & 0xFF) == Constants.POLL_REQ_X10) && l.getNumDataElements() == 4) {
046                // valid poll of X10 message
047                int dat = l.getElement(2) & 0xFF;
048                int flag = l.getElement(3) & 0xFF;
049                String newHouseCode = X10Sequence.houseValueToText(X10Sequence.decode((dat >> 4) & 0x0F));
050                int newCmdCode = dat & 0x0F;
051                int newAddrCode = -1;
052                Sensor sensor = null;
053                if ((flag & Constants.FLAG_BIT_X10_CMDUNIT) == Constants.FLAG_X10_RECV_CMD) {
054                    if ((newCmdCode == X10Sequence.FUNCTION_ALL_LIGHTS_OFF || newCmdCode == X10Sequence.FUNCTION_ALL_UNITS_OFF || newCmdCode == X10Sequence.FUNCTION_ALL_LIGHTS_ON)) {
055                        // some sort of 'global' command, process for all matching the house code
056
057                        getNamedBeanSet().forEach(sensorInSet -> {
058                            String sName = sensorInSet.getSystemName();
059                            if (newHouseCode.compareTo(tc.getAdapterMemo().getSerialAddress().houseCodeFromSystemName(sName)) == 0) {
060                                try {
061                                    if (newCmdCode == X10Sequence.FUNCTION_ALL_LIGHTS_OFF || newCmdCode == X10Sequence.FUNCTION_ALL_UNITS_OFF) {
062                                        sensorInSet.setKnownState(Sensor.INACTIVE);
063                                    } else {
064                                        sensorInSet.setKnownState(Sensor.ACTIVE);
065                                    }
066                                } catch (jmri.JmriException e) {
067                                    if (newCmdCode == X10Sequence.FUNCTION_ALL_LIGHTS_OFF || newCmdCode == X10Sequence.FUNCTION_ALL_UNITS_OFF) {
068                                        log.error("Exception setting {} sensor INACTIVE", sName, e);
069                                    } else {
070                                        log.error("Exception setting {} sensor ACTIVE", sName, e);
071                                    }
072                                }
073                            }
074                        });
075                    } else {
076                        if (newHouseCode != null && newAddrCode > 0) {
077                            String sysName = getSystemPrefix() + "S" + newHouseCode + newAddrCode;
078                            sensor = provideSensor(sysName);
079                            if (newCmdCode == X10Sequence.FUNCTION_ON || newCmdCode == X10Sequence.FUNCTION_BRIGHT || newCmdCode == X10Sequence.FUNCTION_STATUS_ON) {
080                                try {
081                                    sensor.setKnownState(Sensor.ACTIVE);
082                                } catch (jmri.JmriException e) {
083                                    log.error("Exception setting {} sensor ACTIVE", sysName, e);
084                                }
085                            }
086                            if (newCmdCode == X10Sequence.FUNCTION_OFF || newCmdCode == X10Sequence.FUNCTION_DIM || newCmdCode == X10Sequence.FUNCTION_STATUS_OFF) {
087                                try {
088                                    sensor.setKnownState(Sensor.INACTIVE);
089                                } catch (jmri.JmriException e) {
090                                    log.error("Exception setting {} sensor INACTIVE", sysName, e);
091                                }
092                            }
093                        }
094                    }
095                }
096            } else if (((l.getElement(1) & 0xFF) == Constants.POLL_REQ_STD) && l.getNumDataElements() == 11) {
097                // figure how to decode an standard Insteon poll command
098                int highAddr = l.getElement(5) & 0xFF;
099                int middleAddr = l.getElement(6) & 0xFF;
100                int lowAddr = l.getElement(7) & 0xFF;
101                int cmd1 = l.getElement(9) & 0xFF;
102                StringBuilder sysName = new StringBuilder();
103                sysName.append(getSystemPrefix());
104                sysName.append("S");
105                sysName.append(StringUtil.twoHexFromInt(highAddr));
106                sysName.append(".");
107                sysName.append(StringUtil.twoHexFromInt(middleAddr));
108                sysName.append(".");
109                sysName.append(StringUtil.twoHexFromInt(lowAddr));
110                Sensor sensor = null;
111                try {
112                    sensor = provideSensor(new String(sysName));
113                } catch(java.lang.IllegalArgumentException iae){
114                    // if provideSensor fails, it will throw an IllegalArgumentException, so catch that,log it if debugging is enabled, and then re-throw it.
115                    log.debug("Attempt access sensor {} failed", sysName);
116                    throw iae;
117                }
118                if (cmd1 == Constants.CMD_LIGHT_ON_FAST || cmd1 == Constants.CMD_LIGHT_ON_RAMP) {
119                    try {
120                        sensor.setKnownState(Sensor.ACTIVE);
121                    } catch (jmri.JmriException e) {
122                        log.error("Exception setting {} sensor ACTIVE", sysName, e);
123                    }
124                }
125                if (cmd1 == Constants.CMD_LIGHT_OFF_FAST || cmd1 == Constants.CMD_LIGHT_OFF_RAMP) {
126                    try {
127                        sensor.setKnownState(Sensor.INACTIVE);
128                    } catch (jmri.JmriException e) {
129                        log.error("Exception setting {} sensor INACTIVE", sysName, e);
130                    }
131                }
132            }
133        }
134    }
135
136    private final static Logger log = LoggerFactory.getLogger(SpecificSensorManager.class);
137}
138