001package jmri.jmrix.can.cbus; 002 003import jmri.*; 004import jmri.implementation.DefaultMeter; 005import jmri.implementation.MeterUpdateTask; 006import jmri.jmrix.can.CanSystemConnectionMemo; 007import jmri.jmrix.can.CanListener; 008import jmri.jmrix.can.CanMessage; 009import jmri.jmrix.can.CanReply; 010import jmri.jmrix.can.TrafficController; 011import jmri.jmrix.can.cbus.node.CbusNode; 012import jmri.jmrix.can.cbus.node.CbusNodeTableDataModel; 013 014/** 015 * Provide access to current meter from a MERG CBUS Command Station 016 * 017 * @author Steve Young (C) 2019 018 * 019 * @author Andrew Crosland 2020 020 * Added voltage capability to use with new jmrit.voltmeter class 021 * 022 * @author Daniel Bergqvist Copyright (C) 2020 023 * 024 * @author Andrew Crosland 2021 025 * Added extra current meter for systems with two track outputs 026*/ 027public class CbusPredefinedMeters implements CanListener, Disposable { 028 029 private final TrafficController tc; 030 private int _nodeToListen; 031 private int _eventToListenCurrent; 032 private int _eventToListenCurrentExtra; 033 private int _eventToListenVoltage; 034 private final CanSystemConnectionMemo _memo; 035 final MeterUpdateTask updateTask; 036 final Meter currentMeter; 037 final Meter currentMeterExtra; 038 final Meter voltageMeter; 039 040 public CbusPredefinedMeters(CanSystemConnectionMemo memo) { 041 042 tc = memo.getTrafficController(); 043 _memo = memo; 044 045 updateTask = new UpdateTask(-1); 046 047 currentMeter = new DefaultMeter.DefaultCurrentMeter( 048 memo.getSystemPrefix() + InstanceManager.getDefault(MeterManager.class).typeLetter() + "CBUSCurrentMeter", 049 Meter.Unit.Milli, 0, 65535.0, 1.0, updateTask); 050 051 currentMeterExtra = new DefaultMeter.DefaultCurrentMeter( 052 memo.getSystemPrefix() + InstanceManager.getDefault(MeterManager.class).typeLetter() + "CBUSCurrentMeter2", 053 Meter.Unit.Milli, 0, 65535.0, 1.0, updateTask); 054 055 voltageMeter = new DefaultMeter.DefaultVoltageMeter( 056 memo.getSystemPrefix() + InstanceManager.getDefault(MeterManager.class).typeLetter() + "CBUSVoltageMeter", 057 Meter.Unit.NoPrefix, 0, 6553.5, 0.1, updateTask); 058 059 InstanceManager.getDefault(MeterManager.class).register(currentMeter); 060 InstanceManager.getDefault(MeterManager.class).register(currentMeterExtra); 061 InstanceManager.getDefault(MeterManager.class).register(voltageMeter); 062 063 log.debug("CbusMultiMeter constructor called"); 064 } 065 066 /** 067 * Listen for CAN Frames sent by Command Station 0 068 * Typically sent every 4-5 seconds. 069 * 070 * {@inheritDoc} 071 */ 072 @Override 073 public void reply(CanReply r) { 074 if ( r.extendedOrRtr() 075 || CbusMessage.getOpcode(r) != CbusConstants.CBUS_ACON2 076 || CbusMessage.getNodeNumber(r) != _nodeToListen 077 || ((CbusMessage.getEvent(r) != _eventToListenCurrent) 078 && (CbusMessage.getEvent(r) != _eventToListenVoltage) 079 && (CbusMessage.getEvent(r) != _eventToListenCurrentExtra))) { 080 return; 081 } 082 try { 083 if (CbusMessage.getEvent(r) == _eventToListenCurrent) { 084 int currentInt = ( r.getElement(5) * 256 ) + r.getElement(6); 085 currentMeter.setCommandedAnalogValue(currentInt * 1.0f ); // mA value, min 0, max 65535, NOT percentage 086 } else if (CbusMessage.getEvent(r) == _eventToListenCurrentExtra) { 087 int currentInt = ( r.getElement(5) * 256 ) + r.getElement(6); 088 currentMeterExtra.setCommandedAnalogValue(currentInt * 1.0f ); // mA value, min 0, max 65535, NOT percentage 089 } else { 090 // Voltage from the command station is scaled by a factor of 10 to allow one decimal place 091 int voltageInt = ( r.getElement(5) * 256 ) + r.getElement(6); 092 voltageMeter.setCommandedAnalogValue(voltageInt / 10.0f ); // V value, min 0, max 6553.5, NOT percentage 093 } 094 } catch (JmriException e) { 095 log.error("exception thrown by setCurrent or setVoltage", e); 096 } 097 } 098 099 /** 100 * Outgoing CAN Frames ignored 101 * 102 * {@inheritDoc} 103 */ 104 @Override 105 public void message(CanMessage m) { 106 } 107 108 @Override 109 public void dispose() { 110 updateTask.disable(currentMeter); 111 updateTask.disable(currentMeterExtra); 112 updateTask.disable(voltageMeter); 113 InstanceManager.getDefault(MeterManager.class).deregister(currentMeter); 114 InstanceManager.getDefault(MeterManager.class).deregister(currentMeterExtra); 115 InstanceManager.getDefault(MeterManager.class).deregister(voltageMeter); 116 updateTask.dispose(currentMeter); 117 updateTask.dispose(currentMeterExtra); 118 updateTask.dispose(voltageMeter); 119 } 120 121 122 private class UpdateTask extends MeterUpdateTask { 123 124 protected UpdateTask(int interval) { 125 super(interval); 126 } 127 128 /** 129 * Starts listening for ExData2 CAN Frames using the Node of the Master Command Station 130 * 131 * {@inheritDoc} 132 */ 133 @Override 134 public void enable() { 135 _nodeToListen = 65534; 136 _eventToListenCurrent = 1; // hard coded at present 137 _eventToListenVoltage = 2; // hard coded at present 138 _eventToListenCurrentExtra = 3; // hard coded at present 139 CbusNodeTableDataModel cs = _memo.get(CbusNodeTableDataModel.class); 140 if (cs != null) { 141 CbusNode csnode = cs.getCsByNum(0); 142 if (csnode!=null) { 143 _nodeToListen = csnode.getNodeNumber(); 144 } 145 } else { 146 log.info("Unable to fetch Master Command Station from Node Manager"); 147 } 148 tc.addCanListener(CbusPredefinedMeters.this); 149 log.info("Enabled meter Long Ex2Data {} {} {}", 150 new CbusNameService(_memo).getEventNodeString(_nodeToListen,_eventToListenCurrent), 151 new CbusNameService(_memo).getEventNodeString(_nodeToListen,_eventToListenVoltage), 152 new CbusNameService(_memo).getEventNodeString(_nodeToListen,_eventToListenCurrentExtra)); 153 154 super.enable(); 155 } 156 157 /** 158 * Stops listening for updates 159 * 160 * {@inheritDoc} 161 */ 162 @Override 163 public void disable() { 164 super.disable(); 165 tc.removeCanListener(CbusPredefinedMeters.this); 166 log.info("Disabled meter."); 167 } 168 169 /** 170 * Adjust CBUS Command station settings to change frequency of updates 171 * No local action performed 172 * 173 * {@inheritDoc} 174 */ 175 @Override 176 public void requestUpdateFromLayout() { 177 } 178 } 179 180 181 private final static org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(CbusPredefinedMeters.class); 182}