#ifndef VCASDO_FSM_H
#define VCASDO_FSM_H

#include <sys/time.h> 

#include "can.h"
#include "ul_dbuff.h"

#ifdef __cplusplus
extern "C" {
#endif

typedef unsigned char byte;
typedef unsigned short word;

struct vcasdo_fsm_t;
struct canmsg_t;

typedef int (vcasdo_fsm_state_fnc_t)(struct vcasdo_fsm_t *fsm, const struct canmsg_t *in_msg);

enum {sdofsmUploader = 1, sdofsmDownloader};
enum {sdofsmMsgRefuse = -1, sdofsmMsgEat, sdofsmMsgEatAnswer, sdofsmMsgEatError};
enum {sdofsmIdle = 0, sdofsmRun, sdofsmDone, sdofsmError, sdofsmAbort};
enum {sdofsmErrNone = 0, sdofsmErrTimeout, sdofsmErrFsmExists};

/**
 * struct vcasdo_fsm_t - structure representing SDO FSM
 * @server_port:    number of SDO server port (default is 0x580)
 * @client_port:    number of SDO client port (default is 0x600)
 * @node:           SDO node number
 * @index:          index of communicated object
 * @subindex:       subindex of communicated object
 * @type:           type of FSM (%sdofsmUploader = 1, %sdofsmDownloader = 2)
 * @state:          state of SDO (%sdofsmIdle = 0, %sdofsmRun, %sdofsmDone, %sdofsmError, %sdofsmAbort)
 * @err_no:         number of error in state sdofsmError
 * @data:           uploaded/downloaded bytes (see %ul_dbuff.h)
 * @out_msg:        if vcasdo_taste_msg() generates answer, it is stored to the %out_msg
 * @statefnc:       pointer to the state function (internal use)
 * @last_activity:  time of last FSM activity (internal use)
 * @bytes_to_load:  number of stil not uploaded SDO data bytes (internal use)
 * @toggle_bit:     (internal use)
 */
typedef struct vcasdo_fsm_t {
    unsigned server_port, client_port;
    unsigned node;
    unsigned index, subindex;
    
    struct timeval last_activity; 
    
    int bytes_to_load; 
    char toggle_bit;
    
    int type; 
    int state;
    vcasdo_fsm_state_fnc_t *statefnc;

    int err_no;
    
    ul_dbuff_t data;
    canmsg_t out_msg; 
} vcasdo_fsm_t;

vcasdo_fsm_t* vcasdo_init_fsm(vcasdo_fsm_t *fsm, unsigned server_port, unsigned client_port, unsigned node);
void vcasdo_destroy_fsm(vcasdo_fsm_t *fsm);
//__inline__ unsigned vcasdo_get_index(vcasdo_fsm_t *fsm) {return fsm->multiplexor[0] + (fsm->multiplexor[1] << 8);}
//__inline__ unsigned vcasdo_get_subindex(vcasdo_fsm_t *fsm) {return fsm->multiplexor[2];}
int vcasdo_run(vcasdo_fsm_t *fsm);
//int vcasdo_upload(vcasdo_fsm_t *fsm, unsigned index, unsigned subindex);
//int vcasdo_download(vcasdo_fsm_t *fsm, unsigned index, unsigned subindex);
int vcasdo_fsm_taste_msg(vcasdo_fsm_t *fsm, const canmsg_t *msg);

const char* vcasdo_error_msg(int err_no);
            
#ifdef __cplusplus
} /* extern "C"*/
#endif

#endif
