How to Controlling a Treadmill with Csafe

I have been working on trying to figure out how to communicate with a Precor 811 treadmills C10 control panels CSAFE port. It has an RJ-45 plug for using the CSAFE protocols, I have made a cable that lets me have the Rx, Tx, and Ground wires required for an RS-232 conversion board. Now that I have shifted the normal RS-232 to TTL style for the Mega, I can't seem to get it to work.

I have the RX TX ground attached to the RS-232 converter and pin 0 and 1 attached to the converters Rx Tx pins, along with the 5v and ground. I have tried to send a simple array but am unsure why I get no response. Could somebody point out a potential direction on how to send and receive instruction sets?

Here is the code I am trying to use, I took out everything that isn't important and just send and receive.

byte incomingByte =0;
void setup()
{
 Serial.begin(9600);
}

void loop()
{
 Serial.write(0xF1); //Start flag
 Serial.write(0x81); //Request for status
 Serial.write(0xF2); //Stop flag
 delay(1000);
 if(Serial.available() > 0){
  incomingByte = Serial.read(); // read the incoming byte:
  Serial.print(" I received:");
  Serial.println(incomingByte);
  }
}

Info on Csafe commands are on the bottom of the wiki, any help would be amazing.

My first suggestion is to move the treadmill communication to one of the Mega's other hardware serial ports (Serial1, Serial2, Serial3) so you can use the Serial hardware (USB) port for program upload and to monitor program flow and variable values with Serial prints. Having 2 things (treadmill and serial monitor) connected to the same port will never work well.

As per GroundFungus suggestion I have altered to use Serial1 to make uploading to the mega easier. Also now I am getting this as a reply to my send, I am looking into how to receive information and decode it.

This is the 4 lines I get when listening.
0
FFFFFFFF
FFFFFFFF
1

void setup(){
  Serial.begin(9600); //requested rate for csafe
  Serial1.begin(9600); //communication line for treadmill on Serial1
  while(!Serial){ //wait for monitor to open
  }
}

void loop(){
  Serial1.write(0xF1); //Start Flag
  Serial.print(0xF1,HEX);
  Serial1.write(0x80); //Request Status
  Serial.print(0x80,HEX);
  Serial1.write(0x80); //Request Status
  Serial.print(0x80,HEX);
  Serial1.write(0xF2); //Stop Flag
  Serial.println(0xF2,HEX);
  Serial.println(Serial1.read(),HEX);
  Serial.println(Serial1.read(),HEX);
  Serial.println(Serial1.read(),HEX);
  Serial.println(Serial1.read(),HEX);
  delay(2000);
}
Serial.println(Serial1.read(),HEX);
  Serial.println(Serial1.read(),HEX);
  Serial.println(Serial1.read(),HEX);
  Serial.println(Serial1.read(),HEX);

It takes time for serial to read a byte into the receive buffer. It takes far less time to read a byte from the buffer. You are reading bytes before you know if there is actually data waiting in the buffer. No telling what you are getting.

The serial input basics tutorial may help you to read the serial data.

Example #3, Receive with start- and end-markers might be a start.
According to the protocol that I found there is a start marker (0xF1) and an end marker (0xF2).

What do you see in serial monitor when you run the following code?

void setup()
{
   Serial.begin(9600); //requested rate for csafe
   Serial1.begin(9600); //communication line for treadmill on Serial1
   while (!Serial) //wait for monitor to open
   {
   }
   Serial.println("Ready\n");
}

void loop()
{
   Serial1.write(0xF1); //Start Flag
   Serial.print(0xF1, HEX);
   Serial1.write(0x80); //Request Status
   Serial.print(0x80, HEX);
   Serial1.write(0x80); //Request Status
   Serial.print(0x80, HEX);
   Serial1.write(0xF2); //Stop Flag
   Serial.println(0xF2, HEX);
   while (Serial1.available())
   {
      Serial.print(Serial1.read(), HEX);
      Serial.print(",");
      delay(20);
   }
   Serial.println();
   delay(2000);
}

groundFungus:
What do you see in serial monitor when you run the following code?

void setup()

{
  Serial.begin(9600); //requested rate for csafe
  Serial1.begin(9600); //communication line for treadmill on Serial1
  while (!Serial) //wait for monitor to open
  {
  }
  Serial.println(“Ready\n”);
}

void loop()
{
  Serial1.write(0xF1); //Start Flag
  Serial.print(0xF1, HEX);
  Serial1.write(0x80); //Request Status
  Serial.print(0x80, HEX);
  Serial1.write(0x80); //Request Status
  Serial.print(0x80, HEX);
  Serial1.write(0xF2); //Stop Flag
  Serial.println(0xF2, HEX);
  while (Serial1.available())
  {
     Serial.print(Serial1.read(), HEX);
     Serial.print(",");
     delay(20);
  }
  Serial.println();
  delay(2000);
}

When running this code I get back the following, which I don’t think has an order to it as it seems to be random. Here are a few seconds of serial monitor:

F18080F2
1,0,1,0,
F18080F2
F18080F2
0,0,0,
F18080F2
F18080F2
1,0,1,0,
F18080F2
F18080F2
0,0,
F18080F2
F18080F2
1,0,1,0,
F18080F2
F18080F2
1,0,1,0,
F18080F2
F18080F2
1,0,1,0,
F18080F2
F18080F2
0,0,
F18080F2
F18080F2
1,0,1,0,
F18080F2
F18080F2
0,0,0,
F18080F2
F18080F2
1,0,1,0,

Can you try:

/*
 * Sketch:  CSAFE_Treadmill.ino
 * Target:  Mega2560
 */
 
#define START_FLAG          0xF1
#define STOP_FLAG           0xF2

#define TIME_TX_CHAR        10ul
#define TIME_RX_TIMEOUT     2000ul
#define TIME_FRAME_DELAY    2000ul

#define TX_MSG              0
#define RX_MSG              1
#define TX_DELAY            2

HardwareSerial *serialConsole = (HardwareSerial *)&Serial;
HardwareSerial *serialTreadmill = (HardwareSerial *)&Serial1;

const uint8_t grTxMsg[] = {START_FLAG, 0x00, STOP_FLAG};    //empty frame should give status reply

char
    szStr[10];
    
void setup()
{
   serialConsole->begin(9600); //requested rate for csafe
   serialTreadmill->begin(9600); //communication line for treadmill on Serial1
      
   serialConsole->print( "TX Msg: " );
   
}//setup

void loop()
{
    CSAFE_RxTx();
    
}//loop

void CSAFE_RxTx( void )
{
    uint8_t
        rxC,
        txC;
    static uint32_t
        timeRx = 0,
        timeTx = 0;
    static uint8_t
        stateRxTx = TX_DELAY,
        indexTx = 0;
    uint32_t
        timeNow = millis();
        
    switch( stateRxTx )
    {
        case    TX_MSG:
            //transmit a character every TIME_TX_CHAR mS
            if( (timeNow - timeTx) >= TIME_TX_CHAR )
            {
                //update char timer
                timeTx = timeNow;
                //get character to send
                txC = grTxMsg[indexTx++];
                //echo to the console
                sprintf( szStr, "%02X ", txC );
                serialConsole->print( szStr );                
                //send to the treadmill
                serialTreadmill->write( txC );

                //when we've just sent the STOP_FLAG, move to the RX state
                if( txC ==  STOP_FLAG )
                {
                    serialConsole->print( "\n\tRX Msg: " );
                    timeRx = timeNow;                    
                    stateRxTx = RX_MSG;
                    
                }//if
                
            }//if
            
        break;
    
        case    RX_MSG:
            //any chars available?
            if( serialTreadmill->available() > 0 )
            {
                //yes; process any and all
                while( serialTreadmill->available() > 0 )
                {
                    //reset timeout timer
                    timeRx = timeNow;
                    //get the char from the treadmill
                    rxC = serialTreadmill->read();
                    //echo to the console
                    sprintf( szStr, "%02X ", rxC );
                    serialConsole->print( szStr );

                    //if we get the stop flag, prep for next TX
                    if( rxC == STOP_FLAG )
                    {                        
                        timeTx = timeNow;
                        stateRxTx = TX_DELAY;    
                        
                    }//if
                    
                }//while
                
            }//if
            else if( (timeNow - timeRx) >= TIME_RX_TIMEOUT )
            {
                //if here, TIME_RX_TIMEOUT expired without receiving a character
                serialConsole->println( "\n*** RX TIMEOUT\n" );
                timeTx = timeNow;
                stateRxTx = TX_DELAY;    
                
            }//else if
                            
        break;

        case    TX_DELAY:
            if( (timeNow - timeTx) >= TIME_FRAME_DELAY )
            {
                serialConsole->print( "\nTX Msg: " );               
                timeTx = timeNow;
                indexTx = 0;
                stateRxTx = TX_MSG;
                   
            }//if
            
        break;
        
    }//switch
    
}//CSAFE_RxTx

I tried your code

Blackfin:
Can you try:

/*
  • Sketch:  CSAFE_Treadmill.ino
  • Target:  Mega2560
    */

#define START_FLAG          0xF1
#define STOP_FLAG           0xF2

#define TIME_TX_CHAR        10ul
#define TIME_RX_TIMEOUT     2000ul
#define TIME_FRAME_DELAY    2000ul

#define TX_MSG              0
#define RX_MSG              1
#define TX_DELAY            2

HardwareSerial *serialConsole = (HardwareSerial *)&Serial;
HardwareSerial *serialTreadmill = (HardwareSerial *)&Serial1;

const uint8_t grTxMsg = {START_FLAG, 0x00, STOP_FLAG};    //empty frame should give status reply

char
   szStr[10];
   
void setup()
{
  serialConsole->begin(9600); //requested rate for csafe
  serialTreadmill->begin(9600); //communication line for treadmill on Serial1
     
  serialConsole->print( "TX Msg: " );
 
}//setup

void loop()
{
   CSAFE_RxTx();
   
}//loop

void CSAFE_RxTx( void )
{
   uint8_t
       rxC,
       txC;
   static uint32_t
       timeRx = 0,
       timeTx = 0;
   static uint8_t
       stateRxTx = TX_DELAY,
       indexTx = 0;
   uint32_t
       timeNow = millis();
       
   switch( stateRxTx )
   {
       case    TX_MSG:
           //transmit a character every TIME_TX_CHAR mS
           if( (timeNow - timeTx) >= TIME_TX_CHAR )
           {
               //update char timer
               timeTx = timeNow;
               //get character to send
               txC = grTxMsg[indexTx++];
               //echo to the console
               sprintf( szStr, "%02X ", txC );
               serialConsole->print( szStr );                
               //send to the treadmill
               serialTreadmill->write( txC );

//when we've just sent the STOP_FLAG, move to the RX state
               if( txC ==  STOP_FLAG )
               {
                   serialConsole->print( "\n\tRX Msg: " );
                   timeRx = timeNow;                    
                   stateRxTx = RX_MSG;
                   
               }//if
               
           }//if
           
       break;
   
       case    RX_MSG:
           //any chars available?
           if( serialTreadmill->available() > 0 )
           {
               //yes; process any and all
               while( serialTreadmill->available() > 0 )
               {
                   //reset timeout timer
                   timeRx = timeNow;
                   //get the char from the treadmill
                   rxC = serialTreadmill->read();
                   //echo to the console
                   sprintf( szStr, "%02X ", rxC );
                   serialConsole->print( szStr );

//if we get the stop flag, prep for next TX
                   if( rxC == STOP_FLAG )
                   {                        
                       timeTx = timeNow;
                       stateRxTx = TX_DELAY;    
                       
                   }//if
                   
               }//while
               
           }//if
           else if( (timeNow - timeRx) >= TIME_RX_TIMEOUT )
           {
               //if here, TIME_RX_TIMEOUT expired without receiving a character
               serialConsole->println( "\n*** RX TIMEOUT\n" );
               timeTx = timeNow;
               stateRxTx = TX_DELAY;    
               
           }//else if
                           
       break;

case    TX_DELAY:
           if( (timeNow - timeTx) >= TIME_FRAME_DELAY )
           {
               serialConsole->print( "\nTX Msg: " );              
               timeTx = timeNow;
               indexTx = 0;
               stateRxTx = TX_MSG;
                 
           }//if
           
       break;
       
   }//switch
   
}//CSAFE_RxTx

And it will consistently output these two lines:

TX Msg: F1 00 F2
RX Msg: F1 00 F2

Hmm. From what I've read online an empty frame (F1 00 F2) should elicit a ready-state reply like "F1 01 01 F2" or "F1 81 81 F2".

Maybe try changing the line:

const uint8_t grTxMsg[] = {START_FLAG, 0x00, STOP_FLAG};    //empty frame should give status reply

to

const uint8_t grTxMsg[] = {START_FLAG, 0x80, 0x80, STOP_FLAG};

would yield a status frame.

I attempted to alter the line to elicit a response with 0x80, 0x80 and this is the output:

TX Msg: F1 80 80 F2
RX Msg: F1 80 80 F2

It seems to be parroting the input no matter the input, I put in random pair values to the same type effect.

And you have Serial1 connected to the treadmill and not, say, in a TX to RX loopback?

I have the Rx and Tx from serial1 line on the mega board (pins 18 and 19) to the rs232 breakout and same rs232 breakout to the treadmill, correctly inverted rx to tx.