org.bidib.jbidibc.pomupdate.DecoderPomUpdate Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jbidibc-pomupdate Show documentation
Show all versions of jbidibc-pomupdate Show documentation
jBiDiB jbidibc POMupdate POM
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.");
}
}
}