3

Here i am trying to make state machine where FsmHdlr should call a appropriate function based on state and event. What i am getting the above error. How to resolve this.

   S16 handleParamReqEvt(void)
    {
      /* doing something */
      RETVALUE(ROK);    
    }

    S16 handleParamRspEvt(param_resp *paramRsp) 
    {
      /* doing something */
      RETVALUE(ROK);    
    }

    typedef enum{
      IDLE,
      CONFIGURED,
      MAX_STATE
    }STATE;

    /* Events in CL */
    typedef enum{
      PARAM_REQ,
      PARAM_RSP 
      MAX_EVENT
    }EVENT;

    param_resp *paramMsg;

    S16 FsmHdlr[MAX_STATE][MAX_EVENT] = 
    {
      {
        /* PHY_STATE_IDLE */
        handleParamReqEvt(),           //error :initializer element is not constant
        handleParamRspEvt(paramMsg)    //error: initializer element is not constant
      }
    };
MAMTHA SRI
  • 31
  • 3

3 Answers3

3

It sounds like you don't actually want to call the function during initialization (which you can't do for static storage variables anyway, as you've discovered). It sounds like you are building a dispatch table. What you want is called a function pointer.

This how one uses function pointers:

int foo(void) { ... }

int main(void) {
   int (*bar)(void) = foo;
   bar();  // Calls foo
}

Since the parameters vary based on the type of the event, a 2d array doesn't make much sense. I'd use the following in your case:

S16 fsm_hdrl_idle_param_req(void)                { ... }
S16 fsm_hdrl_idle_param_rsp(ParamRsp *param_rsp) { ... }
S16 fsm_hdrl_conf_param_req(void)                { ... }
S16 fsm_hdrl_conf_param_rsp(ParamRsp *param_rsp) { ... }

typedef S16 (*FsmReqHdlr)(void);
typedef S16 (*FsmRspHdlr)(ParamRsp*);

typedef struct {
   FsmReqHdlr fsm_req_hdlr;
   FsmRspHdlr fsm_rsp_hdlr;
} FsmHdlrs;

FsmHdlrs fsm_hdlrs_by_state[MAX_STATE] = {
   { fsm_hdrl_idle_param_req, fsm_hdrl_idle_param_rsp },
   { fsm_hdrl_conf_param_req, fsm_hdrl_conf_param_rsp },
};

Later:

fsm_hdlrs_by_state[state].fsm_req_hdlr();

fsm_hdlrs_by_state[state].fsm_rsp_hdlr(param_rsp);
ikegami
  • 367,544
  • 15
  • 269
  • 518
0

You could declare pointer to FsmHdlr[MAX_STATE][MAX_EVENT] as a global variable.

S16 (*FsmHdlr)[MAX_STATE][MAX_EVENT] = NULL;

Somewhere in main function allocate the memory to the global pointer as below.

FsmHdlr = malloc(sizeof(S16 [MAX_STATE][MAX_EVENT]));

Then use memcpy to copy array compound literal as below.

   memcpy(FsmHdlr,
         (S16 [MAX_STATE][MAX_EVENT])    {
             {
                 /* PHY_STATE_IDLE */
                handleParamReqEvt(), handleParamRspEvt(paramMsg) 
             }
           },
         sizeof((S16 [MAX_STATE][MAX_EVENT])    {
             {
                 /* PHY_STATE_IDLE */
                handleParamReqEvt(), handleParamRspEvt(paramMsg) 
             }
           })
   );

And dereference as below,

(*FsmHdlr)[0][0];//to access 1st element
(*FsmHdlr)[0][1];//to access 2nd element
kiran Biradar
  • 12,700
  • 3
  • 19
  • 44
0

You cannot initialise array during declaration using values, what are unknown while compilation. And, your initialization values are values returned by handleParamReqEvt() and handleParamRspEvt(...), what are unknown. I suppose that you are thinking about pointers to these functions, nor function values. So, you should use function names instead of function calls, like below:

S16 FsmHdlr[MAX_STATE][MAX_EVENT] = 
{
  {
    /* PHY_STATE_IDLE */
    handleParamReqEvt,   //initializer element is NOW constant
    handleParamRspEvt    //initializer element is NOW constant
  }
};

Unfortunately, this will not compile because of wrong array type - now it is not S16[][] (or S16**) like before. Additionaly, both pointers are pointers of different types: - first is S16 ( * )(); - second is S16 ( * )(param_resp*); Fortunately, you can store them both as void* (pointer to anything), but remember that you MUST PROPERLY CAST them before usage. For cast simplification you can declare the types of these function using typedef directive.

So, the final form of declaration+initialization and usage will be:

// declaration + initialisation of array
void* FsmHdlr[MAX_STATE][MAX_EVENT] = 
{
  {
    /* PHY_STATE_IDLE */
    handleParamReqEvt,
    handleParamRspEvt
  }
};

// declaration of types
typedef S16 (*reqEvt_ptr)();            //signature of handleParamReqEvt()
typedef S16 (*rspEvt_ptr)(param_resp*); //signature of handleParamRspEvt(param_resp*)

// usage:
// handleParamReqEvt
reqEvt_ptr reqEvt = (reqEvt_ptr)FsmHdlr[/* index here */][PARAM_REQ]; // cast
S16 reqResult = reqEvt(); // call
// handleParamRspEvt
rspEvt_ptr rspEvt = (rspEvt_ptr)FsmHdlr[/* index here */][PARAM_RSP]; // cast
S16 rspResult = rspEvt(/* pointer to paramMsg here */); // call
VillageTech
  • 1,968
  • 8
  • 18