implementation details

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • MPowell

    implementation details

    Lets suppose the return value on new_command is MSG2_STATUS

    My intent then is to memcpy the data via the call to CMDHolder and
    have a function that'll retrieve a copy of the 'stored' data. The
    latter I'm unsure how to do. Any help appreaciated.


    #include <iostream>
    #include <map>


    using namespace std;

    int msg2_status_ind ex = 0;
    int msg1_status_ind ex = 0;
    int msg1_cmd_index = 0;

    MSG2_STATUS _msg2_stat[ 2 ]; // used for double buffering
    MSG1_STATUS _msg1_stat[ 2 ]; // used for double buffering
    MSG1_CMD _msg1_cmd[ 2 ]; // used for double buffering

    typedef enum
    {
    _msg1_cmd = 0,
    _msg1_status,
    _msg2_status
    } MSG_ID;

    typedef struct // this is ++. Why use typedef. 'details' I suppose
    {
    MSG_ID source;
    unsigned int msg_length : 12;
    unsigned int count : 4;
    } MSG_HEADER;

    typedef struct _MSG2_STATUS
    {
    MSG_HEADER header;
    unsigned int idx : 1;
    unsigned int jdx : 3;
    unsigned int kdx : 4;
    unsigned int spare : 24;
    unsigned int ldx : 32;
    } MSG2_STATUS;

    typedef struct _MSG1_STATUS
    {
    MSG_HEADER header;
    unsigned int idx : 1;
    unsigned int jdx : 3;
    unsigned int kdx : 4;
    unsigned int spare : 8;
    } MSG1_STATUS;

    typedef struct _MSG1_CMD
    {
    MSG_HEADER header;
    unsigned int idx : 1;
    unsigned int jdx : 3;
    } MSG1_CMD;



    class CMDBase
    {
    public:
    virtual ~CMDBase(){}
    /* what operations do you perform on these commands?
    virtual void operation1() = 0;
    virtual void operation2() = 0; */
    };


    template <class CMD>
    class CMDHolder: public CMDBase
    {
    public:
    CMDHolder(unsig ned char const* buffer)
    {
    memcpy(&m_CMDSt ruct, buffer, sizeof m_CMDStruct);
    }

    /* virtual void operation1()
    {
    //use overloaded global functions?
    structOperation 1(m_CMDStruct);
    }

    virtual void operation2()
    {
    structOperation 2(m_CMDStruct);
    } */
    private:
    CMD m_CMDStruct;
    };

    class CMDFactory
    {
    public:
    static CMDFactory& instance()
    {
    CMDFactory fact;
    return fact;
    }

    // Register the creator
    template <class T> void Register(int Id)
    {
    m_creators[Id] = CMDCreator<T>;
    }
    // unregister creator
    bool Unregister( const int& Id )
    {
    return m_creators.eras e( Id ) == 1;
    }

    CMDBase* Create(unsigned char const* buffer)
    {
    //MSG_HEADER* msg_id = reinterpret_cas t<MSG_HEADER*>( buffer);
    MSG_HEADER* msg_id; // only here because reinterpret_cas t error
    complaint

    //insert error checking!
    return (m_creators[msg_id->source])(buffer);
    }


    reinterpret_cas t generates an error with respect to the constant
    buffer and the non constant MSG_HEADER*. ??

    return (m_creators[msg_id->source])(buffer); // return here might be
    a bit confusing

    private:
    typedef CMDBase* (*CMDCreator_t) (unsigned char const*);

    template <class T>
    static CMDBase* CMDCreator(unsi gned char const* buffer)
    {
    return new T(buffer);
    }

    std::map<int, CMDCreator_t> m_creators;
    };

    int main ( void )
    {
    //called once, in initialization function:
    CMDFactory::ins tance().Registe r<MSG2_STATUS> (1);
    CMDFactory::ins tance().Registe r<MSG1_STATUS> (2);


    // inside your command processing loop:
    unsigned char buffer[512];
    // Read_1553_Data( CHANNEL_FIVE, &buffer);
    CMDBase* newCommand = CMDFactory::ins tance().Create( buffer);

    // newCommand->operation1() ; //whatever you want to do with it
    //maybe add it to a queue<CMDBase*> ?
    //myqueue.push(ne wCommand);

    return EXIT_SUCCESS;
    }
  • tom_usenet

    #2
    Re: implementation details

    On 2 Oct 2003 03:57:29 -0700, mpowell_jr@hotm ail.com (MPowell) wrote:
    [color=blue]
    >Lets suppose the return value on new_command is MSG2_STATUS
    >
    >My intent then is to memcpy the data via the call to CMDHolder and
    >have a function that'll retrieve a copy of the 'stored' data. The
    >latter I'm unsure how to do. Any help appreaciated.[/color]

    Well, I can fix the errors in the code, but you'll have to explain
    what the code is meant to do. What do you want to do with the messages
    that you receive? Do you need to perform some action depending on the
    type of message you receive?
    [color=blue]
    > CMDBase* Create(unsigned char const* buffer)
    > {
    > //MSG_HEADER* msg_id = reinterpret_cas t<MSG_HEADER*>( buffer);
    > MSG_HEADER* msg_id; // only here because reinterpret_cas t error
    >complaint
    >
    > //insert error checking!
    > return (m_creators[msg_id->source])(buffer);
    > }[/color]

    The above function should go more like this:

    CMDBase* Create(unsigned char const* buffer)
    {
    MSG_HEADER const* msg_id = reinterpret_cas t<MSG_HEADER
    const*>(buffer) ;
    map_t::const_it erator i = m_creators.find (msg_id->source);
    if (i == m_creators.end( ))
    {
    throw runtime_error(" Invalid source");
    }
    else
    {
    //call create function through pointer.
    return (i->second)(buffer );
    }
    [color=blue]
    >reinterpret_ca st generates an error with respect to the constant
    >buffer and the non constant MSG_HEADER*. ??[/color]

    Making the header const fixes your problem.
    [color=blue]
    >return (m_creators[msg_id->source])(buffer); // return here might be
    >a bit confusing[/color]

    The above is actuall a function call made through a function pointer.
    m_creators maps source id onto a creation function pointer than can
    create the Holder object for messages of that type. The above accesses
    that function pointer and calls the function, passing "buffer" as the
    first parameter. That function in tern returns a new Holder object,
    initialized with the buffer.

    Tom

    Comment

    • Kevin Goodsell

      #3
      Re: implementation details

      MPowell wrote:

      <snip>[color=blue]
      >
      > MSG2_STATUS _msg2_stat[ 2 ]; // used for double buffering
      > MSG1_STATUS _msg1_stat[ 2 ]; // used for double buffering
      > MSG1_CMD _msg1_cmd[ 2 ]; // used for double buffering
      >
      > typedef enum
      > {
      > _msg1_cmd = 0,
      > _msg1_status,
      > _msg2_status
      > } MSG_ID;[/color]

      Every one of these variables and enumerators is illegal. Identifiers
      beginning with an underscore followed by a lowercase letter are reserved
      in the global namespace.

      Just don't use identifiers beginning with an underscore. It's the
      easiest way to avoid this problem.

      -Kevin
      --
      My email address is valid, but changes periodically.
      To contact me please use the address from a recent posting.

      Comment

      • MPowell

        #4
        Re: implementation details

        > Well, I can fix the errors in the code, but you'll have to explain[color=blue]
        > what the code is meant to do. What do you want to do with the messages
        > that you receive? Do you need to perform some action depending on the
        > type of message you receive?[/color]

        Consider

        #define ID_ERROR_MASK 0x08 // #defined at top of the translation unit
        #define ID_MASK 0x07 // #defined at top of the translation unit


        int _msg2_header_er ror_count = 0;
        int _msg1_header_er ror_count = 0;

        int _msg2_message_i ndex = 0;
        int _msg1_message_i ndex = 0;
        // lots more

        struct _MSG2_STATUS // here for demo and lots more of these
        {
        // for simplicity strip out 'stuff'.
        unsigned int idx : 1;
        unsigned int ldx : 32;
        } MSG2_STATUS;

        MSG2_STATUS _msg2_message[ 2 ]; // for double buffering
        // lots more

        The Create function will look at the msg_id (which it does) then check
        for error.

        if (msg_id & ID_ERROR_MASK) == 0 )
        {
        // if no error look at msg_type
        MSG_HEADER msg_type =
        (((( msg_id >> 4 ) & ID_MASK ) <<3 )) | ( msg_id &
        ID_MASK );

        Lets suppose now the msg_type maps to MSG2_STATUS defined above

        switch (msg_type)
        {
        case _msg2_status: //got a status 2 message

        // double buffer it
        i = _msg2_message_i ndex ^ 1;
        memcpy( &_msg2_messa ge[i], buffer, sizeof(MSG2_STA TUS) );
        _msg2_message_i ndex ^= 1;
        _msg2_message_r eady = TRUE;
        break;

        case _msg1_status: //got a status 1 message

        // double buffer it
        i = _msg1_message_i ndex ^ 1;
        memcpy( &_msg1_messa ge[i], buffer, sizeof(MSG1_STA TUS) );
        _msg1_message_i ndex ^= 1;
        _msg1_message_r eady = TRUE;
        break;
        // and so on
        default:
        break;
        }
        else
        {
        switch( msg_id )
        {
        case _msg2_header_er ror: //got a status 2 message
        _msg2_header_er ror_count++;
        printf (" msg2_header_err or = &d ", msg2_header_err or);
        break;
        case _msg1_header_er ror: //got a status 2 message
        _msg1_header_er ror_count++;

        // I suspect it'd be prudent to pass in the counters and
        have values returend by the ++ ostream approach
        printf (" msg1_header_err or = &d ", msg1_header_err or);
        break;
        // and so on
        default:
        break;
        }
        }

        So now, double buffer the data,increment a counter, then set a flag -
        for no errors. For errors, increment an error counter. The current
        template style approach is certainly more elegant

        A separate function within the class should retrieve the most current
        double buffer data. I suspect (assuming i understand templates) each
        buffered data will be 'pushed' into a container/holder/?? and when
        necessary (a 120hz processing rountine retrieves the latest) retrieved
        via a call to some function with the template parameter being the
        appropriate struct.

        Lastly, the individual structs form a part of an overall struct. ie
        struct OVERALL
        {
        MSG1_TYPE msg1;
        MSG2_TYPE msg2;
        lots more.
        }

        A separate function will retrieve the 'overall'.

        In essence, a template to 'get' the data and hold data for the
        requestor
        [color=blue]
        >[color=green]
        > > CMDBase* Create(unsigned char const* buffer)
        > > {
        > > //MSG_HEADER* msg_id = reinterpret_cas t<MSG_HEADER*>( buffer);
        > > MSG_HEADER* msg_id; // only here because reinterpret_cas t error
        > >complaint
        > >
        > > //insert error checking!
        > > return (m_creators[msg_id->source])(buffer);
        > > }[/color]
        >
        > The above function should go more like this:
        >
        > CMDBase* Create(unsigned char const* buffer)
        > {
        > MSG_HEADER const* msg_id = reinterpret_cas t<MSG_HEADER
        > const*>(buffer) ;
        > map_t::const_it erator i = m_creators.find (msg_id->source);[/color]

        map_t error ??
        [color=blue]
        > if (i == m_creators.end( ))
        > {
        > throw runtime_error(" Invalid source");
        > }
        > else
        > {
        > //call create function through pointer.
        > return (i->second)(buffer );
        > }
        >[color=green]
        > >reinterpret_ca st generates an error with respect to the constant
        > >buffer and the non constant MSG_HEADER*. ??[/color]
        >
        > Making the header const fixes your problem.
        >[color=green]
        > >return (m_creators[msg_id->source])(buffer); // return here might be
        > >a bit confusing[/color]
        >
        > The above is actuall a function call made through a function pointer.
        > m_creators maps source id onto a creation function pointer than can
        > create the Holder object for messages of that type. The above accesses
        > that function pointer and calls the function, passing "buffer" as the
        > first parameter. That function in tern returns a new Holder object,
        > initialized with the buffer.
        >
        > Tom[/color]

        Tom, truly appreaciate the assistance. Feel free to use my email
        address if necessary.

        Comment

        • Kevin Goodsell

          #5
          Re: implementation details

          MPowell wrote:

          <snip>
          [color=blue]
          >
          > int _msg2_header_er ror_count = 0;
          > int _msg1_header_er ror_count = 0;
          >
          > int _msg2_message_i ndex = 0;
          > int _msg1_message_i ndex = 0;[/color]

          These are all illegal (assuming this is the global namespace).
          [color=blue]
          > // lots more
          >
          > struct _MSG2_STATUS // here for demo and lots more of these[/color]

          This is illegal anywhere. From the standard:

          17.4.3.1.2 Global names [lib.global.name s]

          1 Certain sets of names and function signatures are always reserved to
          the implementation:

          --Each name that contains a double underscore __) or begins with an
          underscore followed by an uppercase letter (_lex.key_) is reserved
          to the implementation for any use.

          --Each name that begins with an underscore is reserved to the imple-
          mentation for use as a name in the global namespace.


          I still don't understand your question - can it be demonstrated in a
          smaller, simpler code sample?

          -Kevin
          --
          My email address is valid, but changes periodically.
          To contact me please use the address from a recent posting.

          Comment

          • tom_usenet

            #6
            Re: implementation details

            On 2 Oct 2003 13:47:49 -0700, mpowell_jr@hotm ail.com (MPowell) wrote:
            [color=blue][color=green]
            >> Well, I can fix the errors in the code, but you'll have to explain
            >> what the code is meant to do. What do you want to do with the messages
            >> that you receive? Do you need to perform some action depending on the
            >> type of message you receive?[/color]
            >
            >Consider[/color]

            The below doesn't answer the question, a couple of paragraphs of text
            might.
            [color=blue]
            >
            >#define ID_ERROR_MASK 0x08 // #defined at top of the translation unit
            >#define ID_MASK 0x07 // #defined at top of the translation unit
            >
            >
            >int _msg2_header_er ror_count = 0;
            >int _msg1_header_er ror_count = 0;
            >
            >int _msg2_message_i ndex = 0;
            >int _msg1_message_i ndex = 0;
            >// lots more
            >
            >struct _MSG2_STATUS // here for demo and lots more of these
            >{
            > // for simplicity strip out 'stuff'.
            > unsigned int idx : 1;
            > unsigned int ldx : 32;
            >} MSG2_STATUS;
            >
            >MSG2_STATUS _msg2_message[ 2 ]; // for double buffering[/color]

            I now finally understand what you mean by double buffering - you want
            to keep the last two messages of each type.
            [color=blue]
            >// lots more
            >
            >The Create function will look at the msg_id (which it does) then check
            >for error.
            >
            > if (msg_id & ID_ERROR_MASK) == 0 )
            > {
            > // if no error look at msg_type
            > MSG_HEADER msg_type =
            > (((( msg_id >> 4 ) & ID_MASK ) <<3 )) | ( msg_id &
            >ID_MASK );
            >
            >Lets suppose now the msg_type maps to MSG2_STATUS defined above
            >
            > switch (msg_type)
            > {
            > case _msg2_status: //got a status 2 message
            >
            > // double buffer it
            > i = _msg2_message_i ndex ^ 1;
            > memcpy( &_msg2_messa ge[i], buffer, sizeof(MSG2_STA TUS) );
            > _msg2_message_i ndex ^= 1;
            > _msg2_message_r eady = TRUE;
            > break;
            >
            > case _msg1_status: //got a status 1 message
            >
            > // double buffer it
            > i = _msg1_message_i ndex ^ 1;
            > memcpy( &_msg1_messa ge[i], buffer, sizeof(MSG1_STA TUS) );
            > _msg1_message_i ndex ^= 1;
            > _msg1_message_r eady = TRUE;
            > break;
            > // and so on
            > default:
            > break;[/color]

            The above code doesn't really do anything. Instead, you should
            probably just add the message to a queue and signal a condition
            variable on that queue so that another thread whose job is to process
            these messages can do so.
            [color=blue]
            > }
            > else
            > {
            > switch( msg_id )
            > {
            > case _msg2_header_er ror: //got a status 2 message
            > _msg2_header_er ror_count++;
            > printf (" msg2_header_err or = &d ", msg2_header_err or);
            > break;
            > case _msg1_header_er ror: //got a status 2 message
            > _msg1_header_er ror_count++;
            >
            > // I suspect it'd be prudent to pass in the counters and
            >have values returend by the ++ ostream approach
            > printf (" msg1_header_err or = &d ", msg1_header_err or);
            > break;
            > // and so on
            > default:
            > break;
            > }
            > }
            >
            >So now, double buffer the data,increment a counter, then set a flag -
            >for no errors. For errors, increment an error counter. The current
            >template style approach is certainly more elegant[/color]

            Yes, since all messages can be treated the same - no switch
            statements. Polymorphism is the important thing here though -
            templates are just an implementation detail.
            [color=blue]
            >A separate function within the class should retrieve the most current
            >double buffer data.[/color]

            Does this operate in the same thread? It might be good to put it in
            another thread.

            I suspect (assuming i understand templates) each[color=blue]
            >buffered data will be 'pushed' into a container/holder/??[/color]

            Seems like a good idea.

            and when[color=blue]
            >necessary (a 120hz processing rountine retrieves the latest) retrieved
            >via a call to some function with the template parameter being the
            >appropriate struct.[/color]

            Yes, something like that. You could use the visitor pattern as Gianni
            suggested.
            [color=blue]
            >Lastly, the individual structs form a part of an overall struct. ie
            >struct OVERALL
            >{
            > MSG1_TYPE msg1;
            > MSG2_TYPE msg2;
            > lots more.
            >}
            >
            >A separate function will retrieve the 'overall'.[/color]

            Now I'm confused - aren't the messages separate? What *are* these
            messages? What do they signify? Where do they come from? Some hardware
            device? How are you meant to react to different messages? Why is there
            more than one message type?
            [color=blue]
            >In essence, a template to 'get' the data and hold data for the
            >requestor
            >[color=green]
            >>[color=darkred]
            >> > CMDBase* Create(unsigned char const* buffer)
            >> > {
            >> > //MSG_HEADER* msg_id = reinterpret_cas t<MSG_HEADER*>( buffer);
            >> > MSG_HEADER* msg_id; // only here because reinterpret_cas t error
            >> >complaint
            >> >
            >> > //insert error checking!
            >> > return (m_creators[msg_id->source])(buffer);
            >> > }[/color]
            >>
            >> The above function should go more like this:
            >>
            >> CMDBase* Create(unsigned char const* buffer)
            >> {
            >> MSG_HEADER const* msg_id = reinterpret_cas t<MSG_HEADER
            >> const*>(buffer) ;
            >> map_t::const_it erator i = m_creators.find (msg_id->source);[/color]
            >
            >map_t error ??[/color]

            Whoops, that's meant to be a typedef for the map type that you need to
            add to your class definition. e.g.
            typedef std::map<int, Creator*> map_t;

            Following is some complete compileable code that might help. It
            basically shows how to enqueue all messages onto a queue, and how you
            might go about processing those messages. If you might need different
            processors for the messages in different circumstances, then the
            visitor pattern might be appropriate. This is rather a lot to take in
            if you are quite new to C++, but I hope it helps in any case.

            #include <iostream>
            #include <map>
            #include <queue>

            using namespace std;

            //message queue
            class CMDBase;
            queue<CMDBase*> CMDQueue;

            enum MSG_ID
            {
            msg1_cmd = 0,
            msg1_status = 1,
            msg2_status = 2
            };

            struct MSG_HEADER
            {
            MSG_ID source;
            unsigned int msg_length : 12;
            unsigned int count : 4;
            };

            struct MSG2_STATUS
            {
            MSG_HEADER header;
            unsigned int idx : 1;
            unsigned int jdx : 3;
            unsigned int kdx : 4;
            unsigned int spare : 24;
            unsigned int ldx : 32;
            };

            struct MSG1_STATUS
            {
            MSG_HEADER header;
            unsigned int idx : 1;
            unsigned int jdx : 3;
            unsigned int kdx : 4;
            unsigned int spare : 8;
            };

            struct MSG1_CMD
            {
            MSG_HEADER header;
            unsigned int idx : 1;
            unsigned int jdx : 3;
            };

            class CMDProcessor
            {
            public:
            void process(MSG2_ST ATUS& msg)
            {
            std::cout << "MSG2_STATU S processed\n";
            }

            void process(MSG1_ST ATUS& msg)
            {
            std::cout << "MSG1_STATU S processed\n";
            }

            void process(MSG1_CM D& cmd)
            {
            std::cout << "MSG1_CMD processed\n";
            }
            };

            class CMDBase
            {
            public:
            virtual ~CMDBase(){}
            virtual void process(CMDProc essor* processor) = 0;
            };


            template <class CMD>
            class CMDHolder: public CMDBase
            {
            public:
            CMDHolder(unsig ned char const* buffer)
            {
            memcpy(&m_CMDSt ruct, buffer, sizeof m_CMDStruct);
            }

            virtual void process(CMDProc essor* processor)
            {
            processor->process(m_CMDS truct);
            }

            private:
            CMD m_CMDStruct;
            };

            class CMDFactory
            {
            public:
            static CMDFactory& instance()
            {
            static CMDFactory fact;
            return fact;
            }

            // Register the creator
            template <class T> void Register(int Id)
            {
            m_creators[Id] = CMDCreator<CMDH older<T> >;
            }
            // unregister creator
            bool Unregister( const int& Id )
            {
            return m_creators.eras e( Id ) == 1;
            }

            CMDBase* Create(unsigned char const* buffer)
            {
            MSG_HEADER const* msg_id = reinterpret_cas t<MSG_HEADER
            const*>(buffer) ;
            map_t::const_it erator i = m_creators.find (msg_id->source);

            if (i == m_creators.end( ))
            {
            throw runtime_error(" Invalid source");
            }
            else
            {
            //call create function through pointer.
            return (i->second)(buffer );
            }
            }
            private:
            typedef CMDBase* (*CMDCreator_t) (unsigned char const*);

            template <class T>
            static CMDBase* CMDCreator(unsi gned char const* buffer)
            {
            return new T(buffer);
            }

            typedef std::map<int, CMDCreator_t> map_t;
            map_t m_creators;
            };

            void register_types( )
            {
            CMDFactory::ins tance().Registe r<MSG1_CMD>(0) ;
            CMDFactory::ins tance().Registe r<MSG1_STATUS>( 1);
            CMDFactory::ins tance().Registe r<MSG2_STATUS>( 2);
            }

            size_t ReadData(unsign ed char* buffer, size_t size)
            {
            //generate sample data
            static bool doMsg1 = false;
            void* data;
            size_t actualSize;
            MSG1_STATUS msg1 = {};
            MSG2_STATUS msg2 = {};
            if (doMsg1)
            {
            msg1.header.sou rce = msg1_status;
            data = &msg1;
            actualSize = sizeof msg1;
            }
            else
            {
            msg2.header.sou rce = msg2_status;
            data = &msg2;
            actualSize = sizeof msg2;
            }
            if (size < actualSize)
            throw runtime_error(" buffer too short");
            memcpy(buffer, data, actualSize);
            doMsg1 = !doMsg1;
            return actualSize;
            }

            CMDProcessor processor;

            void processQueue()
            {
            while (!CMDQueue.empt y())
            {
            CMDBase* cmd = CMDQueue.front( );
            CMDQueue.pop();
            cmd->process(&proce ssor);
            delete cmd;
            }
            }

            void fillQueue()
            {
            unsigned char buffer[512];
            ReadData(buffer , 512);
            CMDBase* newCommand = CMDFactory::ins tance().Create( buffer);
            CMDQueue.push(n ewCommand);
            }

            int main ( void )
            {
            register_types( );

            for (int i = 0; i < 5; ++i)
            {
            fillQueue();
            processQueue();
            }

            return EXIT_SUCCESS;
            }

            Comment

            • MPowell

              #7
              Re: implementation details

              tom_usenet <tom_usenet@hot mail.com> wrote in message >
              [color=blue]
              > Following is some complete compileable code that might help. It
              > basically shows how to enqueue all messages onto a queue, and how you
              > might go about processing those messages. If you might need different
              > processors for the messages in different circumstances, then the
              > visitor pattern might be appropriate. This is rather a lot to take in
              > if you are quite new to C++, but I hope it helps in any case.[/color]

              Truly appreaciate the assistance. I'm starting to get a feel for what
              a poster REALLY meant when he highlighted that C is not C++.
              Theoretically I have to change my 'C' style design approach. This was
              truly a lesson in implementation.

              I was reading a post on recommended texts from a Mike Whaler and I've
              since placed some orders.

              Really despise having to continue/drag this post out, nonetheless I've
              got a few more questions on this.


              class CMDProcessor
              {
              public:
              void process(MSG2_ST ATUS& msg)
              {
              std::cout << "MSG2_STATU S processed\n";
              }
              :
              :
              :
              };

              I assume these process functions is where I need to do my 'double
              buffering'?
              The system like any another is riddled with asynchrous processing. In
              other words assume I had this.
              MSG2_STATUS msg2_stat [ 2 ];
              Now fillQueue() and processQueue(); fills and processes a
              "MSG2_STATU S'. I'll copy the data to msg2_stat [ 0 ]. Lets suppose
              now that we're filling (fillQueue()) and processing (processQueue() )
              another MSG2_STATUS BUT while filling or processing a separate 60
              Hertz task (which I have) is getting the most current MSG2_STATUS.
              The 60 Hertz task will grab/read the data in msg2_status[ 0 ] while
              fill (fillQueue()) and process (processQueue() ) writes to msg2_status
              [ 1 ].

              Yes, there's the 'unlikely' event where I'll have a race condition
              where they're both trying to read (the 60 Hertz) and write
              (processQueue) to the same location but i've got a handle on that via
              the mechanisms of the RTOS.
              [color=blue]
              >
              > template <class CMD>
              > class CMDHolder: public CMDBase
              > {
              > public:
              > CMDHolder(unsig ned char const* buffer)
              > {
              > memcpy(&m_CMDSt ruct, buffer, sizeof m_CMDStruct);
              > }
              >
              > virtual void process(CMDProc essor* processor)
              > {
              > processor->process(m_CMDS truct);
              > }
              >
              > private:
              > CMD m_CMDStruct;
              > };
              >
              > class CMDFactory
              > {
              > public:
              > static CMDFactory& instance()
              > {
              > static CMDFactory fact;
              > return fact;
              > }
              >
              > // Register the creator
              > template <class T> void Register(int Id)
              > {
              > m_creators[Id] = CMDCreator<CMDH older<T> >;
              > }
              > // unregister creator
              > bool Unregister( const int& Id )
              > {
              > return m_creators.eras e( Id ) == 1;
              > }
              >
              > CMDBase* Create(unsigned char const* buffer)
              > {
              > MSG_HEADER const* msg_id = reinterpret_cas t<MSG_HEADER
              > const*>(buffer) ;
              > map_t::const_it erator i = m_creators.find (msg_id->source);
              >
              > if (i == m_creators.end( ))
              > {
              > throw runtime_error(" Invalid source");
              > }
              > else
              > {
              > //call create function through pointer.
              > return (i->second)(buffer );[/color]

              Get an exception here in Visual C.NET. Not sure if a C style try
              catch handler would be ideal
              [color=blue]
              > }
              > }
              > private:
              > typedef CMDBase* (*CMDCreator_t) (unsigned char const*);
              >
              > template <class T>
              > static CMDBase* CMDCreator(unsi gned char const* buffer)
              > {
              > return new T(buffer);
              > }
              >
              > typedef std::map<int, CMDCreator_t> map_t;
              > map_t m_creators;
              > };
              >
              > void register_types( )
              > {
              > CMDFactory::ins tance().Registe r<MSG1_CMD>(0) ;
              > CMDFactory::ins tance().Registe r<MSG1_STATUS>( 1);
              > CMDFactory::ins tance().Registe r<MSG2_STATUS>( 2);
              > }
              >
              > size_t ReadData(unsign ed char* buffer, size_t size)
              > {
              > //generate sample data
              > static bool doMsg1 = false;
              > void* data;
              > size_t actualSize;
              > MSG1_STATUS msg1 = {};
              > MSG2_STATUS msg2 = {};[/color]

              Interesting I had to change above to.
              MSG1_STATUS msg1;
              MSG2_STATUS msg2;

              VC.NET complier complained that 'local function definitions are
              illegal
              [color=blue]
              > if (doMsg1)
              > {
              > msg1.header.sou rce = msg1_status;
              > data = &msg1;
              > actualSize = sizeof msg1;
              > }
              > else
              > {
              > msg2.header.sou rce = msg2_status;
              > data = &msg2;
              > actualSize = sizeof msg2;
              > }
              > if (size < actualSize)
              > throw runtime_error(" buffer too short");
              > memcpy(buffer, data, actualSize);
              > doMsg1 = !doMsg1;
              > return actualSize;
              > }
              >
              > CMDProcessor processor;
              >
              > void processQueue()
              > {
              > while (!CMDQueue.empt y())
              > {
              > CMDBase* cmd = CMDQueue.front( );
              > CMDQueue.pop();
              > cmd->process(&proce ssor);
              > delete cmd;
              > }
              > }[/color]
              I suspect I understand the simplistic version of queues. The
              cmd->process and delete cmd should be placed outside the while loop??
              Each element that gets 'popped' off the queue results in a call to
              cmd-process/delete cmd. so now assume two bytes.

              BYTE1. while !empty 1 results in : <- pop .. cmd->process(byte 1)
              BYTE2. while !empty 2 results in : <- pop .. cmd->process(byte 2)
              &process is in effect a pass through to
              processor->process(m_CMDS truct);?
              I missed how the CMD type was passed in?


              Thanks again.

              Comment

              Working...