001package jmri.jmrix.loconet;
002
003import org.slf4j.Logger;
004import org.slf4j.LoggerFactory;
005
006/**
007 * Only change compared to standard LocoNet SlotManager is CV programming. The
008 * Uhlenbrock IB-COM / Intellibox II uses some special and undocumented means
009 * (OPC_IMM_PACKET).
010 *
011 * {@code PC -> IB: BB 7F 00 3B OPC_RQ_SL_DATA, 127(Command Station Options ), 0
012 * IB -> PC: B4 3B 00 70 OPC_LONG_ACK, on OPC_RQ_SL_DATA, 0}
013 *
014 * {@code # start of programming session PC -> IB: E5 07 01 49 42 41 56
015 * OPC_PEER_XFER, src=7, dst=9345, ?? PC -> IB: 82 7D OPC_GPOFF}
016 *
017 * {@code # read cv 1 R CV CV PC -> IB: ED 1F 01 49 42 71 72 01 00 00 70 00 00
018 * 00 00 10 OPC_IMM_PACKET 00 00 00 00 00 00 00 00 00 00 00 00 00 00 65 IB ->
019 * PC: B4 6D 01 27 OPC_LONG_ACK, on OPC_IMM_PACKET # cv 1 has value 3 VV IB ->
020 * PC: E7 0E 7C 00 00 00 72 06 00 00 03 00 00 1D OPC_SL_RD_DATA, len, PT slot,}
021 *
022 * {@code # end off programming session PC -> IB: E5 07 01 49 42 40 57
023 * OPC_PEER_XFER, src=7, dst=}
024 *
025 * {@code # start of programming session PC -> IB: E5 07 01 49 42 41 56
026 * OPC_PEER_XFER, src=7, dst= PC -> IB: 82 7D OPC_GPOFF}
027 *
028 * {@code # write cv 1 W CV CV VV PC -> IB: ED 1F 01 49 42 71 71 01 00 03 70 00
029 * 00 00 00 10 OPC_IMM_PACKET 00 00 00 00 00 00 00 00 00 00 00 00 00 00 65 IB
030 * -> PC: B4 6D 01 27 OPC_LONG_ACK, on OPC_IMM_PACKET # cv 1 has value 3 VV IB
031 * -> PC: E7 0E 7C 00 00 00 71 06 00 00 03 00 00 1E OPC_SL_RD_DATA, len, PT
032 * slot,}
033 *
034 * {@code # end off programming session PC -> IB: E5 07 01 49 42 40 57
035 * OPC_PEER_XFER, src=7, dst=}
036 *
037 * {@code # write 254 in cv 27 HB W CV CV VV ED 1F 01 49 42 79 71 1B 00 7E 70 00
038 * 00 00 00 10 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0A # HB = high bit for
039 * CV value}
040 *
041 * {@code # response HB VV E7 0E 7C 00 00 00 71 06 02 00 7E 00 00 61}
042 *
043 * {@code # write 255 in cv 545 HB W CV CV VV ED 1F 01 49 42 79 71 21 02 7F 70
044 * 00 00 00 00 10 00 00 00 00 00 00 00 00 00 00 00 00 00 00 33}
045 *
046 * {@code # read cv 393 HB R CV CV VV ED 1F 01 49 42 73 72 09 02 00 70 00 00 00
047 * 00 10 00 00 00 00 00 00 00 00 00 00 00 00 00 00 6D}
048 *
049 * @author Lisby Copyright (C) 2014
050 */
051public class UhlenbrockSlotManager extends SlotManager {
052
053    public UhlenbrockSlotManager(LnTrafficController tc) {
054        super(tc);
055    }
056
057    /*
058     * NUM_SLOTS fixed for Uhlenbrock
059     */
060    // private final int NUM_SLOTS = 128;
061    /**
062     * Provide Uhlenbrock-specific slot implementation
063     * @param initialize - not used by Uhlenbrock
064     */
065    @Override
066    protected void loadSlots(boolean initialize) {
067        // initialize slot array
068        // TODO does UhlenBrock support extended slots?
069        for (int i = 0; i < getNumSlots(); i++) {
070            _slots[i] = new UhlenbrockSlot(i);
071        }
072    }
073
074    @Override
075    protected boolean checkLackByte1(int Byte1) {
076        //    log.info("Uhlenbrock checkLackByte1 "+Byte1);
077        if ((Byte1 & 0xED) == 0x6D) {
078            return true;
079        } else {
080            return false;
081        }
082    }
083
084    @Override
085    protected boolean checkLackTaskAccepted(int Byte2) {
086        //    log.info("Uhlenbrock checkLackTaskAccepted "+Byte2);
087        if (Byte2 == 1 // task accepted
088                || Byte2 == 0x23 || Byte2 == 0x2B || Byte2 == 0x6B)// added as DCS51 fix
089        {
090            return true;
091        } else {
092            return false;
093        }
094    }
095
096    @Override
097    protected boolean checkLackAcceptedBlind(int Byte2) {
098        //    log.info("Uhlenbrock checkLackAcceptedBlind "+Byte2);
099        if (Byte2 == 0x40 || Byte2 == 0x7F) {
100            return true;
101        } else {
102            return false;
103        }
104    }
105
106    /**
107     * Look for IB-specific messages on the LocoNet, deferring all others to the
108     * parent SlotManager implementation.
109     *
110     * @param m incoming message
111     */
112    @Override
113    public void message(LocoNetMessage m) {
114
115        // see if message for Intellibox-II functions F9 thru F12
116        if (m.getOpCode() == LnConstants.RE_OPC_IB2_F9_F12) {
117            UhlenbrockSlot slot = (UhlenbrockSlot) slot(m.getElement(1));
118            slot.iB2functionMessage(m);
119        }
120
121        // see if message for Intellibox_I and -II functions F9 thru F128
122        if (m.getOpCode() == LnConstants.OPC_EXP_SLOT_MOVE_RE_OPC_IB2_SPECIAL && m.getElement(1) == LnConstants.RE_IB2_SPECIAL_FUNCS_TOKEN) {
123            UhlenbrockSlot slot = (UhlenbrockSlot) slot(m.getElement(2));
124            slot.iBfunctionMessage(m);
125        }
126
127        super.message(m);
128    }
129
130    /**
131     * Internal method to create the LocoNetMessage for programming on main The
132     * table below contains value observed from an Intellibox II when doing
133     * programming on main.
134     *
135     * {@literal
136     * Address  CV      Value   Element Decimal Hex     Decimal Hex     Decimal Hex     4       5
137     * 60       11      12      13      14      15      16      17      18      19      20      21      22      23      24      25      26      27      28      29      30 1
138     * 01       2       02      1       01      ED      1F      1       49      42      71      5E      1       0       2       70      0       1       0       0       10      0       0       0       0       0       0       0       0       0       0
139     * 0        0       0       0       4A 1    01      115     73      127     7F      ED      1F      1       49      42      71      5E      1       0       73      70      0       7F      0       0       10      0
140     * 0        0       0       0       0       0       0       0       0       0       0       0       0       45 56   38      2       02      1       01      ED      1F      1       49      42      71      5E      38      0       2
141     * 70       0       1       0       0       10      0       0       0       0       0       0       0       0       0       0       0       0       0       0       73 87   57      255     FF      1       01      ED      1F      1       49
142     * 42       79      5E      57      0       7F      70      0       1       0       0       10      0       0       0       0       0       0       0       0       0       0       0       0       0       0       69 87   57      255
143     * FF       127     7F      ED      1F      1       49      42      79      5E      57      0       7F      70      0       7F      0       0       10      0       0       0       0       0       0       0       0       0       0
144     * 0        0       0       0       17 87   57      255     FF      255     FF      ED      1F      1       49      42      79      5E      57      0       7F      72      0       7F      0       0       10
145     * 0        0       0       0       0       0       0       0       0       0       0       0       0       0       15 87   57      256     100     1       01      ED      1F      1       49      42      71      5E      57
146     * 0        0       70      1       1       0       0       10      0       0       0       0       0       0       0       0       0       0       0       0       0       0       1F 87   57      256     100     127     7F      ED
147     * 1F       1       49      42      71      5E      57      0       0       70      1       7F      0       0       10      0       0       0       0       0       0       0       0       0       0       0       0       0       0       61 87
148     * 57       256     100     255     FF      ED      1F      1       49      42      71      5E      57      0       0       72      1       7F      0       0       10      0       0       0       0       0       0       0
149     * 0        0       0       0       0       0       0       63 87   57      513     201     1       01      ED      1F      1       49      42      71      5E      57      0       1       70      2       1       0       0
150     * 10       0       0       0       0       0       0       0       0       0       0       0       0       0       0       1D 87   57      513     201     127     7F      ED      1F      1       49      42      71
151     * 5E       57      0       1       70      2       7F      0       0       10      0       0       0       0       0       0       0       0       0       0       0       0       0       0       63 87   57      513     201     255
152     * FF       ED      1F      1       49      42      71      5E      57      0       1       72      2       7F      0       0       10      0       0       0       0       0       0       0       0       0       0       0       0       0       0
153     * 61 87    57      1024    400     1       01      ED      1F      1       49      42      71      5E      57      0       0       70      4       1       0       0       10      0       0       0       0       0
154     * 0        0       0       0       0       0       0       0       0       1A 87   57      1024    400     127     7F      ED      1F      1       49      42      71      5E      57      0       0       70
155     * 4        7F      0       0       10      0       0       0       0       0       0       0       0       0       0       0       0       0       0       64 87   57      1024    400     255     FF      ED      1F      1
156     * 49       42      71      5E      57      0       0       72      4       7F      0       0       10      0       0       0       0       0       0       0       0       0       0       0       0       0       0       66 120  78
157     * 127      7F      127     7F      ED      1F      1       49      42      71      5E      78      0       7F      70      0       7F      0       0       10      0       0       0       0       0       0       0       0
158     * 0        0       0       0       0       0       30 120  78      255     FF      127     7F      ED      1F      1       49      42      79      5E      78      0       7F      70      0       7F      0
159     * 0        10      0       0       0       0       0       0       0       0       0       0       0       0       0       0       38 120  78      255     FF      128     80      ED      1F      1       49      42      79
160     * 5E       78      0       7F      72      0       0       0       0       10      0       0       0       0       0       0       0       0       0       0       0       0       0       0       45 120  78      255     FF      254
161     * FE       ED      1F      1       49      42      79      5E      78      0       7F      72      0       7E      0       0       10      0       0       0       0       0       0       0       0       0       0       0       0       0       0
162     * 3B 120   78      255     FF      255     FF      ED      1F      1       49      42      79      5E      78      0       7F      72      0       7F      0       0       10      0       0       0
163     * 0        0       0       0       0       0       0       0       0       0       0       3A 127  7F      3       03      1       01      ED      1F      1       49      42      71      5E      7F      0       3       70      0
164     * 1        0       0       10      0       0       0       0       0       0       0       0       0       0       0       0       0       0       35 127  7F      3       03      127     7F      ED      1F      1       49      42
165     * 71       5E      7F      0       3       70      0       7F      0       0       10      0       0       0       0       0       0       0       0       0       0       0       0       0       0       4B 127  7F      3       03
166     * 128      80      ED      1F      1       49      42      71      5E      7F      0       3       72      0       0       0       0       10      0       0       0       0       0       0       0       0       0       0       0       0       0
167     * 0        36 255  FF      3       03      1       01      ED      1F      1       49      42      73      5E      7F      0       3       70      0       1       0       0       10      0       0       0       0       0
168     * 0        0       0       0       0       0       0       0       0       37 255     FF      255     FF      127     7F      ED      1F      1       49      42      7B      5E      7F      0       7F      70
169     * 0        7F      0       0       10      0       0       0       0       0       0       0       0       0       0       0       0       0       0       3D 255  FF      255     FF      128     80      ED      1F      1
170     * 49       42      7B      5E      7F      0       7F      72      0       0       0       0       10      0       0       0       0       0       0       0       0       0       0       0       0       0       0       40 256  100
171     * 2        02      1       01      ED      1F      1       49      42      71      5E      0       1       2       70      0       1       0       0       10      0       0       0       0       0       0       0       0       0       0       0       0
172     * 0        0       4A 256  100     255     FF      255     FF      ED      1F      1       49      42      79      5E      0       1       7F      72      0       7F      0       0       10      0
173     * 0        0       0       0       0       0       0       0       0       0       0       0       0       43 1000 3E8       3       03      1       01      ED      1F      1       49      42      73      5E      68      3
174     * 3        70      0       1       0       0       10      0       0       0       0       0       0       0       0       0       0       0       0       0       0       23
175     * }
176     * <p>
177     * Element 0: OPC_IMM_PACKET Element 1: Always 1F Element 2: Always 01
178     * Element 3: Always 49 Element 4: Always 42 Element 5: Basic value 71. Bit
179     * 1 (value 02) equals bit 7 in address. Bit 3 (value 08) equals bit 7 in CV
180     * number. Element 6: 5E=Write on main, 71=Write on PT, 72=Read on PT
181     * Element 7: LOPSA, i.e. Bit 0-6 of address Element 8: Bit 8-14 of address.
182     * This is not equal to HOPSA, since bit 7 is stored in element 5. Element
183     * 9: Bit 0-6 of CV number. Element 10: Basic value 70. Bit 1 (value 02)
184     * equals bit 7 in CV value. Element 11: Bit 8-11 of CV number. Element 12:
185     * Bit 0-6 in CV value. Element 15: Always 10 Element 30: Checksum
186     *
187     * @param hopsa high status byte for message
188     * @param lopsa low status byte for message
189     * @param val Value for programming operation
190     * @param cvnum CV number for programming operation
191     * @return formatted message
192     */
193    protected LocoNetMessage progOnMainMessage(int hopsa, int lopsa, int val, int cvnum) {
194        LocoNetMessage m = new LocoNetMessage(0x1F);
195        m.setOpCode(LnConstants.OPC_IMM_PACKET);
196        m.setElement(1, 0x1F);
197        m.setElement(2, 0x01);
198        m.setElement(3, 0x49);
199        m.setElement(4, 0x42);
200        m.setElement(5, 0x71 | (hopsa & 0x01) << 1 | (cvnum & 0x80) >> 4);
201        m.setElement(6, 0x5E);
202        m.setElement(7, lopsa);
203        m.setElement(8, hopsa / 2);
204        m.setElement(9, cvnum & 0x7F);
205        m.setElement(10, 0x70 | ((val & 0x80) >> 6));
206        m.setElement(11, cvnum / 256);
207        m.setElement(12, val & 0x7F);
208        m.setElement(15, 0x10);
209        return m;
210    }
211
212    /**
213     * Internal method to create the LocoNetMessage for programming on
214     * programming track. The table below contains value observed from an
215     * Intellibox II when doing programming on programming track.
216     *
217     * {@literal
218     * Operation        CV      Value   Byte # Decimal  Hex     Decimal Hex     0       1       2       3       4       5       6       7       8       9       10
219     * 11       12      13      14      15      16      17      18      19      20      21      22      23      24      25      26      27      28      29      30 Read 1       01      ED
220     * 1F       1       49      42      71      72      1       0       0       70      0       0       0       0       10      0       0       0       0       0       0       0       0       0       0       0       0       0       0       65 Write
221     * 1        01      3       03      ED      1F      1       49      42      71      71      1       0       3       70      0       0       0       0       10      0       0       0       0       0       0       0       0       0       0       0       0
222     * 0        0       65 Write        27      1B      254     FE      ED      1F      1       49      42      79      71      1B      0       7E      70      0       0       0       0       10      0       0       0
223     * 0        0       0       0       0       0       0       0       0       0       0       0A Write        545     221     255     FF      ED      1F      1       49      42      79      71      21      2       7F
224     * 70       0       0       0       0       10      0       0       0       0       0       0       0       0       0       0       0       0       0       0       33 Read 393     189     ED      1F      1       49      42
225     * 73       72      9       1       0       70      0       0       0       0       10      0       0       0       0       0       0       0       0       0       0       0       0       0       0       6D Write        n
226     * 01       ED      1F      1       49      42      73      71      7F      0       1       70      0       0       0       0       10      0       0       0       0       0       0       0       0       0       0       0       0       0       0
227     * 1B Write 255     FF      127     7F      ED      1F      1       49      42      73      71      7F      0       7F      70      0       0       0       0       10      0       0       0       0
228     * 0        0       0       0       0       0       0       0       0       0       65 Write        255     FF      255     FF      ED      1F      1       49      42      7B      71      7F      0       7F      70
229     * 0        0       0       0       10      0       0       0       0       0       0       0       0       0       0       0       0       0       0       6D Write        256     100     1       01      ED      1F      1       49
230     * 42       71      71      0       1       1       70      0       0       0       0       10      0       0       0       0       0       0       0       0       0       0       0       0       0       0       67 Write        256     100
231     * 127      7F      ED      1F      1       49      42      71      71      0       1       7F      70      0       0       0       0       10      0       0       0       0       0       0       0       0       0       0       0       0       0
232     * 0        19 Write        256     100     255     FF      ED      1F      1       49      42      79      71      0       1       7F      70      0       0       0       0       10      0       0       0
233     * 0        0       0       0       0       0       0       0       0       0       0       11 Write        513     201     1       01      ED      1F      1       49      42      71      71      1       2       1       70
234     * 0        0       0       0       10      0       0       0       0       0       0       0       0       0       0       0       0       0       0       65 Write        513     201     127     7F      ED      1F      1       49
235     * 42       71      71      1       2       7F      70      0       0       0       0       10      0       0       0       0       0       0       0       0       0       0       0       0       0       0       1B Write        513
236     * 201      255     FF      ED      1F      1       49      42      79      71      1       2       7F      70      0       0       0       0       10      0       0       0       0       0       0       0       0       0       0       0
237     * 0        0       0       13 Write        1024    400     1       01      ED      1F      1       49      42      71      71      0       4       1       70      0       0       0       0       10      0       0
238     * 0        0       0       0       0       0       0       0       0       0       0       0       62 Write        1024    400     127     7F      ED      1F      1       49      42      71      71      0       4
239     * 7F       70      0       0       0       0       10      0       0       0       0       0       0       0       0       0       0       0       0       0       0       1C Write        1024    400     255     FF      ED
240     * 1F       1       49      42      79      71      0       4       7F      70      0       0       0       0       10      0       0       0       0       0       0       0       0       0       0       0       0       0       0       14
241     * }
242     * <p>
243     * Element 0: OPC_IMM_PACKET Element 1: Always 1F Element 2: Always 01
244     * Element 3: Always 49 Element 4: Always 42 Element 5: Basic value 71. Bit
245     * 1 (value 02) equals bit 7 in CV number. Bit 3 (value 08) equals bit 7 in
246     * CV value. Element 6: 5E=Write on main, 71=Write on PT, 72=Read on PT
247     * Element 7: Bit 0-6 of CV number Element 8: Bit 8-11 of CV number. Element
248     * 9: Bit 0-6 of CV value. Element 10: Always 70. Element 15: Always 10
249     * Element 30: Checksum
250     *
251     * @param element6 Byte from message
252     * @param val Value for programming operation
253     * @param cvnum CV number for programming operation
254     * @return formatted message
255     */
256    protected LocoNetMessage progOnProgrammingTrackMessage(int element6, int val, int cvnum) {
257        //       log.error("About to create read/write CV command for IB-COM.", new Excception());
258        LocoNetMessage m = new LocoNetMessage(0x1F);
259//log.info("--------SENDING OPC_IMM_PACKET TO IB-COM PROGRAMMING TRACK. pcmd=" + pcmd + "val="+val+" cvnum="+cvnum+" write="+write);
260        m.setOpCode(LnConstants.OPC_IMM_PACKET);
261        m.setElement(1, 0x1F);
262        m.setElement(2, 0x01);
263        m.setElement(3, 0x49);
264        m.setElement(4, 0x42);
265        m.setElement(5, 0x71 | (val & 0x80) >> 4 | (cvnum & 0x80) >> 6);
266        m.setElement(6, element6);
267        m.setElement(7, cvnum & 0x7F);
268        m.setElement(8, cvnum / 256);
269        m.setElement(9, val & 0x7F);
270        m.setElement(10, 0x70);
271        m.setElement(15, 0x10);
272        return m;
273    }
274
275    /*
276     * Internal method to create the LocoNetMessage for programmer task start
277     * @param pcmd command byte values
278     * @param val Value to write if writing
279     * @parma cvnum CV number to access
280     * @param write is this a write?
281     * @return Message to send to do this function
282     */
283    @Override
284    protected LocoNetMessage progTaskStart(int pcmd, int val, int cvnum, boolean write) {
285        switch (pcmd) {
286            case 0x67:
287                return progOnMainMessage(hopsa, lopsa, val, cvnum);  // write on main
288
289            case 0x63:
290                return progOnProgrammingTrackMessage(0x6F, val, cvnum); // write on PT in PageMode
291            case 0x6B:
292                return progOnProgrammingTrackMessage(0x71, val, cvnum); // write on PT in DirectByteMode
293            case 0x53:
294                return progOnProgrammingTrackMessage(0x6D, val, cvnum); // write on PT in RegisterMode or AddressMode
295
296            case 0x23:
297                return progOnProgrammingTrackMessage(0x6E, 0, cvnum); // read on PT in PageMode
298            case 0x2B:
299                return progOnProgrammingTrackMessage(0x72, 0, cvnum); // read on PT in DirectByteMode
300            case 0x13:
301                return progOnProgrammingTrackMessage(0x6C, 0, cvnum); // read on PT in RegisterMoode or AddressMode
302            default:
303                log.warn("Unhandled programming type: {}", pcmd);
304                break;
305        }
306        // We are probably being asked to read CV on main track, which is not suppoorted by IB. So get out of programming mode.
307        return stopIBComPT();
308    }
309
310    /**
311     * Internal method to create the LocoNetMessage for enabling programming
312     * track in IB-COM / Intellibox II Note: This method is specific to
313     * Uhlenbrock
314     * @return Message to send to do this function
315     */
316    protected LocoNetMessage startIBComPT() {
317        //       log.error("About to initiate programming track for IB-COM.", new Exception());
318
319        LocoNetMessage m = new LocoNetMessage(7);
320//log.info("--------startIBComPT");
321        m.setOpCode(LnConstants.OPC_PEER_XFER);
322        m.setElement(1, 0x07);
323        m.setElement(2, 0x01);
324        m.setElement(3, 0x49);
325        m.setElement(4, 0x42);
326        m.setElement(5, 0x41);
327        return m;
328    }
329
330    /**
331     * Internal method to create the LocoNetMessage for disabling programming
332     * track in IB-COM / Intellibox II Note: This method is currently not used
333     * @return Message to send to do this function
334     */
335    protected LocoNetMessage stopIBComPT() {
336        //       log.error("About to stop using programming track for IB-COM.", new Exception());
337
338        LocoNetMessage m = new LocoNetMessage(7);
339
340        m.setOpCode(LnConstants.OPC_PEER_XFER);
341        m.setElement(1, 0x07);
342        m.setElement(2, 0x01);
343        m.setElement(3, 0x49);
344        m.setElement(4, 0x42);
345        m.setElement(5, 0x40);
346        return m;
347    }
348
349    // internal method to remember who's using the programmer
350    // Note: Overridden in order to also call the startIBComPT method
351    @Override
352    protected void useProgrammer(jmri.ProgListener p) throws jmri.ProgrammerException {
353        super.useProgrammer(p);
354        tc.sendLocoNetMessage(startIBComPT());
355    }
356
357    // A couple of seconds after the last programming command, power is meant to be turned on.
358    // However, for the Uhlenbrock IB-COM / Intellibox II, the command station is taken out of programming mode instead.
359    @Override
360    synchronized protected void doEndOfProgramming() {
361        log.debug("Uhlenbrock doEndOfProgramming");
362        tc.sendLocoNetMessage(stopIBComPT());
363    }
364
365    // initialize logging
366    private final static Logger log = LoggerFactory.getLogger(UhlenbrockSlotManager.class);
367
368}