All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.bidib.jbidibc.pomupdate.DecoderPomUpdate Maven / Gradle / Ivy

There is a newer version: 2.0.27
Show newest version
package org.bidib.jbidibc.pomupdate;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import org.bidib.jbidibc.messages.PomAddressData;
import org.bidib.jbidibc.messages.enums.CommandStationPom;
import org.bidib.jbidibc.messages.enums.PomAddressTypeEnum;
import org.bidib.jbidibc.messages.message.CommandStationPomMessage;
import org.bidib.jbidibc.messages.utils.ByteUtils;
import org.bidib.jbidibc.pomupdate.DecoderInformation.DecoderType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class DecoderPomUpdate {
    private static final Logger LOGGER = LoggerFactory.getLogger(DecoderPomUpdate.class);

    private static final int ADDR_NEW_ROW = 0x2100; /* 8448 */

    private static final int ADDR_DATA_PACKET = 0x2000; /* 8192 */

    private static final int ADDR_INIT_PACKET = 0x2201; /* 8705 */

    private static final int ADDR_TERM_PACKET = 0x2200; /* 8704 */

    private static final String SECURITY_LINE = "5F7369636865725F";

    private int currentDataColumnIndex;

    private int currentDataPacketIndex;

    public DecoderPomUpdate() {

    }

    public List loadFirmwareFile(File firmwareFile) {

        List firmwareContent = null;

        BufferedReader input = null;
        try {
            input = new BufferedReader(new FileReader(firmwareFile, StandardCharsets.UTF_8));
            String line = null;
            firmwareContent = new ArrayList();
            while ((line = input.readLine()) != null) {
                firmwareContent.add(line.trim());
            }
        }
        catch (IOException ex) {
            LOGGER.info("No firmware file found with name: {}", firmwareFile.getPath());
        }
        finally {
            if (input != null) {
                try {
                    input.close();
                }
                catch (Exception e) {
                    LOGGER.warn("Close reader failed.", e);
                }
                input = null;
            }
        }

        if (firmwareContent != null) {
            return firmwareContent;
        }
        return Collections.emptyList();
    }

    public FirmwarePacket parseLine(String line) {

        FirmwarePacket packet = new FirmwarePacket(line);

        return packet;
    }

    public String trimData(String line) {

        // line must start with ':'
        if (line.charAt(0) != ':') {
            throw new IllegalArgumentException("Line of Intel hex must start with ':'");
        }

        if (line.length() < 13) {
            return null;
        }
        return line.substring(9, line.length() - 2);
    }

    public DecoderInformation findDecoderInformation(List firmwareContent) {
        // concatenate the data of all packets
        StringBuilder sb = new StringBuilder();
        for (String line : firmwareContent) {
            String data = trimData(line);
            if (data != null) {
                sb.append(data);
            }
        }

        // get the start of the information
        int startOfInfo = sb.indexOf(SECURITY_LINE);
        if (startOfInfo < 0) {
            // no info found
            LOGGER.warn("No decoder information found in the 'Sicherheitszeile'");
            throw new IllegalArgumentException("No decoder information found in the 'Sicherheitszeile'");
        }
        LOGGER.info("The information starts at index: {}", startOfInfo);

        // get the relevant CV values
        String securityLine =
            sb
                .substring(startOfInfo + SECURITY_LINE.length(),
                    startOfInfo + SECURITY_LINE.length() + DecoderInformation.DECODER_INFO_CV_COUNT * 2);
        LOGGER.info("Found CV values in security line: {}", securityLine);

        DecoderInformation information = new DecoderInformation(securityLine);

        return information;
    }

    public CommandStationPomMessage prepareNextRowPacket(
        FirmwarePacket packet, DecoderInformation.DecoderType decoderType) {

        // :1000000080090020ED000000C1000000C1000000D8
        // :aabbbbxx80090020ED000000C1000000C1000000D8
        // aa : num of relevant bytes in row
        // bbbb: address of first byte in flash
        // xx: target -> 0 -> flash
        //
        // 805,562s R12 E1 00 EF 00 00 0E L08448 CV Access: Write: 0769:0000
        // ------------ 21 00 --> 8448 <-- decoder address for new line
        // ------------------ EF --> POM Write (111011xx) --> Bit 1,0: 11 -> Part of CV address >>> num of packets: 16
        // >>> (bit 1*2 + bit 0 + 1) * 4 -> 16
        // --------------------- 00 -----> CV: 00
        // ------------------------ 00 --> data: 00

        // prepare the decoder type
        PomAddressTypeEnum addressType = PomAddressTypeEnum.LOCOMOTIVE;
        if (decoderType == DecoderType.accessoryDecoder) {
            addressType = PomAddressTypeEnum.ACCESSORY;
        }

        PomAddressData decoderAddress = new PomAddressData(ADDR_NEW_ROW, addressType);
        CommandStationPom opCode = CommandStationPom.WR_BYTE;

        // prepare the CV number with high byte the flash position
        // + 1 because the cvNumber is decremented before send
        int cvNumber = ByteUtils.getHighByte(packet.getTargetAddress()) + 1;
        // and set the (number of bytes in the line)/4 in bit 8+9
        cvNumber += ((packet.getLen() / 4 - 1) << 8);

        // prepare the low byte of the flash position
        byte[] data = { ByteUtils.getLowByte(packet.getTargetAddress()) };

        CommandStationPomMessage message = new CommandStationPomMessage(decoderAddress, opCode, cvNumber, data);

        // reset the current data column index to start of data in line
        currentDataColumnIndex = 0;
        currentDataPacketIndex = 0;
        return message;
    }

    public CommandStationPomMessage prepareNextDataPacket(
        FirmwarePacket packet, DecoderInformation.DecoderType decoderType) {
        LOGGER
            .trace("Current currentDataColumnIndex: {}, currentDataPacketIndex: {}", currentDataColumnIndex,
                currentDataPacketIndex);
        // prepare the decoder type
        PomAddressTypeEnum addressType = PomAddressTypeEnum.LOCOMOTIVE;
        if (decoderType == DecoderType.accessoryDecoder) {
            addressType = PomAddressTypeEnum.ACCESSORY;
        }

        int lowAddress = ByteUtils.getInt(packet.getData()[currentDataColumnIndex]);
        // set the first data byte as low byte of the address
        PomAddressData decoderAddress = new PomAddressData(ADDR_DATA_PACKET + lowAddress, addressType);
        CommandStationPom opCode = CommandStationPom.WR_BYTE;

        // + 1 because the cvNumber is decremented before send ??
        byte cvNum = 0;
        if (packet.getData().length > (currentDataColumnIndex + 1)) {
            cvNum = packet.getData()[currentDataColumnIndex + 1];
        }
        int cvNumber = ByteUtils.getInt(cvNum) + 1 + (currentDataPacketIndex << 8);

        // prepare the data
        byte dataVal = 0;
        if (packet.getData().length > (currentDataColumnIndex + 2)) {
            dataVal = packet.getData()[currentDataColumnIndex + 2];
        }
        byte[] data = { dataVal };
        CommandStationPomMessage message = new CommandStationPomMessage(decoderAddress, opCode, cvNumber, data);

        currentDataColumnIndex += 3;
        currentDataPacketIndex++;
        if (currentDataPacketIndex > 3) {
            LOGGER.debug("Reset the currentDataPacketIndex.");
            currentDataPacketIndex = 0;
        }

        return message;
    }

    public CommandStationPomMessage prepareInitiatingDataPacket(DecoderInformation decoderInfo) {

        DecoderInformation.DecoderType decoderType = decoderInfo.getDecoderType();
        // prepare the decoder type
        PomAddressTypeEnum addressType = PomAddressTypeEnum.LOCOMOTIVE;
        if (decoderType == DecoderType.accessoryDecoder) {
            addressType = PomAddressTypeEnum.ACCESSORY;
        }

        PomAddressData decoderAddress = new PomAddressData(ADDR_INIT_PACKET, addressType);
        CommandStationPom opCode = CommandStationPom.WR_BYTE;

        // + 1 because the cvNumber is decremented before send
        int cvNumber = ByteUtils.getHighByte(decoderInfo.getDecoderId()) + 1;
        byte[] data = { ByteUtils.getLowByte(decoderInfo.getDecoderId()) };
        CommandStationPomMessage message = new CommandStationPomMessage(decoderAddress, opCode, cvNumber, data);

        return message;
    }

    public CommandStationPomMessage prepareTerminatingDataPacket(DecoderInformation.DecoderType decoderType) {
        LOGGER.info("Prepare terminating data packet for decoder type: {}", decoderType);
        // prepare the decoder type
        PomAddressTypeEnum addressType = PomAddressTypeEnum.LOCOMOTIVE;
        if (decoderType == DecoderType.accessoryDecoder) {
            addressType = PomAddressTypeEnum.ACCESSORY;
        }

        PomAddressData decoderAddress = new PomAddressData(ADDR_TERM_PACKET, addressType);
        CommandStationPom opCode = CommandStationPom.WR_BYTE;

        int cvNumber = 166;
        byte[] data = { 0 };
        CommandStationPomMessage message = new CommandStationPomMessage(decoderAddress, opCode, cvNumber, data);

        return message;
    }

    public CommandStationPomMessage prepareDecoderInfoPomMessage(
        DecoderInformation decoderInfo, int decoderAddress, int cvNumber) {

        // prepare the decoder type
        PomAddressTypeEnum addressType = PomAddressTypeEnum.LOCOMOTIVE;
        if (decoderInfo.getDecoderType() == DecoderType.accessoryDecoder) {
            addressType = PomAddressTypeEnum.ACCESSORY;
        }

        PomAddressData address = new PomAddressData(decoderAddress, addressType);
        CommandStationPom opCode = CommandStationPom.WR_BYTE;

        byte[] data = { decoderInfo.getCvValue(cvNumber) };
        CommandStationPomMessage message = new CommandStationPomMessage(address, opCode, cvNumber, data);

        return message;
    }

    public List prepareDecoderInfoPomMessages(
        DecoderInformation decoderInfo, int decoderAddress) {

        // prepare the decoder type
        PomAddressTypeEnum addressType = PomAddressTypeEnum.LOCOMOTIVE;
        if (decoderInfo.getDecoderType() == DecoderType.accessoryDecoder) {
            addressType = PomAddressTypeEnum.ACCESSORY;
        }

        PomAddressData address = new PomAddressData(decoderAddress, addressType);
        CommandStationPom opCode = CommandStationPom.WR_BYTE;

        List messages = new ArrayList();
        for (int cvNumber = 800; cvNumber < 812; cvNumber++) {

            byte[] data = { decoderInfo.getCvValue(cvNumber) };
            CommandStationPomMessage message = new CommandStationPomMessage(address, opCode, cvNumber, data);
            messages.add(message);
        }

        return messages;
    }

    public List prepareDecoderUpdatePomMessages(
        List firmwareContent, DecoderInformation decoderInformation) {
        List messages = new ArrayList();

        DecoderType decoderType = decoderInformation.getDecoderType();
        // add the initiating pom message
        messages.add(prepareInitiatingDataPacket(decoderInformation));

        for (String line : firmwareContent) {
            addPackets(line, messages);
        }

        // add the terminating pom message
        messages.add(prepareTerminatingDataPacket(decoderType));
        return messages;
    }

    protected void addPackets(String line, final List messages) {

        FirmwarePacket packet = parseLine(line);
        LOGGER.debug("Prepared packet: {}, line: {}", packet, line);

        int packetLen = ByteUtils.getInt(packet.getLen());
        if (packetLen > 0) {
            CommandStationPomMessage message = prepareNextRowPacket(packet, DecoderType.locoDecoder);
            LOGGER.debug("Adding row packet.");
            messages.add(message);
            for (int index = 0; index < (packetLen / 3 + (packetLen % 3 != 0 ? 1 : 0)); index++) {
                message = prepareNextDataPacket(packet, DecoderType.locoDecoder);
                LOGGER.trace("Prepared data packet: {}", message);
                messages.add(message);
            }
        }
        else {
            LOGGER.warn("Current packet has no length.");
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy