001package jmri.jmrix.powerline.cm11; 002 003import jmri.Sensor; 004import jmri.jmrix.powerline.SerialReply; 005import jmri.jmrix.powerline.SerialTrafficController; 006import jmri.jmrix.powerline.X10Sequence; 007import org.slf4j.Logger; 008import org.slf4j.LoggerFactory; 009 010/** 011 * Manage the system-specific Sensor implementation. 012 * <p> 013 * System names are "PSann", where a is the unit id, nn is the unit number 014 * without padding. 015 * <p> 016 * Sensors are numbered from 1. 017 * 018 * @author Bob Jacobsen Copyright (C) 2003, 2006, 2007, 2008 019 * @author Ken Cameron, (C) 2009, sensors from poll replies Converted to 020 * multiple connection 021 * @author kcameron Copyright (C) 2011 022 */ 023public class SpecificSensorManager extends jmri.jmrix.powerline.SerialSensorManager { 024 025 public SpecificSensorManager(SerialTrafficController tc) { 026 super(tc); 027 this.tc = tc; 028 } 029 030 SerialTrafficController tc = null; 031 032 /** 033 * Process a reply to a poll of Sensors of one node 034 */ 035 @Override 036 public synchronized void reply(SerialReply r) { 037 // process for updates 038 processForPollReq(r); 039 } 040 041 /** 042 * These values need to persist between calls as the address is a different 043 * reply from the command packet and timing might have them in separate 044 * reads 045 */ 046 private String newHouseCode = null; 047 private int newCmdCode = -1; 048 private int newAddrCode = -1; 049 050 private void processForPollReq(SerialReply l) { 051 // process the POLL_REQ and update/create sensors as needed 052 if ((l.getElement(0) & 0xFF) == Constants.POLL_REQ) { 053 // must be received data 054 int last = (l.getElement(1) & 0xFF) + 1; 055 int bits = (l.getElement(2) & 0xFF); 056 Sensor sensor = null; 057 for (int i = 3; i <= last; i++) { 058 int dat = l.getElement(i) & 0xFF; 059 if ((bits & 0x01) != 0) { 060 // this is a function byte, so the address came from prior pass 061 newHouseCode = X10Sequence.houseValueToText(X10Sequence.decode((dat >> 4) & 0x0F)); 062 newCmdCode = dat & 0x0f; 063 064 if (newHouseCode != null && (newCmdCode == X10Sequence.FUNCTION_ALL_LIGHTS_OFF || newCmdCode == X10Sequence.FUNCTION_ALL_UNITS_OFF || newCmdCode == X10Sequence.FUNCTION_ALL_LIGHTS_ON)) { 065 // some sort of 'global' command, process for all matching the house code 066 getNamedBeanSet().forEach(sensorInSet -> { 067 String sName = sensorInSet.getSystemName(); 068 if (newHouseCode.compareTo(tc.getAdapterMemo().getSerialAddress().houseCodeFromSystemName(sName)) == 0) { 069 try { 070 if (newCmdCode == X10Sequence.FUNCTION_ALL_LIGHTS_OFF || newCmdCode == X10Sequence.FUNCTION_ALL_UNITS_OFF) { 071 sensorInSet.setKnownState(Sensor.INACTIVE); 072 } else { 073 sensorInSet.setKnownState(Sensor.ACTIVE); 074 } 075 } catch (jmri.JmriException e) { 076 if (newCmdCode == X10Sequence.FUNCTION_ALL_LIGHTS_OFF || newCmdCode == X10Sequence.FUNCTION_ALL_UNITS_OFF) { 077 log.error("Exception setting {} sensor INACTIVE", sName, e); 078 } else { 079 log.error("Exception setting {} sensor ACTIVE", sName, e); 080 } 081 } 082 } 083 }); 084 } else { 085 // was not a global command, so might be a sensor 086 if (newAddrCode > 0) { 087 String sysName = getSystemPrefix() + "S" + newHouseCode + newAddrCode; 088 try { 089 sensor = provideSensor(sysName); 090 } catch(java.lang.IllegalArgumentException iae){ 091 // if provideSensor fails, it will throw an IllegalArgumentException, so catch that,log it if debugging is enabled, and then re-throw it. 092 log.debug("Attempt access sensor {} failed", sysName); 093 throw iae; 094 } 095 if (newCmdCode == X10Sequence.FUNCTION_ON || newCmdCode == X10Sequence.FUNCTION_BRIGHT || newCmdCode == X10Sequence.FUNCTION_STATUS_ON) { 096 try { 097 sensor.setKnownState(Sensor.ACTIVE); 098 } catch (jmri.JmriException e) { 099 log.error("Exception setting {} sensor ACTIVE", sysName, e); 100 } 101 } 102 if (newCmdCode == X10Sequence.FUNCTION_OFF || newCmdCode == X10Sequence.FUNCTION_DIM || newCmdCode == X10Sequence.FUNCTION_STATUS_OFF) { 103 try { 104 sensor.setKnownState(Sensor.INACTIVE); 105 } catch (jmri.JmriException e) { 106 log.error("Exception setting {} sensor INACTIVE", sysName, e); 107 } 108 } 109 110 // if we decide we want to add sensors automatically when seen on the wire, this is the place 111 } 112 } 113 // used the pair of address/function, so clear them 114 newHouseCode = null; 115 newCmdCode = -1; 116 newAddrCode = -1; 117 } else { 118 // this is an address byte, so just save it 119 newHouseCode = X10Sequence.houseValueToText(X10Sequence.decode((dat >> 4) & 0x0F)); 120 newAddrCode = X10Sequence.decode(dat & 0x0f); 121 } 122 bits = bits >> 1; // shift over before next byte 123 } 124 } 125 } 126 127 private final static Logger log = LoggerFactory.getLogger(SpecificSensorManager.class); 128 129}