#ifndef _VCA_OD_H
#define _VCA_OD_H

#ifndef __RTL__
#include <inttypes.h>
#else /*__RTL__*/
#include <linux/types.h>
#endif /*__RTL__*/

#include "ul_gavl.h"
#include "ul_dbuff.h"
#include "sui_dinfo.h"

#define BOOLEAN             unsigned char
#define INTEGER8            signed char
#define INTEGER16           signed short
#define INTEGER32           signed long
#define UNSIGNED8           unsigned char
#define UNSIGNED16          unsigned short
#define UNSIGNED32          unsigned long
#define REAL32
#define VISIBLE_STRING
#define OCTET_STRING
#define UNICODE_STRING
#define TIME_OF_DAY
#define TIME_DIFFERENCE
#define INTEGER24
#define REAL64
#define INTEGER40
#define INTEGER48
#define INTEGER56
#define INTEGER64           signed long long
#define UNSIGNED24
#define UNSIGNED40
#define UNSINGED48
#define UNSINGED56
#define UNSIGNED64          unsigned long long

enum vcaod_access_attrs { vcaod_access_UNDEF = 0, vcaod_access_CONST, vcaod_access_RO, vcaod_access_RW, vcaod_access_RWR, vcaod_access_RWW, vcaod_access_WO};
enum vcaod_object_types { vcaod_object_type_UNDEF=0, vcaod_object_type_DOMAIN=2, vcaod_object_type_DEFTYPE=5, 
                        vcaod_object_type_DEFSTRUCT=6, vcaod_object_type_VAR=7, vcaod_object_type_ARRAY=8, 
                        vcaod_object_type_RECORD=9 };

// to have oportunity to use other static buffer len tha 32 bytes
#define vcaod_dbuff_t ul_dbuff_t
//#define vcaod_dbuff_t ul_dbuff64_t

/**
 * struct vcaod_root_t - structure representing root of OD
 * @my_root:        object dictionary GAVL tree root
 * Header: vca_od.h
 */
typedef struct vcaod_root_t 
{
    gavl_node_t *my_root;
} vcaod_root_t;

#define VCAOD_OBJECT_NAME_LEN  32
#define VCAOD_OBJECT_FLAG_MANDATORY    (1 << 0)
#define VCAOD_OBJECT_FLAG_PDO_MAPPING  (1 << 1)
#define VCAOD_OBJECT_FLAG_WEAK_DINFO   (1 << 2)
struct vcaod_object_t;

/**
 * struct vcaod_object_t - structure representing single object in OD
 * @my_node:        structure neccessary for storing node in GAVL tree, is NULL for subindicies
 * @index:          index of object
 * @subindex:       subindex of subobject or -1 if object is not subobject
 * @data_type:      can be one of (BOOLEAN, INTEGER8, ...)
 * @object_type:    type of object (DOMAIN=2, DEFTYPE=5, DEFSTRUCT=6, VAR=7, ARRAY=8, RECORD=9)
 * @access:         access attributes (RW, WO, RO, CONST)
 * @flags:          flags can be:
 *                  %VCAOD_OBJECT_FLAG_MANDATORY object is mandatory/optional,
 *                  %VCAOD_OBJECT_FLAG_PDO_MAPPING object is supposed to be PDO mapped,
 *                  %VCAOD_OBJECT_FLAG_WEAK_DINFO @dinfo is weak pointer
 * @name:           textual name of object
 * @subobjects:     pointer to array of subobjects (definition==DEFSTRUCT, RECORD) or NULL
 * @subcnt:         number of subobjects
 * @value:          object values (definition==ARRAY) or single value (other definitions).
 *                  If definition==ARRAY all values have the same length and they are stored sequently in %value
 * @valcnt:         number of values (definition==ARRAY)
 * @dinfo:          If object is PDO mapped or coming from HW, PDOProcessor holds reference to dinfo object used for data transfer. 
 *                  In such a case only weak pointer to dinfo is stored in OD object dinfo parameter. 
 *                  Weak in this context means that dinfo object clears this reference
 *                  Weak pointer is in OD to provide also SDO accesibility to such an object. 
 *                  There are two possibilities on the SDO request.
 *                  1. object is PDO mapped, so it is acessed using weak_dinfo,
 *                  2. object is not PDO mapped, so it is accesed using functions vcaod_get_value() and vcaod_set_value()
 * Header: vca_od.h
 */
typedef struct vcaod_object_t
{
    gavl_node_t my_node;
    
    unsigned index;
    int subindex;
    unsigned char data_type;
    unsigned object_type;
    int access;
    unsigned flags;
    /*unsigned char mandatory;*/
    /*unsigned char pdo_mapping;*/
    char name[VCAOD_OBJECT_NAME_LEN];
    
    /* DEFSTRUCT, RECORD */
    struct vcaod_object_t *subobjects;
    int subcnt;
    
    /* DOMAIN, DEFTYPE, VAR (valcnt == 1) */
    /* ARRAY can have more values (valcnt >= 1) */
    vcaod_dbuff_t value;
    int valcnt;
    
    sui_dinfo_t    *dinfo;
    
} vcaod_object_t;

//enum {vcaodErrObjectNotFound=-1};

/**
 * _vcaod_find_object - finds object in OD. This function is not a part of the SDO API
 * @odroot:     object dictionary
 * @ix:         object index
 * @subix:      object subindex, ignored if object does not have subobjects
 * @abort_code: Pointer to the abort code in case of an ERROR. It can be NULL, than it is ignored.
 *              Abort codes are defined in CANopen standart 301 and can be translated to text calling vcasdo_abort_msg().
 *
 * Returns: found object or NULL
 * Header: vca_od.h
 */
vcaod_object_t* _vcaod_find_object(vcaod_root_t *odroot, unsigned ix, unsigned subix, uint32_t *abort_code);

/**
 * vcaod_get_value - reads object value from Object Dictionary and copies them to caller buffer
 * @odroot:     object dictionary
 * @ix:         object index
 * @subix:      object subindex, ignored if object does not have subobjects
 * @buff:       buffer to write requested data
 * @len:        length of the buffer
 * @abort_code: Pointer to the abort code in case of an ERROR. It can be NULL, than it is ignored.
 *              Abort codes are defined in CANopen standart 301 and can be translated to text calling vcasdo_abort_msg().
 *
 * Returns: actual length of object in bytes
 *          negative value in case of an error
 * Header: vca_od.h
 */
int vcaod_get_value(vcaod_root_t *odroot, unsigned ix, unsigned subix, void *buff, int len, uint32_t *abort_code);

/**
 * vcaod_set_value - copies object value from caller's buffer to Object Dictionary
 * @odroot: object dictionary
 * @ix:     object index
 * @subix:  object subindex, ignored if object does not have subobjects
 * @buff:   buffer containing written data
 * @len:    length of the data
 * @abort_code: area to fill the abort code in case of an ERROR. It can be NULL, than it is ignored.
 *              Abort codes are defined in CANopen standart 301 and can be translated to text calling vcasdo_abort_msg().
 *
 * Returns: actual length of object in bytes
 *          negative value in case of an error
 * Header: vca_od.h
 */
int vcaod_set_value(vcaod_root_t *odroot, unsigned ix, unsigned subix, const void *buff, int len, uint32_t *abort_code);

// prenos z OD dal do systemu nebo HW
//int vcaod_approve_value(vcaod_object_t *obj, int subix, const void *buff, int len);
// prenos v opacnem smeru
//int vcaod_acquire_value(vcaod_object_t *obj, int subix, void ** buff, int *len);

/**
 * vcaod_od_free - release all OD memory
 * @odroot:  pointer to the object dictionary root
 * Header: vca_od.h
 */
void vcaod_od_free(vcaod_root_t *odroot);

/**
 * vcaod_load_eds - opens file and create new OD acording to its contens
 * @odroot:     root, which will contain loaded EDS
 * @eds_file_name: name of file to load
 * Returns: zero in case of success
 * Header: vca_od.h
 */
int vcaod_load_eds(vcaod_root_t *odroot, const char* eds_file_name);

/**
 * vcaod_dump_od - debug function, dumps OD to log
 * @odroot:     root, which contains OD
 * Header: vca_od.h
 */
void vcaod_dump_od(vcaod_root_t *odroot);


/**
 * vcaod_get_dinfo_ref - returns reference to dinfo corresponting to @obj
 * @obj:         object from OD
 * @create_weak: if there is no HW dinfo for object, creates temporary dbuff dinfo
 *
 * If @obj allready has its &dinfo assigned vcaod_get_dinfo_ref() returns this pointer, 
 * if it is not function creates new &dinfo object.
 *
 * Returns: pointer to associated dinfo with reference count increased
 *          or NULL if creation fails
 * Header: vca_od.h
 */
sui_dinfo_t *vcaod_get_dinfo_ref(vcaod_object_t *obj, int create_weak);

/**
 * vcaod_connect_hw_dinfos_to_OD - reads HW module dinfos and connect them to appropriate objects in OD
 * @odroot:     root, which contains OD
 * Header: vca_od.h
 */
void vcaod_connect_hw_dinfos_to_OD(vcaod_root_t *odroot);
#endif
