001package jmri.jmrix.roco.z21; 002 003import jmri.Sensor; 004import org.slf4j.Logger; 005import org.slf4j.LoggerFactory; 006 007/** 008 * Z21CanSensor implements the Sensor interface 009 * for Can connected sensors on Roco Z21 systems. 010 * 011 * @author Paul Bender Copyright (C) 2018 012 */ 013public class Z21CanSensor extends jmri.implementation.AbstractSensor implements Z21Listener { 014 015 private Z21SystemConnectionMemo _memo; 016 017 private int networkID=0; // CAN network ID associated with this reporter's module. 018 private int moduleAddress=-1; // User assigned address associated with this reporter's module. 019 private int port; // module port (0-7) associated with this reporter. 020 021 /** 022 * Create a new Z21CanSensor. 023 * 024 * @param systemName the system name of the new reporter. 025 * @param userName the user name of the new reporter. 026 * @param memo an instance of Z21SystemConnectionMemo this reporter 027 * is associated with. 028 * 029 */ 030 public Z21CanSensor(String systemName,String userName,Z21SystemConnectionMemo memo){ 031 super(systemName,userName); 032 _memo = memo; 033 // register for messages 034 _memo.getTrafficController().addz21Listener(this); 035 //Address format passed is in the form of moduleAddress:pin 036 try { 037 setIdentifiersFromSystemName(systemName); 038 } catch (NumberFormatException ex) { 039 log.debug("Unable to convert {} into the cab and input format of nn:xx",systemName); 040 throw new IllegalArgumentException("requires mm:pp format address."); 041 } 042 } 043 044 private void setIdentifiersFromSystemName(String systemName) { 045 String moduleAddressText = Z21CanBusAddress.getEncoderAddressString(systemName, _memo.getSystemPrefix()); 046 try { 047 moduleAddress = Integer.parseInt(moduleAddressText); 048 } catch (NumberFormatException ex) { 049 // didn't parse as a decimal, check to see if network ID 050 // was used instead. 051 networkID = Integer.parseInt(moduleAddressText, 16); 052 } 053 port = Z21CanBusAddress.getBitFromSystemName(systemName, _memo.getSystemPrefix()); 054 } 055 056 /** 057 * request an update from the layout. 058 */ 059 @Override 060 public void requestUpdateFromLayout(){ 061 if(networkID==0){ 062 return; // no networkID has been set yet. 063 } 064 _memo.getTrafficController().sendz21Message(Z21Message.getLanCanDetector(networkID),this); 065 } 066 067 // the Z21 Listener interface 068 069 /** 070 * Member function that will be invoked by a z21Interface implementation to 071 * forward a z21 message from the layout. 072 * 073 * @param msg The received z21 reply. Note that this same object may be 074 * presented to multiple users. It should not be modified here. 075 */ 076 @Override 077 public void reply(Z21Reply msg){ 078 // for incoming messages all the reporter cares about is 079 // LAN_CAN_DETECTOR messages. 080 if(msg.isCanSensorMessage()){ 081 int netID = ( msg.getElement(4)&0xFF) + ((msg.getElement(5)&0xFF) << 8); 082 int address = ( msg.getElement(6)&0xFF) + ((msg.getElement(7)&0xFF) << 8); 083 int msgPort = ( msg.getElement(8) & 0xFF); 084 if(!messageForSensor(address,netID,msgPort)){ 085 return; 086 } 087 // status message, use to set state. 088 int value1 = (msg.getElement(10)&0xFF) + ((msg.getElement(11)&0xFF) << 8); 089 log.debug("value {}",value1); 090 if(value1 == 0x0000) { 091 log.debug("Free without voltage"); 092 setOwnState(Sensor.INACTIVE); 093 } else if(value1 == 0x0100) { 094 log.debug("Free with voltage"); 095 setOwnState(Sensor.INACTIVE); 096 } else if(value1 == 0x1000) { 097 log.debug("Busy without voltage"); 098 setOwnState(Sensor.ACTIVE); 099 } else if(value1 == 0x1100) { 100 log.debug("Busy with voltage"); 101 setOwnState(Sensor.ACTIVE); 102 } else if(value1 == 0x1201) { 103 log.debug("Busy Overload 1"); 104 setOwnState(Sensor.ACTIVE); 105 } else if(value1 == 0x1202) { 106 log.debug("Busy Overload 2"); 107 setOwnState(Sensor.ACTIVE); 108 } else if(value1 == 0x1203) { 109 log.debug("Busy Overload 3"); 110 setOwnState(Sensor.ACTIVE); 111 } 112 } 113 } 114 115 private boolean messageForSensor(int address,int netId,int msgPort){ 116 return (address == moduleAddress || netId == networkID) && msgPort == port; 117 } 118 119 /** 120 * {@inheritDoc} 121 */ 122 @Override 123 public void message(Z21Message msg){ 124 // we don't need to handle outgoing messages, so just ignore them. 125 } 126 127 @Override 128 public void dispose(){ 129 _memo.getTrafficController().removez21Listener(this); 130 super.dispose(); 131 } 132 133 private static final Logger log = LoggerFactory.getLogger(Z21CanSensor.class); 134 135}