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

Était-ce utile?

La 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;
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top