001package jmri.jmrix.maple; 002 003import org.slf4j.Logger; 004import org.slf4j.LoggerFactory; 005 006/** 007 * Utility Class supporting output to Maple HMI's 008 * <p> 009 * All of the Maple HMI panels receive the same output bits. This keeps them 010 * synchronized. Output is sent in "broadcast" mode to Station Address 0. All 011 * HMI's receive the output. Output is sent at the end of each polling cycle, 012 * whether or not anything has changed. That way, if an HMI panel is plugged in, 013 * it will be up-to-date within one polling cycle. Serial systems with unique 014 * output bits for each node keep their output array in each node. That code has 015 * been moved to this utility class for Maple Systems because all nodes share 016 * the same output bits. Coil bits within Maple Systems HMI's are divided into 017 * input (1-1000) and output (1001-9000), so input bits are read starting from 018 * HMI address 1, and output bits are written starting at HMI address 1001. 019 * 020 * @author Dave Duchamp, Copyright (C) 2009 021 */ 022public class OutputBits { 023 024 public OutputBits(SerialTrafficController _tc) { 025 // clear all output bits 026 for (int i = 0; i < 256; i++) { 027 outputArray[i] = 0; 028 } 029 } 030 031 // operational variables 032// private int mPulseWidth = 500; 033 private static int mSendDelay = 200; 034 private static int mNumOutputBits = 98; 035 protected byte[] outputArray = new byte[256]; // current values of the output bits 036 037 // access routines 038 public static void setNumOutputBits(int n) { 039 mNumOutputBits = n; 040 } 041 042 public static int getNumOutputBits() { 043 return mNumOutputBits; 044 } 045// public int getPulseWidth() {return (mPulseWidth);} 046// public void setPulseWidth(int width) {mPulseWidth = width;} 047 048 public static void setSendDelay(int n) { 049 mSendDelay = n; 050 } 051 052 public static int getSendDelay() { 053 return mSendDelay; 054 } 055 056 /** 057 * Set an output bit. 058 * <p> 059 * Note: state = 'true' for 0, 'false' for 1. 060 * Bits are numbered from 1 (not 0) 061 * @param bitNumber bit index number starting from 1. 062 * @param state true for 0, false for 1. 063 */ 064 public void setOutputBit(int bitNumber, boolean state) { 065 // validate that this bitNumber is defined 066 if (bitNumber > mNumOutputBits) { 067 log.warn("Output bit out-of-range for configured bits"); 068 return; 069 } 070 // locate in the outputArray 071 int byteNumber = (bitNumber - 1) / 8; 072 // update the byte 073 byte bit = (byte) (1 << ((bitNumber - 1) % 8)); 074 if (state) { 075 outputArray[byteNumber] &= (~bit); 076 } else { 077 outputArray[byteNumber] |= bit; 078 } 079 } 080 081 /** 082 * Get the current state of an output bit. 083 * <p> 084 * Bits are numbered from 1 (not 0). 085 * 086 * @param bitNumber bit number to check, index starts at 1. 087 * @return 'true' for 0, 'false' for 1 088 */ 089 public boolean getOutputBit(int bitNumber) { 090 // locate in the outputArray 091 int byteNumber = (bitNumber - 1) / 8; 092 // validate that this byte number is defined 093 if (byteNumber >= 256) { 094 byteNumber = 255; 095 } 096 // update the byte 097 byte bit = (byte) (1 << ((bitNumber - 1) % 8)); 098 byte testByte = outputArray[byteNumber]; 099 testByte &= bit; 100 if (testByte == 0) { 101 return (true); 102 } else { 103 return (false); 104 } 105 } 106 107 /** 108 * Create a Transmit packet (SerialMessage). 109 * @param startBitNum start bit number. 110 * @param endBitNum end bit number. 111 * @return serial message. 112 */ 113 public SerialMessage createOutPacket(int startBitNum, int endBitNum) { 114 int nBits = endBitNum - startBitNum + 1; 115 if (nBits > 99) { 116 log.error("Number of bits for this packet greater than 99 - {}", nBits); 117 return null; 118 } 119 int sAdd = 1000 + startBitNum; // write starting at 1001 for output 1 in HMI's 120 // create message 121 SerialMessage m = new SerialMessage(14 + nBits); 122 m.setElement(0, 02); 123 m.setElement(1, '0'); // send in broadcast mode so all devices update 124 m.setElement(2, '0'); 125 m.setElement(3, 'W'); 126 m.setElement(4, 'C'); 127 m.setElement(5, '0' + (sAdd / 1000)); 128 m.setElement(6, '0' + ((sAdd - ((sAdd / 1000) * 1000)) / 100)); 129 m.setElement(7, '0' + ((sAdd - ((sAdd / 100) * 100)) / 10)); 130 m.setElement(8, '0' + (sAdd - ((sAdd / 10) * 10))); 131 m.setElement(9, '0' + (nBits / 10)); 132 m.setElement(10, '0' + (nBits - ((nBits / 10) * 10))); 133 for (int i = 0; i < nBits; i++) { 134 int j = i - ((i / 8) * 8); 135 int val = outputArray[i / 8]; 136 if (j == 0) { 137 m.setElement(11 + i, ((val & 0x01) != 0) ? '1' : '0'); 138 } else if (j == 1) { 139 m.setElement(11 + i, ((val & 0x02) != 0) ? '1' : '0'); 140 } else if (j == 2) { 141 m.setElement(11 + i, ((val & 0x04) != 0) ? '1' : '0'); 142 } else if (j == 3) { 143 m.setElement(11 + i, ((val & 0x08) != 0) ? '1' : '0'); 144 } else if (j == 4) { 145 m.setElement(11 + i, ((val & 0x10) != 0) ? '1' : '0'); 146 } else if (j == 5) { 147 m.setElement(11 + i, ((val & 0x20) != 0) ? '1' : '0'); 148 } else if (j == 6) { 149 m.setElement(11 + i, ((val & 0x40) != 0) ? '1' : '0'); 150 } else if (j == 7) { 151 m.setElement(11 + i, ((val & 0x80) != 0) ? '1' : '0'); 152 } 153 } 154 m.setElement(11 + nBits, 03); 155 m.setChecksum(12 + nBits); 156 m.setTimeout(mSendDelay); 157 m.setNoReply(); 158 return m; 159 } 160 161 private final static Logger log = LoggerFactory.getLogger(OutputBits.class); 162 163}