#include <stdlib.h>
#include <stdint.h>
#include <string.h>

#include "generic/circular_buf.h"
#include "os/os_api.h"
#include "update_loader_download.h"
#include "system/task.h"
#include "system/timer.h"
#include "init.h"
#include "smartbox_update_tws.h"
#include "dual_bank_updata_api.h"
#include "bt_tws.h"
#include "app_config.h"
#include "btstack/avctp_user.h"
#include "update.h"
#include "app_main.h"

#if (SMART_BOX_EN && OTA_TWS_SAME_TIME_ENABLE)

//#define LOG_TAG_CONST       EARPHONE
#define LOG_TAG             "[UPDATE_TWS]"
#define log_errorOR_ENABLE
#define LOG_DEBUG_ENABLE
#define LOG_INFO_ENABLE
/* #define LOG_DUMP_ENABLE */
#define LOG_CLI_ENABLE
#include "debug.h"

#define THIS_TASK_NAME	            "tws_ota"
#define SLAVE_REV_BUF_LEN           1024*2

enum {
    TWS_UPDATE_START,
    TWS_UPDATE_RESULT_EXCHANGE,
    TWS_UPDATE_RESULT_EXCHANGE_RES,
    TWS_UPDATE_OVER,
    TWS_UPDATE_OVER_CONFIRM,
    TWS_UPDATE_OVER_CONFIRM_REQ,
    TWS_UPDATE_OVER_CONFIRM_RES,
    TWS_UPDATE_VERIFY,
};

extern void sys_enter_soft_poweroff(void *priv);

void db_update_notify_fail_to_phone();

struct __tws_ota_var {
    OS_SEM master_sem;
    OS_SEM slave_sem;
    OS_SEM confirm_sem;
    struct __tws_ota_para para;
    u8 ota_type;
    u8 ota_status;
    u8 ota_remote_status;
    u8 ota_result;
    volatile u32 ota_data_len;
    u16 ota_timer_id;
    u8 ota_verify_cnt;
    volatile u32 ota_confirm;
    cbuffer_t cbuffer;
    u8 *slave_r_buf;
};
struct __tws_ota_var tws_ota_var;
#define __this (&tws_ota_var)

void tws_ota_event_post(u32 type, u8 event)
{
    struct sys_event e;
    e.type = SYS_BT_EVENT;
    e.arg  = (void *)type;
    e.u.bt.event = event;
    sys_event_notify(&e);
}

u8 tws_ota_control(int type, ...)
{
    int ret   = 0;
    int role  = 0;
    int value = 0;

    va_list argptr;
    va_start(argptr, type);

    switch (type) {
    case OTA_TYPE_SET:
        value = va_arg(argptr, int);
        __this->ota_type = value;
        break;
    case OTA_TYPE_GET:
        ret = __this->ota_type;
        break;
    case OTA_STATUS_SET:
        value = va_arg(argptr, int);
        __this->ota_status = value;
        break;
    case OTA_STATUS_GET:
        ret = __this->ota_status;
        break;
    case OTA_REMOTE_STATUS_SET:
        value = va_arg(argptr, int);
        __this->ota_remote_status = value;
        break;
    case OTA_REMOTE_STATUS_GET:
        ret = __this->ota_remote_status;
        break;
    case OTA_RESULT_SET:
        value = va_arg(argptr, int);
        role  = va_arg(argptr, int);
        if (value == 1) {
            __this->ota_result |= BIT(role);
        } else {
            __this->ota_result &= ~BIT(role);
        }
        break;
    case OTA_RESULT_GET:
        ret = __this->ota_result;
        break;
    }

    va_end(argptr);

    return ret;
}

int tws_ota_init(void)
{
    memset((u8 *)__this, 0, sizeof(struct __tws_ota_var));
    __this->ota_status = OTA_INIT;
    __this->ota_type = OTA_TWS;

    if (a2dp_get_status() == BT_MUSIC_STATUS_STARTING) {
        /* log_info("try pause a2dp music"); */
        user_send_cmd_prepare(USER_CTRL_AVCTP_OPID_PAUSE, 0, NULL);
    }
    return 0;
}

#define TWS_FUNC_ID_OTA_SYNC    TWS_FUNC_ID('O', 'T', 'A', 'S')
static void tws_ota_data_read_s_from_m(void *_data, u16 len, bool rx)
{
    if (rx && __this->ota_status == OTA_START && __this->slave_r_buf) {
        /* r_log_info("Offset:%x r_len:%d\n",__this->ota_data_len,len); */
        /* put_buf(_data, len); */
        __this->ota_data_len += len;
        if (cbuf_is_write_able(&(__this->cbuffer), len)) {
            cbuf_write(&(__this->cbuffer), _data, len);
        } else {
            log_info("ota cbuf write err\n");
        }
        os_sem_post(&__this->slave_sem);
    }
}

REGISTER_TWS_FUNC_STUB(app_ota_sync_stub) = {
    .func_id = TWS_FUNC_ID_OTA_SYNC,
    .func    = tws_ota_data_read_s_from_m,
};

int tws_ota_data_send_m_to_s(u8 *buf, u16 len)
{
    if (!(tws_api_get_tws_state() & TWS_STA_SIBLING_CONNECTED)) {
        return 0;
    }

    if (tws_api_get_role() == TWS_ROLE_SLAVE) {
        return 0;
    }

    int ret = tws_api_send_data_to_slave(buf, len, TWS_FUNC_ID_OTA_SYNC);
    return ret;
}

int tws_ota_err_callback(u8 reason)
{
    tws_ota_event_post(SYS_BT_OTA_EVENT_TYPE_STATUS, OTA_UPDATE_ERR);
    return 0;
}

static void tws_ota_update_loop(void *priv)
{
    u32 total_len = 0;
    u32 len = 0;
    u8 *tmp_buf = NULL;
    int ret = 0;

    u8 sniff_wait_exit_timeout = 30;//3s

    log_info("tws_ota_update_loop\n");

    while (1) {
        os_sem_pend(&__this->slave_sem, 0);

        if (sniff_wait_exit_timeout) {
            //wait slave exit sniff
            extern u8 btstcak_get_bt_mode(void);
            while (btstcak_get_bt_mode() && sniff_wait_exit_timeout--) {
                log_info("wait sniff exit \n");
                os_time_dly(10);
            }
            log_info(">>>>>>>sniff timeout:%d \n", sniff_wait_exit_timeout);

            if (!sniff_wait_exit_timeout) {
                log_info(">>>>>>wait sniff exit timeout !!!! \n");
            }
            sniff_wait_exit_timeout = 0;
            dual_bank_passive_update_init(__this->para.fm_crc16, __this->para.fm_size, __this->para.max_pkt_len, NULL);
            ret = dual_bank_update_allow_check(__this->para.fm_size);
            if (ret) {
                log_info("fm_size:%x can't update\n", __this->para.fm_size);
                tws_ota_event_post(SYS_BT_OTA_EVENT_TYPE_STATUS, OTA_UPDATE_ERR);
                continue;
            }
            tws_api_sync_call_by_uuid(0xA2E22223, SYNC_CMD_START_UPDATE, 400);
            continue;
        }

        total_len = cbuf_get_data_size(&(__this->cbuffer));
        /* log_info("total_len : %d\n",total_len); */
        while (total_len) {
            if (total_len > get_dual_bank_passive_update_max_buf()) {
                len =  get_dual_bank_passive_update_max_buf();
            } else {
                len = total_len;
            }

            if (!len) {
                continue;
            }
            tmp_buf = malloc(len);
            if (tmp_buf) {
                if (cbuf_read(&(__this->cbuffer), tmp_buf, len) == len) {
                    putchar('D');
                    dual_bank_update_write(tmp_buf, len, NULL);
                } else {
                    log_error("read err\n");
                }
                free(tmp_buf);
            } else {
                log_error("malloc err\n");
            }
            total_len -= len;
        }
    }
}

static void ota_finish_confirm(void *priv)
{
    log_info("ota_finish_confirm:%d\n", __this->ota_confirm);
    if (!__this->ota_confirm) {
        //ota tws confirm err,earse boot info
        flash_update_clr_boot_info(CLEAR_APP_UPDATE_BANK);
        /* ASSERT(0, "ota tws confirm err\n"); */
    }
    tws_ota_event_post(SYS_BT_OTA_EVENT_TYPE_STATUS, OTA_UPDATE_SUCC);

}

u16 tws_ota_enter_verify(void *priv)
{
    if (tws_api_get_tws_state() & TWS_STA_SIBLING_DISCONNECTED) {
        log_info("tws_disconn in verify\n");
        db_update_notify_fail_to_phone();
        return -1;
    }
    tws_ota_send_data_to_sibling(TWS_UPDATE_VERIFY, NULL, 0);
    os_sem_pend(&__this->master_sem, 1000);
    //这里pend完，要做超时的准备
    if (__this->ota_status == OTA_VERIFY_ING) {
        return 0;
    } else {
        db_update_notify_fail_to_phone();
        return -1;
    }
}

u16 tws_ota_exit_verify(u8 *res, u8 *up_flg)
{
    //not updata boot info in lib
    *up_flg = 1;

    u8 tws_ota_result[2];
    u8 master_result = *res;
    u8 result = 0;
    tws_ota_control(OTA_STATUS_SET, OTA_VERIFY_END);
    tws_ota_control(OTA_RESULT_SET, !master_result, TWS_ROLE_MASTER);
__RESTART:
    if (tws_api_get_tws_state() & TWS_STA_SIBLING_DISCONNECTED) {
        db_update_notify_fail_to_phone();
        return 0;
    }
    result = tws_ota_control(OTA_RESULT_GET);
    tws_ota_result[0] = result;
    tws_ota_result[1] = tws_ota_control(OTA_STATUS_GET);
    tws_ota_send_data_to_sibling(TWS_UPDATE_RESULT_EXCHANGE, (u8 *)&tws_ota_result, 2);

    if ((result & BIT(TWS_ROLE_SLAVE)) && (result & BIT(TWS_ROLE_SLAVE))) {
        log_info("tws already ota succ1\n");
        os_sem_set(&__this->master_sem, 0);
        tws_ota_event_post(SYS_BT_OTA_EVENT_TYPE_STATUS, OTA_UPDATE_OVER);
        return 1;
    } else if (__this->ota_remote_status ==  OTA_VERIFY_END || __this->ota_remote_status ==  OTA_OVER) {
        tws_ota_event_post(SYS_BT_OTA_EVENT_TYPE_STATUS, OTA_UPDATE_ERR);
        return 0;
    } else {
        os_sem_pend(&__this->master_sem, 200);
        goto __RESTART;
    }
    return 1;
}

u16 tws_ota_updata_boot_info_over(void *priv)
{
    log_info("master update_burn_boot_info succ\n");
    if (tws_api_get_tws_state() & TWS_STA_SIBLING_DISCONNECTED) {
        log_info("tws_disconn, ota open fail");
        db_update_notify_fail_to_phone();
        return -1;
    }

    //等待从机更新完成
    log_info("1------pend in");
    os_sem_pend(&__this->confirm_sem, 300);
    log_info("1------pend out");

    log_info("-------mz01");
    if (__this->ota_confirm) {
        log_info("-------mz02");
        os_sem_set(&__this->confirm_sem, 0);
        tws_ota_send_data_to_sibling(TWS_UPDATE_OVER_CONFIRM_REQ, NULL, 0);
        log_info("2------pend in");
        if (OS_TIMEOUT == os_sem_pend(&__this->confirm_sem, 300)) {
            __this->ota_confirm = 0;
        }
        log_info("2------pend out");
    }

    if (!__this->ota_confirm) {
        log_info("-------mz03");
        //ota tws confirm err,earse boot info
        flash_update_clr_boot_info(CLEAR_APP_UPDATE_BANK);
        /* ASSERT(0, "ota tws confirm err\n"); */
        return -1;
    }
    /* tws_ota_event_post(SYS_BT_OTA_EVENT_TYPE_STATUS,OTA_UPDATE_SUCC); //主机等手机发重启命令*/
    return 0;

}

int tws_ota_open(struct __tws_ota_para *para)
{
    int ret = 0;
    log_info("tws_ota_open\n");

    if (tws_api_get_tws_state() & TWS_STA_SIBLING_DISCONNECTED) {
        log_info("tws_disconn, ota open fail");
        db_update_notify_fail_to_phone();
        return -1;
    }

    os_sem_create(&__this->master_sem, 0);
    os_sem_create(&__this->slave_sem, 0);
    os_sem_create(&__this->confirm_sem, 0);

    if (tws_api_get_role() == TWS_ROLE_MASTER) {
        extern void bt_check_exit_sniff();
        bt_check_exit_sniff();
        //master 发命令给slave启动升级


        log_info("master updata info: crc16:%x size:%x max_pkt_len:%d\n", para->fm_crc16, para->fm_size, para->max_pkt_len);
        if (__this->ota_type == OTA_TWS) {
            tws_ota_send_data_to_sibling(TWS_UPDATE_START, (u8 *)para, sizeof(struct __tws_ota_para));
            log_info("sem pend in ...");
            os_sem_pend(&__this->master_sem, 600);
            log_info("sem pend out ...");
            //判断对耳状态
            if (__this->ota_status == OTA_START) {
                log_info("slave has ready");
                ret = 0;
            } else {
                log_info("slave answer timeout");
                db_update_notify_fail_to_phone();
                ret = -1;
            }
        }
    } else {
        log_info("slave updata info: crc16:%x size:%x max_pkt_len:%d\n", para->fm_crc16, para->fm_size, para->max_pkt_len);

        /* tws_api_sync_call_by_uuid('T', SYNC_CMD_START_UPDATE, 100); */
        tws_ota_event_post(SYS_BT_OTA_EVENT_TYPE_STATUS, OTA_START_UPDATE_READY);
    }
    return ret;
}

int tws_ota_close(void)
{
    int ret = 0;
    log_info("%s", __func__);
    if (__this->slave_r_buf) {
        free(__this->slave_r_buf);
        __this->slave_r_buf = 0;
        task_kill(THIS_TASK_NAME);
    }
    return ret;
}

static void ota_verify_timeout(void *priv)
{
    log_info("ota_verify_timeout:%x %x\n", __this->para.fm_size, __this->ota_data_len);
    if (__this->ota_data_len == __this->para.fm_size) {
        /* tws_api_sync_call_by_uuid('T', SYNC_CMD_START_VERIFY, 100); */
        tws_ota_event_post(SYS_BT_OTA_EVENT_TYPE_STATUS, OTA_START_VERIFY);
        return;
    }

    if (__this->ota_verify_cnt > 4) {
        log_info("code len err\n");
        tws_ota_event_post(SYS_BT_OTA_EVENT_TYPE_STATUS, OTA_UPDATE_ERR);
        if (__this->ota_timer_id) {
            sys_timeout_del(__this->ota_timer_id);
            __this->ota_timer_id = 0;
        }
        return;
    }

    __this->ota_verify_cnt ++;
    __this->ota_timer_id = 0;
    __this->ota_timer_id = sys_timeout_add(NULL, ota_verify_timeout, 500);
}

int tws_ota_get_data_from_sibling(u8 opcode, u8 *data, u8 len)
{
    u8 tws_ota_result[2];
    switch (opcode) {
    //master->slave
    case  TWS_UPDATE_START:
        log_info("TWS_AI_START_UPDATE:%d\n", opcode);
        if (tws_api_get_role() == TWS_ROLE_SLAVE) {
            if (__this->slave_r_buf) {
                tws_ota_close();
            }
            tws_ota_init();
            memcpy((u8 *) & (__this->para), data, len);
            tws_ota_open(&(__this->para));
        }
        break;

    //master->slave
    case TWS_UPDATE_RESULT_EXCHANGE:
        log_info("TWS_UPDATE_RESULT_EXCHANGE:%d %d\n", data[0], data[1]);
        __this->ota_remote_status = data[1];
        tws_ota_control(OTA_RESULT_SET, (data[0] & BIT(TWS_ROLE_MASTER) ? 1 : 0), TWS_ROLE_MASTER);

        tws_ota_result[0] = __this->ota_result;
        tws_ota_result[1] = __this->ota_status;
        tws_ota_send_data_to_sibling(TWS_UPDATE_RESULT_EXCHANGE_RES, (u8 *)tws_ota_result, 2);
        log_info("master ota result:%x %d\n", tws_ota_control(OTA_RESULT_GET), __this->ota_status);
        break;

    //slave->master
    case TWS_UPDATE_RESULT_EXCHANGE_RES:
        log_info("TWS_UPDATE_RESULT_EXCHANGE_RES:%d %d\n", data[0], data[1]);
        __this->ota_remote_status = data[1];
        tws_ota_control(OTA_RESULT_SET, (data[0] & BIT(TWS_ROLE_SLAVE) ? 1 : 0), TWS_ROLE_SLAVE);
        log_info("slave ota result:%x %d\n", tws_ota_control(OTA_RESULT_GET), __this->ota_status);

        if (tws_ota_control(OTA_RESULT_GET) & BIT(TWS_ROLE_SLAVE)) {
            os_sem_post(&__this->master_sem);
        }
        break;

    //master->slave
    case TWS_UPDATE_VERIFY:
        log_info("TWS_UPDATE_VERIFY\n");
        tws_ota_event_post(SYS_BT_OTA_EVENT_TYPE_STATUS, OTA_START_VERIFY);
        break;

    case TWS_UPDATE_OVER:
        log_info("TWS_AI_UPDATE_OVER:%d\n", opcode);
        __this->ota_status = OTA_OVER;
        break;

    //slave to master
    case TWS_UPDATE_OVER_CONFIRM:
        log_info("TWS_UPDATE_OVER_CONFIRM\n");
        __this->ota_confirm = 1;
        if (tws_api_get_role() == TWS_ROLE_MASTER) {
            log_info("1------post");
            os_sem_post(&__this->confirm_sem);
        }
        break;
    //master->slave
    case TWS_UPDATE_OVER_CONFIRM_REQ:
        log_info("TWS_UPDATE_OVER_CONFIRM_REQ\n");
        if (tws_api_get_role() == TWS_ROLE_SLAVE) {
            __this->ota_confirm = 1;
            tws_ota_send_data_to_sibling(TWS_UPDATE_OVER_CONFIRM_RES, NULL, 0);
            log_info("2------post");
            os_sem_post(&__this->confirm_sem);
        }
        break;
    //slave->master
    case TWS_UPDATE_OVER_CONFIRM_RES:
        log_info("TWS_UPDATE_OVER_CONFIRM_RES\n");
        if (tws_api_get_role() == TWS_ROLE_MASTER) {
            log_info("3------post");
            os_sem_post(&__this->confirm_sem);
        }
        break;
    }
    return 0;
}

void tws_ota_send_data_to_sibling(u8 opcode, u8 *data, u8 len)
{
    extern void tws_data_to_sibling_send(u8 opcode, u8 * data, u8 len);
    tws_data_to_sibling_send(opcode, data, len);
}



u8 dual_bank_update_burn_boot_info_callback(u8 ret)
{
    if (ret) {
        log_info("update_burn_boot_info err\n");
    } else {
        log_info("slave update_burn_boot_info succ\n");
        tws_ota_send_data_to_sibling(TWS_UPDATE_OVER_CONFIRM, NULL, 0);

        //not recive master confirm
        log_info("3------pend in");
        os_sem_pend(&__this->confirm_sem, 300);
        log_info("3------pend out");

        if (!__this->ota_confirm) {
            //ota tws confirm err,earse boot info
            flash_update_clr_boot_info(CLEAR_APP_UPDATE_BANK);
            /* ASSERT(0, "ota tws confirm err\n"); */
            return 0;
        }

        //确保从机的回复命令送达到主机
        os_time_dly(50);

        tws_ota_event_post(SYS_BT_OTA_EVENT_TYPE_STATUS, OTA_UPDATE_SUCC);
        return 0;
    }

    return 1;
}

//slave ota result
static sint32_t gma_ota_slave_result(int crc_res)
{
    u8 ret = crc_res;

    tws_ota_control(OTA_STATUS_SET, OTA_VERIFY_END);

    tws_ota_control(OTA_RESULT_SET, crc_res, TWS_ROLE_SLAVE);

    log_info("gma_ota_slave_result:%d %d\n", crc_res, tws_ota_control(OTA_STATUS_GET));
    return 0;
}

int tws_ota_sync_cmd(int reason)
{
    int ret = 1;

    switch (reason) {
    //slave request
    case SYNC_CMD_START_UPDATE:
        log_info("SYNC_CMD_START_UPDATE\n");

        if (__this->ota_status != OTA_INIT) {
            log_info("tws ota no init");
            break;
        }
        __this->ota_status = OTA_START;
        __this->ota_data_len = 0;
        __this->ota_remote_status = OTA_START;
        if (tws_api_get_role() == TWS_ROLE_MASTER) {
            os_sem_post(&__this->master_sem);
        } else {
        }
        break;

    //slave request
    case SYNC_CMD_START_VERIFY:
        log_info("SYNC_CMD_START_VERIFY\n");
        __this->ota_status = OTA_VERIFY_ING;
        __this->ota_remote_status = OTA_VERIFY_ING;

        if (tws_api_get_role() == TWS_ROLE_MASTER) {
            os_sem_post(&__this->master_sem);
        } else {
            dual_bank_update_verify(NULL, NULL, gma_ota_slave_result);
        }
        break;

    //master request
    case SYNC_CMD_UPDATE_OVER:
        log_info("SYNC_CMD_UPDATE_OVER\n");

        __this->ota_status = OTA_OVER;
        __this->ota_remote_status = OTA_OVER;
        if ((__this->ota_result & BIT(TWS_ROLE_MASTER)) && (__this->ota_result & BIT(TWS_ROLE_SLAVE))) {
            log_info("OTA SUCCESS\n");
            //update boot info
            if (tws_api_get_role() == TWS_ROLE_SLAVE) {
                dual_bank_update_burn_boot_info(dual_bank_update_burn_boot_info_callback);
            }
        } else {
            log_info("OTA ERR\n");
            /* tws_ota_event_post(SYS_BT_OTA_EVENT_TYPE_STATUS,OTA_UPDATE_SUCC); */
        }
        break;

    //slave request
    case SYNC_CMD_UPDATE_ERR:
        log_info("SYNC_CMD_UPDATE_ERR\n");
        if (tws_api_get_role() == TWS_ROLE_MASTER) {
        } else {
            tws_ota_stop(OTA_STOP_UPDATE_OVER_ERR);
        }
        break;

    default:
        ret = 0;
        break;
    }
    return ret;
}

void tws_ota_app_event_deal(u8 evevt)
{
    if (__this->ota_status == OTA_OVER) {
        return;
    }

    switch (evevt) {
    case TWS_EVENT_CONNECTION_DETACH:
    /* case TWS_EVENT_PHONE_LINK_DETACH: */
    case TWS_EVENT_REMOVE_PAIRS:
        log_info("stop ota : %d --1\n", evevt);
        tws_ota_stop(OTA_STOP_LINK_DISCONNECT);
        break;
    default:
        break;
    }
}

void tws_ota_stop(u8 reason)
{
    log_info("%s", __func__);

    if (__this->ota_status != OTA_OVER) {

        //reconnect hfp when start err
        if (reason == OTA_STOP_APP_DISCONNECT || reason == OTA_STOP_UPDATE_OVER_ERR) {
            //在更新信息的时候，手机app断开

            /* if(tws_api_get_role() == TWS_ROLE_MASTER) { */
            /*     extern void user_post_key_msg(u8 user_msg); */
            /*     user_post_key_msg(USER_TWS_OTA_RESUME); */
            /* } */
        }

        __this->ota_status = OTA_OVER;
        if (__this->ota_timer_id) {
            sys_timeout_del(__this->ota_timer_id);
            __this->ota_timer_id = 0;
        }

        tws_ota_close();
        dual_bank_passive_update_exit(NULL);
        extern void rcsp_db_update_fail_deal(); //双备份升级失败处理
        rcsp_db_update_fail_deal();
    }
}

int bt_ota_event_handler(struct bt_event *bt)
{
    int ret = 0;
    switch (bt->event) {
    case OTA_START_UPDATE:
        log_info("OTA_START_UPDATE\n");
        tws_api_sync_call_by_uuid(0xA2E22223, SYNC_CMD_START_UPDATE, 400);
        break;
    case OTA_START_UPDATE_READY:
        log_info("OTA_START_UPDATE_READY:%x %x %d\n", __this->para.fm_crc16, __this->para.fm_size, __this->para.max_pkt_len);
        extern void rcsp_before_enter_db_update_mode();
        rcsp_before_enter_db_update_mode();
        if (__this->slave_r_buf) {
            ASSERT(0, "tws_ota_update_loop already exit\n");
        }
        task_create(tws_ota_update_loop, NULL, THIS_TASK_NAME);
        __this->slave_r_buf = malloc(SLAVE_REV_BUF_LEN);
        ASSERT(__this->slave_r_buf, "slave_r_buf malloc err\n");
        cbuf_init(&(__this->cbuffer), __this->slave_r_buf, SLAVE_REV_BUF_LEN);

        os_sem_post(&__this->slave_sem);
        /* tws_ota_event_post(SYS_BT_OTA_EVENT_TYPE_STATUS,OTA_START_UPDATE); */
        break;
    case OTA_START_VERIFY:
        log_info("OTA_START_VERIFY\n");
        if (__this->ota_data_len == __this->para.fm_size) {
            tws_api_sync_call_by_uuid(0xA2E22223, SYNC_CMD_START_VERIFY, 1000);
        } else {
            if (__this->ota_timer_id) {
                sys_timeout_del(__this->ota_timer_id);
                __this->ota_timer_id = 0;
            }
            __this->ota_timer_id = sys_timeout_add(NULL, ota_verify_timeout, 500);
        }
        break;
    case OTA_UPDATE_OVER:
        log_info("OTA_UPDATE_OVER\n");
        tws_api_sync_call_by_uuid(0xA2E22223, SYNC_CMD_UPDATE_OVER, 400);
        break;
    case OTA_UPDATE_ERR:
        log_info("OTA_UPDATE_ERR\n");
        tws_api_sync_call_by_uuid(0xA2E22223, SYNC_CMD_UPDATE_ERR, 400);
        break;
    case OTA_UPDATE_SUCC:
        log_info("OTA_UPDATE_SUCC\n");
        update_result_set(UPDATA_SUCC);
        dual_bank_passive_update_exit(NULL);

        /* update_result_set(UPDATA_SUCC); */
        /* extern void cpu_reset(); */
        /* cpu_reset(); */
        //user_ctl.shutdown_need_adv = 0;
        sys_enter_soft_poweroff((void *)1);
        break;
    default:
        break;
    }

    return 0;
}

static void smartbox_tws_ota_sync_handler(int reason, int err)
{
    tws_ota_sync_cmd(reason);
}

TWS_SYNC_CALL_REGISTER(smartbox_tws_ota_sync) = {
    .uuid = 0xA2E22223,
    .task_name = "app_core",
    .func = smartbox_tws_ota_sync_handler,
};

#endif

