
/*
 *******************************************************************************
 *  Copyright (c) 2010-2022 VATICS(KNERON) Inc. All rights reserved.
 *
 *  +-----------------------------------------------------------------+
 *  | THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY ONLY BE USED |
 *  | AND COPIED IN ACCORDANCE WITH THE TERMS AND CONDITIONS OF SUCH  |
 *  | A LICENSE AND WITH THE INCLUSION OF THE THIS COPY RIGHT NOTICE. |
 *  | THIS SOFTWARE OR ANY OTHER COPIES OF THIS SOFTWARE MAY NOT BE   |
 *  | PROVIDED OR OTHERWISE MADE AVAILABLE TO ANY OTHER PERSON. THE   |
 *  | OWNERSHIP AND TITLE OF THIS SOFTWARE IS NOT TRANSFERRED.        |
 *  |                                                                 |
 *  | THE INFORMATION IN THIS SOFTWARE IS SUBJECT TO CHANGE WITHOUT   |
 *  | ANY PRIOR NOTICE AND SHOULD NOT BE CONSTRUED AS A COMMITMENT BY |
 *  | VATICS(KNERON) INC.                                             |
 *  +-----------------------------------------------------------------+
 *
 *******************************************************************************
 */
/**
 * @file        vmf_nnm_inference_app.h
 * @brief       for kdp2 fw only - inference structures and functions
 *
 * @copyright   Copyright (c) 2022 Kneron Inc. All rights reserved.
 */

#ifndef VMF_NNM_INFERENCE_H
#define VMF_NNM_INFERENCE_H
#include "kp_struct.h"
#include "ncpu_gen_struct.h"

/**
 * @brief prototype for inference entry callback function
 *
 * @param[in] num_input_buf number of input buffer in list
 * @param[in] inf_input_buf_list transmitted from host SW = list of (header + image, input buffer for inference)
 *
 */
typedef void (*VMF_NNM_INFERENCE_APP_CALLBACK_T)(int num_input_buf, void **inf_input_buf_list);

/**
 * @brief prototype for inference result callback function
 *
 * @param[out] status used to indicate exeuction status, refer to KP_API_RETURN_CODE.
 * @param[out] inf_result_buf used to carry inference result back to host SW = header + inferernce result (from ncpu/npu)
 * @param[out] ncpu_result_buf post-processing result buffer done by ncpu
 *
 */
typedef void (*VMF_NNM_INFERENCE_APP_RESULT_CALLBACK_T)(int status, void *inf_result_buf, int inf_result_buf_size, void *ncpu_result_buf);

/**
 * @brief prototype for pre-process function
 * @param[in] model_id model id
 * @param[in] pKdpImage KDP image structure
 */
typedef int (*VMF_NNM_INFERENCE_PRE_PROC_FUNC_T)(int model_id, kdp_image_t *pKdpImage);

/**
 * @brief prototype for post-process function
 * @param[in] model_id model id
 * @param[in] pKdpImage KDP image structure
 */
typedef int (*VMF_NNM_INFERENCE_POST_PROC_FUNC_T)(int model_id, kdp_image_t *pKdpImage);

typedef struct
{
    int32_t pad_top;    /**< padding pixel number at the top of image */
    int32_t pad_bottom; /**< padding pixel number at the bottom of image */
    int32_t pad_left;   /**< padding pixel number at the left of image */
    int32_t pad_right;  /**< padding pixel number at the right of image */
} VMF_NNM_PAD_VALUE_T;

/**
 * @brief structure of image and pre process info
 */
typedef struct
{
    void *image_buf;                    /**< image buffer address */
    uint32_t image_width;               /**< width in pixel */
    uint32_t image_height;              /**< height in pixel */
    uint32_t image_channel;             /**< channel count */
    uint32_t image_resize;              /**< for resize image, part of pre-process, kp_resize_mode_t */
    uint32_t image_padding;             /**< for padding image, part of pre-process, kp_padding_mode_t */
    uint32_t image_format;              /**< for color space conversion, part of pre-process, kp_image_format_t */
    uint32_t image_norm;                /**< for data normalization, part of pre-process, kp_normalize_mode_t */
    uint32_t image_rotation;            /**< for data rotation, part of pre-process, kp_rotation_mode_t */
    bool enable_crop;                   /**< if true then 'crop_area' should be set */
    VMF_NNM_INF_CROP_BOX_T crop_area;   /**< inference cropping area */
    VMF_NNM_PAD_VALUE_T *pad_value;     /**< pad_value for ncpu/npu pre-processing */

    bool bypass_pre_proc;               /**< if true, then all pre-process will be ignored */
    uint32_t image_buf_size;            /**< only used for bypass pre-process */
} VMF_NNM_IMG_PRE_PROC_T;

/**
 * @brief inference configuration
 */
typedef struct
{
    /* input */
    int num_image;                                                  /**< number of available images in image_list */
    VMF_NNM_IMG_PRE_PROC_T image_list[MAX_INPUT_NODE_COUNT];        /**< list of images and pre process info */
    int model_id;                                                   /**< target inference model ID */
    bool enable_raw_output;                                         /**< should be true if ncpu does not do post-process */

    /* parallel control */
    bool enable_parallel;                                           /**< only works for single model and post-process in ncpu */
    VMF_NNM_INFERENCE_APP_RESULT_CALLBACK_T result_callback;        /**< callback function for parallel mode */

    /* buffers */
    int inf_result_buf_size;                                        /**< size of inf_result_buf */
    void *inf_result_buf;                                           /**< works for enable_parallel=true to carry it back to user callback function */
    void *ncpu_result_buf;                                          /**< for ncpu/npu to output, if enable_parallel=true, it will be passed to 'VMF_INFERENCE_APP_RESULT_CALLBACK_T' */
    void *user_define_data;                                         /**< user define data for ncpu/npu pre-processing */

    /* pre/post process function */
    VMF_NNM_INFERENCE_PRE_PROC_FUNC_T pre_proc_func;                /**< user define pre-processing function */
    VMF_NNM_INFERENCE_POST_PROC_FUNC_T post_proc_func;              /**< user define post-processing function, only works when enable_raw_output is false */
} VMF_NNM_INFERENCE_APP_CONFIG_T;

/**
 * @brief configuration of one time IE execution
 */
typedef struct
{
    unsigned char* src_buffer_addr;     /**< src image virtual address */
    uint32_t src_buffer_size;           /**< src image buffer size */
    uint32_t src_format;                /**< for color space conversion, part of pre-process, kp_image_format_t */
    uint32_t src_width;                 /**< src image width in pixel */
    uint32_t src_height;                /**< src image height in pixel */

    unsigned char* dst_buffer_addr;           /**< dst image virtual address */
    uint32_t dst_buffer_size;           /**< dst image buffer size */
    uint32_t dst_format;                /**< for color space conversion, part of pre-process, kp_image_format_t */
    uint32_t dst_width;                 /**< dst image width in pixel */
    uint32_t dst_height;                /**< dst image height in pixel */
    uint32_t dst_angle;                 /**< dst image angle */

    bool enable_crop;                   /**< if true then 'crop_area' should be set */
    VMF_NNM_INF_CROP_BOX_T crop_area;   /**< inference cropping area */

    uint32_t image_resize;              /**< for resize image, part of pre-process, kp_resize_mode_t */
    uint32_t image_padding;             /**< for padding image, part of pre-process, kp_padding_mode_t */
    uint32_t image_norm;                /**< for data normalization, part of pre-process, kp_normalize_mode_t */
} VMF_NNM_IE_CONFIG_T;

/**
 * @brief a basic descriptor for a input/output node in model
 */
typedef struct
{
    uint32_t    index;              /**< index of node */
    uint32_t    shape_npu_len;      /**< length of npu shape */
    uint32_t    shape_npu[4];       /**< npu shape BxCxHxW (KL630 NEFv1 only support 4-dims shape) */
    uint32_t    data_layout;        /**< npu memory layout */
    float       scale;              /**< scale of node (KL630 NEFv1 only support layer wised quantization param) */
    int32_t     radix;              /**< radix of node (KL630 NEFv1 only support layer wised quantization param) */
} VMF_NNM_MODEL_TENSOR_DESCRIPTOR_T;

/**
 * @brief Model NPU target
 */
typedef enum {
    VMF_NNM_MODEL_NPU_TARGET_KL520 = 0,     /**< This nef should run on KL520 */
    VMF_NNM_MODEL_NPU_TARGET_KL720 ,        /**< This nef should run on KL720 */
    VMF_NNM_MODEL_NPU_TARGET_KL530,         /**< This nef should run on KL530 */
    VMF_NNM_MODEL_NPU_TARGET_KL730,         /**< This nef should run on KL730 */
    VMF_NNM_MODEL_NPU_TARGET_KL630,         /**< This nef should run on KL630 */
    VMF_NNM_MODEL_NPU_TARGET_KL540,         /**< This nef should run on KL540 */
} VMF_NNM_MODEL_NPU_TARGET;

/**
 * @brief Model encrytion Mode
 */
typedef enum {
    VMF_NNM_MODEL_EMC_None = 0,             /**< No Encrytion */
    VMF_NNM_MODEL_EMC_CUSTOM,               /**< Encrytion with Custom Key */
    VMF_NNM_MODEL_EMC_KNNum,                /**< Encrytion with Kn Number */
} VMF_NNM_MODEL_ENC_MODE;

/**
 * @brief Structure for model schema version
 */
typedef struct
{
    uint32_t major_num;             /**< major number of version */
    uint32_t minor_num;             /**< minor number of version */
    uint32_t revision_num;          /**< revision number of version */
} VMF_NNM_MODEL_SCHEMA_VERSION;

/**
 * @brief Structure for NEF header
 */
typedef struct
{
    char *platform;                                 /**< target platform */
    VMF_NNM_MODEL_NPU_TARGET target;                /**< model NPU target */

    uint32_t crc;                                   /**< crc of the NEF */
    uint32_t uuid;                                  /**< uuid of the NEF */
    uint32_t kn_number;                             /**< kn number of specific device */
    VMF_NNM_MODEL_ENC_MODE ency_mode;               /**< encrytion mode of this NEF */

    char *compiler_version;                         /**< compiler version */
    char *toolchain_version;                        /**< toolchain version */
    VMF_NNM_MODEL_SCHEMA_VERSION schema_version;    /**< schema version */

    char *solution_id;                              /**< solution id */
    char *solution_tag;                             /**< solution tag */
} VMF_NNM_MODEL_NEF_HEADER;

/**
 * @brief initialize all components for inference
 *
 * @param[in] app_entry entry function for application
 * @return int refer to KP_API_RETURN_CODE in kp_struct.h
 *
 */
int VMF_NNM_Inference_App_Init(VMF_NNM_INFERENCE_APP_CALLBACK_T app_entry);

/**
 * @brief destroy all components for inference
 * @return int refer to KP_API_RETURN_CODE in kp_struct.h
 *
 */
int VMF_NNM_Inference_App_Destroy(void);

/**
 * @brief do one inference, result_callback works only while enable_parallel = true
 *
 * @param[in] inf_config desired inference configuration
 *
 * @return refer to KP_API_RETURN_CODE in kp_struct.h
 */
int VMF_NNM_Inference_App_Execute(VMF_NNM_INFERENCE_APP_CONFIG_T *inf_config);

/**
 * @brief do one IE execution
 *
 * @param ie_config desired IE configuration
 *
 * @return refer to KP_API_RETURN_CODE in kp_struct.h
 */
int VMF_NNM_IE_Execute(VMF_NNM_IE_CONFIG_T *ie_config);

/**
 * @brief Similar to VMF_NNM_Load_Model_From_File(), and it accepts NEF file path instead of a buffer
 * @param[in] nef_path: NEF model file path
 * @return 0: failes;  1: OK(means 1 model is loaded)
 */
int32_t VMF_NNM_Load_Model_From_File(const char* nef_path);

/**
 * @brief Process all kind of PLUS bulk command
 * @param cmd_buf address of command buffer
 * @return int refer to KP_API_RETURN_CODE in kp_struct.h
 */
int VMF_NNM_Handle_Plus_Command(uint32_t cmd_buf);

/**
 * @brief Get kn number
 * @return uint32_t kn number
 */
uint32_t VMF_NNM_Get_Kn_Number();

/**
 * @brief Get NNM Version
 *
 * @param major NNM major number
 * @param minor NNM minor number
 * @param patch NNM patch number
 * @param build NNM build number
 * @return int refer to KP_API_RETURN_CODE in kp_struct.h
 */
int VMF_NNM_Get_Version(uint32_t *major, uint32_t *minor, uint32_t *patch, uint32_t *build);

/**
 * @brief get firmware boot configuration
 *
 * @param[out] usb_boot 1: usb boot mode, 0: flash boot mode, -1: error
 * @return int refer to KP_API_RETURN_CODE in kp_struct.h
 */
int VMF_NNM_Is_Usb_Boot_Mode(int *usb_boot);


void *VMF_NNM_Inference_Image_Dispatcher_Thread(void *argument);//for dual fifo

/**
 * @brief Get model input tensor/node number
 * @param[in] model_type model type
 * @return input tensor/node number, 0 means failed
 */
int VMF_NNM_MODEL_Get_Input_Tensor_Num(uint32_t model_type);

/**
 * @brief Get model input tensor/node information
 * @param[in] model_type model type
 * @param[in] tensor_idx input tensor index
 * @param[out] tensor_descriptor input tensor information
 * @return 1: success; 0: fail
 */
int VMF_NNM_MODEL_Get_Input_Tensor_Descriptor(uint32_t model_type, uint32_t tensor_idx, VMF_NNM_MODEL_TENSOR_DESCRIPTOR_T *tensor_descriptor);

/**
 * @brief Get model output tensor/node number
 * @param[in] model_type model type
 * @return output tensor/node number, 0 means failed
 */
int VMF_NNM_MODEL_Get_Output_Tensor_Num(uint32_t model_type);

/**
 * @brief Check if a model is loaded in memory
 * @param[in] model_type model type
 * @param[in] tensor_idx output tensor index
 * @param[out] tensor_descriptor output tensor information
 * @return 1: success; 0: fail
 */
int VMF_NNM_MODEL_Get_Output_Tensor_Descriptor(uint32_t model_type, uint32_t tensor_idx, VMF_NNM_MODEL_TENSOR_DESCRIPTOR_T *tensor_descriptor);

/**
 * @brief Get Nef header
 *
 * @param nef_header nef header
 * @return int refer to KP_API_RETURN_CODE in kp_struct.h
 */
int VMF_NNM_MODEL_Get_Nef_Header(VMF_NNM_MODEL_NEF_HEADER *nef_header);

/**
 * @brief Get model id from specific model index
 *
 * @param[in] model_index model index
 * @param[out] model_id model id
 * @return int refer to KP_API_RETURN_CODE in kp_struct.h
 */
int VMF_NNM_MODEL_Get_Id_From_Index(uint32_t model_index, uint32_t *model_id);

/**
 * @brief Get model version of specific model id
 *
 * @param[in] model_id model id
 * @param[out] model_version version of the model
 * @return int refer to KP_API_RETURN_CODE in kp_struct.h
 */
int VMF_NNM_MODEL_Get_Version_From_Id(uint32_t model_id, uint32_t *model_version);

#endif //VMF_NNM_INFERENCE_H
