001package jmri.jmrix.can.cbus.node;
002
003import java.util.Collections;
004import java.util.HashMap;
005import java.util.Map;
006
007import javax.annotation.Nonnull;
008
009import static jmri.jmrix.can.cbus.CbusConstants.*;
010
011// import org.slf4j.Logger;
012// import org.slf4j.LoggerFactory;
013
014/**
015 * Static Methods relating to nodes ( modules ).
016 *
017 * @author Steve Young (C) 2019
018 */
019public class CbusNodeConstants {
020
021    /**
022     * Node Parameters
023     *
024     * Para 0 Number of parameters
025     * Para 1 The manufacturer ID
026     * Para 2 Minor code version as an alphabetic character (ASCII)
027     * Para 3 Manufacturer module identifier as a HEX numeric
028     * Para 4 Number of supported events as a HEX numeric
029     * Para 5 Number of Event Variables per event as a HEX numeric
030     * Para 6 Number of supported Node Variables as a HEX numeric
031     * Para 7 Major version
032     * Para 8 Node flags
033     * Para 9 Processor type
034     * Para 10 Bus type
035     * Para 11 load address, 4 bytes
036     * Para 15 CPU manufacturer's id as read from the chip config space, 4 bytes
037     * Para 19 CPU manufacturer code
038     * Para 20 Beta revision (numeric), or 0 if release
039     * Para 21 - 24 Zero filled spare
040     * Not readable by index:
041     * Para 25 - 26 Number of paranmeters can be read as parameter 0
042     * Para 27 - 30 Name string base address
043     * Para 31 - 32 Checksum. Para 1 - 32 must sum to zero
044     */
045    public static final int NUM_PARAM_IDX = 0;      // Para 0 Number of parameters
046    public static final int MANU_ID_IDX = 1;        // Para 1 The manufacturer ID
047    public static final int MINOR_VER_IDX = 2;      // Para 2 Minor code version as an alphabetic character (ASCII)
048    public static final int MODULE_ID_IDX = 3;      // Para 3 Manufacturer module identifier as a HEX numeric
049    public static final int NUM_EV_IDX = 4;         // Para 4 Number of supported events as a HEX numeric
050    public static final int EV_PER_EN_IDX = 5;      // Para 5 Number of Event Variables per event as a HEX numeric
051    public static final int NUM_NV_IDX = 6;         // Para 6 Number of supported Node Variables as a HEX numeric
052    public static final int MAJOR_VER_IDX = 7;      // Para 7 Major version
053    public static final int FLAGS_IDX = 8;          // Para 8 Node flags
054    public static final int PROC_TYPE_IDX = 9;      // Para 9 Processor type
055    public static final int BUS_TYPE_IDX = 10;      // Para 10 Bus type
056    public static final int LOAD_ADDR_IDX = 11;     // Para 11 load address, 4 bytes
057    public static final int CPU_ID_IDX = 15;        // Para 15 CPU manufacturer's id as read from the chip config space, 4 bytes, only firs two used for PIC18
058    public static final int CPU_CODE_IDX = 19;      // Para 19 CPU manufacturer code
059    public static final int BETA_REV_IDX = 20;      // Para 20 Beta revision (numeric), or 0 if release
060    public static final int SPARE_IDX = 21;         // Para 21 - 24 
061    // Following are available from hex data but not readable by index
062    public static final int PARAM_COUNT_IDX = 25;    // Para 25 - 26 parameter count high byte
063    public static final int NAME_STRING_BASE_IDX = 27; // Para 27 - 30 parameter count high byte
064    public static final int PARAM_CHECK_IDX = 31;    // Para 31 - 32 parameter count high byte
065   
066    
067    /**
068     * Set traits for a node where there is a minor deviance to MERG CBUS protocol
069     * or provide extra info. which is missing for a known module firmware.
070     * @param node The CbusNode object we are setting the traits for
071     */
072    public static void setTraits(@Nonnull CbusNode node ){
073        
074        // defaults
075        node.setsendsWRACKonNVSET(true);
076        
077        if ( node.getNodeParamManager().getParameter(MANU_ID_IDX) == MANU_MERG ) { // MERG MODULE
078            switch (node.getNodeParamManager().getParameter(MODULE_ID_IDX)) { // Module Type ID Number
079                case 1: // CANACC4
080                case 8: // CANACC4_2
081                case 29: // CANPAN
082                case 34: // CANSOL
083                case 37: // CANACC4CDU
084                    node.setsendsWRACKonNVSET(false);
085                    break;
086                case 10 : // CANCMD
087                case 55 : // or CANCSB 
088                case 12 : // or CANBC
089                    if ( node.getNodeParamManager().getParameter(MAJOR_VER_IDX) == 4 ) { // v4 Firmware
090                        node.getNodeEventManager().resetNodeEventsToZero(); // sets num events to 0 as does not respond to RQEVN
091                        node.setStatResponseFlagsAccurate(false);
092                    }
093                    break;
094                case 46: // CANPiWi
095                    if ( node.getNodeParamManager().getParameter(MAJOR_VER_IDX) == 1 ) { // v1 Firmware
096                        node.getNodeEventManager().resetNodeEventsToZero(); // sets num events to 0 as does not respond to RQEVN
097                    }
098                    break;
099                case 9: // CANCAB
100                    node.getNodeEventManager().resetNodeEventsToZero(); // sets num events to 0 as does not respond to RQEVN
101                    break;
102                case 50: // CANMIO-SVO
103                case 19: // CANSERVO8C
104                    node.setnvWriteInLearnOnly(true);
105                    break;
106                default:
107                    break;
108            }
109        } else if ( node.getNodeParamManager().getParameter(MANU_ID_IDX) == SPROG_DCC ) {    // SPROG DCC module
110            switch (node.getNodeParamManager().getParameter(MODULE_ID_IDX)) {           // Module Type ID Number
111                case MTYP_CANSERVOIO:
112                    node.setnvWriteInLearnOnly(true);
113                    break;
114                    
115                default:
116                    break;
117            }
118        }
119    }
120
121    /**
122     * Return a string representation of a decoded Module Manufacturer
123     * @param man manufacturer int
124     * @return decoded CBUS message
125     */
126    public static String getManu(int man) {
127        if (man < 1 ) {
128            return ("");
129        }
130        // look for the manufacturer
131        String format = manMap.get(man);
132        if (format == null) {
133            return "Manufacturer " + man;
134        } else {
135            return format; 
136        }
137    }
138    
139    /**
140     * Hashmap for decoding Module Manufacturers
141     */
142    private static final Map<Integer, String> manMap = createManMap();
143
144    /**
145     * Populate hashmap with format strings
146     *
147     */
148    private static Map<Integer, String> createManMap() {
149        Map<Integer, String> result = new HashMap<>();
150        result.put(MANU_ROCRAIL, "ROCRAIL"); // NOI18N
151        result.put(MANU_SPECTRUM, "SPECTRUM"); // NOI18N
152        result.put(MANU_MERG, "MERG"); // NOI18N
153        result.put(SPROG_DCC, "SPROG DCC"); // NOI18N
154        return Collections.unmodifiableMap(result);
155    }
156    
157    /**
158     * Return a string representation of a decoded Bus Type
159     * @param type Bus type
160     * @return decoded CBUS message
161     */
162    public static String getBusType(int type) {
163        // look for the opcode
164        String format = busMap.get(type);
165        if (format == null) {
166            return "Unknown";
167        } else {
168            return format; 
169        }
170    }
171    
172    /**
173     * Hashmap for decoding Bus Type
174     */
175    private static final Map<Integer, String> busMap = createBusMap();
176
177    /**
178     * Populate hashmap with format strings
179     *
180     */
181    private static Map<Integer, String> createBusMap() {
182        Map<Integer, String> result = new HashMap<>();
183        result.put(0, "None"); // NOI18N
184        result.put(1, "CAN"); // NOI18N
185        result.put(2, "ETH"); // NOI18N
186        result.put(3, "MIWI"); // NOI18N
187        result.put(4, "USB"); // NOI18N
188        return Collections.unmodifiableMap(result);
189    }
190    
191    // manufacturer specific stuff from here down
192    // do not rely on these as defs, may be moved to module config file.
193    
194    // getModuleTypeExtra
195    // getModuleSupportLink
196
197    /**
198     * Return a string representation of a decoded Module Name for
199     * manufacturer MERG.
200     * @param man int manufacturer
201     * @param type module type int
202     * @return decoded String module type name else empty string
203     */
204    public static String getModuleType(int man, int type) {
205        String format="";
206        if (man == MANU_MERG) {
207            format = type165Map.get(type);
208        }
209        else if (man == MANU_ROCRAIL) {
210            format = type70Map.get(type);
211        }
212        else if (man == MANU_SPECTRUM) {
213            format = type80Map.get(type);
214        }
215        else if (man == SPROG_DCC) {
216            format = type44Map.get(type);
217        }
218        
219        if ( format == null ){
220            return ("");
221        }
222        else {
223            return format;
224        }
225    }
226    
227    /**
228     * Hashmap for decoding Module Names
229     */
230    private static final Map<Integer, String> type165Map = createType165Map();
231    private static final Map<Integer, String> type70Map = createType70Map();
232    private static final Map<Integer, String> type80Map = createType80Map();
233    private static final Map<Integer, String> type44Map = createType44Map();
234    
235    /**
236     * Populate hashmap with format strings for manufacturer MERG
237     */
238    private static Map<Integer, String> createType165Map() {
239        Map<Integer, String> result = new HashMap<>();
240        result.put(0, "SLIM"); // NOI18N
241        result.put(1, "CANACC4"); // NOI18N
242        result.put(2, "CANACC5"); // NOI18N
243        result.put(3, "CANACC8"); // NOI18N
244        result.put(4, "CANACE3"); // NOI18N
245        result.put(5, "CANACE8C"); // NOI18N
246        result.put(6, "CANLED"); // NOI18N
247        result.put(7, "CANLED64"); // NOI18N
248        result.put(8, "CANACC4_2"); // NOI18N
249        result.put(9, "CANCAB"); // NOI18N
250        result.put(10, "CANCMD"); // NOI18N
251        result.put(11, "CANSERVO"); // NOI18N
252        result.put(12, "CANBC"); // NOI18N
253        result.put(13, "CANRPI"); // NOI18N
254        result.put(14, "CANTTCA"); // NOI18N
255        result.put(15, "CANTTCB"); // NOI18N
256        result.put(16, "CANHS"); // NOI18N
257        result.put(17, "CANTOTI"); // NOI18N
258        result.put(18, "CAN8I8O"); // NOI18N
259        result.put(19, "CANSERVO8C"); // NOI18N
260        result.put(20, "CANRFID"); // NOI18N
261        result.put(21, "CANTC4"); // NOI18N
262        result.put(22, "CANACE16C"); // NOI18N
263        result.put(23, "CANIO8"); // NOI18N
264        result.put(24, "CANSNDX"); // NOI18N
265        result.put(25, "CANEther"); // NOI18N
266        result.put(26, "CANSIG64"); // NOI18N
267        result.put(27, "CANSIG8"); // NOI18N
268        result.put(28, "CANCOND8C"); // NOI18N
269        result.put(29, "CANPAN"); // NOI18N
270        result.put(30, "CANACE3C"); // NOI18N
271        result.put(31, "CANPanel"); // NOI18N
272        result.put(32, "CANMIO"); // NOI18N
273        result.put(33, "CANACE8MIO"); // NOI18N
274        result.put(34, "CANSOL"); // NOI18N
275        result.put(35, "CANBIP"); // NOI18N
276        result.put(36, "CANCDU"); // NOI18N
277        result.put(37, "CANACC4CDU"); // NOI18N
278        result.put(38, "CANWiBase"); // NOI18N
279        result.put(39, "WiCAB"); // NOI18N
280        result.put(40, "CANWiFi"); // NOI18N
281        result.put(41, "CANFTT"); // NOI18N
282        result.put(42, "CANHNDST"); // NOI18N
283        result.put(43, "CANTCHNDST"); // NOI18N
284        result.put(44, "CANRFID8"); // NOI18N
285        result.put(45, "CANmchRFID"); // NOI18N
286        result.put(46, "CANPiWi"); // NOI18N
287        result.put(47, "CAN4DC"); // NOI18N
288        result.put(48, "CANELEV"); // NOI18N
289        result.put(49, "CANSCAN"); // NOI18N
290        result.put(50, "CANMIO_SVO"); // NOI18N
291        result.put(51, "CANMIO_INP"); // NOI18N
292        result.put(52, "CANMIO_OUT"); // NOI18N
293        result.put(53, "CANBIP_OUT"); // NOI18N
294        result.put(54, "CANASTOP"); // NOI18N
295        result.put(55, "CANCSB"); // NOI18N
296        result.put(56, "CANMAG"); // NOI18N
297        result.put(57, "CANACE16CMIO"); // NOI18N
298        result.put(58, "CANPiNODE"); // NOI18N
299        result.put(59, "CANDISP"); // NOI18N
300        result.put(60, "CANCOMPUTE"); // NOI18N
301        result.put(61, "CANRC522"); // NOI18N
302        result.put(62, "CANINP"); // NOI18N
303        result.put(63, "CANOUT"); // NOI18N
304        result.put(64, "CANEMIO"); // NOI18N
305        result.put(65, "CANCABDC"); // NOI18N
306        result.put(66, "CANRCOM"); // NOI18N
307        result.put(67, "CANMP3");
308        result.put(68, "CANXMAS");
309        result.put(69, "CANSVOSET");
310        result.put(70, "CANCMDDC");
311        result.put(71, "CANTEXT");
312        result.put(72, "CANASIGNAL");
313        result.put(73, "CANSLIDER");
314        result.put(74, "CANDCATC");
315        result.put(75, "CANGATE");
316        result.put(76, "CANSINP");
317        result.put(77, "CANSOUT");
318        result.put(78, "CANSBIP");
319        result.put(79, "CANBUFFER");
320        result.put(80, "CANLEVER");
321        
322        result.put(253, "CANUSB"); // NOI18N
323        result.put(254, "EMPTY"); // NOI18N
324        result.put(255, "CAN_SW"); // NOI18N
325        return Collections.unmodifiableMap(result);
326    }
327
328    /*
329     * Populate hashmap with format strings
330     *
331     */
332    private static Map<Integer, String> createType70Map() {
333        Map<Integer, String> result = new HashMap<>();
334        result.put(1, "CANGC1"); // NOI18N
335        result.put(2, "CANGC2"); // NOI18N
336        result.put(3, "CANGC3"); // NOI18N
337        result.put(4, "CANGC4"); // NOI18N
338        result.put(5, "CANGC5"); // NOI18N
339        result.put(6, "CANGC6"); // NOI18N
340        result.put(7, "CANGC7"); // NOI18N
341        result.put(11, "CANGC1e"); // NOI18N
342        return Collections.unmodifiableMap(result);
343    }
344
345    
346    /*
347     * Populate hashmap with format strings
348     *
349     */
350    private static Map<Integer, String> createType80Map() {
351        Map<Integer, String> result = new HashMap<>();
352        result.put(1, "AMCTRLR"); // NOI18N
353        result.put(2, "DUALCAB"); // NOI18N
354        return Collections.unmodifiableMap(result);
355    }
356    
357    
358    /*
359     * Populate hashmap with format strings.
360     * Visible name of module, not the CBUS NAME OPC Response.
361     */
362    private static Map<Integer, String> createType44Map() {
363        Map<Integer, String> result = new HashMap<>();
364        result.put(1, "Pi-SPROG 3"); // NOI18N
365        result.put(2, "CANSPROG3P"); // NOI18N
366        result.put(3, "CANSPROG"); // NOI18N
367        result.put(4, "SBOOST"); // NOI18N
368        result.put(5, "Unsupported"); // NOI18N
369
370        result.put(8, "CANSOLNOID"); // NOI18N. Matches MERG CANSOL
371        result.put(50, "CANSERVOIO"); // NOI18N. Matches MERG canmio-svo
372        
373        result.put(100, "CANISB"); // NOI18N
374        result.put(101, "CANSOLIO"); // NOI18N
375        return Collections.unmodifiableMap(result);
376    }
377    
378    
379    /**
380     * Return a string representation of extra module info
381     * @param man int manufacturer code
382     * @param type int module type
383     * @return string value of extra module info
384     */
385    public static String getModuleTypeExtra(int man, int type) {
386        String format="";
387        switch (man) {
388            case MANU_MERG:
389                format = extra165Map.get(type);
390                break;
391            case MANU_ROCRAIL:
392                format = extra70Map.get(type);
393                break;
394            case MANU_SPECTRUM:
395                format = extra80Map.get(type);
396                break;
397            case SPROG_DCC:
398                format = extra44Map.get(type);
399                break;
400            default:
401                break;
402        }
403        return format;
404    }
405    
406    /**
407     * Hashmap for decoding Module extra info
408     */
409    private static final Map<Integer, String> extra165Map = createExtra165Map();
410    private static final Map<Integer, String> extra70Map = createExtra70Map();
411    private static final Map<Integer, String> extra80Map = createExtra80Map();
412    private static final Map<Integer, String> extra44Map = createExtra44Map();
413    
414    /*
415     * Populate hashmap with format strings
416     */
417    private static Map<Integer, String> createExtra165Map() {
418        Map<Integer, String> result = new HashMap<>();
419        result.put(0, "Default for SLiM nodes");
420        result.put(1, "Solenoid point driver");
421        result.put(2, "Motorised point driver");
422        result.put(3, "8 digital outputs ( + 8 inputs if modded)");
423        result.put(4, "Control panel switch/button encoder");
424        result.put(5, "8 digital inputs");
425        result.put(6, "64 led driver");
426        result.put(7, "64 led driver (multi leds per event)");
427        result.put(8, "12v version of CANACC4 Solenoid point driver");
428        result.put(9, "CANCAB hand throttle");
429        result.put(10, "Command Station");
430        result.put(11, "8 servo driver (on canacc8 or similar hardware)");
431        result.put(12, "BC1a Command Station");
432        result.put(13, "RPI and RFID interface");
433        result.put(14, "Turntable controller (turntable end)");
434        result.put(15, "Turntable controller (control panel end)");
435        result.put(16, "Handset controller for old BC1a type handsets");
436        result.put(17, "Track occupancy detector");
437        result.put(18, "8 inputs 8 outputs");
438        result.put(19, "Canservo with servo position feedback");
439        result.put(20, "RFID input");
440        result.put(21, "CANTC4");
441        result.put(22, "16 inputs");
442        result.put(23, "8 way I/O");
443        result.put(24, "CANSNDX");
444        result.put(25, "Ethernet interface");
445        result.put(26, "Multiple aspect signalling for CANLED module");
446        result.put(27, "Multiple aspect signalling for CANACC8 module");
447        result.put(28, "Conditional event generation");
448        result.put(29, "Control panel 32 Outputs + 32 Inputs");
449        result.put(30, "Newer version of CANACE3 firmware");
450        result.put(31, "Control panel 64 Inputs / 64 Outputs");
451        result.put(32, "Multiple I/O – Universal CANMIO firmware");
452        result.put(33, "Multiple IO module 16 inputs emulating CANACE8C on CANMIO hardware");
453        result.put(34, "Solenoid driver module");
454        result.put(35, "Universal CANBIP firmware - Bipolar IO module with additional 8 I/O pins (CANMIO family)");
455        result.put(36, "Solenoid driver module with additional 6 I/O pins (CANMIO family)");
456        result.put(37, "CANACC4 firmware ported to CANCDU");
457        result.put(38, "CAN to MiWi base station");
458        result.put(39, "Wireless cab using MiWi protocol");
459        result.put(40, "CAN to WiFi connection with Withrottle to CBUS protocol conversion");
460        result.put(41, "Turntable controller configured using FLiM");
461        result.put(42, "Handset (alternative to CANCAB)");
462        result.put(43, "Touchscreen handset");
463        result.put(44, "multi-channel RFID reader");
464        result.put(45, "either a 2ch or 8ch RFID reader");
465        result.put(46, "Raspberry Pi based module for WiFi");
466        result.put(47, "DC train controller");
467        result.put(48, "Nelevator controller");
468        result.put(49, "128 switch inputs");
469        result.put(50, "16MHz 25k80 version of CANSERVO8c on CANMIO hardware");
470        result.put(51, "16MHz 25k80 version of CANACE8MIO on CANMIO hardware");
471        result.put(52, "16MHz 25k80 version of CANACC8 on CANMIO hardware");
472        result.put(53, "16MHz 25k80 version of CANACC5 on CANMIO hardware");
473        result.put(54, "DCC stop generator");
474        result.put(55, "Command Station with 3A booster");
475        result.put(56, "Magnet on Track detector");
476        result.put(57, "16 input equivaent to CANACE8C");
477        result.put(58, "CBUS module based on Raspberry Pi");
478        result.put(59, "25K80 version of CANLED64");
479        result.put(60, "Compute Event processing engine");
480        result.put(61, "Read/Write from/to RC522 RFID tags");
481        result.put(62, "8 inputs module (2g version of CANACE8c)");
482        result.put(63, "8 outputs module (2g version of CANACC8)");
483        result.put(64, "Extended CANMIO (24 I/O ports)");
484        result.put(65, "DC cab");
485        result.put(66, "DCC Railcom detector/reader");
486        result.put(67, "MP3 sound player in response to events (eg: station announcements)");
487        result.put(68, "Addressed RGB LED driver");
488        result.put(69, "Servo setting box");
489        result.put(70, "DC Command station");
490        result.put(71, "Text message display");
491        result.put(72, "Signal controller");
492        result.put(73, "DCC cab with slider control");
493        result.put(74, "DC ATC module");
494        result.put(75, "Logic module using and/or gates");
495        result.put(76, "Q series PIC input module");
496        result.put(77, "Q series PIC output module");
497        result.put(78, "Q series PIC BIP module");
498        result.put(79, "Message buffer");
499        result.put(80, "Lever frame module");
500        
501        result.put(253, "USB interface");
502        result.put(254, "Empty module, bootloader only");
503        result.put(255, "Software nodes");
504        return Collections.unmodifiableMap(result);
505    }
506    
507    /*
508     * Populate hashmap with format strings
509     * extra text for Rocrail Modules
510     */
511    private static Map<Integer, String> createExtra70Map() {
512        Map<Integer, String> result = new HashMap<>();
513        result.put(1, "RS232 PC interface.");
514        result.put(2, "16 I/O.");
515        result.put(3, "Command station (derived from cancmd).");
516        result.put(4, "8 channel RFID reader.");        
517        result.put(5, "Cab for fixed panels (derived from cancab).");        
518        result.put(6, "4 channel servo controller.");        
519        result.put(7, "Fast clock module.");        
520        result.put(11, "CAN Ethernet interface.");
521        return Collections.unmodifiableMap(result);
522    }    
523    
524    /*
525     * Populate hashmap with format strings
526     * extra text for Animated Modeller module types
527     */
528    private static Map<Integer, String> createExtra80Map() {
529        Map<Integer, String> result = new HashMap<>();
530        result.put(1, "Animation controller (firmware derived from cancmd).");
531        result.put(2, "Dual cab based on cancab.");
532        return Collections.unmodifiableMap(result);
533    }   
534
535    
536    /*
537     * Populate hashmap with format strings
538     * extra text for Animated Modeller module types
539     */
540    private static Map<Integer, String> createExtra44Map() {
541        Map<Integer, String> result = new HashMap<>();
542        result.put(1, "Pi-SPROG 3 programmer/command station.");
543        result.put(2, "SPROG 3 Plus programmer/command station.");
544        result.put(3, "CAN SPROG programmer/command station.");
545        result.put(4, "System booster");
546        result.put(5, "Unsupported module type");
547        
548        result.put(8, "8-channel twin-coil solenoid, like MERG CANACC4_2.");
549        result.put(50, "8-channel servo I/O, like MERG CANMIO_SVO.");
550        
551        result.put(100, "Isolated USB to CAN interface with CBUS node.");
552        result.put(101, "8-channel twin-coil solenoid I/O.");
553        return Collections.unmodifiableMap(result);
554    }   
555
556  
557    /**
558     * Return a string representation of Module Support Link
559     * @param man int manufacturer ID
560     * @param type int module type ID
561     * @return string module support link, else empty string
562     */
563    public static String getModuleSupportLink(int man, int type) {
564        String format="";
565        if (man == MANU_MERG) {
566            format = link165Map.get(type);
567        }
568        else if (man == MANU_ROCRAIL) {
569            format = link70Map.get(type);
570        }
571        else if (man == SPROG_DCC) {
572            format = link44Map.get(type);
573        }
574        if ( format == null ){
575            return ("");
576        }
577        return format;
578    }
579    
580    private static final Map<Integer, String> link165Map = createLink165Map();
581    private static final Map<Integer, String> link70Map = createLink70Map();
582    private static final Map<Integer, String> link44Map = createLink44Map();
583    
584    /*
585     * Populate hashmap with merg module support links
586     */
587    private static Map<Integer, String> createLink165Map() {
588        Map<Integer, String> result = new HashMap<>();
589        
590        result.put(1, "https://www.merg.org.uk/merg_wiki/doku.php?id=cbus:canacc4"); // NOI18N
591        result.put(2, "https://www.merg.org.uk/merg_wiki/doku.php?id=cbus:canacc5"); // NOI18N
592        result.put(3, "https://www.merg.org.uk/merg_wiki/doku.php?id=cbus:canacc8"); // NOI18N
593        result.put(4, "https://www.merg.org.uk/merg_wiki/doku.php?id=cbus:canace3"); // NOI18N
594        result.put(5, "https://www.merg.org.uk/merg_wiki/doku.php?id=cbus:canace8c"); // NOI18N
595        // result.put(6, "CANLED"); // NOI18N
596        result.put(7, "https://www.merg.org.uk/merg_wiki/doku.php?id=cbus:canled64"); // NOI18N
597        result.put(8, "https://www.merg.org.uk/merg_wiki/doku.php?id=cbus:canacc4"); // NOI18N
598        result.put(9, "https://www.merg.org.uk/merg_wiki/doku.php?id=cbus:cancab"); // NOI18N
599        result.put(10, "https://www.merg.org.uk/merg_wiki/doku.php?id=cbus:cancmd"); // NOI18N
600        // result.put(11, "CANSERVO"); // NOI18N
601        // result.put(12, "CANBC"); // NOI18N
602        // result.put(13, "CANRPI"); // NOI18N
603        result.put(14, "https://www.merg.org.uk/merg_wiki/doku.php?id=other_download:turntable"); // NOI18N
604        result.put(15, "https://www.merg.org.uk/merg_wiki/doku.php?id=other_download:turntable"); // NOI18N
605        // result.put(16, "CANHS"); // NOI18N
606        result.put(17, "https://www.merg.org.uk/merg_wiki/doku.php?id=cbus:canace8c"); // NOI18N
607        // result.put(18, "CAN8I8O"); // NOI18N
608        result.put(19, "https://www.merg.org.uk/merg_wiki/doku.php?id=cbus:canservo8"); // NOI18N
609        result.put(20, "https://www.merg.org.uk/merg_wiki/doku.php?id=cbus:canrfid"); // NOI18N
610        // result.put(21, "CANTC4"); // NOI18N
611        // result.put(22, "CANACE16C"); // NOI18N
612        // result.put(23, "CANIO8"); // NOI18N
613        // result.put(24, "CANSNDX"); // NOI18N
614        result.put(25, "https://www.merg.org.uk/merg_wiki/doku.php?id=cbus:canether"); // NOI18N
615        result.put(26, "https://www.merg.org.uk/merg_wiki/doku.php?id=cbus:cansig"); // NOI18N
616        result.put(27, "https://www.merg.org.uk/merg_wiki/doku.php?id=cbus:cansig"); // NOI18N
617        result.put(28, "https://www.merg.org.uk/merg_wiki/doku.php?id=cbus:canccond8c"); // NOI18N
618        result.put(29, "https://www.merg.org.uk/merg_wiki/doku.php?id=cbus:canpan"); // NOI18N
619        result.put(30, "https://www.merg.org.uk/merg_wiki/doku.php?id=cbus:canace3"); // NOI18N
620        result.put(31, "https://www.merg.org.uk/merg_wiki/doku.php?id=cbus:canpanel"); // NOI18N
621        result.put(32, "https://www.merg.org.uk/merg_wiki/doku.php?id=cbus:canmio"); // NOI18N
622        // result.put(33, "CANACE8MIO"); // NOI18N
623        result.put(34, "https://www.merg.org.uk/merg_wiki/doku.php?id=cbus:cansol"); // NOI18N
624        result.put(35, "https://www.merg.org.uk/merg_wiki/doku.php?id=cbus:canbip"); // NOI18N
625        result.put(36, "https://www.merg.org.uk/merg_wiki/doku.php?id=cbus:cancdu"); // NOI18N
626        // result.put(37, "CANACC4CDU"); // NOI18N
627        // result.put(38, "CANWiBase"); // NOI18N
628        // result.put(39, "WiCAB"); // NOI18N
629        // result.put(40, "CANWiFi"); // NOI18N
630        // result.put(41, "CANFTT"); // NOI18N
631        // result.put(42, "CANHNDST"); // NOI18N
632        // result.put(43, "CANTCHNDST"); // NOI18N
633        result.put(44, "https://www.merg.org.uk/merg_wiki/doku.php?id=cbus:canrfid8"); // NOI18N
634        result.put(45, "https://www.merg.org.uk/merg_wiki/doku.php?id=cbus:canmchrfid"); // NOI18N
635        result.put(46, "https://www.merg.org.uk/merg_wiki/doku.php?id=cbus:canwi"); // NOI18N
636        result.put(47, "https://www.merg.org.uk/merg_wiki/doku.php?id=cbus:can4dc"); // NOI18N
637        // result.put(48, "CANELEV"); // NOI18N
638        result.put(49, "https://www.merg.org.uk/merg_wiki/doku.php?id=cbus:canscan"); // NOI18N
639        result.put(50, "https://www.merg.org.uk/merg_wiki/doku.php?id=cbus:canmio"); // NOI18N
640        result.put(51, "https://www.merg.org.uk/merg_wiki/doku.php?id=cbus:canmio"); // NOI18N
641        result.put(52, "https://www.merg.org.uk/merg_wiki/doku.php?id=cbus:canmio"); // NOI18N
642        // result.put(53, "CANBIP_OUT"); // NOI18N
643        result.put(54, "https://www.merg.org.uk/merg_wiki/doku.php?id=cbus:canastop"); // NOI18N
644        result.put(55, "https://www.merg.org.uk/merg_wiki/doku.php?id=cbus:cancsb"); // NOI18N
645        // result.put(56, "CANMAGOT"); // NOI18N
646        // result.put(57, "CANACE16CMIO"); // NOI18N
647        // result.put(58, "CANPiNODE"); // NOI18N
648        result.put(59, "https://www.merg.org.uk/merg_wiki/doku.php?id=cbus:candisp"); // NOI18N
649        result.put(60, "https://www.merg.org.uk/merg_wiki/doku.php?id=cbus:cancompute"); // NOI18N
650        result.put(61, "https://merg.org.uk/merg_wiki/doku.php?id=cbus:canrc522"); // NOI18N
651        result.put(62, "https://merg.org.uk/merg_wiki/doku.php?id=cbus:caninp"); // NOI18N
652        result.put(63, "https://merg.org.uk/merg_wiki/doku.php?id=cbus:canout"); // NOI18N
653        // result.put(64, "CANEMIO"); // NOI18N
654        result.put(65, "https://merg.org.uk/merg_wiki/doku.php?id=cbus:cancabdc"); // NOI18N
655        result.put(66, "https://www.merg.org.uk/merg_wiki/doku.php?id=cbus:canrcom"); // NOI18N
656        // result.put(67, "CANMP3");
657        result.put(68, "https://www.merg.org.uk/merg_wiki/doku.php?id=projects:canxmas");
658        // result.put(69, "CANSVOSET");
659        // result.put(70, "CANCMDDC");
660        // result.put(71, "CANTEXT");
661        // result.put(72, "CANASIGNAL");
662        result.put(73, "https://www.merg.org.uk/merg_wiki/doku.php?id=projects:canslider");
663        // result.put(74, "CANDCATC");
664        result.put(75, "https://www.merg.org.uk/merg_wiki/doku.php?id=cbus:cangate");
665        // result.put(76, "CANSINP");
666        // result.put(77, "CANSOUT");
667        // result.put(78, "CANSBIP");
668        // result.put(79, "CANBUFFER");
669        // result.put(80, "CANLEVER");
670
671        // result.put(253, "CANUSB"); // NOI18N
672        // result.put(254, "EMPTY"); // NOI18N
673        // result.put(255, "CAN_SW"); // NOI18N        
674        
675        return Collections.unmodifiableMap(result);
676    }
677    
678    /*
679     * Populate hashmap with rocrail module support links
680     */
681    private static Map<Integer, String> createLink70Map() {
682        Map<Integer, String> result = new HashMap<>();
683        result.put(1, "https://wiki.rocrail.net/doku.php?id=can-gca1-en"); // NOI18N
684        result.put(2, "https://wiki.rocrail.net/doku.php?id=can-gca2-en"); // NOI18N
685        result.put(3, "https://wiki.rocrail.net/doku.php?id=can-gc3-en"); // NOI18N
686        result.put(4, "https://wiki.rocrail.net/doku.php?id=can-gc4-en"); // NOI18N
687        result.put(5, "https://wiki.rocrail.net/doku.php?id=can-gca5-en"); // NOI18N
688        result.put(6, "https://wiki.rocrail.net/doku.php?id=can-gc6-en"); // NOI18N
689        result.put(7, "https://wiki.rocrail.net/doku.php?id=can-gc7-en"); // NOI18N
690        result.put(11, "https://wiki.rocrail.net/doku.php?id=can-gca1e-en"); // NOI18N
691        return Collections.unmodifiableMap(result);
692    }
693    
694    
695    /*
696     * Populate hashmap with SPROG module support links
697     */
698    private static Map<Integer, String> createLink44Map() {
699        Map<Integer, String> result = new HashMap<>();
700        result.put(1, "https://www.sprog-dcc.co.uk/download-page"); // NOI18N
701        result.put(2, "https://www.sprog-dcc.co.uk/download-page"); // NOI18N
702        result.put(3, "https://www.sprog-dcc.co.uk/download-page"); // NOI18N
703        result.put(4, "https://www.sprog-dcc.co.uk/download-page"); // NOI18N
704        result.put(5, "https://www.sprog-dcc.co.uk/download-page"); // NOI18N
705        result.put(8, "https://www.sprog-dcc.co.uk/download-page"); // NOI18N
706        result.put(50, "https://www.sprog-dcc.co.uk/download-page"); // NOI18N
707        result.put(100, "https://www.sprog-dcc.co.uk/download-page"); // NOI18N
708        result.put(101, "https://www.sprog-dcc.co.uk/download-page"); // NOI18N
709        return Collections.unmodifiableMap(result);
710    }
711    
712    
713    /**
714     * Return a string representation of a reserved node number
715     * @param modnum node number
716     * @return reserved node number reason
717     */
718    public static String getReservedModule(int modnum) {
719        // look for the opcode
720        String format = resMod.get(modnum);
721        if (format == null) {
722            return "";
723        } else {
724            return format; 
725        }
726    }
727    
728    /**
729     * Hashmap for fixed Module Numbers
730     */
731    private static final Map<Integer, String> resMod = createModMap();
732
733    /*
734     * Populate hashmap with format strings
735     *
736     */
737    private static Map<Integer, String> createModMap() {
738        Map<Integer, String> result = new HashMap<>();
739
740        for (int i = 100; i < 126; i++) {
741            result.put(i, Bundle.getMessage("NdNumReserveFixed")); // NOI18N
742        }
743        // use html with br so text fits into dialogue
744        result.put(120, "Reserved / Command Station Shuttles");
745        result.put(126, "Reserved for CAN_RS Modules");
746        result.put(127, "Reserved for CAN_USB Modules");
747        result.put(162, "Used in Command Station Shuttles");
748        result.put(163, "Used in Command Station Shuttles");
749        result.put(164, "Used in Command Station Shuttles");
750        result.put(167, "Used in Command Station Shuttles");
751        result.put(65534, "Reserved for Command Station");
752        result.put(65535, "Reserved, used by all CABS");
753        return Collections.unmodifiableMap(result);
754    }
755
756    private static final Map<String, BackupType> nameIndex =
757            new HashMap<>(BackupType.values().length);
758    static {
759        for (BackupType t : BackupType.values()) {
760            nameIndex.put(t.name(), t);
761        }
762    }
763
764    private static final Map<BackupType, String> displayPhraseIndex =
765            new HashMap<>(BackupType.values().length);
766    static {
767        displayPhraseIndex.put(BackupType.INCOMPLETE, Bundle.getMessage("BackupIncomplete"));
768        displayPhraseIndex.put(BackupType.COMPLETE, Bundle.getMessage("BackupComplete"));
769        displayPhraseIndex.put(BackupType.COMPLETEDWITHERROR, Bundle.getMessage("BackupCompleteError"));
770        displayPhraseIndex.put(BackupType.NOTONNETWORK, Bundle.getMessage("BackupNotOnNetwork"));
771        displayPhraseIndex.put(BackupType.OUTSTANDING, Bundle.getMessage("BackupOutstanding"));
772        displayPhraseIndex.put(BackupType.SLIM, Bundle.getMessage("NodeInSlim"));
773    }
774    
775    /*
776     * Get the display phrase for an enum value
777     * <p>
778     * eg. displayPhrase(BackupType.INCOMPLETE) will return "Backup InComplete"
779     *
780     * @param type The enum to translate
781     * @return The phrase
782     *
783     */
784    public static String displayPhrase(BackupType type) {
785        return displayPhraseIndex.get(type);
786    }
787    
788    /*
789     * Get the enum type for a String value
790     * <p>
791     * eg. lookupByName("Complete") will return BackupType.COMPLETE
792     *
793     * @param name The String to lookup
794     * @return The BackupType enum, else null
795     *
796     */
797    public static BackupType lookupByName(String name) {
798        return nameIndex.get(name);
799    }
800    
801    /*
802     * enum to represent Node Backup Conditions in a CBUS Node XML File
803     *
804     */
805    public enum BackupType{
806        INCOMPLETE(0),
807        COMPLETE(1),
808        COMPLETEDWITHERROR(2),
809        NOTONNETWORK(3),
810        OUTSTANDING(4),
811        SLIM(5);
812        
813        private final int v;
814
815        BackupType(final int v) {
816            this.v = v;
817        }
818    
819        public int getValue() {
820            return v;
821        }
822    
823    }
824
825    // private final static Logger log = LoggerFactory.getLogger(CbusNodeConstants.class);
826}