Question

I'm trying to write a program to upload a file to an arduino. The program can open a serial port and receive data from the arduino. The problem comes when I try to use a callback to a function in a statechart state, the program crashes.

I have never used boost before and decided that this would be a good opportunity to try it out.

I have a statechart object with the basic transitions as so: Idle; -> PortOpening; -> PortOpen; -> WaitForCurveChoiceConfirmation; -> ChooseFile; -> WaitForFileReceive; -> CompareFiles; -> CloseProgram;

Theres a port closing state too but that works fine.

My main program is only as follows

int main(int argc, char* argv[]){

  if(argc!=4){

    cerr<<"Usage: serialPort baudRate file"<<endl;



    return 1;

  }

  try {

    myInterface deviceInterface;
    stateMachine fsm(deviceInterface);
    fsm.initiate();

  } catch (std::exception& e) {

    cerr<<"Exception: "<<e.what()<<endl;

  }

}

I can open the serial port and receive data perfectly. The problem comes when I try to use a callback to a function in my WaitForCurveChoiceConfirmation state. The arduino sends a message every few seconds, I use the call back when a full message is received by the program. As soon as the message is received and the callback is called, my program crashes.

The WaitForCurveChoiceConfirmationState is as follows

class WaitForCurveChoiceConfirmation: public sc::state< WaitForCurveChoiceConfirmation, Active > {

    public:
        WaitForCurveChoiceConfirmation(my_context ctx);
        typedef boost::mpl::list<
            sc::custom_reaction< EvSensorChoiceConfirm > ,
            sc::custom_reaction< EvSensorChoiceTimeout >
        > reactions;

    sc::result react( const EvSensorChoiceConfirm & );
    sc::result react( const EvSensorChoiceTimeout & );
    void curveChoiceConfirmed(myMessage & msg);
};

WaitForCurveChoiceConfirmation::WaitForCurveChoiceConfirmation(my_context ctx): my_base(  ctx ){
    context< stateMachine >().getInterface().setfullMsgReceivedCallback(boost::bind(&WaitForCurveChoiceConfirmation::curveChoiceConfirmed, this, _1));
}

void WaitForCurveChoiceConfirmation::curveChoiceConfirmed(my1100Message & msg){
    std::cout << "curveChoiceConfirmed callback " << std::endl;
    if(msg.isExpectingTemperatureCurve()){

        post_event( EvSensorChoiceConfirm() );
    }
}

sc::result WaitForCurveChoiceConfirmation::react( const EvSensorChoiceConfirm & ){
    std::cout<<"EvSensorChoiceConfirm"<<std::endl;
    return transit<ChooseFile>();
}

sc::result WaitForCurveChoiceConfirmation::react( const EvSensorChoiceTimeout & ){
    return transit<PortClosing>();
}

The relevant parts of the myInterface class is as follows

class myInterface: public CallbackAsyncSerial
{

        /** Default constructor */
        myInterface();
        /** Default destructor */
        virtual ~myInterface();

        void processReceivedData(const char *data, unsigned int len);
        void setfullMsgReceivedCallback( boost::function<void(myMessage &msg )>);
        void clearfullMsgReceivedCallback( );


    private:

        boost::circular_buffer<char> * incomingMsg;
        static const int MESSAGE_DATA_LENGTH = 73; //length of data, not including flags or checksum
        static const uint8_t PROTOCOL_OUTGOING_LENGTH = 22; // number of characters in received message
        uint8_t receive_buffer[MESSAGE_DATA_LENGTH + 2]; // plus 2 for checksum
        char outgoingMsg[PROTOCOL_OUTGOING_LENGTH + 1];
        uint8_t statusByte;
        uint8_t statusByte2;
        uint8_t userByte;
        uint8_t userByte2;
        uint8_t notificationByte;
        uint8_t errorByte;
        uint8_t actionByte;

        int msgIndex ;
        int flagIndex ;
        int byteCount;
        int checkSum ;
        int dispPreambleCount ;
        int rcvCalculatedCheckSum ;
        char rcvdFlag;
        dispMsgState_t dispMsgState ;

        static const int FLAG_COUNT = 17;
        static const char flags[FLAG_COUNT] ;
        boost::function<void(myMessage & msg )> fullMsgReceivedCallback;


};

// this is used as a callback in CallBackAsyncSerial. It takes the data received by serial and processes it
void myInterface::processReceivedData(const char *data, unsigned int len)
{

    for (unsigned int i = 0; i < len; i++)
    {
        incomingMsg->push_back(data[i] );
        switch (dispMsgState){
                case DISP_PREAMBLE: {//msg start flags
                    //std::cout << "DISP_PREAMBLE "  <<std::endl;
                    if(incomingMsg->back() == START_FLAG){
                        dispPreambleCount++;
                        if (dispPreambleCount == 5){
                            dispMsgState = DISP_BYTE;
                            msgIndex = 0;
                            flagIndex = 0;
                            rcvCalculatedCheckSum = 5 * START_FLAG;
                            dispPreambleCount = 0;
                            rcvdFlag = 0;
                        }
                    }
                    else{
                        dispPreambleCount = 0; //reset counter if a different character was found

                    }
                    incomingMsg->pop_back();
                }
                break;
                case DISP_BYTE:{ //status, user, notification, error bytes
                    rcvCalculatedCheckSum += incomingMsg->back();
                    receive_buffer[msgIndex] = incomingMsg->back();
                    msgIndex++;
                    incomingMsg->pop_back();
                    if (msgIndex == 7){
                         dispMsgState = DISP_INTEGER_FLAG;
                    }
                }
                break;
                case DISP_INTEGER_FLAG:{ //integer flag
                    rcvCalculatedCheckSum += incomingMsg->back();
                    rcvdFlag = incomingMsg->back();
                    incomingMsg->pop_back();
                    dispMsgState = DISP_INTEGER;
                }
                break;
                case DISP_INTEGER:{ // integers
                    rcvCalculatedCheckSum += incomingMsg->back();
                    if(rcvdFlag == flags[flagIndex]){
                        receive_buffer[msgIndex] = incomingMsg->back();
                    }
                    incomingMsg->pop_back();
                    msgIndex++;


                    byteCount++;
                    if (byteCount >= 2){
                        if(msgIndex < 21){
                            dispMsgState = DISP_INTEGER_FLAG;
                        }
                        else{
                            dispMsgState = DISP_FLOAT_FLAG;
                        }
                        byteCount = 0;
                        flagIndex++;
                    }
                }
                break;
                case DISP_FLOAT_FLAG:{ // float flag
                    rcvCalculatedCheckSum += incomingMsg->back();
                    rcvdFlag = incomingMsg->back();
                    incomingMsg->pop_back();
                    dispMsgState = DISP_FLOAT;
                }
                break;
                case DISP_FLOAT:{ // floats
                    rcvCalculatedCheckSum += incomingMsg->back();
                    if(rcvdFlag == flags[flagIndex]){
                        receive_buffer[msgIndex] = incomingMsg->back();
                    }
                    incomingMsg->pop_back();

                    msgIndex++;

                    byteCount++;
                    if (byteCount >= 4){
                        if(msgIndex < 49){
                            dispMsgState = DISP_FLOAT_FLAG;
                        }
                        else{
                            dispMsgState = DISP_STRING_FLAG;
                        }
                        byteCount = 0;
                        flagIndex++;
                    }
                }
                break;
                case DISP_STRING_FLAG:{ // pressure flag
                    rcvCalculatedCheckSum += incomingMsg->back();
                    rcvdFlag = incomingMsg->back();
                    incomingMsg->pop_back();
                    dispMsgState = DISP_STRING;
                }
                break;
                case DISP_STRING:{ // pressure string
                     rcvCalculatedCheckSum += incomingMsg->back();
                    if(rcvdFlag == flags[flagIndex]){
                        receive_buffer[msgIndex] = incomingMsg->back();
                    }
                    incomingMsg->pop_back();
                    msgIndex++;

                    byteCount++;
                    if (byteCount >= 8){
                        if(msgIndex < 73){
                            dispMsgState = DISP_STRING_FLAG;
                        }
                        else{
                            dispMsgState = DISP_CHECKSUM;
                        }
                        byteCount = 0;
                        flagIndex++;
                    }
                }
                break;
                case DISP_CHECKSUM:{ // rcv checksum
                    if (byteCount == 0){
                         receive_buffer[msgIndex  ] = incomingMsg->back() ;
                         byteCount ++;

                    }
                    else{

                         receive_buffer[msgIndex ] = incomingMsg->back();

                        if (rcvCalculatedCheckSum == ((receive_buffer[msgIndex - 1 ] << 8) | receive_buffer[msgIndex ])) {


                            std::cout<<"FULL MSG CONFIRMED "<<std::endl;
                            statusByte = receive_buffer[0];
                            statusByte2 = receive_buffer[1];
                            userByte = receive_buffer[2];
                            userByte2 = receive_buffer[3];
                            notificationByte = receive_buffer[4];
                            errorByte = receive_buffer[5];
                            actionByte = receive_buffer[6];

                            myMessage * msg = new myMessage();
                            msg->initialise(statusByte,statusByte2,userByte,userByte2,notificationByte,errorByte,actionByte) ;
                            std::cout<<"made new msg"<<std::endl;
                            fullMsgReceivedCallback(*msg); //THIS IS WHERE IT CRASHES
                            std::cout<<"callback returned"<<std::endl;
                            delete msg;
                            std::cout<<"msg deleted"<<std::endl;

                            /* to convert string to float
                            #include <sstream>
                            using namespace std;
                            string s = "1.60000000000000000000000000000000000e+01";
                            istringstream os(s);
                                double d;
                            os >> d;
                            cout << d << endl;
                            */


                        }
                        else{
                            std::cout<<"FULL MSG NOT CONFIRMED "<<std::endl;
                            std::cout << std::hex << rcvCalculatedCheckSum <<"  " << std::hex<<  int((receive_buffer[msgIndex - 1 ] ) )<<" "<< std::hex << int(receive_buffer[msgIndex ] )<<std::endl;


                        }




                        dispMsgState = DISP_PREAMBLE;
                        rcvCalculatedCheckSum = 0;
                        msgIndex = 0;
                        byteCount = 0;

                    }
                    msgIndex++;
                    incomingMsg->pop_back();


                }
                break;


        }

    }
    //incomingMsg->insert( incomingMsg->end(), data, data + len );
    //for( boost::circular_buffer<char>::const_iterator i = incomingMsg->begin(); i != incomingMsg->end(); ++i)
    //    std::cout << *i   ;

    for( int i = 0; i < MESSAGE_DATA_LENGTH + 1; i++){
        //std::cout << std::hex<< (uint8_t)*i << ' '   ;

        std::cout << std::hex << receive_buffer[i] << ' ';

    }
    std::cout <<endl;

}

void myInterface::setfullMsgReceivedCallback(boost::function<void(my0Message & msg)> cb){
    fullMsgReceivedCallback = cb;
}


void myInterface::clearfullMsgReceivedCallback( ){
    fullMsgReceivedCallback = NULL;
}

The crash occurs at the line "fullMsgReceivedCallback(*msg);" in processReceivedData. I'm sure I'm just binding the function incorrectly or declaring the function pointer object incorrectly.

Can anyone see where I am going wrong?

thanks for your help

Was it helpful?

Solution

I've managed to solve it. It wasn't anything to do with statechart, bind or function.

It was my mistake with calling the callback. I was calling the "full message received" callback even if it didn't have a callback assigned to it and was just NULL. I fixed this by adding and if clause:

if (fullMsgReceivedCallback!= NULL){
    Message * msg = Message ;
    std::cout<<"made new msg"<<std::endl;
    msg->initialise(statusByte,statusByte2,userByte,userByte2,notificationByte,errorByte,actionByte);
    std::cout<<" msg initialised"<<std::endl;
    fullMsgReceivedCallback(*msg);
    delete msg;
    std::cout<<"msg deleted"<<std::endl;
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top