001package jmri.jmrix.loconet.locoio;
002
003import jmri.jmrix.loconet.LnTrafficController;
004import jmri.jmrix.loconet.LocoNetMessage;
005
006/**
007 * Manage the communication to/from a LocoIO board. Deprecated since version 5.12. Will be removed 2025 version 5.13
008 * <p>
009 * Uses the LOCONETSV1MODE programming mode.
010 * <p>
011 * Uses LnProgrammer LOCOIO_PEER_CODE_SV_VER1 message format, comparable to DecoderPro LOCONETSV1MODE
012 * Since JMRI 4.11.6 the LocoIO tool does not work with the HDL LocoIO rev 3 and newer boards,
013 * with risk of breaking the stored config. Use the DecoderPro decoder definition.
014 *
015 * @see jmri.jmrix.loconet.LnOpsModeProgrammer#message(LocoNetMessage)
016 *
017 * Programming SV's
018 * <p>
019 * The SV's in a LocoIO hardware module can be programmed using LocoNet OPC_PEER_XFER messages.
020 * <p>
021 * Commands for setting SV's:
022 * <p>
023 * PC to LocoIO LocoNet message (OPC_PEER_XFER)
024 * <pre><code>
025 * Code LOCOIO_SV_READ _or_ LOCOIO_SV_WRITE ----
026 * 0xE5 OPC_PEER_XFER
027 * 0x10 Message length
028 * SRCL 0x50            0x50 // low address byte of LocoBuffer
029 * DSTL LocoIO low address
030 * DSTH 0x01 0x01 // Fixed LocoIO high address
031 * PXCT1
032 * D1 LOCOIO_SV_READ _or_ LOCOIO_SV_WRITE // Read/Write command
033 * D2 SV number         SV number
034 * D3 0x00              0x00
035 * D4 0x00              Data to Write
036 * PXCT2
037 * D5 LocoIO Sub-address
038 * D6 0x00              0x00
039 * D7 0x00              0x00
040 * D8 0x00              0x00
041 * CHK Checksum         Checksum
042 * </code></pre>
043 *
044 * LocoIO to PC reply message (OPC_PEER_XFER)
045 * <pre><code>
046 * Code LOCOIO_SV_READ _or_ LOCOIO_SV_WRITE ----
047 * 0xE5 OPC_PEER_XFER
048 * 0x10 Message length
049 * SRCL LocoIO low address
050 * DSTL 0x50                0x50 // low address byte of LocoBuffer
051 * DSTH 0x01                0x01 // high address byte of LocoBuffer
052 * PXCT1 MSB LocoIO version // High order bit of LocoIO version
053 * D1 LOCOIO_SV_READ _or_   LOCOIO_SV_WRITE // Original Command
054 * D2 SV number requested
055 * D3 LSBs LocoIO version // Lower 7 bits of LocoIO version
056 * D4 0x00                  0x00
057 * PXCT2 MSB Requested Data // High order bit of requested data
058 * D5 LocoIO Sub-address
059 * D6 Requested Data        0x00
060 * D7 Requested Data + 1    0x00
061 * D8 Requested Data + 2    Written Data
062 * CHK Checksum             Checksum
063 * </code></pre>
064 *
065 * @author John Plocher 2006, 2007
066 */
067public class LocoIO {
068
069    public static final int LOCOIO_SV_WRITE = 0x01;
070    public static final int LOCOIO_SV_READ = 0x02;
071    public static final int LOCOIO_BROADCAST_ADDRESS = 0x0100; // LocoIO broadcast
072
073    public static final int LOCOIO_PEER_CODE_7BIT_ADDRS = 0x00;
074    public static final int LOCOIO_PEER_CODE_ANSI_TEXT = 0x00; // not used
075    public static final int LOCOIO_PEER_CODE_SV_VER1 = 0x08;
076    public static final int LOCOIO_PEER_CODE_SV_VER2 = 0x09; // not used
077
078    /**
079     * Create a new instance of LocoIO.
080     */
081    public LocoIO() {
082    }
083
084    public static int SENSOR_ADR(int a1, int a2) {
085        return (((a2 & 0x0f) * 128) + (a1 & 0x7f)) + 1;
086    }
087
088    /**
089     * Compose a LocoNet message from the given ingredients for reading
090     * the value of one specific SV from a given LocoIO.
091     *
092     * @param locoIOAddress base address of the LocoIO board to read from
093     * @param locoIOSubAddress subAddress of the LocoIO board
094     * @param sv the SV index to query
095     * @return complete message to send
096     */
097    public static LocoNetMessage readSV(int locoIOAddress, int locoIOSubAddress, int sv) {
098        int[] contents = {LOCOIO_SV_READ, sv, 0, 0, locoIOSubAddress, 0, 0, 0};
099        int dstExtr = locoIOAddress | 0x0100; // force version 1 tag, cf. LnOpsModeProgrammer
100
101        return LocoNetMessage.makePeerXfr(
102                0x1050, // B'cast locobuffer address
103                dstExtr,
104                contents, // SV and SubAddr to read
105                LOCOIO_PEER_CODE_SV_VER1
106        );
107    }
108
109    /**
110     * Compose a LocoNet message from the given ingredients for reading
111     * the value of one specific SV from a given LocoIO.
112     *
113     * @param locoIOAddress base address of the LocoIO board to read from
114     * @param locoIOSubAddress subAddress of the LocoIO board
115     * @param sv the SV index to change
116     * @param data the new value to store in the board's SV
117     * @return complete message to send
118     */
119    public static LocoNetMessage writeSV(int locoIOAddress, int locoIOSubAddress, int sv, int data) {
120        int[] contents = {LOCOIO_SV_WRITE, sv, 0, data, locoIOSubAddress, 0, 0, 0};
121        int dstExtr = locoIOAddress | 0x0100; // force version 1 tag, cf. LnOpsModeProgrammer
122
123        return LocoNetMessage.makePeerXfr(
124                0x1050, // B'cast locobuffer address
125                dstExtr,
126                contents, // SV and SubAddr to read
127                LOCOIO_PEER_CODE_SV_VER1
128        );
129    }
130
131    /**
132     * Compose and send a message out onto LocoNet changing the LocoIO hardware board
133     * address of all connected LocoIO boards.
134     * <p>
135     * User is warned that this is a broadcast type operation.
136     *
137     * @param address the new base address of the LocoIO board to change
138     * @param subAddress the new subAddress of the board
139     * @param ln the TrafficController to use for sending the message
140     */
141    public static void programLocoIOAddress(int address, int subAddress, LnTrafficController ln) {
142        LocoNetMessage msg;
143        msg = LocoIO.writeSV(LOCOIO_BROADCAST_ADDRESS, 0, 1, address & 0xFF);
144        ln.sendLocoNetMessage(msg);
145        if (subAddress != 0) {
146            msg = LocoIO.writeSV(LOCOIO_BROADCAST_ADDRESS, 0, 2, subAddress);
147            ln.sendLocoNetMessage(msg);
148        }
149    }
150
151    /**
152     * Send out a probe of all connected LocoIO units on a given LocoNet connection.
153     *
154     * @param ln the TrafficController to use for sending the message
155     */
156    public static void probeLocoIOs(LnTrafficController ln) {
157        LocoNetMessage msg;
158        msg = LocoIO.readSV(LOCOIO_BROADCAST_ADDRESS, 0, 2);
159        ln.sendLocoNetMessage(msg);
160    }
161
162}