001package jmri.jmrix.can.cbus.swing.bootloader;
002
003import static jmri.jmrix.can.cbus.CbusConstants.MANU_MERG;
004import static jmri.jmrix.can.cbus.node.CbusNodeConstants.*;
005
006/**
007 * Extend hex file class for a CBUS PIC with parameter block
008 * 
009 * Assumes hex record addresses are "nicely" aligned, i.e., on 8, 16, 32, ...
010 * -byte boundaries and that addresses increase monotonically. With Microchip
011 * tools you should select the options to format the hex file for download and 
012 * program with default config words.
013 *
014 * @author Andrew Crosland Copyright (C) 2022
015 */
016public class CbusPicHexFile extends HexFile{
017
018    public static final int PARAM_OLD_START = 0x810;
019    public static final int PARAM_OLD_END = 0x817;
020    public static final int PARAM_OLD_LEN = 7;
021    public static final int PARAM_NEW_START = 0x820;
022    public static final int PARAM_NEW_END = 0x839;
023    public static final int PARAM_NEW_LEN = 32;
024    
025    private CbusParameters newParams = new CbusParameters();
026    private CbusParameters oldParams = new CbusParameters();
027    
028    private boolean checkValid = false;
029    
030    /**
031     * Create a new HexFile object and initialize data to unprogrammed state.
032     *
033     * @param fileName file name to use for the hex file
034     */
035    public CbusPicHexFile(String fileName) {
036        super(fileName);
037    }
038
039
040    /**
041     * Check one hex record from the file
042     * 
043     * Overridden to capture CBUS PIC parameter block.
044     * 
045     * Assumes hex record addresses are "nicely" aligned, i.e., on 8, 16, 32, ...
046     * -byte boundaries and that addresses increase monotonically. With Microchip
047     * tools you should select the options to format the hex file for download
048     * and program with default config words.
049     *
050     * @param r hex record
051     */
052    @Override
053    protected void checkRecord(HexRecord r) {
054        int rStart = 0;
055        int rEnd = 0;
056        int pStart = 0;
057        int checksum = 0;
058        
059        if (r.type == HexRecord.TYPE_DATA) {
060            // Look for "old" 8-byte paraneter block at 0x810, assuming aligned hex address
061            if (r.address == PARAM_OLD_START) {
062                for (int i = 0; i <= PARAM_OLD_LEN; i++) {
063                    oldParams.setParam(pStart++, r.getData(i) & 0xFF);
064                }
065                checkValid = true;
066            } else {
067                // Look for "new" 32-byte parameter block starting at 0x820
068                if ((r.address < PARAM_NEW_START) && (r.address + r.len > PARAM_NEW_START)) {
069                    // Record overlaps at start. Should only happen if record is greater than 32 bytes
070                    // and encompasses the whole parameter block.
071                    rStart = PARAM_NEW_START - r.address;
072                    pStart = 1;
073                    if (r.len > PARAM_NEW_LEN) {
074                        rEnd = rStart + PARAM_NEW_LEN;
075                    } else {
076                        rEnd = rStart + r.len;
077                    }
078                    checkValid = true;
079                } else if ((r.address >= PARAM_NEW_START) && (r.address < PARAM_NEW_END)) {
080                    // Record starts within the parameter block. Should only happen for
081                    // 32, 16 or 8-byte records and we want all the data in the record.
082                    rStart = 0;
083                    rEnd = r.len;
084                    pStart = r.address - 0x820 + 1;
085                    checkValid = true;
086                }
087                
088                if (checkValid) {
089                    // Copy data to parameters and add to checksum
090                    for (int i = rStart; i < rEnd; i++) {
091                        newParams.setParam(pStart++, r.getData(i) & 0xFF);
092                        checksum += r.getData(i) & 0xFF;
093                    }
094                }
095            }
096
097            if ((r.address >= PARAM_NEW_END) && (checkValid == true)) {
098                // First record after parameter block so check if parameters are
099                checkValid = false;
100                // Copy new parameter count to parameter
101                newParams.setParam(NUM_PARAM_IDX, newParams.getParam(PARAM_COUNT_IDX));
102                if (checksum == 0) {
103                    newParams.setValid(true);
104                } else if (oldParams.getParam(MANU_ID_IDX) == (byte)MANU_MERG) {
105                    // Assume old style parameter block @ 0x810 and assume only MERG made these
106                    oldParams.setParam(NUM_PARAM_IDX, PARAM_OLD_LEN);
107                    oldParams.setValid(true);
108                }
109            }
110        }
111    }
112    
113    /**
114     * Get the file parameters
115     * 
116     * Create an invalid parameter set of necessary
117     * 
118     * @return CBUS parameters from the file
119     */
120    @Override
121    public CbusParameters getParams() {
122        if (newParams.areValid()) {
123            return newParams;
124        } else if (oldParams.areValid()) {
125            return oldParams;
126        } else
127            return new CbusParameters();
128    }
129    
130//    private final static Logger log = LoggerFactory.getLogger(CbusPicHexFile.class);
131
132}