#ifndef _VCA_PDO_H
#define _VCA_PDO_H

#include "ul_evcbase.h"
#include "ul_gavl.h"
#include "ul_dbuff.h"
#include "vca_od.h"
#include "sui_dinfo_dbuff.h"

struct sui_dinfo_t;

/**
 * struct vcapdolst_mapping_t - structure representing mapping of sigle object in PDO
 * @object:     pointer to the mapped object
 * @start:      bit offset of object value in PDO
 * @len:        bit length of object value in PDO
 * @dinfo:       pointer to object data source. 
 *              Every PDO can be read/written through @dinfo to the OD or to hardware.
 *              Actualy there is no other way for PDO object to do that.
 */
typedef struct vcapdo_mapping_t 
{
    vcaod_object_t *object;
    unsigned char   start;
    unsigned char   len;
    sui_dinfo_t    *dinfo;
} vcapdo_mapping_t;

enum {vcapdoFlagNotValid=0, vcapdoFlagRPDO, vcapdoFlagRTRAllowed, vcapdoFlag29BitId, 
      vcapdoFlagTransReserved, vcapdoFlagTransSynchronous, vcapdoFlagTransCyclic, vcapdoFlagTransRTROnly};

/* forward declaration for vcapdolst_object_t to vcaPDOProcessor_t mapping */
struct vcaPDOProcessor_t;

/**
 * struct vcapdolst_object_t - structure representing single PDO object
 * @my_node:         structure necessary for storing node in GAVL tree
 * @pdo_processor:   pointer to PDO processor servicing this PDO
 * @cob_id:          COB ID of PDO
 * @transmition_type:type of PDO transmission according to DS301 table 55
 * @flags:           PDO characteristics and parsed transmission_type
 * @sync_every:      synchronous PDO will be processed every n-th SYNC message
 * @sync_counter:    auxiliary variable for %sync_every
 * @inhibit_time:    minimum gap between two PDO transmissions (multiples of 100 us)
 * @event_timer:     if nonzero, PDO is transmitted every @event_timer ms. 
 *                   Valid only in transmission modes 254, 255.
 *                   (!vcapdoFlagSynchronous && !vcapdoFlagRTROnly)
 * pdo_buff:         buffer for received/transmitted PDO
 * @mapped_cnt:      number of mapped objects in OD
 * @mapped_objects:  array to structures describing mapping details for all mapped objects
 * @rx_hub:          If PDO communication is event driven, appropriate events are connected to this hub
 */
typedef struct vcapdolst_object_t
{
    gavl_node_t my_node;
    struct vcaPDOProcessor_t *pdo_processor;
    
    unsigned long cob_id;
    unsigned char transmition_type;
    unsigned flags;
    unsigned char sync_every;
    unsigned char sync_counter;
    uint16_t inhibit_time;
    uint16_t event_timer;
    /*vcaod_object_t *comm_params;*/
    /*vcaod_object_t *map_params;*/
    unsigned char pdo_buff[8];

    int mapped_cnt;
    vcapdo_mapping_t *mapped_objects;
    
    evc_rx_hub_t  rx_hub;
} vcapdolst_object_t;

//=================================================================
//                  PDO list
//=================================================================
/**
 * struct vcapdolst_root_t - structure representing root of OD
 * @my_root:        object dictionary GAVL tree root
 */
typedef struct vcapdolst_root_t 
{
    gavl_node_t *my_root;
} vcapdolst_root_t;

typedef unsigned long vcapdolst_key_t;

static inline int vcapdolst_cmp_fnc(const vcapdolst_key_t *a, const vcapdolst_key_t *b)
{
  if (*a > *b) return 1;
  if (*a < *b) return -1;
  return 0;
}

GAVL_CUST_NODE_INT_DEC(vcapdolst, vcapdolst_root_t, vcapdolst_object_t, vcapdolst_key_t,
	my_root, my_node, cob_id, vcapdolst_cmp_fnc)
//=================================================================


//=================================================================
//                  vcaPDOProcessor
//=================================================================
typedef int vcapdo_send_to_can_fnc_t(canmsg_t *msg);
/**
 * struct vcaPDOProcessor_t - structure used for PDO communication
 * @pdolst_root:     GAVL containing all defined &vcapdolst_object_t structures
 * @send_to_can_fnc: PDOProcessor should use this function if it needs to send CAN message during processing
 * @od_root:         pointer to used OD (necessary for PDOs creation and initialization in vcaPDOProcessor_createPDOLIst())
 * @dinfo_mgr:       pointer to used DinfoManager (providing HW dinfos during initialization)
 * @node_id:         Node number, optional parameter, if it is specified, default PDO COB-IDs can be assigned
 *                   if they are not specified in EDS. If @node_id is 0, then it is ignored.
 *
 * vcaPDOProcessor is responsible for all PDO related tasks in CANopen device
 */
typedef struct vcaPDOProcessor_t
{
    vcapdolst_root_t pdolst_root;
    vcapdo_send_to_can_fnc_t *send_to_can_fnc;
    vcaod_root_t *od_root;
    //vcaDinfoManager_t *dinfo_mgr;
    int node_id;
} vcaPDOProcessor_t;

/**
 * vcaPDOProcessor_init - vcaPDOProcessor constructor
 * @proc:    pointer to PDO processor to work with
 */
void vcaPDOProcessor_init(vcaPDOProcessor_t *proc); 
/**
 * vcaPDOProcessor_destroy - vcaPDOProcessor destructor
 * @proc:    pointer to PDO processor to work with
 *
 * It releases all PDO objects
 */
void vcaPDOProcessor_destroy(vcaPDOProcessor_t *proc); 

/**
 * vcaPDOProcessor_setOD - assign OD to PDOProcessor
 * @proc:    pointer to PDO processor to work with
 * @od_root: assigned root of Object Dictionary
 */
static inline void vcaPDOProcessor_setOD(vcaPDOProcessor_t *proc, vcaod_root_t *od_root)
{
    if(proc) proc->od_root = od_root;
} 
/*
 * vcaPDOProcessor_setDinfoMgr - assign DinfoManager to PDOProcessor
 */
/*
static inline void vcaPDOProcessor_setDinfoMgr(vcaPDOProcessor_t *proc, vcaDinfoManager_t *dimgr)
{
    if(proc) proc->dinfo_mgr = dimgr;
} 
*/
/**
 * vcaPDOProcessor_createPDOLIst - scans OD and creates all valid PDO structures.
 * @proc:    pointer to PDO processor to work with
 *
 * It also deletes previously created PDO structures (if any).
 * 
 * Return: 0 or negative number in case of an error
 */
int vcaPDOProcessor_createPDOList(vcaPDOProcessor_t *proc); 

/**
 * _vcaPDOProcessor_disconnectDinfoLinks - disconnect all PDOs and their dinfo structures
 * @proc:    pointer to PDO processor to work with
 * 
 * Actualy it only decrements RefCnt, so only dinfos with RefCnt==1 will be deleted
 */
void _vcaPDOProcessor_disconnectDinfoLinks(vcaPDOProcessor_t *proc); 

/**
 * vcaPDOProcessor_makeDinfoLinks - scans defined PDOs and makes necessary data links from PDOs to OD and HW
 * @proc:    pointer to PDO processor to work with
 * 
 * Disconnect all connected dinfos.
 * For each mapped object tries to find appropriate dinfo asking DinfoManager.
 * If DinfoManager returns NULL, thats means, that no HW is connected to this object.
 * In such case function creates dbuff_dinfo for data stored in OD and connect it to mapped PDO.
 */
void vcaPDOProcessor_makeDinfoLinks(vcaPDOProcessor_t *proc); 

/**
 * vcaPDOProcessor_processMsg - tries to process @msg
 * @proc:    pointer to PDO processor to work with
 * @msg:     CAN msg to proceed
 * 
 * Return: zero if msg is processed
 */
int vcaPDOProcessor_processMsg(vcaPDOProcessor_t *proc, canmsg_t *msg); 

//=================================================================

#endif
