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

org.bidib.jbidibc.ch341a.lococard.LocoCardDecoder Maven / Gradle / Ivy

package org.bidib.jbidibc.ch341a.lococard;

import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.nio.charset.Charset;
import java.util.Arrays;

import javax.imageio.ImageIO;

import org.apache.commons.lang3.StringUtils;
import org.bidib.jbidibc.messages.utils.ByteUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * The {@code LocoCardDecoder} decodes the data of the M*rklin and Trix loco card.
 * 

* The main work was done by Gerhard Bertelsmann () and I owe him a beer ... {@link https * ://github.com/GBert/railroad/blob/master/can2udp/src/sc/read_loccard.c} *

*/ public class LocoCardDecoder { private static final Logger LOGGER = LoggerFactory.getLogger(LocoCardDecoder.class); // preamble for mfx private static final byte[] PRE_MFX = { 0x02, (byte) 0xf5, 0x00 }; // preamble for other protocols private static final byte[] PRE_OTHER = { 0x02, (byte) 0xc5, 0x00 }; private static final byte[] MAGIC_NUMBER_PNG = new byte[] { (byte) 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a }; /** * Decode the data of a loco card. * * @param rawLocoCard * the data from the loco card * @param imageDir * the image dir to store the filename */ public void decodeLocoCardData(byte[] rawLocoCard, final File imageDir) { // check the preamble to distinguish between mfx and dcc byte[] preamble = ByteUtils.subArray(rawLocoCard, 0, 3); if (Arrays.equals(PRE_MFX, preamble)) { LOGGER.info("Loco card is of type: mfx"); } else if (Arrays.equals(PRE_OTHER, preamble)) { LOGGER.info("Loco card is of type: other"); } else { LOGGER.warn("The loco card has an unknown preamble: {}", ByteUtils.bytesToHex(preamble)); throw new RuntimeException("The loco card has an unknown preamble: " + ByteUtils.bytesToHex(preamble)); } String locoPictureName = null; // start index after preamble int i = 3; int index = 0; int length = 0; int temp = 0; int id = 0; while (i < rawLocoCard.length) { index = ByteUtils.getInt(rawLocoCard[i++]); length = ByteUtils.getInt(rawLocoCard[i++]); switch (index) { case 0: LOGGER.info(String.format("index [0x%02x @ 0x%04x] sub-indexes [%d]: ", index, i, length)); temp = ByteUtils.getInt(rawLocoCard[i++]); length = (ByteUtils.getInt(rawLocoCard[i++]) << 8) + temp; LOGGER.info(" total length [{}]", length); id = ByteUtils.getInt(rawLocoCard[i++]); while ((id != 0) && (id != 255)) { length = rawLocoCard[i++]; LOGGER .info(String .format("i 0x%02x [i] 0x%02x length %d, id: %02x\n", i, rawLocoCard[i], length, id)); switch (id) { case 0x1e: // get the loco name byte[] rawLocoName = ByteUtils.subArray(rawLocoCard, i, length); String locoName = new String(rawLocoName, Charset.forName("ISO-8859-1")); LOGGER.info("loco name: >{}<", locoName); i += length; break; case 0x1f: // get the proto name byte[] rawProtoName = ByteUtils.subArray(rawLocoCard, i, length); String protoName = new String(rawProtoName, Charset.forName("ISO-8859-1")); LOGGER.info("proto name: >{}<", protoName); i += length; break; case 0x20: // get the picture name byte[] rawPictureName = ByteUtils.subArray(rawLocoCard, i, length); String pictureName = new String(rawPictureName, Charset.forName("ISO-8859-1")); LOGGER.info("picture name: >{}<", pictureName); locoPictureName = pictureName; i += length; break; default: // LOGGER.warn("decoding problem:\n"); byte[] rawName = ByteUtils.subArray(rawLocoCard, i, length); String name = new String(rawName, Charset.forName("ISO-8859-1")); LOGGER.info("unknown name: >{}<", name); i += length; break; } id = rawLocoCard[i++]; LOGGER.info(String.format("Next id: %02x", id)); } break; case 9: LOGGER.info(String.format("index [0x%02x @ 0x%04x] length [%d]: ", index, i, length)); int func = 0; LOGGER.info("\n"); for (int j = 0; j < length / 10; j++) { StringBuilder sb = new StringBuilder(); sb.append(String.format(" function %2d: ", func++)); for (int k = 0; k < 10; k++) { sb.append(String.format(" 0x%02x", rawLocoCard[i++])); } LOGGER.info("{}", sb); } break; default: LOGGER.info(String.format("index [0x%02x @ 0x%04x] length [%d]: ", index, i, length)); byte[] sub = null; if (length <= 4) { LOGGER.info("Len is <= 4"); sub = ByteUtils.subArray(rawLocoCard, i, length); } switch (index) { case 1: // loco_data->long_uid = temp; LOGGER.info(" long UID : {}", ByteUtils.bytesToHex(sub)); break; case 2: // loco_data->uid = temp; LOGGER.info(" short UID : {}", ByteUtils.bytesToHex(sub)); break; case 3: // loco_data->acc_delay = temp; LOGGER.info("acceleration delay : {}", ByteUtils.bytesToHex(sub)); break; case 4: // loco_data->slow_down_delay = temp; LOGGER.info(" slow down delay : {}", ByteUtils.bytesToHex(sub)); break; case 5: // loco_data->vmin = temp; LOGGER.info(" Vmin : {}", ByteUtils.bytesToHex(sub)); break; case 6: // loco_data->vmax = temp; LOGGER.info(" Vmax : {}", ByteUtils.bytesToHex(sub)); break; case 8: // loco_data->volume = temp; LOGGER.info(" Volume : {}", ByteUtils.bytesToHex(sub)); break; default: LOGGER.info(" unknown : {}", ByteUtils.bytesToHex(sub)); break; } LOGGER.info("raw value: {}", ByteUtils.bytesToHex(ByteUtils.subArray(rawLocoCard, i, length))); i += length; break; } LOGGER.info("Current index: {}, current i: {}", index, i); if (index == 0) { int totalLen = rawLocoCard.length; int startIndex = i + 3; LOGGER .info("Try to read image from startIndex: {}, totalLen: {}, byte: {}", startIndex, totalLen, ByteUtils.byteToHex(rawLocoCard[startIndex])); // check if the picture starts with magic number for png byte[] check = ByteUtils.subArray(rawLocoCard, startIndex, 8); if (!Arrays.equals(check, MAGIC_NUMBER_PNG)) { LOGGER.warn("No valid picture data found!"); } else { if (StringUtils.isBlank(locoPictureName)) { locoPictureName = "locoimage"; } locoPictureName = locoPictureName + ".png"; try (ByteArrayInputStream bais = new ByteArrayInputStream(ByteUtils.subArray(rawLocoCard, startIndex, totalLen - startIndex))) { BufferedImage locoImage = ImageIO.read(bais); ImageIO.write(locoImage, "png", new File(imageDir, locoPictureName)); } catch (IOException ex) { LOGGER.warn("Load loco image failed.", ex); } } break; } } } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy