Skip to content

Commit

Permalink
Enable Accessory OpsMode Programming for NCE Power Cab.
Browse files Browse the repository at this point in the history
  • Loading branch information
dheap committed Feb 16, 2017
1 parent 5b6ca8e commit 078e671
Show file tree
Hide file tree
Showing 4 changed files with 308 additions and 7 deletions.
94 changes: 94 additions & 0 deletions java/src/jmri/NmraPacket.java
Expand Up @@ -302,6 +302,9 @@ public static byte[] accDecoderPktOpsMode(int addr, int active, int outputChanne

int lowAddr = addr & 0x3F;
int highAddr = ((~addr) >> 6) & 0x07;
// log.info("addr = {} active = {} outputChannel = {} cvNum = {} data = {}", addr, active, outputChannel, cvNum, data);
// log.info("hex lowAddr = {} highAddr = {}", String.format("%H", lowAddr), String.format("%H", highAddr));
// log.info("lowAddr = {} highAddr = {}", lowAddr, highAddr);

int lowCVnum = (cvNum - 1) & 0xFF;
int highCVnum = ((cvNum - 1) >> 8) & 0x03;
Expand Down Expand Up @@ -433,6 +436,97 @@ public static boolean isAccSignalDecoderPkt(byte[] packet) {
return true;
}

/**
* Determine if a packet is an Basic Accessory Decoder Packet address for
* operations mode programming.
* <p>
* This inverts the computation done by the {@link #accDecoderPktOpsMode}
* method.
* <p>
* Currently used by {@link jmri.jmrix.nce.NceTrafficController#sendPacket}
*/
public static boolean isAccDecoderPktOpsMode(byte[] packet) {
if (packet.length != 5 && packet.length != 6) {
return false; // allow ECC to be present or not
}
if ((packet[0] & 0xC0) != 0x80) {
return false;
}
if ((packet[1] & 0x88) != 0x88) {
return false;
}
if ((packet[2] & 0xFC) != 0xEC) {
return false;
}
return true;
}

/**
* Determine if a packet is an Legacy Accessory Decoder Packet address for
* operations mode programming.
* <p>
* This inverts the computation done by the
* {@link #accDecoderPktOpsModeLegacy} method.
* <p>
* Currently used by {@link jmri.jmrix.nce.NceTrafficController#sendPacket}
*/
public static boolean isAccDecoderPktOpsModeLegacy(byte[] packet) {
if (packet.length != 4 && packet.length != 5) {
return false; // allow ECC to be present or not
}
if ((packet[0] & 0xC0) != 0x80) {
return false;
}
if ((packet[1] & 0x8C) != 0x0C) {
return false;
}
return true;
}

/**
* Recover the decoder address from an Legacy Accessory Decoder Packet Ops
* Mode Packet.
* <p>
*/
public static int getAccDecPktOpsModeLegacyAddress(byte[] packet) {
int midAddr = packet[0] & 0x3f;
int hiAddr = ((~packet[1]) & 0x70) >> 4;

return (hiAddr << 6 | midAddr);
}

/**
* Recover the equivalent accessory address from an Legacy Accessory Decoder
* Packet Ops Mode Packet.
* <p>
* Currently used by {@link jmri.jmrix.nce.NceTrafficController#sendPacket}
*/
public static int getAccDecoderPktOpsModeLegacyAddress(byte[] packet) {
int midAddr = packet[0] & 0x3f;
int hiAddr = ((~packet[1]) & 0x70) >> 4;

int boardAddr = (hiAddr << 6 | midAddr) - 1;

// return ((boardAddr << 2)) + 1;
return ((boardAddr << 2)) + 1;
}

/**
* Recover the 1-based output address from an Basic Accessory Decoder Packet
* Ops Mode Packet.
* <p>
* Currently used by {@link jmri.jmrix.nce.NceTrafficController#sendPacket}
*/
public static int getAccDecoderPktOpsModeAddress(byte[] packet) {
int midAddr = packet[0] & 0x3f;
int lowAddr = (packet[1] & 0x06) >> 1;
int hiAddr = ((~packet[1]) & 0x70) >> 4;

int boardAddr = (hiAddr << 6 | midAddr) - 1;

return ((boardAddr << 2) | lowAddr) + 1;
}

/**
* Recover the 1-based output address from an Extended Accessory Decoder
* Control Packet otherwise known as a Signal Decoder Packet.
Expand Down
17 changes: 15 additions & 2 deletions java/src/jmri/jmrix/nce/NceMessage.java
Expand Up @@ -536,7 +536,20 @@ public static NceMessage createAccySignalMacroMessage(NceTrafficController tc, i
return m;
}

public static NceMessage createAccDecoderPktOpsMode(NceTrafficController tc, int accyAddr, int cvAddr, int cvData) {
NceMessage m = new NceMessage(6);
m.setBinary(true);
m.setReplyLen(1);
m.setTimeout(SHORT_TIMEOUT);
byte[] mess = NceBinaryCommand.usbOpsModeAccy(accyAddr, cvAddr, cvData);
m.setOpCode(mess[0]);
m.setElement(1, mess[1]);
m.setElement(2, mess[2]);
m.setElement(3, mess[3]);
m.setElement(4, mess[4]);
m.setElement(5, mess[5]);
return m;
}

private final static Logger log = LoggerFactory.getLogger(NceMessage.class.getName());
}


20 changes: 20 additions & 0 deletions java/src/jmri/jmrix/nce/NceTrafficController.java
Expand Up @@ -54,11 +54,31 @@ protected int enterProgModeDelayTime() {
@Override
public void sendPacket(byte[] packet, int count) {
NceMessage m;

boolean isUsb = ((getUsbSystem() == NceTrafficController.USB_SYSTEM_POWERCAB
|| getUsbSystem() == NceTrafficController.USB_SYSTEM_SB3
|| getUsbSystem() == NceTrafficController.USB_SYSTEM_SB5
|| getUsbSystem() == NceTrafficController.USB_SYSTEM_TWIN));

if (NmraPacket.isAccSignalDecoderPkt(packet)) {
// intercept NMRA signal cmds
int addr = NmraPacket.getAccSignalDecoderPktAddress(packet);
int aspect = packet[2];
m = NceMessage.createAccySignalMacroMessage(this, 5, addr, aspect);
} else if (isUsb && NmraPacket.isAccDecoderPktOpsMode(packet)) {
// intercept NMRA accessory decoder ops programming cmds to USB systems
int accyAddr = NmraPacket.getAccDecoderPktOpsModeAddress(packet);
int cvAddr = (((0x03 & packet[2]) << 8) | (0xFF & packet[3])) + 1;
int cvData = (0xFF & packet[4]);
log.debug("isAccDecoderPktOpsMode(packet) accyAddr ={}, cvAddr = {}, cvData ={}", accyAddr, cvAddr, cvData);
m = NceMessage.createAccDecoderPktOpsMode(this, accyAddr, cvAddr, cvData);
} else if (isUsb && NmraPacket.isAccDecoderPktOpsModeLegacy(packet)) {
// intercept NMRA accessory decoder ops programming cmds to USB systems
int accyAddr = NmraPacket.getAccDecoderPktOpsModeLegacyAddress(packet);
int cvData = (0xFF & packet[3]);
int cvAddr = (((0x03 & packet[1]) << 8) | (0xFF & packet[2])) + 1;
log.debug("isAaccDecoderPktOpsModeLegacy(packet) accyAddr ={}, cvAddr = {}, cvData ={}", accyAddr, cvAddr, cvData);
m = NceMessage.createAccDecoderPktOpsMode(this, accyAddr, cvAddr, cvData);
} else {
m = NceMessage.sendPacketMessage(this, packet);
}
Expand Down

0 comments on commit 078e671

Please sign in to comment.