001package jmri.jmrix.loconet; 002 003import jmri.*; 004import jmri.implementation.DefaultMeter; 005import jmri.implementation.MeterUpdateTask; 006import jmri.jmrix.loconet.duplexgroup.swing.LnIPLImplementation; 007import org.slf4j.Logger; 008import org.slf4j.LoggerFactory; 009 010/** 011 * Provide access to current and voltage meter from some LocoNet command stations 012 * 013 * @author Steve G Copyright (C) 2019 014 * @author Bob Jacobsen Copyright (C) 2019 015 * @author Egbert Boerse Copyright (C) 2019 016 * @author Daniel Bergqvist Copyright (C) 2020 017 * @author B. Milhaupt Copyright (C) 2020 018 */ 019public class LnPredefinedMeters implements LocoNetListener { 020 021 private SlotManager sm = null; 022 private LnTrafficController tc = null; 023 private final MeterUpdateTask updateTask; 024 private final LnMeterInitTask initializationTask; 025 026 /** 027 * Create a LnPredefinedMeters object 028 * 029 * @param scm connection memo 030 */ 031 public LnPredefinedMeters(LocoNetSystemConnectionMemo scm) { 032 this.sm = scm.getSlotManager(); 033 this.tc = scm.getLnTrafficController(); 034 035 updateTask = new MeterUpdateTask(LnConstants.METER_INTERVAL_MS) { 036 @Override 037 public void requestUpdateFromLayout() { 038 sm.sendReadSlot(249); 039 } 040 }; 041 042 tc.addLocoNetListener(~0, this); 043 044 updateTask.initTimer(); 045 046 // a work-around to ensure that the LocoNet transmit path is established 047 // before making an initial query-mode request 048 initializationTask = new LnMeterInitTask(sm.tc, 85); 049 initializationTask.initTimer(); 050 initializationTask.enable(); 051 } 052 053 @Override 054 public void message(LocoNetMessage msg) { 055 if (msg.getNumDataElements() != 21 056 || msg.getOpCode() != LnConstants.OPC_EXP_RD_SL_DATA 057 || msg.getElement(1) != 21 058 || msg.getElement(2) != 1 059 || msg.getElement(3) != 0x79) { 060 return; 061 } 062 int srcDeviceType = msg.getElement(16); 063 if ((srcDeviceType == LnConstants.RE_IPL_DIGITRAX_HOST_BXP88) 064 || (srcDeviceType == LnConstants.RE_IPL_DIGITRAX_HOST_LNWI) 065 || (srcDeviceType == LnConstants.RE_IPL_DIGITRAX_HOST_BXPA1)) { 066 // these devices support Query Mode but always return 0s for 067 // voltage/current data 068 return; 069 } 070 071 float valAmps = msg.getElement(6)/10.0f; 072 float valVolts = msg.getElement(4)*2.0f/10.0f; 073 074 int srcSerNum = msg.getElement(18)+128*msg.getElement(19); 075 076 String voltSysName = createSystemName(srcDeviceType, srcSerNum, "Voltage"); // NOI18N 077 Meter m = InstanceManager.getDefault(MeterManager.class).getBySystemName(voltSysName); 078 updateAddMeter(m, voltSysName, valVolts, true); 079 080 String ampsSysName = createSystemName(srcDeviceType, srcSerNum, "InputCurrent"); // NOI18N 081 m = InstanceManager.getDefault(MeterManager.class).getBySystemName(ampsSysName); 082 updateAddMeter(m, ampsSysName, valAmps, false); 083 } 084 085 public void dispose() { 086 var meters = new java.util.HashSet<>(InstanceManager.getDefault(MeterManager.class).getNamedBeanSet()); 087 for (Meter m: meters) { 088 if (m.getSystemName().startsWith(sm.getSystemPrefix()+"V")) { // NOI18N 089 updateTask.disable(m); 090 InstanceManager.getDefault(MeterManager.class).deregister(m); 091 updateTask.dispose(m); 092 } 093 } 094 } 095 096 public void requestUpdateFromLayout() { 097 log.debug("sending request for voltmeter/ammeter information"); 098 sm.sendReadSlot(249); 099 } 100 101 private final String createSystemName(int device, int sn, String typeString) { 102 String devName = LnIPLImplementation.getDeviceName(0, device,0,0); 103 if (devName == null) { 104 devName="["+device+"]"; // NOI18N 105 } 106 return sm.getSystemPrefix()+"V"+ devName + "(s/n"+sn+")"+typeString; // NOI18N 107 } 108 109 private void updateAddMeter(Meter m, String sysName, float value, boolean typeVolt ) { 110 if (m == null) { 111 Meter newMeter; 112 if (typeVolt) { 113 // voltMeter not (yet) registered 114 newMeter = new DefaultMeter.DefaultVoltageMeter(sysName, 115 Meter.Unit.NoPrefix, 0, 25.4, 0.2, updateTask); 116 } else { 117 // ammeter not (yet) registered 118 newMeter = new DefaultMeter.DefaultCurrentMeter(sysName, 119 Meter.Unit.NoPrefix, 0, 12.7, 0.1, updateTask); 120 } 121 try { 122 newMeter.setCommandedAnalogValue(value); 123 } catch (JmriException e) { 124 log.debug("Exception setting {}Meter {} to value {}", 125 (typeVolt?"volt":"current"), // NOI18N 126 sysName, value, e); 127 } 128 InstanceManager.getDefault(MeterManager.class).register(newMeter); 129 log.debug("Added new {}Meter {} with value {}", 130 (typeVolt?"volt":"current"), // NOI18N 131 sysName, value); 132 } else { 133 try { 134 m.setCommandedAnalogValue(value); 135 } catch (JmriException e) { 136 log.debug("Exception setting {}Meter {} to value {}", 137 (typeVolt?"volt":"current"), // NOI18N 138 sysName, value, e); 139 } 140 log.debug("Updating currentMeter {} with value {}", 141 sysName, value); 142 } 143 } 144 145 private final static Logger log = LoggerFactory.getLogger(LnPredefinedMeters.class); 146}