001package jmri.jmrix.bidib; 002 003import java.util.HashMap; 004import java.util.Map; 005import jmri.*; 006import jmri.implementation.DefaultMeter; 007import jmri.implementation.MeterUpdateTask; 008 009import org.bidib.jbidibc.core.DefaultMessageListener; 010import org.bidib.jbidibc.core.MessageListener; 011import org.bidib.jbidibc.messages.CurrentValue; 012import org.bidib.jbidibc.messages.Node; 013import org.bidib.jbidibc.messages.message.BoostQueryMessage; 014import org.bidib.jbidibc.messages.utils.NodeUtils; 015 016import org.slf4j.Logger; 017import org.slf4j.LoggerFactory; 018 019 020/** 021 * Provide access to voltage and current readings 022 * 023 * @author Mark Underwood Copyright (C) 2015 024 * @author Paul Bender Copyright (C) 2017 025 * @author Daniel Bergqvist Copyright (C) 2020 026 * @author Eckart Meyer Copyright (C) 2021 027 */ 028public class BiDiBPredefinedMeters { 029 030 private BiDiBTrafficController tc; 031 private final BiDiBSystemConnectionMemo _memo; 032 private final MeterUpdateTask updateTask; 033 private final Map<Integer, Meter> currentMeters = new HashMap<>(); 034 private final Map<Integer, Meter> voltageMeters = new HashMap<>(); 035 036 private boolean enabled = false; // disable by default; prevent polling when not being used. 037 038 public BiDiBPredefinedMeters(BiDiBSystemConnectionMemo memo) { 039 040 _memo = memo; 041 tc = _memo.getBiDiBTrafficController(); 042 043 updateTask = new UpdateTask(-1); 044 045// // scan nodes list for booster nodes 046 Map<Long, Node> nodes = tc.getNodeList(); 047 for(Map.Entry<Long, Node> entry : nodes.entrySet()) { 048 Node node = entry.getValue(); 049 if (NodeUtils.hasBoosterFunctions(node.getUniqueId())) { 050 log.trace("Booster - node addr: {}, node uid: {}", node.getAddr(), node); 051 String sysname = String.format("X%010x", node.getUniqueId() & 0xffffffffffL); 052 Meter currentMeter = new DefaultMeter.DefaultCurrentMeter( 053 memo.getSystemPrefix() + InstanceManager.getDefault(MeterManager.class).typeLetter() + sysname + ":BoosterCurrent", 054 Meter.Unit.Milli, 0, 20224.0, 1, updateTask); 055 currentMeters.put(NodeUtils.convertAddress(node.getAddr()), currentMeter); 056 057 Meter voltageMeter = new DefaultMeter.DefaultVoltageMeter( 058 memo.getSystemPrefix() + InstanceManager.getDefault(MeterManager.class).typeLetter() + sysname + ":BoosterVoltage", 059 Meter.Unit.Milli, 0, 25000.0, 100, updateTask); 060 voltageMeters.put(NodeUtils.convertAddress(node.getAddr()), voltageMeter); 061 062 InstanceManager.getDefault(MeterManager.class).register(currentMeter); 063 InstanceManager.getDefault(MeterManager.class).register(voltageMeter); 064 065 log.debug("BiDiBPredefinedMeters constructor called"); 066 } 067 } 068 } 069 070 public void setBiDiBTrafficController(BiDiBTrafficController controller) { 071 tc = controller; 072 } 073 074 private void disposeMeter(Meter meter) { 075 updateTask.disable(meter); 076 InstanceManager.getDefault(MeterManager.class).deregister(meter); 077 updateTask.dispose(meter); 078 } 079 080 public void dispose() { 081 for(Map.Entry<Integer, Meter> entry : currentMeters.entrySet()) { 082 disposeMeter(entry.getValue()); 083 } 084 for(Map.Entry<Integer, Meter> entry : voltageMeters.entrySet()) { 085 disposeMeter(entry.getValue()); 086 } 087// updateTask.disable(currentMeter); 088// updateTask.disable(voltageMeter); 089// InstanceManager.getDefault(MeterManager.class).deregister(currentMeter); 090// InstanceManager.getDefault(MeterManager.class).deregister(voltageMeter); 091// updateTask.dispose(currentMeter); 092// updateTask.dispose(voltageMeter); 093 } 094 095 096 private class UpdateTask extends MeterUpdateTask { 097 098 MessageListener messageListener = null; 099 100 public UpdateTask(int interval) { 101 super(interval); 102 createBoosterDiagListener(); 103 } 104 105 @Override 106 public void enable(){ 107 enabled = true; 108 // TODO: set feature to enable booster diag messages - and switch it off by default somewhere 109 tc.addMessageListener(messageListener); 110 log.info("Enabled meter."); 111 super.enable(); 112 } 113 114 @Override 115 public void disable(){ 116 if (!enabled) return; 117 super.disable(); 118 enabled = false; 119 // TODO: set feature to disable booster diag messages 120 tc.removeMessageListener(messageListener); 121 log.info("Disabled meter."); 122 } 123 124 private void setCurrent(byte[] address, double value) throws JmriException { 125 Meter meter = currentMeters.get(NodeUtils.convertAddress(address)); 126 log.trace("setCurrent - addr: {}, Meter: {}, value: {}", address, meter, value); 127 if (meter != null) { 128 meter.setCommandedAnalogValue(value); 129 } 130 } 131 132 private void setVoltage(byte[] address, double value) throws JmriException { 133 Meter meter = voltageMeters.get(NodeUtils.convertAddress(address)); 134 log.trace("setVoltage - addr: {}, Meter: {}, value: {}", address, meter, value); 135 if (meter != null) { 136 meter.setCommandedAnalogValue(value); 137 } 138 } 139 140 @Override 141 public void requestUpdateFromLayout() { 142 Map<Long, Node> nodes = tc.getNodeList(); 143 for(Map.Entry<Long, Node> entry : nodes.entrySet()) { 144 Node node = entry.getValue(); 145 if (NodeUtils.hasBoosterFunctions(node.getUniqueId())) { 146 tc.sendBiDiBMessage(new BoostQueryMessage(), node); 147 } 148 } 149 } 150 151 private void createBoosterDiagListener() { 152 // to listen messages related to track power. 153 messageListener = new DefaultMessageListener() { 154 @Override 155 public void boosterDiag(byte[] address, int messageNum, CurrentValue current, int voltage, int temperature) { 156 log.info("METER booster diag was signalled: node addr: {}, current: {}, voltage: {}, temperature: {}", 157 address, current, voltage, temperature); 158 try { 159 setCurrent(address, current.getCurrent() * 1.0f); 160 setVoltage(address, voltage * 100.0f); //units of 100mV 161 } catch (JmriException e) { 162 log.error("exception thrown by setCurrent or setVoltage", e); 163 } 164 } 165 }; 166 } 167 168 169 } 170 171 private static final Logger log = LoggerFactory.getLogger(BiDiBPredefinedMeters.class); 172 173}