Chris,
I've just gone through this myself for a project I'm working on, and have become very familiar with how TMCC commands work over serial. Lots of folks also supplied a bunch of useful help on this thread.
What I think your issue is, is not exactly understanding how the commands are sent. The TMCC commands are always 3 bytes long, exactly 24 bits. the first byte/8bits is meaningless other than to confirm that you do have a TMCC command, and not just garbage data. (always 0xFE) The second and third bytes are best used added together into a 16 bit number. These 16 bits form your actual command word, which contains 4 types of information A device type (engine, switch, route, etc) , the device's assigned address, (engine 52, switch 16, route 4), a command type, (is this a normal command, a speed command, a programing command, etc) , and lastly a data field( what is the actual command you want done.)
The command type and the data field are always the last 7 bits of the 16 bit command word, but the device type and address are not always the same. Engines, Switches and Accessories have a 2 bit device type identifier and a 7 bit address. Trains/Tracks and Routes use a 5 bit device type and 4 bit address.
Because of this, the very first thing you have to do with the data is have a way to read the first (most significant) 5 bits to see what type of device the command is for, then you tell your program how to deal with each device type. For example, in pseudo code:
if (first 5 bits) == switch device type :
then the device being addressed = the last 7 bits of the most significant 9 bits
and the command type = bits 6 and 7, and the data field = the first(least significant) 5 bits.
What follows if the actual code i have running on the Arduino platform to accomplish this job. For my purposes I decided to treat the command type field and the data field as one 7 bit field rather than split them into two separate variables. Arduino uses a language called Processing, which is based on C language. If you can follow C it should be pretty straight forward. There are better ways to do this, I'm sure, but using if statements was what worked for me.
In this code the var currentCommandWord is the 16 bits of data (last 2 of the 3 bytes sent by the TMCC base)
the code returns the following vars to be used elsewhere in the program:
commandType: What is the command talking to? Engine, Switch, etc.
addressedDevice: what address is being talked to. ex, which engine, or which switch.
assignedCommand: what is the actual command. ex, what do you want that engine to do.
//layerd command breakdown Set command type-> Set address-> set assigned command.
commandTypeFirstCheck = currentCommandWord>>11; // first check of type = most significnt 5 bits of fullWord.
if (commandTypeFirstCheck < 24) { // if the 5 bits is < 24 it is a 2 bit commandType (0=Engine, 1=Switch, 2=Accessory)
commandType = currentCommandWord>>14; // set command type to two bit type.
// addrsss setup for 7 bit device addresses
commandAddressFirstShift = currentCommandWord<<2; // shift off left most 2 bits
addressedDevice = commandAddressFirstShift>>9; // shift off all but 7 most significant bits.
}
else if (commandTypeFirstCheck == 24) { // if the 5 bits = 24...
commandType = 24; // type = 24 (Group Accessorys)
// address setup for 4 bit addressed
commandAddressFirstShift = currentCommandWord<<5; // shift off left most 5 bits
addressedDevice = commandAddressFirstShift>>12; // shift off all but 4 most significant bits.
}
else if (commandTypeFirstCheck == 25) { // if the 5 bits = 25...
commandType = 25; // type = 25 (Train Command)
// address setup for 4 bit addressed
commandAddressFirstShift = currentCommandWord<<5; // shift off left most 5 bits
addressedDevice = commandAddressFirstShift>>12; // shift off all but 4 most significant bits.
}
else if (commandTypeFirstCheck == 26) { // if the 5 bits are 26 or 27...
commandType = 13; // type = 13 (Route Command)
// address setup for 5 bit addressed
commandAddressFirstShift = currentCommandWord<<4; // shift off left most 4 bits
addressedDevice = commandAddressFirstShift>>11; // shift off all but 5 most significant bits.
}
else if (commandTypeFirstCheck == 27) { // if the 5 bits are 26 or 27...
commandType = 13; // type = 13 (Route Command)
// address setup for 5 bit addressed
commandAddressFirstShift = currentCommandWord<<4; // shift off left most 4 bits
addressedDevice = commandAddressFirstShift>>11; // shift off all but 5 most significant bits.
}
else if (commandTypeFirstCheck == 31) { // if the 5 bits = 31 (all HIGH) set a HALT condition.
haltCommand = 1;
systemHALTcheck();
// this is here as a failsafe on halt if for some reason a halt was missed by earlier code.
}
assignedCommandShift = currentCommandWord<<9;
assignedCommand = assignedCommandShift>>9;
If you need more help, let me know.
JGL
EDIT: It seems I don't know how to use code tags on this forum... Maybe someone could enlighten me. <code> doesn't seem to work, and using the option of "code" on the formatting drop down looks like garbage. Not sure how to get it formatted correctly.