001package jmri.jmrix.can.cbus.swing.bootloader;
002
003import java.util.Arrays;
004
005import static jmri.jmrix.can.cbus.node.CbusNodeConstants.*;
006
007import org.slf4j.Logger;
008import org.slf4j.LoggerFactory;
009
010/**
011 * CBUS Node parameters
012 * 
013 * @author Andrew Crosland Copyright (C) 2020
014 */
015public class CbusParameters {
016
017    /**
018     * Maximum number of parameters.
019     * paramData holds the parameter count at index 0, then the parameters
020     * at indexes 1 to MAX_PARAMS.
021     */
022    public static final int MAX_PARAMS = 32;
023
024    protected int [] paramData = null;
025    protected boolean valid = false;
026
027    
028    /**
029     * Create blank parameters
030     */
031    public CbusParameters() {
032        paramData = new int[MAX_PARAMS + 1];
033        Arrays.fill(paramData, -1);
034    }
035    
036    
037    /**
038     * Create parameters from byte []
039     * 
040     * @param d byte [] array 
041     */
042    public CbusParameters(byte [] d) {
043        this();
044        
045        if (d.length > MAX_PARAMS) {
046            log.error("Too many parameters");
047            valid = false;
048        } else {
049            paramData[0] = d.length;
050            for (int i = 0; i < paramData[0]; i++) {
051                paramData[i+1] = d[i] & 0xFF;
052            }
053            valid = true;
054        }
055    }
056
057
058    /**
059     * Get a parameter
060     * @param i index of parameter to get
061     * @return parameter value
062     */
063    public int getParam(int i) {
064        return paramData[i];
065    }
066
067
068    /**
069     * Set a parameter
070     * @param i index of the parameter to set
071     * @param v value for the parameter
072     */
073    public void setParam(int i, int v) {
074        paramData[i] = v;
075    }
076
077
078    /**
079     * Check if a parameter index can be used with getParam or setParam
080     *
081     * @param i index of the parameter
082     * @return true if the index is within the parameter array
083     */
084    public boolean isValidIndex(int i) {
085        return (i >= 0) && (i < paramData.length);
086    }
087
088
089    /**
090     * Valid parameter block in a hex file by comparing against one
091     * read from hardware (or some other source)
092     *
093     * @param fp Parameters from hex file
094     * @param hp parameters to validate against
095     * @return true if parameter blocks match
096     */
097    public boolean validate(CbusParameters fp, CbusParameters hp) {
098
099        if ((fp == null) || (hp == null) || !fp.valid || !hp.valid) {
100            return false;
101        }
102
103        // As a minimum, check manufacturer ID, module ID and processor type
104        if (fp.paramData[MANU_ID_IDX] != hp.paramData[MANU_ID_IDX]) {
105            log.error("Manufacturer ID mismatch {} {}", fp.paramData[MANU_ID_IDX], hp.paramData[MANU_ID_IDX]);
106            return false;
107        }
108        
109        if (fp.paramData[MODULE_ID_IDX] != hp.paramData[MODULE_ID_IDX]) {
110            log.error("Module ID mismatch {} {}", fp.paramData[MODULE_ID_IDX], hp.paramData[MODULE_ID_IDX]);
111            return false;
112        }
113        
114//        if (!checkVersion(fp, hp)) {
115//            log.error("Version mismatch {}.{} {}.{}", , fp.paramData[MAJOR_VER_IDX], fp.paramData[MINOR_VER_IDX],
116//                                hp.paramData[MAJOR_VER_IDX], hp.paramData[MINOR_VER_IDX]);
117//            return false;
118//        }
119
120        if (hp.paramData[NUM_PARAM_IDX] > 7) {
121            if (fp.paramData[PROC_TYPE_IDX] != hp.paramData[PROC_TYPE_IDX]) {
122                log.error("Processor type mismatch {} {}", fp.paramData[PROC_TYPE_IDX], hp.paramData[PROC_TYPE_IDX]);
123                return false;
124            }
125        }
126        
127        return true;
128    }
129    
130    
131// Not yet used in any meaningful way.
132// Comment out to make spotbugs happy for now
133//    /**
134//     * Compare two parameter blocks to see if one is a new version
135//     * 
136//     * @param pNew possible new version
137//     * @param pOld original parameters
138//     */
139//    public void checkVersion(CbusParameters pNew, CbusParameters pOld) {
140//        if (pNew.paramData[MAJOR_VER_IDX] > pOld.paramData[MAJOR_VER_IDX]) {
141//            newVersion = true;
142//        } else if (pNew.paramData[MAJOR_VER_IDX] < pOld.paramData[MAJOR_VER_IDX]) {
143//            newVersion = false;
144//        } else newVersion = pNew.paramData[MINOR_VER_IDX] > pOld.paramData[MINOR_VER_IDX];
145//    }
146    
147    
148    /**
149     * Return the load address which is stored in little endian order in four
150     * parameters
151     * 
152     * @return the load address
153     */
154    public int getLoadAddress() {
155        if (paramData[NUM_PARAM_IDX] == 7) {
156            return 0x800;
157        } else {
158            int la = (paramData[LOAD_ADDR_IDX]
159                    + paramData[LOAD_ADDR_IDX+1]*256
160                    + paramData[LOAD_ADDR_IDX+2]*256*256
161                    + paramData[LOAD_ADDR_IDX+3]*256*256*256);
162            log.debug("Load address is {}", la);
163            return la;
164        }
165    }
166    
167    
168    /**
169     * Return String representation of CBUS parameters
170     * 
171     * @return String
172     */
173    @Override
174    public String toString() {
175        if (valid == false) {
176            return Bundle.getMessage("ParamsInvalid");
177        } else {
178            StringBuilder sb = new StringBuilder();
179            // Parameter 0 is the number of parameters that follow
180            int n = Math.min(paramData[0], paramData.length - 1);
181            for (int i = 1; i <= n; i++) {
182                sb.append(paramData[i] + " ");
183            }
184            return sb.toString();
185        }
186    }
187    
188    
189    /**
190     * Are the parameters valid?
191     * 
192     * @return true if valid
193     */
194    public boolean areValid() {
195        return valid;
196    }
197    
198    
199    /**
200     * Set parameter valid status
201     * 
202     * @param s true or false valid status
203     */
204    public void setValid(boolean s) {
205        valid = s;
206    }
207    
208    private static final Logger log = LoggerFactory.getLogger(CbusParameters.class);
209    
210}