10 years, 2 months ago.

Importing custom serial library from Arduino, getting a little confused

Hello all,

I come from Arduino-land where things are made just a little easier. I just got my first mbed platform, an LPC4088, to use a new brain for my hexapod robot. I'm a hack of a programmer at best and have hit a bit of a wall.

I'm trying to port over a "Commander" library that is used with the Arbotix Commander remote controller. The library's purpose is to open the serial connection to the Xbee and decipher the controller's messages.

Here are the original Arduino files:

Commander.h:

#ifndef Commander_h
#define Commander_h

/* bitmasks for buttons array */
#define BUT_R1      0x01
#define BUT_R2      0x02
#define BUT_R3      0x04
#define BUT_L4      0x08
#define BUT_L5      0x10
#define BUT_L6      0x20
#define BUT_RT      0x40
#define BUT_LT      0x80

/* the Commander will send out a frame at about 30hz, this class helps decipher the output. */
class Commander
{    
  public:
    Commander(); 
    void begin(int baud);
    void UseSouthPaw();     // enable southpaw configuration
    int ReadMsgs();         // must be called regularly to clean out Serial buffer

    // joystick values are -125 to 125
    signed char leftV;      // vertical stick movement = forward speed
    signed char leftH;      // horizontal stick movement = sideways or angular speed
    signed char rightV;      // vertical stick movement = tilt    
    signed char rightH;      // horizontal stick movement = pan (when we run out of pan, turn body?)
    // 0-1023, use in extended mode    
    int pan;
    int tilt;
    
    // buttons are 0 or 1 (PRESSED), and bitmapped
    unsigned char buttons;  // 
    unsigned char ext;      // Extended function set
        
    // Hooks are used as callbacks for button presses -- NOT IMPLEMENT YET
        
  private:
    // internal variables used for reading messages
    unsigned char vals[7];  // temporary values, moved after we confirm checksum
    int index;              // -1 = waiting for new packet
    int checksum;
    unsigned char status; 
};

#endif

Commander.cpp:

#include <Arduino.h>
#include "Commander.h"

/* Constructor */
Commander::Commander(){
    index = -1;
    status = 0;
}
void Commander::begin(int baud){
    Serial.begin(baud);
}

/* SouthPaw Support */
void Commander::UseSouthPaw(){
    status |= 0x01;
}

/* process messages coming from Commander 
 *  format = 0xFF RIGHT_H RIGHT_V LEFT_H LEFT_V BUTTONS EXT CHECKSUM */
int Commander::ReadMsgs(){
    while(Serial.available() > 0){
        if(index == -1){         // looking for new packet
            if(Serial.read() == 0xff){
                index = 0;
                checksum = 0;
            }
        }else if(index == 0){
            vals[index] = (unsigned char) Serial.read();
            if(vals[index] != 0xff){            
                checksum += (int) vals[index];
                index++;
            }
        }else{
            vals[index] = (unsigned char) Serial.read();
            checksum += (int) vals[index];
            index++;
            if(index == 7){ // packet complete
                if(checksum%256 != 255){
                    // packet error!
                    index = -1;
                    return 0;
                }else{
                    if((status&0x01) > 0){     // SouthPaw
                        walkV = (signed char)( (int)vals[0]-128 );
                        walkH = (signed char)( (int)vals[1]-128 );
                        lookV = (signed char)( (int)vals[2]-128 );
                        lookH = (signed char)( (int)vals[3]-128 );
                    }else{
                        lookV = (signed char)( (int)vals[0]-128 );
                        lookH = (signed char)( (int)vals[1]-128 );
                        walkV = (signed char)( (int)vals[2]-128 );
                        walkH = (signed char)( (int)vals[3]-128 );
                    }
                    pan = (vals[0]<<8) + vals[1];
                    tilt = (vals[2]<<8) + vals[3];
                    buttons = vals[4];
                    ext = vals[5];
                }
                index = -1;
                Serial.flush();
                return 1;
            }
        }
    }
    return 0;
}

So normally in my main ardinuo program, i just do a:

Commander command = Commander();

And then a:

command.begin(38400);  // setup serial for Xbee on USART2

In my setup() function.

The problem i'm having now with mbed, is that i'm using:

Serial xbee(p4_22, p4_23);

to create the xbee object of type Serial for the UART that the Xbee is on. However, if i do this in my main.cpp, "xbee" is undefined over in my Commander.cpp. Creating the object in Commander.cpp doesn't seem right, because that's a library i shouldn't need to touch.

I did try to have the commander object create the serial anyway like this:

void Commander::begin(int pTX, int pRX, int baud){
    Serial xbee(pTX, pRX);// setup serial for Xbee on USART2
    xbee.baud(baud);
}

But that didn't work either.

What am i missing here? I'm getting lost in the Arudino to standard C++ translation.

Thanks a lot, Dan

2 Answers

10 years, 2 months ago.

You will have to modify the Commander class to make it compatible with the mbed Serial lib, There are several solutions, but in case you dont need the xbee Serial port anywhere else, the easiest fix is to declare the serial port as private inside Commander.

#ifndef Commander_h
#define Commander_h

//NEW
#include "mbed.h"
 
/* bitmasks for buttons array */
#define BUT_R1      0x01
#define BUT_R2      0x02
#define BUT_R3      0x04
#define BUT_L4      0x08
#define BUT_L5      0x10
#define BUT_L6      0x20
#define BUT_RT      0x40
#define BUT_LT      0x80
 
/* the Commander will send out a frame at about 30hz, this class helps decipher the output. */
class Commander
{    
  public:
    Commander(); 
    void begin(int baud);
    void UseSouthPaw();     // enable southpaw configuration
    int ReadMsgs();         // must be called regularly to clean out Serial buffer
 
    // joystick values are -125 to 125
    signed char leftV;      // vertical stick movement = forward speed
    signed char leftH;      // horizontal stick movement = sideways or angular speed
    signed char rightV;      // vertical stick movement = tilt    
    signed char rightH;      // horizontal stick movement = pan (when we run out of pan, turn body?)
    // 0-1023, use in extended mode    
    int pan;
    int tilt;
    
    // buttons are 0 or 1 (PRESSED), and bitmapped
    unsigned char buttons;  // 
    unsigned char ext;      // Extended function set
        
    // Hooks are used as callbacks for button presses -- NOT IMPLEMENT YET
        
  private:
    // internal variables used for reading messages
    unsigned char vals[7];  // temporary values, moved after we confirm checksum
    int index;              // -1 = waiting for new packet
    int checksum;
    unsigned char status; 

    Serial xbee(p4_22, p4_23);   // <== NEW
};
 
#endif

You also need to change some calls to Serial port methods inside the Commander.cpp: baud, read

#include <Arduino.h>  // <== probably get rid of that
#include "Commander.h"
 
//NEW
#include "mbed.h"

/* Constructor */
Commander::Commander(){
    index = -1;
    status = 0;
}
void Commander::begin(int baudrate){
//    Serial.begin(baud);
    xbee.baud(baudrate); //<== NEW
}
 
/* SouthPaw Support */
void Commander::UseSouthPaw(){
    status |= 0x01;
}
 
/* process messages coming from Commander 
 *  format = 0xFF RIGHT_H RIGHT_V LEFT_H LEFT_V BUTTONS EXT CHECKSUM */
int Commander::ReadMsgs(){
//    while(Serial.available() > 0){
    while(xbee.readable() > 0){      ///<==NEW
        if(index == -1){         // looking for new packet
//            if(Serial.read() == 0xff){
            if(xbee.getc() == 0xff){   // <==NEW
                index = 0;
                checksum = 0;
            }
        }else if(index == 0){
//            vals[index] = (unsigned char) Serial.read();
            vals[index] = (unsigned char) xbee.getc();   //<=== NEW
            if(vals[index] != 0xff){            
                checksum += (int) vals[index];
                index++;
            }
        }else{
//            vals[index] = (unsigned char) Serial.read();
            vals[index] = (unsigned char) xbee.getc();   //<=== NEW
            checksum += (int) vals[index];
            index++;
            if(index == 7){ // packet complete
                if(checksum%256 != 255){
                    // packet error!
                    index = -1;
                    return 0;
                }else{
                    if((status&0x01) > 0){     // SouthPaw
                        walkV = (signed char)( (int)vals[0]-128 );
                        walkH = (signed char)( (int)vals[1]-128 );
                        lookV = (signed char)( (int)vals[2]-128 );
                        lookH = (signed char)( (int)vals[3]-128 );
                    }else{
                        lookV = (signed char)( (int)vals[0]-128 );
                        lookH = (signed char)( (int)vals[1]-128 );
                        walkV = (signed char)( (int)vals[2]-128 );
                        walkH = (signed char)( (int)vals[3]-128 );
                    }
                    pan = (vals[0]<<8) + vals[1];
                    tilt = (vals[2]<<8) + vals[3];
                    buttons = vals[4];
                    ext = vals[5];
                }
                index = -1;
////                Serial.flush();
                xbee.flush();   // <=== NEW
                return 1;
            }
        }
    }
    return 0;
}

Note: I didnt compile any of this. There are probably some more errors due to Arduino/mbed differences

Dan D.
poster
10 years, 2 months ago.

Awesome, thanks for taking the time to look this over. I was actually somewhat close to what you had, i just copied in the originals to start from square one. I hadn't thought to create the xbee Serial object in the Commander.h which makes sense in hindsight. It only needs to exist in Commander. I access the xbee through the Commander object which is created in main.cpp.

I do have a new issue though:

Error: Identifier "p4_22" is undefined in "Commander/Commander.h", Line: 65, Col: 17
Error: Identifier "p4_23" is undefined in "Commander/Commander.h", Line: 65, Col: 24

I am including "mbed.h" in the Commander.h file. I can't remember where i found those pin names, but somewhere deep in the guts of the mbed repository on this site under the LPC4088 stuff. Is there an easy place for me to find what handy pin definition/macros have been created for my board? I'm also not 100% sure those are the correct UART pins for the Xbee port, but i think so based on the "lpc4088_qsb_pinning.xlsx" file i found in the documentation.

I'm also getting a lot of:

Error: Expression must have class type in "Commander/Commander.cpp", Line: 39, Col: 11

referencing xbee.getc(), xbee.readable(), etc

Latest Commander.h:

#ifndef Commander_h
#define Commander_h

#include "mbed.h"

/* bitmasks for buttons array */
#define BUT_R1      0x01
#define BUT_R2      0x02
#define BUT_R3      0x04
#define BUT_L4      0x08
#define BUT_L5      0x10
#define BUT_L6      0x20
#define BUT_RT      0x40
#define BUT_LT      0x80

/* the Commander will send out a frame at about 30hz, this class helps decipher the output. */
class Commander
{    
  public:
    Commander(); 
    void begin(int baud);
    int ReadMsgs();         // must be called regularly to clean out Serial buffer

    // joystick values are -125 to 125
    signed char leftV;      // vertical stick movement = forward speed
    signed char leftH;      // horizontal stick movement = sideways or angular speed
    signed char rightV;      // vertical stick movement = tilt    
    signed char rightH;      // horizontal stick movement = pan (when we run out of pan, turn body?)
    // 0-1023, use in extended mode    
    int pan;
    int tilt;
    
    // buttons are 0 or 1 (PRESSED), and bitmapped
    unsigned char buttons;  // 
    unsigned char ext;      // Extended function set
        
    // Hooks are used as callbacks for button presses -- NOT IMPLEMENT YET
        
  private:
    // internal variables used for reading messages
    unsigned char vals[7];  // temporary values, moved after we confirm checksum
    int index;              // -1 = waiting for new packet
    int checksum;
    unsigned char status; 
    
    Serial xbee(p4_22, p4_23);   // <== NEW
};

#endif

Latest Commander.cpp:

#include "mbed.h"
#include "Commander.h"
#include "init.h"



/* Constructor */
Commander::Commander(){
    index = -1;
    status = 0;

}
void Commander::begin(int baud){
    xbee.baud(baud);
}

/* process messages coming from Commander 
 *  format = 0xFF RIGHT_H RIGHT_V LEFT_H LEFT_V BUTTONS EXT CHECKSUM */
int Commander::ReadMsgs(){
    while(xbee.readable() > 0){
        if(index == -1){         // looking for new packet
            if(xbee.getc() == 0xff){
                index = 0;
                checksum = 0;
            }
        }else if(index == 0){
            vals[index] = (unsigned char) xbee.getc();
            if(vals[index] != 0xff){            
                checksum += (int) vals[index];
                index++;
            }
        }else{
            vals[index] = (unsigned char) xbee.getc();
            checksum += (int) vals[index];
            index++;
            if(index == 7){ // packet complete
                if(checksum%256 != 255){
                    // packet error!
                    index = -1;
                    return 0;
                }else{
                    rightV = (signed char)( (int)vals[0]-128 );
                    rightH = (signed char)( (int)vals[1]-128 );
                    leftV = (signed char)( (int)vals[2]-128 );
                    leftH = (signed char)( (int)vals[3]-128 );

                    pan = (vals[0]<<8) + vals[1];
                    tilt = (vals[2]<<8) + vals[3];
                    buttons = vals[4];
                    ext = vals[5];
                }
                index = -1;
                xbee.flush();
                return 1;
            }
        }
    }
    return 0;
}

FFS attempt 3 at an answer (no backspace this time, or pressing wrong button):

In your header file it shouldn't set the serial pins, so make it:

Serial xbee;   // <== NEW

Now in your cpp constructor make it:

Commander::Commander() : xbee(P4_22, P4_23) {

Notice the capital P's, I assume here you got the numbers correct. Generally boards only have their external pins, and then you don't need to worry about those names, and you can simply use the names on the pinout picture (although I see the LPC4088 accidently has those with capitals, while they should be small ones). Here you got the complete list: http://mbed.org/users/mbed_official/code/mbed-src/file/5a6f638110fe/targets/hal/TARGET_NXP/TARGET_LPC408X/PinNames.h.

Finally you say Arduino is easier. However you just switched over, and didn't exactly start with blinking an LED ;). On some points Arduino has it easier, but at the same time mbed is easier on other points. When I do something with Arduino I really miss the Timer and Ticker libraries for example. So give it some time ;).

posted by Erik - 01 Feb 2014

Thanks! This is really cleaning up. The only problem left is that there doesn't seem to be a Serial .flush() function. I searched a bit and people (at least a few years ago) agree that there is not and that you should write one like:

void flushSerialBuffer(void) { char char1 = 0; while (device.readable()) { char1 = device.getc(); } return; }

Is this the best way?

Thanks again!

Oh, i'm looking forward to getting back to a more standard programming environment. Arduino can hurt in that it hides a lot of things from you. My issues here are simply lack of solid programming foundation, but i have several books that i keep reading over and over. someday. Thanks again.

posted by Dan D. 01 Feb 2014