/**
  ******************************************************************************
  * @file    plantnetwork.c
  * @author  AST Embedded Analytics Research Platform
  * @date    Wed Nov  8 17:53:57 2023
  * @brief   AI Tool Automatic Code Generator for Embedded NN computing
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2023 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  ******************************************************************************
  */


#include "plantnetwork.h"
#include "plantnetwork_data.h"

#include "ai_platform.h"
#include "ai_platform_interface.h"
#include "ai_math_helpers.h"

#include "core_common.h"
#include "core_convert.h"

#include "layers.h"



#undef AI_NET_OBJ_INSTANCE
#define AI_NET_OBJ_INSTANCE g_plantnetwork
 
#undef AI_PLANTNETWORK_MODEL_SIGNATURE
#define AI_PLANTNETWORK_MODEL_SIGNATURE     "4b668ac65e6f55050aa6451c8b5bcf31"

#ifndef AI_TOOLS_REVISION_ID
#define AI_TOOLS_REVISION_ID     ""
#endif

#undef AI_TOOLS_DATE_TIME
#define AI_TOOLS_DATE_TIME   "Wed Nov  8 17:53:57 2023"

#undef AI_TOOLS_COMPILE_TIME
#define AI_TOOLS_COMPILE_TIME    __DATE__ " " __TIME__

#undef AI_PLANTNETWORK_N_BATCHES
#define AI_PLANTNETWORK_N_BATCHES         (1)

static ai_ptr g_plantnetwork_activations_map[1] = AI_C_ARRAY_INIT;
static ai_ptr g_plantnetwork_weights_map[1] = AI_C_ARRAY_INIT;



/**  Array declarations section  **********************************************/
/* Array#0 */
AI_ARRAY_OBJ_DECLARE(
  _InputLayer_MatMul_output_0_output_array, AI_ARRAY_FORMAT_FLOAT,
  NULL, NULL, 90, AI_STATIC)
/* Array#1 */
AI_ARRAY_OBJ_DECLARE(
  _Output_MatMul_output_0_weights_array, AI_ARRAY_FORMAT_FLOAT,
  NULL, NULL, 90, AI_STATIC)
/* Array#2 */
AI_ARRAY_OBJ_DECLARE(
  _Activation0_LeakyRelu_output_0_output_array, AI_ARRAY_FORMAT_FLOAT,
  NULL, NULL, 90, AI_STATIC)
/* Array#3 */
AI_ARRAY_OBJ_DECLARE(
  _Layer1_MatMul_output_0_output_array, AI_ARRAY_FORMAT_FLOAT,
  NULL, NULL, 90, AI_STATIC)
/* Array#4 */
AI_ARRAY_OBJ_DECLARE(
  Output_bias_array, AI_ARRAY_FORMAT_FLOAT,
  NULL, NULL, 1, AI_STATIC)
/* Array#5 */
AI_ARRAY_OBJ_DECLARE(
  _Activation1_LeakyRelu_output_0_output_array, AI_ARRAY_FORMAT_FLOAT,
  NULL, NULL, 90, AI_STATIC)
/* Array#6 */
AI_ARRAY_OBJ_DECLARE(
  _Output_MatMul_output_0_output_array, AI_ARRAY_FORMAT_FLOAT,
  NULL, NULL, 1, AI_STATIC)
/* Array#7 */
AI_ARRAY_OBJ_DECLARE(
  output_0_output_array, AI_ARRAY_FORMAT_FLOAT|AI_FMT_FLAG_IS_IO,
  NULL, NULL, 1, AI_STATIC)
/* Array#8 */
AI_ARRAY_OBJ_DECLARE(
  _InputLayer_MatMul_output_0_weights_array, AI_ARRAY_FORMAT_FLOAT,
  NULL, NULL, 180, AI_STATIC)
/* Array#9 */
AI_ARRAY_OBJ_DECLARE(
  _InputLayer_MatMul_output_0_bias_array, AI_ARRAY_FORMAT_FLOAT,
  NULL, NULL, 90, AI_STATIC)
/* Array#10 */
AI_ARRAY_OBJ_DECLARE(
  _Layer1_MatMul_output_0_weights_array, AI_ARRAY_FORMAT_FLOAT,
  NULL, NULL, 8100, AI_STATIC)
/* Array#11 */
AI_ARRAY_OBJ_DECLARE(
  _Layer1_MatMul_output_0_bias_array, AI_ARRAY_FORMAT_FLOAT,
  NULL, NULL, 90, AI_STATIC)
/* Array#12 */
AI_ARRAY_OBJ_DECLARE(
  input_0_output_array, AI_ARRAY_FORMAT_FLOAT|AI_FMT_FLAG_IS_IO,
  NULL, NULL, 2, AI_STATIC)
/**  Tensor declarations section  *********************************************/
/* Tensor #0 */
AI_TENSOR_OBJ_DECLARE(
  _InputLayer_MatMul_output_0_output, AI_STATIC,
  0, 0x0,
  AI_SHAPE_INIT(4, 1, 90, 1, 1), AI_STRIDE_INIT(4, 4, 4, 360, 360),
  1, &_InputLayer_MatMul_output_0_output_array, NULL)

/* Tensor #1 */
AI_TENSOR_OBJ_DECLARE(
  _Output_MatMul_output_0_weights, AI_STATIC,
  1, 0x0,
  AI_SHAPE_INIT(4, 90, 1, 1, 1), AI_STRIDE_INIT(4, 4, 360, 360, 360),
  1, &_Output_MatMul_output_0_weights_array, NULL)

/* Tensor #2 */
AI_TENSOR_OBJ_DECLARE(
  _Activation0_LeakyRelu_output_0_output, AI_STATIC,
  2, 0x0,
  AI_SHAPE_INIT(4, 1, 90, 1, 1), AI_STRIDE_INIT(4, 4, 4, 360, 360),
  1, &_Activation0_LeakyRelu_output_0_output_array, NULL)

/* Tensor #3 */
AI_TENSOR_OBJ_DECLARE(
  _Layer1_MatMul_output_0_output, AI_STATIC,
  3, 0x0,
  AI_SHAPE_INIT(4, 1, 90, 1, 1), AI_STRIDE_INIT(4, 4, 4, 360, 360),
  1, &_Layer1_MatMul_output_0_output_array, NULL)

/* Tensor #4 */
AI_TENSOR_OBJ_DECLARE(
  Output_bias, AI_STATIC,
  4, 0x0,
  AI_SHAPE_INIT(4, 1, 1, 1, 1), AI_STRIDE_INIT(4, 4, 4, 4, 4),
  1, &Output_bias_array, NULL)

/* Tensor #5 */
AI_TENSOR_OBJ_DECLARE(
  _Activation1_LeakyRelu_output_0_output, AI_STATIC,
  5, 0x0,
  AI_SHAPE_INIT(4, 1, 90, 1, 1), AI_STRIDE_INIT(4, 4, 4, 360, 360),
  1, &_Activation1_LeakyRelu_output_0_output_array, NULL)

/* Tensor #6 */
AI_TENSOR_OBJ_DECLARE(
  _Output_MatMul_output_0_output, AI_STATIC,
  6, 0x0,
  AI_SHAPE_INIT(4, 1, 1, 1, 1), AI_STRIDE_INIT(4, 4, 4, 4, 4),
  1, &_Output_MatMul_output_0_output_array, NULL)

/* Tensor #7 */
AI_TENSOR_OBJ_DECLARE(
  output_0_output, AI_STATIC,
  7, 0x0,
  AI_SHAPE_INIT(4, 1, 1, 1, 1), AI_STRIDE_INIT(4, 4, 4, 4, 4),
  1, &output_0_output_array, NULL)

/* Tensor #8 */
AI_TENSOR_OBJ_DECLARE(
  _InputLayer_MatMul_output_0_weights, AI_STATIC,
  8, 0x0,
  AI_SHAPE_INIT(4, 2, 90, 1, 1), AI_STRIDE_INIT(4, 4, 8, 720, 720),
  1, &_InputLayer_MatMul_output_0_weights_array, NULL)

/* Tensor #9 */
AI_TENSOR_OBJ_DECLARE(
  _InputLayer_MatMul_output_0_bias, AI_STATIC,
  9, 0x0,
  AI_SHAPE_INIT(4, 1, 90, 1, 1), AI_STRIDE_INIT(4, 4, 4, 360, 360),
  1, &_InputLayer_MatMul_output_0_bias_array, NULL)

/* Tensor #10 */
AI_TENSOR_OBJ_DECLARE(
  _Layer1_MatMul_output_0_weights, AI_STATIC,
  10, 0x0,
  AI_SHAPE_INIT(4, 90, 90, 1, 1), AI_STRIDE_INIT(4, 4, 360, 32400, 32400),
  1, &_Layer1_MatMul_output_0_weights_array, NULL)

/* Tensor #11 */
AI_TENSOR_OBJ_DECLARE(
  _Layer1_MatMul_output_0_bias, AI_STATIC,
  11, 0x0,
  AI_SHAPE_INIT(4, 1, 90, 1, 1), AI_STRIDE_INIT(4, 4, 4, 360, 360),
  1, &_Layer1_MatMul_output_0_bias_array, NULL)

/* Tensor #12 */
AI_TENSOR_OBJ_DECLARE(
  input_0_output, AI_STATIC,
  12, 0x0,
  AI_SHAPE_INIT(4, 1, 2, 1, 1), AI_STRIDE_INIT(4, 4, 4, 8, 8),
  1, &input_0_output_array, NULL)



/**  Layer declarations section  **********************************************/


AI_TENSOR_CHAIN_OBJ_DECLARE(
  output_0_chain, AI_STATIC_CONST, 4,
  AI_TENSOR_LIST_OBJ_INIT(AI_FLAG_NONE, 2, &Output_bias, &_Output_MatMul_output_0_output),
  AI_TENSOR_LIST_OBJ_INIT(AI_FLAG_NONE, 1, &output_0_output),
  AI_TENSOR_LIST_OBJ_EMPTY,
  AI_TENSOR_LIST_OBJ_EMPTY
)

AI_LAYER_OBJ_DECLARE(
  output_0_layer, 8,
  ELTWISE_TYPE, 0x0, NULL,
  eltwise, forward_eltwise,
  &output_0_chain,
  NULL, &output_0_layer, AI_STATIC, 
  .operation = ai_sum_f32, 
  .buffer_operation = ai_sum_buffer_f32, 
)

AI_TENSOR_CHAIN_OBJ_DECLARE(
  _Output_MatMul_output_0_chain, AI_STATIC_CONST, 4,
  AI_TENSOR_LIST_OBJ_INIT(AI_FLAG_NONE, 1, &_Activation1_LeakyRelu_output_0_output),
  AI_TENSOR_LIST_OBJ_INIT(AI_FLAG_NONE, 1, &_Output_MatMul_output_0_output),
  AI_TENSOR_LIST_OBJ_INIT(AI_FLAG_NONE, 1, &_Output_MatMul_output_0_weights),
  AI_TENSOR_LIST_OBJ_EMPTY
)

AI_LAYER_OBJ_DECLARE(
  _Output_MatMul_output_0_layer, 7,
  DENSE_TYPE, 0x0, NULL,
  dense, forward_dense,
  &_Output_MatMul_output_0_chain,
  NULL, &output_0_layer, AI_STATIC, 
)


AI_STATIC_CONST ai_float _Activation1_LeakyRelu_output_0_nl_params_data[] = { 0.0, 0.009999999776482582, -1 };
AI_ARRAY_OBJ_DECLARE(
    _Activation1_LeakyRelu_output_0_nl_params, AI_ARRAY_FORMAT_FLOAT,
    _Activation1_LeakyRelu_output_0_nl_params_data, _Activation1_LeakyRelu_output_0_nl_params_data, 3, AI_STATIC_CONST)
AI_TENSOR_CHAIN_OBJ_DECLARE(
  _Activation1_LeakyRelu_output_0_chain, AI_STATIC_CONST, 4,
  AI_TENSOR_LIST_OBJ_INIT(AI_FLAG_NONE, 1, &_Layer1_MatMul_output_0_output),
  AI_TENSOR_LIST_OBJ_INIT(AI_FLAG_NONE, 1, &_Activation1_LeakyRelu_output_0_output),
  AI_TENSOR_LIST_OBJ_EMPTY,
  AI_TENSOR_LIST_OBJ_EMPTY
)

AI_LAYER_OBJ_DECLARE(
  _Activation1_LeakyRelu_output_0_layer, 6,
  NL_TYPE, 0x0, NULL,
  nl, forward_relu,
  &_Activation1_LeakyRelu_output_0_chain,
  NULL, &_Output_MatMul_output_0_layer, AI_STATIC, 
  .nl_params = &_Activation1_LeakyRelu_output_0_nl_params, 
)

AI_TENSOR_CHAIN_OBJ_DECLARE(
  _Layer1_MatMul_output_0_chain, AI_STATIC_CONST, 4,
  AI_TENSOR_LIST_OBJ_INIT(AI_FLAG_NONE, 1, &_Activation0_LeakyRelu_output_0_output),
  AI_TENSOR_LIST_OBJ_INIT(AI_FLAG_NONE, 1, &_Layer1_MatMul_output_0_output),
  AI_TENSOR_LIST_OBJ_INIT(AI_FLAG_NONE, 2, &_Layer1_MatMul_output_0_weights, &_Layer1_MatMul_output_0_bias),
  AI_TENSOR_LIST_OBJ_EMPTY
)

AI_LAYER_OBJ_DECLARE(
  _Layer1_MatMul_output_0_layer, 5,
  DENSE_TYPE, 0x0, NULL,
  dense, forward_dense,
  &_Layer1_MatMul_output_0_chain,
  NULL, &_Activation1_LeakyRelu_output_0_layer, AI_STATIC, 
)


AI_STATIC_CONST ai_float _Activation0_LeakyRelu_output_0_nl_params_data[] = { 0.0, 0.009999999776482582, -1 };
AI_ARRAY_OBJ_DECLARE(
    _Activation0_LeakyRelu_output_0_nl_params, AI_ARRAY_FORMAT_FLOAT,
    _Activation0_LeakyRelu_output_0_nl_params_data, _Activation0_LeakyRelu_output_0_nl_params_data, 3, AI_STATIC_CONST)
AI_TENSOR_CHAIN_OBJ_DECLARE(
  _Activation0_LeakyRelu_output_0_chain, AI_STATIC_CONST, 4,
  AI_TENSOR_LIST_OBJ_INIT(AI_FLAG_NONE, 1, &_InputLayer_MatMul_output_0_output),
  AI_TENSOR_LIST_OBJ_INIT(AI_FLAG_NONE, 1, &_Activation0_LeakyRelu_output_0_output),
  AI_TENSOR_LIST_OBJ_EMPTY,
  AI_TENSOR_LIST_OBJ_EMPTY
)

AI_LAYER_OBJ_DECLARE(
  _Activation0_LeakyRelu_output_0_layer, 3,
  NL_TYPE, 0x0, NULL,
  nl, forward_relu,
  &_Activation0_LeakyRelu_output_0_chain,
  NULL, &_Layer1_MatMul_output_0_layer, AI_STATIC, 
  .nl_params = &_Activation0_LeakyRelu_output_0_nl_params, 
)

AI_TENSOR_CHAIN_OBJ_DECLARE(
  _InputLayer_MatMul_output_0_chain, AI_STATIC_CONST, 4,
  AI_TENSOR_LIST_OBJ_INIT(AI_FLAG_NONE, 1, &input_0_output),
  AI_TENSOR_LIST_OBJ_INIT(AI_FLAG_NONE, 1, &_InputLayer_MatMul_output_0_output),
  AI_TENSOR_LIST_OBJ_INIT(AI_FLAG_NONE, 2, &_InputLayer_MatMul_output_0_weights, &_InputLayer_MatMul_output_0_bias),
  AI_TENSOR_LIST_OBJ_EMPTY
)

AI_LAYER_OBJ_DECLARE(
  _InputLayer_MatMul_output_0_layer, 2,
  DENSE_TYPE, 0x0, NULL,
  dense, forward_dense,
  &_InputLayer_MatMul_output_0_chain,
  NULL, &_Activation0_LeakyRelu_output_0_layer, AI_STATIC, 
)


#if (AI_TOOLS_API_VERSION < AI_TOOLS_API_VERSION_1_5)

AI_NETWORK_OBJ_DECLARE(
  AI_NET_OBJ_INSTANCE, AI_STATIC,
  AI_BUFFER_INIT(AI_FLAG_NONE,  AI_BUFFER_FORMAT_U8,
    AI_BUFFER_SHAPE_INIT(AI_SHAPE_BCWH, 4, 1, 34204, 1, 1),
    34204, NULL, NULL),
  AI_BUFFER_INIT(AI_FLAG_NONE,  AI_BUFFER_FORMAT_U8,
    AI_BUFFER_SHAPE_INIT(AI_SHAPE_BCWH, 4, 1, 720, 1, 1),
    720, NULL, NULL),
  AI_TENSOR_LIST_IO_OBJ_INIT(AI_FLAG_NONE, AI_PLANTNETWORK_IN_NUM, &input_0_output),
  AI_TENSOR_LIST_IO_OBJ_INIT(AI_FLAG_NONE, AI_PLANTNETWORK_OUT_NUM, &output_0_output),
  &_InputLayer_MatMul_output_0_layer, 0, NULL)

#else

AI_NETWORK_OBJ_DECLARE(
  AI_NET_OBJ_INSTANCE, AI_STATIC,
  AI_BUFFER_ARRAY_OBJ_INIT_STATIC(
  	AI_FLAG_NONE, 1,
    AI_BUFFER_INIT(AI_FLAG_NONE,  AI_BUFFER_FORMAT_U8,
      AI_BUFFER_SHAPE_INIT(AI_SHAPE_BCWH, 4, 1, 34204, 1, 1),
      34204, NULL, NULL)
  ),
  AI_BUFFER_ARRAY_OBJ_INIT_STATIC(
  	AI_FLAG_NONE, 1,
    AI_BUFFER_INIT(AI_FLAG_NONE,  AI_BUFFER_FORMAT_U8,
      AI_BUFFER_SHAPE_INIT(AI_SHAPE_BCWH, 4, 1, 720, 1, 1),
      720, NULL, NULL)
  ),
  AI_TENSOR_LIST_IO_OBJ_INIT(AI_FLAG_NONE, AI_PLANTNETWORK_IN_NUM, &input_0_output),
  AI_TENSOR_LIST_IO_OBJ_INIT(AI_FLAG_NONE, AI_PLANTNETWORK_OUT_NUM, &output_0_output),
  &_InputLayer_MatMul_output_0_layer, 0, NULL)

#endif	/*(AI_TOOLS_API_VERSION < AI_TOOLS_API_VERSION_1_5)*/


/******************************************************************************/
AI_DECLARE_STATIC
ai_bool plantnetwork_configure_activations(
  ai_network* net_ctx, const ai_network_params* params)
{
  AI_ASSERT(net_ctx)

  if (ai_platform_get_activations_map(g_plantnetwork_activations_map, 1, params)) {
    /* Updating activations (byte) offsets */
    
    _InputLayer_MatMul_output_0_output_array.data = AI_PTR(g_plantnetwork_activations_map[0] + 0);
    _InputLayer_MatMul_output_0_output_array.data_start = AI_PTR(g_plantnetwork_activations_map[0] + 0);
    
    _Activation0_LeakyRelu_output_0_output_array.data = AI_PTR(g_plantnetwork_activations_map[0] + 0);
    _Activation0_LeakyRelu_output_0_output_array.data_start = AI_PTR(g_plantnetwork_activations_map[0] + 0);
    
    _Layer1_MatMul_output_0_output_array.data = AI_PTR(g_plantnetwork_activations_map[0] + 360);
    _Layer1_MatMul_output_0_output_array.data_start = AI_PTR(g_plantnetwork_activations_map[0] + 360);
    
    _Activation1_LeakyRelu_output_0_output_array.data = AI_PTR(g_plantnetwork_activations_map[0] + 0);
    _Activation1_LeakyRelu_output_0_output_array.data_start = AI_PTR(g_plantnetwork_activations_map[0] + 0);
    
    _Output_MatMul_output_0_output_array.data = AI_PTR(g_plantnetwork_activations_map[0] + 360);
    _Output_MatMul_output_0_output_array.data_start = AI_PTR(g_plantnetwork_activations_map[0] + 360);
    
    return true;
  }
  AI_ERROR_TRAP(net_ctx, INIT_FAILED, NETWORK_ACTIVATIONS);
  return false;
}



/******************************************************************************/
AI_DECLARE_STATIC
ai_bool plantnetwork_configure_weights(
  ai_network* net_ctx, const ai_network_params* params)
{
  AI_ASSERT(net_ctx)

  if (ai_platform_get_weights_map(g_plantnetwork_weights_map, 1, params)) {
    /* Updating weights (byte) offsets */
    
    _Output_MatMul_output_0_weights_array.format |= AI_FMT_FLAG_CONST;
    _Output_MatMul_output_0_weights_array.data = AI_PTR(g_plantnetwork_weights_map[0] + 0);
    _Output_MatMul_output_0_weights_array.data_start = AI_PTR(g_plantnetwork_weights_map[0] + 0);
    
    Output_bias_array.format |= AI_FMT_FLAG_CONST;
    Output_bias_array.data = AI_PTR(g_plantnetwork_weights_map[0] + 360);
    Output_bias_array.data_start = AI_PTR(g_plantnetwork_weights_map[0] + 360);
    
    _InputLayer_MatMul_output_0_weights_array.format |= AI_FMT_FLAG_CONST;
    _InputLayer_MatMul_output_0_weights_array.data = AI_PTR(g_plantnetwork_weights_map[0] + 364);
    _InputLayer_MatMul_output_0_weights_array.data_start = AI_PTR(g_plantnetwork_weights_map[0] + 364);
    
    _InputLayer_MatMul_output_0_bias_array.format |= AI_FMT_FLAG_CONST;
    _InputLayer_MatMul_output_0_bias_array.data = AI_PTR(g_plantnetwork_weights_map[0] + 1084);
    _InputLayer_MatMul_output_0_bias_array.data_start = AI_PTR(g_plantnetwork_weights_map[0] + 1084);
    
    _Layer1_MatMul_output_0_weights_array.format |= AI_FMT_FLAG_CONST;
    _Layer1_MatMul_output_0_weights_array.data = AI_PTR(g_plantnetwork_weights_map[0] + 1444);
    _Layer1_MatMul_output_0_weights_array.data_start = AI_PTR(g_plantnetwork_weights_map[0] + 1444);
    
    _Layer1_MatMul_output_0_bias_array.format |= AI_FMT_FLAG_CONST;
    _Layer1_MatMul_output_0_bias_array.data = AI_PTR(g_plantnetwork_weights_map[0] + 33844);
    _Layer1_MatMul_output_0_bias_array.data_start = AI_PTR(g_plantnetwork_weights_map[0] + 33844);
    
    return true;
  }
  AI_ERROR_TRAP(net_ctx, INIT_FAILED, NETWORK_WEIGHTS);
  return false;
}


/**  PUBLIC APIs SECTION  *****************************************************/


AI_DEPRECATED
AI_API_ENTRY
ai_bool ai_plantnetwork_get_info(
  ai_handle network, ai_network_report* report)
{
  ai_network* net_ctx = AI_NETWORK_ACQUIRE_CTX(network);

  if (report && net_ctx)
  {
    ai_network_report r = {
      .model_name        = AI_PLANTNETWORK_MODEL_NAME,
      .model_signature   = AI_PLANTNETWORK_MODEL_SIGNATURE,
      .model_datetime    = AI_TOOLS_DATE_TIME,
      
      .compile_datetime  = AI_TOOLS_COMPILE_TIME,
      
      .runtime_revision  = ai_platform_runtime_get_revision(),
      .runtime_version   = ai_platform_runtime_get_version(),

      .tool_revision     = AI_TOOLS_REVISION_ID,
      .tool_version      = {AI_TOOLS_VERSION_MAJOR, AI_TOOLS_VERSION_MINOR,
                            AI_TOOLS_VERSION_MICRO, 0x0},
      .tool_api_version  = AI_STRUCT_INIT,

      .api_version            = ai_platform_api_get_version(),
      .interface_api_version  = ai_platform_interface_api_get_version(),
      
      .n_macc            = 9091,
      .n_inputs          = 0,
      .inputs            = NULL,
      .n_outputs         = 0,
      .outputs           = NULL,
      .params            = AI_STRUCT_INIT,
      .activations       = AI_STRUCT_INIT,
      .n_nodes           = 0,
      .signature         = 0x0,
    };

    if (!ai_platform_api_get_network_report(network, &r)) return false;

    *report = r;
    return true;
  }
  return false;
}


AI_API_ENTRY
ai_bool ai_plantnetwork_get_report(
  ai_handle network, ai_network_report* report)
{
  ai_network* net_ctx = AI_NETWORK_ACQUIRE_CTX(network);

  if (report && net_ctx)
  {
    ai_network_report r = {
      .model_name        = AI_PLANTNETWORK_MODEL_NAME,
      .model_signature   = AI_PLANTNETWORK_MODEL_SIGNATURE,
      .model_datetime    = AI_TOOLS_DATE_TIME,
      
      .compile_datetime  = AI_TOOLS_COMPILE_TIME,
      
      .runtime_revision  = ai_platform_runtime_get_revision(),
      .runtime_version   = ai_platform_runtime_get_version(),

      .tool_revision     = AI_TOOLS_REVISION_ID,
      .tool_version      = {AI_TOOLS_VERSION_MAJOR, AI_TOOLS_VERSION_MINOR,
                            AI_TOOLS_VERSION_MICRO, 0x0},
      .tool_api_version  = AI_STRUCT_INIT,

      .api_version            = ai_platform_api_get_version(),
      .interface_api_version  = ai_platform_interface_api_get_version(),
      
      .n_macc            = 9091,
      .n_inputs          = 0,
      .inputs            = NULL,
      .n_outputs         = 0,
      .outputs           = NULL,
      .map_signature     = AI_MAGIC_SIGNATURE,
      .map_weights       = AI_STRUCT_INIT,
      .map_activations   = AI_STRUCT_INIT,
      .n_nodes           = 0,
      .signature         = 0x0,
    };

    if (!ai_platform_api_get_network_report(network, &r)) return false;

    *report = r;
    return true;
  }
  return false;
}

AI_API_ENTRY
ai_error ai_plantnetwork_get_error(ai_handle network)
{
  return ai_platform_network_get_error(network);
}

AI_API_ENTRY
ai_error ai_plantnetwork_create(
  ai_handle* network, const ai_buffer* network_config)
{
  return ai_platform_network_create(
    network, network_config, 
    &AI_NET_OBJ_INSTANCE,
    AI_TOOLS_API_VERSION_MAJOR, AI_TOOLS_API_VERSION_MINOR, AI_TOOLS_API_VERSION_MICRO);
}

AI_API_ENTRY
ai_error ai_plantnetwork_create_and_init(
  ai_handle* network, const ai_handle activations[], const ai_handle weights[])
{
    ai_error err;
    ai_network_params params;

    err = ai_plantnetwork_create(network, AI_PLANTNETWORK_DATA_CONFIG);
    if (err.type != AI_ERROR_NONE)
        return err;
    if (ai_plantnetwork_data_params_get(&params) != true) {
        err = ai_plantnetwork_get_error(*network);
        return err;
    }
#if defined(AI_PLANTNETWORK_DATA_ACTIVATIONS_COUNT)
    if (activations) {
        /* set the addresses of the activations buffers */
        for (int idx=0;idx<params.map_activations.size;idx++)
            AI_BUFFER_ARRAY_ITEM_SET_ADDRESS(&params.map_activations, idx, activations[idx]);
    }
#endif
#if defined(AI_PLANTNETWORK_DATA_WEIGHTS_COUNT)
    if (weights) {
        /* set the addresses of the weight buffers */
        for (int idx=0;idx<params.map_weights.size;idx++)
            AI_BUFFER_ARRAY_ITEM_SET_ADDRESS(&params.map_weights, idx, weights[idx]);
    }
#endif
    if (ai_plantnetwork_init(*network, &params) != true) {
        err = ai_plantnetwork_get_error(*network);
    }
    return err;
}

AI_API_ENTRY
ai_buffer* ai_plantnetwork_inputs_get(ai_handle network, ai_u16 *n_buffer)
{
  if (network == AI_HANDLE_NULL) {
    network = (ai_handle)&AI_NET_OBJ_INSTANCE;
    ((ai_network *)network)->magic = AI_MAGIC_CONTEXT_TOKEN;
  }
  return ai_platform_inputs_get(network, n_buffer);
}

AI_API_ENTRY
ai_buffer* ai_plantnetwork_outputs_get(ai_handle network, ai_u16 *n_buffer)
{
  if (network == AI_HANDLE_NULL) {
    network = (ai_handle)&AI_NET_OBJ_INSTANCE;
    ((ai_network *)network)->magic = AI_MAGIC_CONTEXT_TOKEN;
  }
  return ai_platform_outputs_get(network, n_buffer);
}

AI_API_ENTRY
ai_handle ai_plantnetwork_destroy(ai_handle network)
{
  return ai_platform_network_destroy(network);
}

AI_API_ENTRY
ai_bool ai_plantnetwork_init(
  ai_handle network, const ai_network_params* params)
{
  ai_network* net_ctx = ai_platform_network_init(network, params);
  if (!net_ctx) return false;

  ai_bool ok = true;
  ok &= plantnetwork_configure_weights(net_ctx, params);
  ok &= plantnetwork_configure_activations(net_ctx, params);

  ok &= ai_platform_network_post_init(network);

  return ok;
}


AI_API_ENTRY
ai_i32 ai_plantnetwork_run(
  ai_handle network, const ai_buffer* input, ai_buffer* output)
{
  return ai_platform_network_process(network, input, output);
}

AI_API_ENTRY
ai_i32 ai_plantnetwork_forward(ai_handle network, const ai_buffer* input)
{
  return ai_platform_network_process(network, input, NULL);
}



#undef AI_PLANTNETWORK_MODEL_SIGNATURE
#undef AI_NET_OBJ_INSTANCE
#undef AI_TOOLS_DATE_TIME
#undef AI_TOOLS_COMPILE_TIME

