/**
* @file tuya_sdk_callback.c
* @brief Common process - adapter the flash api
* @version 0.1
* @date 2021-10-22
*
* @copyright Copyright 2020-2021 Tuya Inc. All Rights Reserved.
*
*/
#include "tuya_tools.h"
#include <stdio.h>
#include "tkl_gpio.h"
#include "tkl_uart.h"
#include "tkl_system.h"
#include "tkl_memory.h"
#include "tkl_network_manager.h"

#include "tal_log.h"
#include "tal_gpio.h"
#include "tal_uart.h"
#include "tal_flash.h"
#include "tal_system.h"
#include "tal_nv_flash.h"
#include "tal_sw_timer.h"
#include "tal_zcl_group.h"
#include "tal_zcl_scene.h"
#include "tal_time_sync.h"
#include "tal_heartbeat.h"
#include "tal_data_send.h"
#include "tal_network_mgr.h"
#include "tal_zcl_identify.h"
#include "tal_data_receive.h"
#include "tal_attribute_rw.h"
#include "tal_firmware_cfg.h"
#include "tal_reset_factory.h"
#include "tal_zll_commissioning.h"
#include "tal_endpoint_register.h"

#include "app_common.h"
#include "app_config.h"

#include "tlPrintf.h"
#include "tuya_sdk_callback.h"
#include "app_battery.h"
#include "app_sensor.h"
#include "app_led.h"

#define DEVICE_TYPE_LP		1	//0:router 1:低功耗

//mfg test flag---这里我们没用到
BOOL_T  mf_test_doing_flag = FALSE;
BOOL_T  sys_init_finish_flag = FALSE;


TIMER_ID etimer_key_scan;
TIMER_ID etimer_blink_sw;
TIMER_ID etimer_join_start_delay;
TIMER_ID etimer_clr_rst_cnt_delay;
TIMER_ID etimer_save_data_delay;
TIMER_ID etimer_mf_blink;
TIMER_ID etimer_power_on_sync;
TIMER_ID etimer_join_end_sync;

extern TIMER_ID etimer_connect_sync;

TAL_ZG_NWK_STATUS_E g_connect_status = TAL_ZG_NWK_IDLE;

#ifdef ENABLE_TAL_LOG
const char *g_net_st_str_test[] = {
    "TAL_ZG_NWK_IDLE",            ///< inner using
    "TAL_ZG_NWK_POWER_ON_LEAVE",  ///< power on and device is not joined network
    "TAL_ZG_NWK_POWER_ON_ONLINE", ///< power on and device is already joined network
    "TAL_ZG_NWK_JOIN_START",      ///< start joining network
    "TAL_ZG_NWK_JOIN_TIMEOUT",    ///< network joining timeout
    "TAL_ZG_NWK_JOIN_OK",         ///< network joined success
    "TAL_ZG_NWK_LOST",            ///< network lost, lost parent
    "TAL_ZG_NWK_REJOIN_OK",       ///< network rejoin ok
    "TAL_ZG_NWK_REMOTE_LEAVE",    ///< remove device by remote device
    "TAL_ZG_NWK_LOCAL_LEAVE",     ///< remove device by local
    "TAL_ZG_NWK_MF_TEST_LEAVE",   ///< remove device by PC test tools
    "TAL_ZG_NWK_ZLL_JOINED",      ///< network joined zll network
    "TAL_ZG_NWK_ZLL_LEAVE",       ///< remove device Zll Reset To Factory New
};
#endif


#ifndef GET_ARRAY_LEN
#define GET_ARRAY_LEN(x) (sizeof(x) / sizeof(x[0]))
#endif

#define PRIVATE_ATTR_LIST \
	{0x0000, ATTR_INT32S_ATTRIBUTE_TYPE, 4, ATTR_MASK_READABLE, 0, (UINT8_T*)0x00 }, 	/* dp101 x轴加速度 */\
	{0x0001, ATTR_INT32S_ATTRIBUTE_TYPE, 4, ATTR_MASK_READABLE, 0, (UINT8_T*)0x00 }, 	/* dp102 y轴加速度*/\
	{0x0002, ATTR_INT32S_ATTRIBUTE_TYPE, 4, ATTR_MASK_READABLE, 0, (UINT8_T*)0x00 }, 	/* dp103 z轴加速度 */\
	{0x0003, ATTR_INT32S_ATTRIBUTE_TYPE, 4, ATTR_MASK_READABLE, 0, (UINT8_T*)0x00 }, 	/* dp104 x轴加速度阈值 */\
	{0x0004, ATTR_INT32S_ATTRIBUTE_TYPE, 4, ATTR_MASK_READABLE, 0, (UINT8_T*)0x00 }, 	/* dp105 y轴加速度阈值 */\
	{0x0005, ATTR_INT32S_ATTRIBUTE_TYPE, 4, ATTR_MASK_READABLE, 0, (UINT8_T*)0x00 }, 	/* dp106 z轴加速度阈值 */\
	{0x0006, ATTR_INT8U_ATTRIBUTE_TYPE,  1, ATTR_MASK_READABLE, 0, (UINT8_T*)0x32 }, 	/* dp107 加速度阈值补偿 */\
	{0x0007, ATTR_INT32S_ATTRIBUTE_TYPE, 4, ATTR_MASK_READABLE, 0, (UINT8_T*)0x00 }, 	/* dp108 噪声阈值 */\
	{0x0008, ATTR_INT16S_ATTRIBUTE_TYPE, 2, ATTR_MASK_READABLE, 0, (UINT8_T*)0x18 }, 	/* dp109 当前温度 */\
	{0x0009, ATTR_INT16S_ATTRIBUTE_TYPE, 2, ATTR_MASK_READABLE, 0, (UINT8_T*)0x00 }, 	/* dp110 温度补偿 */\
	{0x000a, ATTR_ENUM8_ATTRIBUTE_TYPE,  1, ATTR_MASK_READABLE, 0, (UINT8_T*)0x00 }, 	/* dp111 传感器状态 */\
	{0x000b, ATTR_INT16S_ATTRIBUTE_TYPE, 2, ATTR_MASK_READABLE, 0, (UINT8_T*)0x00 }, 	/* dp112 角度上报阈值 */\
	{0x000c, ATTR_INT16S_ATTRIBUTE_TYPE, 2, ATTR_MASK_READABLE, 0, (UINT8_T*)0x00 }, 	/* dp113 x角度值 */\
	{0x000d, ATTR_ENUM8_ATTRIBUTE_TYPE,  1, ATTR_MASK_READABLE, 0, (UINT8_T*)0x01 }, 	/* dp114 工作模式 */\
	{0x000e, ATTR_INT8U_ATTRIBUTE_TYPE,  1, ATTR_MASK_READABLE, 0, (UINT8_T*)0x00 }, 	/* dp115 电量 */\
	{0x000f, ATTR_INT16S_ATTRIBUTE_TYPE, 2, ATTR_MASK_READABLE, 0, (UINT8_T*)0x00 }, 	/* dp116 y角度值 */\
	{0x0010, ATTR_INT16S_ATTRIBUTE_TYPE, 2, ATTR_MASK_READABLE, 0, (UINT8_T*)0x00 }, 	/* dp117 z角度值 */\
    {0xFFFD, ATTR_INT16U_ATTRIBUTE_TYPE, 2, ATTR_MASK_READABLE, 0, (UINT8_T *)0x0001},
    
// application attribute
const TAL_ATTR_T g_private_attr_list[] = {
	PRIVATE_ATTR_LIST};

#define DEF_CLUSTER_PRIVATE_CLUSTER_ID(a) \
    { CLUSTER_PRIVATE_TUYA_CLUSTER_ID, (TAL_ATTR_T *)&((a)[0]), GET_ARRAY_LEN((a)) },

// server cluster
const TAL_CLUSTER_T app_server_cluster_list[] = {
   	DEF_CLUSTER_PRIVATE_CLUSTER_ID(g_private_attr_list)
};
                        

#define SERVER_CLUSTER_NUM GET_ARRAY_LEN(app_server_cluster_list)

TAL_ENDPOINT_T dev_endpoint_desc[] = {
    {1, ZHA_PROFILE_ID, ZG_DEVICE_ID_SMART_PLUG, SERVER_CLUSTER_NUM, (TAL_CLUSTER_T *)&app_server_cluster_list[0], 0, NULL},
};

STATIC VOID_T __power_on_event(void)  //(TIMER_ID timer_id, VOID_T *arg)
{
    TAL_PR_DEBUG("into __power_on_event");
    dev_power_on_indicate();
    //app_gpio_preheat_init();
}

STATIC VOID_T __network_info_print(VOID_T)
{
    TKL_NWK_BASIC_INFO_T nwk_info;
    tkl_zg_nwk_base_info_get(&nwk_info);
    TAL_PR_DEBUG("power_on_online, pan-id=0x%x ch=%d addr=%x tx_power=%d", \
                    nwk_info.panid, \
                    nwk_info.radio_channel, \
                    nwk_info.nwk_addr, 
                    nwk_info.radio_power);
}

VOID_T __tuya_pre_sleep_cb(VOID_T)
{
    TAL_PR_DEBUG("pre_sleep_cb!!!\r\n");
}

VOID_T __tuya_post_sleep_cb(VOID_T)
{
    TAL_PR_DEBUG("post_sleep_cb!!!\r\n");
}

/** 开启配网
 * @note join start delay timer hander, join now 
 * @param[in]  nones
 * @param[out] none
 * @return none
 */
STATIC VOID_T __app_network_join_start_delay_cb(TIMER_ID timer_id, VOID_T *arg)
{
    tal_zg_join_start(ZIGBEE_JOIN_MAX_TIMEOUT);
}

/**
 * @brief zigbee node init
 * 
 * @return VOID_T 
 */
STATIC VOID_T __app_router_node_init(VOID_T)
{
    TAL_ZG_NODE_CFG_T node_config = {
        .node_type = ZG_ROUTER,
        .tx_power = 11,
        .scan_interval = 0,
        .scan_duration = ZG_SCAN_DURATION_3,
    };
    tal_zg_node_config(&node_config);
}

/**
 * @brief register router or sleep device
 * @return none
 */
STATIC VOID_T __app_sleep_device_node_init(VOID_T)
{
 	// sleep end device node init
     TAL_ZG_NODE_CFG_T node_config = {
         .node_type = ZG_SLEEPY_END_DEVICE,
         .tx_power = 11, //10,
         .scan_interval = 100,
         .scan_duration = ZG_SCAN_DURATION_3,
         .config.sleep_ed_cfg.poll_config.forever_flag = 0,
         .config.sleep_ed_cfg.poll_config.fast_swicth_parent = 0,
         .config.sleep_ed_cfg.poll_config.interval_ms = 250,
         .config.sleep_ed_cfg.poll_config.max_failed_times = 10,
         .config.sleep_ed_cfg.poll_config.duration_after_data_ms = 1000,
         .config.sleep_ed_cfg.poll_config.duration_after_join_ms = 60000,
         .config.sleep_ed_cfg.poll_config.duration_after_rejoin_ms = 15000,
         .config.sleep_ed_cfg.rejoin_config.power_on_active = 1,
         .config.sleep_ed_cfg.rejoin_config.send_data_active = 1,
         .config.sleep_ed_cfg.rejoin_config.attempts = 3,
         .config.sleep_ed_cfg.rejoin_config.interval = 3000,
     };
    //config zigbee node
    tal_zg_node_config(&node_config);
}

/**
 * @brief Generally used for peripheral initialization
 * 
 * @return OPERATE_RET 
 */
OPERATE_RET tuya_init_first(VOID_T)
{
#if (ENABLE_TAL_LOG == 1)
    tal_log_create_manage_and_init(TAL_LOG_LEVEL_DEBUG, 128, Tl_printf);
#endif

	tal_mf_test_disable_beacon_test();
    TAL_PR_DEBUG("/*********first init, reason[%d]*********/", tal_system_get_reset_reason(NULL));
    return OPRT_OK;
}
/**
 * @brief Generally used for register zigbee device
 * 
 * @return OPERATE_RET 
 */
OPERATE_RET tuya_init_second(VOID_T)
{
    //initialize firmware infomation
    TAL_PR_DEBUG("Application version:%d", APP_FIRMWARE_VER);

    //register zigbee endpoint
    tal_zg_endpoint_register(dev_endpoint_desc, GET_ARRAY_LEN(dev_endpoint_desc));
    TAL_PR_DEBUG("identify init ret:%d", tal_zg_identify_init());

    //zigbee node configuration
#if DEVICE_TYPE_LP	== 0
    __app_router_node_init();
#else 
	__app_sleep_device_node_init();
#endif
    //zigbee joining network configuration
    TAL_ZG_JOIN_CFG_T join_config = {
        .auto_join_power_on_flag = FALSE,//defalut power on start join or not
        .auto_join_remote_leave_flag = TRUE,//default start join or not when receivew remote leave request
        .join_timeout = ZIGBEE_JOIN_MAX_TIMEOUT,//join timeout times 120s
    };
    tal_zg_join_config(&join_config);

    //tal_time_sync_period_set(60 * 1000);
    
	//disable beacon test
	//tal_mf_test_disable_beacon_test();
	
    //disable network recovery
	tal_zg_nwk_recovery_disable(TRUE);


    TUYA_SLEEP_CB_T  sleep_cb = {
        .pre_sleep_cb = __tuya_pre_sleep_cb,
        .post_wakeup_cb = __tuya_post_sleep_cb,
    };
    tal_cpu_sleep_callback_register(&sleep_cb);
	
    TAL_PR_DEBUG("/*********1.0.0 second init*********/");
    return OPRT_OK;
}
/**
 * @brief Generally used for initialization before manufacturing test
 * 
 * @return OPERATE_RET 
 */
OPERATE_RET tuya_init_third(VOID_T)
{
    TAL_PR_DEBUG("/*********third init*********/");

    OPERATE_RET ret;

	//creat software timer
    tal_sw_timer_create(app_button_scan_cb, NULL, &etimer_key_scan);
    tal_sw_timer_create(__app_network_join_start_delay_cb, NULL, &etimer_join_start_delay);
	
	app_led_init();

    app_button_init();

    ret = lis2dw12_init();
    if (ret != OPRT_OK)
    {
        TAL_PR_DEBUG("sensor init ERROR");
    }
	else
		TAL_PR_DEBUG("sensor init Successful...");
	
    return OPRT_OK;
}
/**
 * @brief Generally used for initialization after manufacturing test
 * 
 * @return OPERATE_RET 
 */
OPERATE_RET tuya_init_last(VOID_T)
{
    UINT8_T version;
    tal_zg_read_attribute(TUYA_PRIMARY_ENDPOINT,
                          CLUSTER_BASIC_CLUSTER_ID,
                          ATTR_APPLICATION_VERSION_ATTRIBUTE_ID,
                          (VOID_T *)&version,
                          sizeof(version));

	__tuya_battery_init();

	dev_dpid_init();
	
	// tal_heartbeat_period_set(30*000);
    // tal_heartbeat_type_set(HEARTBEAT_APP_VERSION);

	sys_init_finish_flag = TRUE;
	__power_on_event();
    TAL_PR_DEBUG("/*********last init %d*********/", version);
    return OPRT_OK;
}
/**
 * @brief user-defined callback interface in main loop.do not block!!!
 * 
 * @return OPERATE_RET 
 */
OPERATE_RET tuya_main_loop(VOID_T)
{
    return OPRT_OK;
}
/**
 * @brief heartbeat report callback
 * NOTE: you can rewrite this API in application layer
 * 
 * @param[in]   status: heartbeat report status
 *
 * @return none
 */
 #if 0
VOID_T tal_heartbeat_report_callback(TAL_HEARTBEAT_TYPE_E type)
{
    TAL_PR_DEBUG("heartbeat: %d", type);
}
#endif
/**
 * @brief general message receive callback
 * 
 * @param msg 
 * @return TAL_MSG_RET_E 
 */
TAL_MSG_RET_E tal_zcl_general_msg_recv_callback(TAL_ZCL_MSG_T *msg)
{
    //TAL_PR_DEBUG("app gen msg cb: cluster 0x%02x, cmd %d", msg->cluster, msg->command);

    return ZCL_MSG_RET_SUCCESS;
}
/**
 * @brief specific message receive callback
 * 
 * @param msg 
 * @return TAL_MSG_RET_E 
 */
TAL_MSG_RET_E tal_zcl_specific_msg_recv_callback(TAL_ZCL_MSG_T *msg)
{	
    TAL_PR_DEBUG("app spec msg cb: cluster 0x%02x, cmd 0x%02x", msg->cluster, msg->command);

    ZIGBEE_CMD_T app_cmd_type = ZIGBEE_CMD_SINGLE;
    if (msg->mode == ZG_UNICAST_MODE)
    {
        app_cmd_type = ZIGBEE_CMD_SINGLE;
        TAL_PR_DEBUG("receive single message");
    }
    else
    {
        app_cmd_type = ZIGBEE_CMD_GROUP;
        TAL_PR_DEBUG("receive group message");
    }

    switch (msg->cluster)
    {
    case CLUSTER_PRIVATE_TUYA_CLUSTER_ID:
    {
    	g_connect_status = TAL_ZG_NWK_JOIN_OK;
    	TAL_PR_DEBUG("==========recv private cluster=========");
		custom_obj_t custom_data = {0};

		custom_data.seq = msg->payload[0]*256 + msg->payload[1];
		custom_data.dpid = msg->payload[2];
		custom_data.type = msg->payload[3];
		custom_data.len = msg->payload[4]*256 + msg->payload[5];
		for(int i = custom_data.len - 1; i >= 0 ; i--)
			custom_data.value |= (msg->payload[6+i]<<(8*(custom_data.len - i - 1)));
		
		TAL_PR_DEBUG("seq_num = %d", custom_data.seq);
		TAL_PR_DEBUG("dpid    = %d", custom_data.dpid);
		TAL_PR_DEBUG("type    = %d", custom_data.type);
		TAL_PR_DEBUG("len     = %d", custom_data.len);
		TAL_PR_DEBUG("value   = %d", custom_data.value);
		
		/*
		TAL_PR_DEBUG("recv: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x", \
				msg->payload[0], msg->payload[1], msg->payload[2], msg->payload[3], msg->payload[4], msg->payload[5], \
				msg->payload[6], msg->payload[7], msg->payload[8], msg->payload[9]);
		*/
		switch(msg->command)
		{
			case 0x04:
				dev_dpid_msg_rsp(QOS_1, 0, &(msg->payload[0]), msg->length);
				sensor_private_handler(&custom_data);
				break;
		}
        break;
    }

	case CLUSTER_GREEN_POWER_CLUSTER_ID:
	{
		break;
	}
	
    default:
    	TAL_PR_DEBUG("==========recv unknow cluster[%04x]=========", msg->cluster);
        break;
    }

    return ZCL_MSG_RET_SUCCESS;
}

/**
 * @brief add group callback
 *
 * @param[in]   ep_id:    endpoint id
 * @param[in]   group_id: group id
 * @return  VOID_T
 */
VOID_T tal_zg_add_group_callback(UINT8_T ep_id, UINT16_T group_id)
{
    TAL_PR_DEBUG("ep id: %d,group id: %d", ep_id, group_id);
}
/**
 * @brief view group callback
 *
 * @param[in]   ep_id:    endpoint id
 * @param[in]   group_id: group id
 * @return  VOID_T
 */
VOID_T tal_zg_view_group_callback(UINT8_T ep_id, UINT16_T group_id)
{
    TAL_PR_DEBUG("ep id: %d,group id: %d", ep_id, group_id);
}
/**
 * @brief remove group callback
 *
 * @param[in]   ep_id:    endpoint id
 * @param[in]   group_id: group id
 * @return  VOID_T
 */
VOID_T tal_zg_remove_group_callback(UINT8_T ep_id, UINT16_T group_id)
{
    TAL_PR_DEBUG("ep id: %d,group id: %d", ep_id, group_id);
}
/**
 * @brief zigbee network network change callback(user can rewrite this API)
 * 
 * @param[in]   status: network status
 * @return VOID_T
 */
VOID_T tal_zg_nwk_status_changed_callback(TAL_ZG_NWK_STATUS_E status)
{
	g_connect_status = status;
	
    switch (status)
    {
    case TAL_ZG_NWK_POWER_ON_LEAVE:
    {
        TAL_PR_DEBUG("power_on_leave---");
        break;
    }
    case TAL_ZG_NWK_POWER_ON_ONLINE:
    {
        TAL_PR_DEBUG("power_on_online---");
		tal_sw_timer_start(etimer_connect_sync, 3000, TAL_TIMER_CYCLE);
		__network_info_print();
		app_battery_start();
        break;
    }
    case TAL_ZG_NWK_JOIN_START:
    {
        TAL_PR_DEBUG("nwk_join_start---");
		dev_start_join_indicate(TRUE);
        break;
    }
    case TAL_ZG_NWK_JOIN_OK:
    {
        TAL_PR_DEBUG("nwk_join_ok---");
		__network_info_print();
     	dev_join_success_indicate();
     	app_battery_start();
        break;
    }
    case TAL_ZG_NWK_REJOIN_OK:
    {
        TAL_PR_DEBUG("nwk_rejoin_ok---");
		app_battery_start();
        break;
    }
    case TAL_ZG_NWK_JOIN_TIMEOUT:
    {
        TAL_PR_DEBUG("nwk_join_timeout---");
		dev_start_join_indicate(FALSE);
        break;
    }
    case TAL_ZG_NWK_LOST:
    {
        TAL_PR_DEBUG("nwk_lost---");
        break;
    }
    case TAL_ZG_NWK_REMOTE_LEAVE:
    {
        TAL_PR_DEBUG("nwk_remote_leave---");
        break;
    }
    case TAL_ZG_NWK_LOCAL_LEAVE:
    {
        TAL_PR_DEBUG("nwk_local_leave---");
        break;
    }
    case TAL_ZG_NWK_MF_TEST_LEAVE:
    {
        TAL_PR_DEBUG("nwk_mf_test_leave---");
        break;
    }
    default:
    {
        break;
    }
    }
}
VOID_T tal_beacon_mf_test_callback(VOID_T)
{
    TAL_PR_DEBUG("enter beacon test\n");
}

/**
 * @brief reset factory default callback
 *
 * @param[in]   type: reset factory type
 * @return  VOID_T
 */
VOID_T tal_zg_reset_factory_default_callback(TAL_RESET_TYPE_T type)
{
    TAL_PR_DEBUG("receive reset to factory default cmd %d", type);
}

VOID_T tal_zll_target_commissioning_complete_callback(TAL_ZLL_TARGET_STATUS_E status)
{
    TAL_PR_DEBUG("zll target status %d",status);
}



VOID_T tal_time_sync_complete_callback(BOOL_T status, UINT_T time_sec)
{
 }


#include "tkl_platform_types.h"

BOOL_T app_print_get_cfg(UINT8_T *print_type, UINT8_T *disable_irq, GPIO_PORT_PIN_T *gpio)
{
    gpio->port = PORT_C;
    gpio->pin = PIN_2;
    *print_type = 0;
    *disable_irq = 1;
#ifdef UART_PRINTF_MODE
    return 1;
#else
    return 0;
#endif
}
