// Copyright(c) 2018, Intel Corporation
//
// Redistribution  and  use  in source  and  binary  forms,  with  or  without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of  source code  must retain the  above copyright notice,
//   this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright notice,
//   this list of conditions and the following disclaimer in the documentation
//   and/or other materials provided with the distribution.
// * Neither the name  of Intel Corporation  nor the names of its contributors
//   may be used to  endorse or promote  products derived  from this  software
//   without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,  BUT NOT LIMITED TO,  THE
// IMPLIED WARRANTIES OF  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED.  IN NO EVENT  SHALL THE COPYRIGHT OWNER  OR CONTRIBUTORS BE
// LIABLE  FOR  ANY  DIRECT,  INDIRECT,  INCIDENTAL,  SPECIAL,  EXEMPLARY,  OR
// CONSEQUENTIAL  DAMAGES  (INCLUDING,  BUT  NOT LIMITED  TO,  PROCUREMENT  OF
// SUBSTITUTE GOODS OR SERVICES;  LOSS OF USE,  DATA, OR PROFITS;  OR BUSINESS
// INTERRUPTION)  HOWEVER CAUSED  AND ON ANY THEORY  OF LIABILITY,  WHETHER IN
// CONTRACT,  STRICT LIABILITY,  OR TORT  (INCLUDING NEGLIGENCE  OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,  EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.

/**
 * @file types.h
 * @brief Type definitions for FPGA API
 *
 * OPAE uses the three opaque types fpga_properties, fpga_token, and
 * fpga_handle to create a hierarchy of objects that can be used to enumerate,
 * reference, acquire, and query FPGA resources. This object model is designed
 * to be extensible to account for different FPGA architectures and platforms.
 *
 * Initialization
 * --------------
 * OPAEs management of the opaque types `fpga_properties`,
 * `fpga_token`, and `fpga_handle` relies on the proper initialization of
 * variables of these types. In other words, before doing anything with a
 * variable of one of these opaque types, you need to first initialize them.
 *
 * The respective functions that initialize opaque types are:
 *
 *   * fpgaGetProperties() and fpgaCloneProperties() for `fpga_properties`
 *   * fpgaEnumerate() and fpgaCloneToken() for `fpga_token`
 *   * fpgaOpen() for `fpga_handle`
 *
 * This should intuitively make sense - fpgaGetProperties() creates
 * `fpga_properties` objects, fpgaEnumerate() creates `fpga_token` objects,
 * fpgaOpen() creates `fpga_handle` objects, and fpgaCloneProperties() and
 * fpgaCloneToken() clone (create) `fpga_properties` and `fpga_token` objects,
 * respectively.
 *
 * Since these opaque types are interpreted as pointers (they are typedef'd to
 * a `void *`), passing an uninitialized opaque type into any function except
 * the respective initailzation function will result in undefined behaviour,
 * because OPAE will try to follow an invalid pointer. Undefined behaviour in
 * this case may include an unexpected error code, or an application crash.
 *
 */

#ifndef __FPGA_TYPES_H__
#define __FPGA_TYPES_H__

#include <stdint.h>
#include <stddef.h>
#include <stdbool.h>
#include <opae/types_enum.h>

/**
 * Object for expressing FPGA resource properties
 *
 * `fpga_properties` objects encapsulate all enumerable information about an
 * FPGA resources. They can be used for two purposes: selective enumeration
 * (discovery) and querying information about existing resources.
 *
 * For selective enumeration, usually an empty `fpga_properties` object is
 * created (using fpgaGetProperties()) and then populated with the desired
 * criteria for enumeration. An array of `fpga_properties` can then be passed
 * to fpgaEnumerate(), which will return a list of `fpga_token` objects
 * matching these criteria.
 *
 * For querying properties of existing FPGA resources, fpgaGetProperties() can
 * also take an `fpga_token` and will return an `fpga_properties` object
 * populated with information about the resource referenced by that token.
 *
 * After use, `fpga_properties` objects should be destroyed using
 * fpga_destroyProperties() to free backing memory used by the
 * `fpga_properties` object.
 */
typedef void *fpga_properties;

/**
 * Token for referencing FPGA resources
 *
 * An `fpga_token` serves as a reference to a specific FPGA resource present in
 * the system. Holding an `fpga_token` does not constitute ownership of the
 * FPGA resource - it merely allows the user to query further information about
 * a resource, or to use fpgaOpen() to acquire ownership.
 *
 * `fpga_token`s are usually returned by fpgaEnumerate() or
 * fpgaPropertiesGetParent(), and used by fpgaOpen() to acquire ownership and
 * yield a handle to the resource. Some API calls also take `fpga_token`s as
 * arguments if they don't require ownership of the resource in question.
 */
typedef void *fpga_token;

/**
 * Handle to an FPGA resource
 *
 * A valid `fpga_handle` object, as populated by fpgaOpen(), denotes ownership
 * of an FPGA resource. Note that ownership can be exclusive or shared,
 * depending on the flags used in fpgaOpen(). Ownership can be released by
 * calling fpgaClose(), which will render the underlying handle invalid.
 *
 * Many OPAE C API functions require a valid token (which is synonymous with
 * ownership of the resource).
 */
typedef void *fpga_handle;

/**
 * Globally unique identifier (GUID)
 *
 * GUIDs are used widely within OPAE for helping identify FPGA resources. For
 * example, every FPGA resource has a `guid` property, which can be (and in the
 * case of FPGA_ACCELERATOR resource primarily is) used for enumerating a resource of a
 * specific type.
  *
 * `fpga_guid` is compatible with libuuid's uuid_t, so users can use libuuid
 * functions like uuid_parse() to create and work with GUIDs.
 */
typedef uint8_t fpga_guid[16];

/**
 * Semantic version
 *
 * Data structure for expressing version identifiers following the semantic
 * versioning scheme. Used in various properties for tracking component
 * versions.
 */
typedef struct {
	uint8_t major;        /**< Major version */
	uint8_t minor;        /**< Minor version */
	uint16_t patch;       /**< Revision or patchlevel */
} fpga_version;

/** Handle to an event object
 *
 * OPAE provides an interface to asynchronous events that can be generated by
 * different FPGA resources. The event API provides functions to register for
 * these events; associated with every event a process has registered for is an
 * `fpga_event_handle`, which encapsulates the OS-specific data structure for
 * event objects.
 *
 * After use, `fpga_event_handle` objects should be destroyed using
 * fpgaDestroyEventHandle() to free backing memory used by the
 * `fpga_event_handle` object.
 */
typedef void *fpga_event_handle;

/** Information about an error register
 *
 * This data structure captures information about an error register exposed by
 * an accelerator resource. The error API provides functions to retrieve these
 * information structures from a particular resource.
 */
#define FPGA_ERROR_NAME_MAX 64
struct fpga_error_info {
	char name[FPGA_ERROR_NAME_MAX];   /** name of the error */
	bool can_clear;                   /** whether error can be cleared */
};

/** Object pertaining to an FPGA resource as identified by a unique name
 *
 * An `fpga_object` represents either a device attribute or a container of
 * attributes. Similar to filesystems, a '/' may be used to seperate objects in
 * an object hierarchy. Once on object is acquired, it may be used to read or
 * write data in a resource attribute or to query sub-objects if the object is
 * a container object. The data in an object is buffered and will be kept
 * around until the object is destroyed. Additionally, the data in an attribute
 * can by synchronized from the owning resource using the FPGA_OBJECT_SYNC flag
 * during read operations.  The name identifying the object is unique with
 * respect to the resource that owns it. A parent resource may be identified by
 * an `fpga_token` object, by an `fpga_handle` object, or another `fpga_object`
 * object. If a handle object is used when opening the object, then the object
 * is opened with read-write access. Otherwise, the object is read-only.
 */
typedef void *fpga_object;

/** FPGA Metric string size
 *
 *
 */
#define FPGA_METRIC_STR_SIZE   256
/** Metric value union
 *
 *
 */
typedef union {
	uint64_t   ivalue;  // Metric integer value
	double     dvalue;  // Metric double value
	float      fvalue;  // Metric float value
	bool       bvalue;  // Metric bool value
} metric_value;


/** Metric info struct
 *
 *
 */
typedef struct fpga_metric_info {
	uint64_t metric_num;                         // Metric index num
	fpga_guid metric_guid;                       // Metric guid
	char qualifier_name[FPGA_METRIC_STR_SIZE];   // Metric full name
	char group_name[FPGA_METRIC_STR_SIZE];       // Metric group name
	char metric_name[FPGA_METRIC_STR_SIZE];      // Metric name
	char metric_units[FPGA_METRIC_STR_SIZE];     // Metric units
	enum fpga_metric_datatype metric_datatype;   // Metric data type
	enum fpga_metric_type metric_type;           // Metric group type
} fpga_metric_info;

/** Metric struct
 *
 *
 */
typedef struct fpga_metric {
	uint64_t metric_num;    // Metric index num
	metric_value value;     // Metric value
	bool isvalid;           // Metric value is valid
} fpga_metric;


/** Threshold struct
 *
 *
 */
typedef struct threshold {
	char threshold_name[FPGA_METRIC_STR_SIZE]; // Threshold name
	uint32_t is_valid;                         // Threshold is valid
	double value;                              // Threshold value
} threshold;

typedef struct metric_threshold {
	char metric_name[FPGA_METRIC_STR_SIZE];        // Metric Threshold name
	threshold upper_nr_threshold;                  // Upper Non-Recoverable Threshold
	threshold upper_c_threshold;                   // Upper Critical Threshold
	threshold upper_nc_threshold;                  // Upper Non-Critical Threshold
	threshold lower_nr_threshold;                  // Lower Non-Recoverable Threshold
	threshold lower_c_threshold;                   // Lower Critical Threshold
	threshold lower_nc_threshold;                  // Lower Non-Critical Threshold
	threshold hysteresis;                          // Hysteresis
} metric_threshold;

#endif // __FPGA_TYPES_H__
