Parse loconet commands

I am using an Arduino Nano with a Loconet interface to provide some indicators and control for the Track Power Status. I have a sketch which works to both control the Track Power Status from push buttons and also display the status using LEDs. I want to add function to this sketch that will display using LEDs when certain Switch Commands are issued. I have found what I think is a suitable subroutine that will do what I want but I cannot determine how to call it correctly.

At line 80 in the attached sketch I correctly see that a switch command has been issued on the Loconet and the routine I think I should use is at line 109. My problem is I don't know how to parse the command to get the parameters to call the routine.

Thanks for help you can give.

Dale Gloer


#include <LocoNet.h>

#define PowerOnPin      3    // Buttons connected to these pins
#define PowerOffPin     4    // GPON GPOFF and ESTOP as well as Clear All Slots
#define EStopPin        5
#define SlotClearPin    2

#define ST_LED_PIN      7
#define DIV_LED_PIN     9

#define LNtxPin         6    // LocoNet Transmit pin (LocoShield uses pin7)

#define PowerOnLEDPin  10    // Assume this pin has a LED+resistor attached...
#define PowerOffLEDPin 11    // Assume this pin has a LED+resistor attached...
#define EStopLEDPin    12    // Assume this pin has a LED+resistor attached...

#define TURNOUT_ADDRESS 44

int turnoutDirection;

// Button press state
// Current
int GPonButton,    GPonButton1,   GPonButton2;
int GPoffButton,   GPoffButton1,  GPoffButton2;
int EStopButton,   EStopButton1,  EStopButton2;
int ClearButton,   ClearButton1,  ClearButton2;

// Last state processed - helps us ensure we don't repeat commands while a button is held down
int lastGPon  = -1;
int lastGPoff = -1;
int lastEStop = -1;
int lastClear = -1;

int ClearIt   =  0;           // Should we clear slots when we get a slot status packet?
    
void setup(){
    pinMode(PowerOnPin,     INPUT_PULLUP);   
    pinMode(PowerOffPin,    INPUT_PULLUP);   
    pinMode(SlotClearPin,   INPUT_PULLUP);   
    pinMode(EStopPin,       INPUT_PULLUP); 
    
    pinMode(EStopLEDPin,    OUTPUT); 
    pinMode(PowerOnLEDPin,  OUTPUT); 
    pinMode(PowerOffLEDPin, OUTPUT); 
    
    digitalWrite(PowerOnLEDPin,  0);   // Power is in an unknown state
    digitalWrite(PowerOffLEDPin, 0);   // 
    digitalWrite(EStopLEDPin,    0);   // and not estopped
 
    // Configure the serial Pin for 115200 baud
    Serial.begin(115200);
    Serial.println("LocoNet Controller");     
    
    // initialize the LocoNet interface
    LocoNet.init(LNtxPin);
}                   
//////////////////////////////////////////////////////////////////////

void processIncomingLoconetCommand(lnMsg* LnPacket) {
    if( LnPacket )      {   
        //LocoNet.processSwitchSensorMessage(LnPacket);
        unsigned char opcode = (int)LnPacket->sz.command;
         Serial.println(opcode,HEX);
      Serial.println((int)LnPacket);
        if (opcode == OPC_GPON)  {     
            Serial.println("Power ON");     
            digitalWrite(PowerOnLEDPin, 1);  
            digitalWrite(PowerOffLEDPin, 0);
            digitalWrite(EStopLEDPin, 0);
        } else if (opcode == OPC_GPOFF) {
            Serial.println("Power OFF");     
            digitalWrite(PowerOnLEDPin, 0);
            digitalWrite(EStopLEDPin, 0);
            digitalWrite(PowerOffLEDPin, 1);
        } else if (opcode == OPC_IDLE) {
            digitalWrite(EStopLEDPin, 1);
            Serial.println("EStop!"); 
        } 
        if (opcode == OPC_SW_REQ){
          Serial.println("got a switch request");
//         Serial.println((int)turnoutAddress);
//          Serial.println(turnoutDirection);
//         notifySwitchRequest(LnPacket);
        }
 /*       else if (opcode == OPC_SL_RD_DATA) {
            if (ClearIt) {
                int slot = LnPacket->sd.slot;
                int stat = LnPacket->sd.stat;
                Serial.print("Clear Slot:"); Serial.print(slot); Serial.print(":");  Serial.println(stat);
                if (stat != 0) {
                   sendOPC_LOCO_SPD(slot,  0);   // speed 0
                   sendOPC_LOCO_DIRF(slot, 0);   // F0-4 off, Fwd
                   sendOPC_LOCO_SND(slot,  0);   // F5-8 off
                    // Don't need to turn off F9 and above because they should go away when track power is turned off...
                   sendOPC_SLOT_STAT1(slot, 0);
                }
            }
        }
*/        
        else {
            // ignore the message...
        }
    }
}

////////////////////////////////////////////////////////////////////////////

void notifySwitchRequest( uint16_t Address, uint8_t Output, uint8_t Direction ) {
  
  if(Address == TURNOUT_ADDRESS) {

    turnoutDirection = Direction;
    
    if(turnoutDirection == 0) {
      digitalWrite(ST_LED_PIN, HIGH);
      digitalWrite(DIV_LED_PIN, LOW);
    } else {
      digitalWrite(ST_LED_PIN, LOW);
      digitalWrite(DIV_LED_PIN, HIGH);       
    }
  }
}

//////////////////////////////////////////////////////////////////////////

void send3bytePacket(int opcode, int slot, int spd) {
        lnMsg SendPacket;

        SendPacket.data[ 0 ] = opcode;
        SendPacket.data[ 1 ] = slot;
        SendPacket.data[ 2 ] = spd;  
        LocoNet.send( &SendPacket );
}

void sendOPC_GP(byte on) {
        lnMsg SendPacket;
        if (on) {
            SendPacket.data[ 0 ] = OPC_GPON;  
        } else {
            SendPacket.data[ 0 ] = OPC_GPOFF;  
        }
        LocoNet.send( &SendPacket ) ;
}

void sendOPC_IDLE() {
        lnMsg SendPacket;
        SendPacket.data[ 0 ] = OPC_IDLE;  
        LocoNet.send( &SendPacket ) ;
}

void sendOPC_RQ_SL_DATA(int slot) {
        send3bytePacket(OPC_RQ_SL_DATA,slot,0);
}

void loop() {  
    // Check for any received LocoNet packets
    while (lnMsg *LnPacket = LocoNet.receive() ) {
        processIncomingLoconetCommand( LnPacket );
    }
    // Debounce logic:
    // ...Check for any buttons pushed, delay, read again...
    GPonButton1  = digitalRead(PowerOnPin);
    GPoffButton1 = digitalRead(PowerOffPin);
    EStopButton1 = digitalRead(EStopPin);
    ClearButton1 = digitalRead(SlotClearPin);
    delay(5);
    GPonButton2  = digitalRead(PowerOnPin);
    GPoffButton2 = digitalRead(PowerOffPin);
    EStopButton2 = digitalRead(EStopPin);
    ClearButton2 = digitalRead(SlotClearPin);

    // ...identical readings mean we have a good result
    if (GPonButton1  == GPonButton2)  { GPonButton  = GPonButton1  ? 0 : 1; }
    if (GPoffButton1 == GPoffButton2) { GPoffButton = GPoffButton1 ? 0 : 1; }
    if (EStopButton1 == EStopButton2) { EStopButton = EStopButton1 ? 0 : 1; }
    if (ClearButton1 == ClearButton2) { ClearButton = ClearButton1 ? 0 : 1; }

                
    if (lastGPon == -1) {
        // need to initialize things the first time thru to ensure buttons don't all fire...
        lastGPon = GPonButton;
        lastGPoff = GPoffButton;
        lastEStop = EStopButton;
        lastClear = ClearButton;
    } else {
        // See if anything has changed since last time thru...

        if (GPonButton != lastGPon) {                // GP_ON
            lastGPon = GPonButton;
            if (GPonButton) {
                sendOPC_GP(1);
            }

            ClearIt = 0;
                
        }
        if (GPoffButton != lastGPoff) {              // GP_OFF
            lastGPoff = GPoffButton;
            if (GPoffButton) {
                sendOPC_GP(0);
            }
            ClearIt = 0;
        }
        if (EStopButton != lastEStop) {              // E_STOP
            lastEStop = EStopButton;
            if (EStopButton) {
                sendOPC_IDLE();
            }
            ClearIt = 0;
        }
        if (ClearButton != lastClear) {              // Clear all Slots
            lastClear = ClearButton;
            if (ClearButton) {
                ClearIt = 1;
                // query all the slots, let the handler clear things
                for (int slot = 0; slot < 120; slot++) {
                    sendOPC_RQ_SL_DATA(slot);
                }
                ClearIt = 0;  // race condition?
            }
        }     
    }
}

Line 80 simply seems to print a message

What is the format of the Loconet message that you want to parse ?

do i understand this correctly ... your code monitor locoNet messages and you want to turn on/off LEDs on a panel indicating the turnout switch position in the received LocoNet msg ?

if so, looks like you want to use notifySwitchRequest() but it is passed LnPacket as the argument where it is called, and 3 arguments are specified where it is defined: Address, Output and Direction. Does the LnPacket need to be decoded first? (LocoNet spec)

OPC_SW_REQ 0xB0 ;REQ SWITCH function NO
               ;<0xB0>,<SW1>,<SW2>,<CHK> REQ SWITCH function
    <SW1> =<0,A6,A5,A4- A3,A2,A1,A0>, 7 ls adr bits. A1,A0 select 1 of 4 input pairs in a DS54
    <SW2> =<0,0,DIR,ON- A10,A9,A8,A7> Control bits and 4 MS adr bits.
        DIR=1 for Closed,/GREEN, =0 for Thrown/RED
         ON=1 for Output ON, =0 FOR output OFF
 Note-,Immediate response of <0xB4><30><00> if command failed, otherwise no response

assuming the address specifies the switch #, do you need a table that maps the address to a pair of LEDs, one LED indicating the switch is set Normal and the other that it is Reversed (set to the diverging route)

to UKHeliBob, according to the line count I get line 80 as if (opcode == OPC_SW_REQ)

gcjr, you understand correctly what I want to do. I think notifySwitchRequest is the routine I want to use and you are correct about the arguments I need to pass when calling it. The problem I have is I haven't been able to figure out how to parse the loconet packet that I receive. This statement at line 66 correctly extracts the opcode so the if statement at line 80 is true but my problem is I don't know how to extract the other parameters from the message.

If I can get the notifySwitchRequest routine to be called correctly then I will just use some if then else logic to controll the LEDs like the code that is there now for one address. I only need to process for three switch addresses.

Thanks for you response.

Dale Gloer

Not for me
image

any chance you have a raw hex message as an example?

Greg, thank you for the time you have spent on my problem. I am sure now that I am trying to use the routine incorrectly and I have now found what I think is the correct to way to achieve what I need. There fore I am closing this thread.

Thanks again.

Dale Gloer

could you please post your working code?

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.