/***************************************************************************
 *
 * Copyright 2015-2019 BES.
 * All rights reserved. All unpublished rights reserved.
 *
 * No part of this work may be used or reproduced in any form or by any
 * means, or stored in a database or retrieval system, without prior written
 * permission of BES.
 *
 * Use of this work is governed by a license granted by BES.
 * This work contains confidential and proprietary information of
 * BES. which is protected by copyright, trade secret,
 * trademark and other intellectual property rights.
 *
 ****************************************************************************/
#include "cmsis_os.h"
#include "list.h"
#include "hal_trace.h"
#include "hal_bootmode.h"
#include "hal_cmu.h"
#include "hal_sleep.h"
#include "app_key.h"
#include "app_factory.h"
#include "bt_drv_interface.h"
#include "bt_drv_reg_op.h"
#include "bluetooth.h"
#include "nvrecord.h"
#include "nvrecord_dev.h"
#include "nvrecord_env.h"
#include "resources.h"
#include "app_bt_stream.h"
#include "app_media_player.h"
#include "pmu.h"

// for init
#include "apps.h"
#include "app_status_ind.h"
#include "app_thread.h"
#include "app_key.h"
#include "app_pwl.h"
#include "app_overlay.h"
#include "app_battery.h"
#include "app_utils.h"

// for bt
#include "besbt.h"
#include "app_bt.h"
#include "app_factory_bt.h"

// for audio
#include "audioflinger.h"
#include "app_audio.h"
#include "app_utils.h"



// for progress
#include "hal_uart.h"
#include "tool_msg.h"

#include "factory_section.h"

#ifdef __FACTORY_MODE_SUPPORT__

#define APP_FACTORYMODE_RETRY_LIMITED (2)

typedef enum APP_FACTORYMODE_STATUS_INDICATION_T {
    APP_FACTORYMODE_STATUS_INDICATION_RUNNING = 0,
    APP_FACTORYMODE_STATUS_INDICATION_PASS,
    APP_FACTORYMODE_STATUS_INDICATION_FAILED,
    APP_FACTORYMODE_STATUS_INDICATION_INVALID,

    APP_FACTORYMODE_STATUS_INDICATION_NUM
}APP_FACTORYMODE_STATUS_INDICATION_T;

static void app_factorymode_timehandler(void const *param);
void app_bt_key_shutdown(APP_KEY_STATUS *status, void *param);
void app_factorymode_result_set(bool result);

static osThreadId app_factorymode_tid= NULL;
static struct message_t send_msg = { { PREFIX_CHAR, }, };
static unsigned char send_seq = 0;

osTimerId app_factory_timer = NULL;
osTimerDef (APP_FACTORY_TIMER, app_factorymode_timehandler);

int app_factorymode_languageswitch_proc(void)
{
#ifdef MEDIA_PLAYER_SUPPORT
    int lan;
    int new_lan;
    struct nvrecord_env_t *nvrecord_env;


    APP_FACTORY_TRACE(1,"%s",__func__);
    lan = app_play_audio_get_lang();
    new_lan = lan;
    app_play_audio_set_lang(new_lan);

    nv_record_env_get(&nvrecord_env);
    nvrecord_env->media_language.language = new_lan;
    nv_record_env_set(nvrecord_env);

    APP_FACTORY_TRACE(2,"languages old:%d new:%d",lan ,new_lan);
    media_PlayAudio(AUD_ID_LANGUAGE_SWITCH, 0);
#endif
    return 0;
}

void app_factorymode_languageswitch(APP_KEY_STATUS *status, void *param)
{
    app_factorymode_languageswitch_proc();
}

void app_factorymode_enter(void)
{
    APP_FACTORY_TRACE(1,"%s",__func__);
    hal_sw_bootmode_set(HAL_SW_BOOTMODE_TEST_MODE|HAL_SW_BOOTMODE_TEST_SIGNALINGMODE);
    hal_cmu_sys_reboot();
}

extern "C" {

static bool isInFactoryMode = false;

bool app_factorymode_get(void)
{
    return isInFactoryMode;
}

void app_factorymode_set(bool set)
{
    isInFactoryMode = set;
}

}
#ifdef POWERKEY_I2C_SWITCH
void app_factorymode_i2c_switch(APP_KEY_STATUS *status, void *param)
{
    static int i = 0;

    i++;
    if (i & 1) {
        TRACE(0,"set analog i2c mode !!!");
        osDelay(100);
        hal_iomux_set_analog_i2c();
    } else {
        hal_iomux_set_uart0();
        osDelay(100);
        TRACE(0,"hal_iomux_set_uart0 !!!");
    }
}
#endif

#ifdef __IBRT_IBRT_TESTMODE__
void bt_drv_ibrt_test_key_click(APP_KEY_STATUS *status, void *param);
void bt_drv_ibrt_test_key_click(APP_KEY_STATUS *status, void *param)
{
    btdrv_connect_ibrt_device(bt_addr);
}
#endif

void app_factorymode_key_init(void)
{
    const APP_KEY_HANDLE  app_factorymode_handle_cfg[] = {
#ifdef POWERKEY_I2C_SWITCH
        {{APP_KEY_CODE_PWR,APP_KEY_EVENT_RAMPAGECLICK},"bt i2c key",app_factorymode_i2c_switch, NULL},
#endif
#ifdef __POWERKEY_CTRL_ONOFF_ONLY__
        {{APP_KEY_CODE_PWR,APP_KEY_EVENT_UP},"bt function key",app_bt_key_shutdown, NULL},
#else
        {{APP_KEY_CODE_PWR,APP_KEY_EVENT_LONGLONGPRESS},"bt function key",app_bt_key_shutdown, NULL},
#endif
#ifdef __IBRT_IBRT_TESTMODE__
        {{APP_KEY_CODE_PWR,APP_KEY_EVENT_CLICK},"bt function key",bt_drv_ibrt_test_key_click, NULL},
#else
        {{APP_KEY_CODE_PWR,APP_KEY_EVENT_CLICK},"bt function key",app_factorymode_languageswitch, NULL},
#endif
        {{APP_KEY_CODE_PWR,APP_KEY_EVENT_DOUBLECLICK},"bt function key",app_factorymode_bt_xtalcalib, NULL},
        {{APP_KEY_CODE_PWR,APP_KEY_EVENT_LONGPRESS},"bt function key",app_factorymode_bt_signalingtest, NULL},
    };

    uint8_t i = 0;

    APP_FACTORY_TRACE(1,"%s",__func__);

    app_key_handle_clear();
    for (i=0; i<(sizeof(app_factorymode_handle_cfg)/sizeof(APP_KEY_HANDLE)); i++){
        app_key_handle_registration(&app_factorymode_handle_cfg[i]);
    }
}

static void app_factorymode_audioloopswitch(APP_KEY_STATUS *status, void *param)
{
    static bool onaudioloop = false;

    onaudioloop = onaudioloop?false:true;

    if (onaudioloop)
        app_audio_sendrequest(APP_FACTORYMODE_AUDIO_LOOP, (uint8_t)APP_BT_SETTING_OPEN, 0);
    else
        app_audio_sendrequest(APP_FACTORYMODE_AUDIO_LOOP, (uint8_t)APP_BT_SETTING_CLOSE, 0);
}

void app_factorymode_test_key_init(void)
{
    const APP_KEY_HANDLE  app_factorymode_handle_cfg[] = {
        {{APP_KEY_CODE_PWR,APP_KEY_EVENT_CLICK},"bt function key",app_factorymode_audioloopswitch, NULL},
    };

    uint8_t i = 0;
    APP_FACTORY_TRACE(1,"%s",__func__);
    for (i=0; i<(sizeof(app_factorymode_handle_cfg)/sizeof(APP_KEY_HANDLE)); i++){
        app_key_handle_registration(&app_factorymode_handle_cfg[i]);
    }
}

void app_factorymode_result_clean(void)
{
    osSignalClear(app_factorymode_tid, 0x01);
    osSignalClear(app_factorymode_tid, 0x02);
}

void app_factorymode_result_set(bool result)
{
    if (result)
        osSignalSet(app_factorymode_tid  ,0x01);
    else
        osSignalSet(app_factorymode_tid  ,0x02);
}

bool app_factorymode_result_wait(void)
{
    bool nRet;
    osEvent evt;

    while(1)
    {
        //wait any signal
        evt = osSignalWait(0x0, osWaitForever);

        //get role from signal value
        if(evt.status == osEventSignal)
        {
            if(evt.value.signals & 0x01)
            {
                nRet = true;
                break;
            }
            else if(evt.value.signals & 0x02)
            {
                nRet = false;
                break;
            }
        }
    }
    return nRet;
}

static int app_factorymode_send_progress (uint8_t progress)
{
    APP_MESSAGE_BLOCK msg;

    msg.mod_id = APP_MODUAL_OHTER;
    msg.msg_body.message_id = 2;
    msg.msg_body.message_Param0 = progress;
    app_mailbox_put(&msg);

    return 0;
}

static int app_factorymode_send_code (uint32_t progress)
{
    APP_MESSAGE_BLOCK msg;

    msg.mod_id = APP_MODUAL_OHTER;
    msg.msg_body.message_id = 3;
    msg.msg_body.message_Param0 = progress;
    app_mailbox_put(&msg);

    return 0;
}

int app_factorymode_proc(void)
{
    uint8_t cnt = 0;
    bool nRet;
    app_factorymode_tid = osThreadGetId();

    app_factorymode_send_progress(60);
    app_factorymode_bt_init_connect();

    do{
        app_factorymode_result_clean();
        app_factorymode_bt_create_connect();
        nRet = app_factorymode_result_wait();
    }while(!nRet && ++cnt < APP_FACTORYMODE_RETRY_LIMITED);

    if (!nRet)
        goto exit;
    app_factorymode_send_progress(90);
    app_factorymode_result_clean();
    if (!nRet)
        goto exit;
    app_factorymode_send_progress(100);
    osDelay(100);
exit:
    app_factorymode_result_clean();
    if (nRet){
        return 0;
    }else{
        return -1;
    }
}

static unsigned char app_factorymode_msg_check_sum(unsigned char *buf, unsigned char len)
{
    int i;
    unsigned char sum = 0;

    for (i = 0; i < len; i++) {
        sum += buf[i];
    }

    return sum;
}

static int app_factorymode_msg_uart_send(const unsigned char *buf, size_t len)
{
    uint32_t sent = 0;

    while (sent < len) {
        hal_uart_blocked_putc(HAL_UART_ID_0, buf[sent++]);
    }

    if (sent != len) {
        return 1;
    }

    return 0;
}

static int app_factorymode_msg_send_ping(void)
{
    int ret;

    send_msg.hdr.type = 0x88;
    send_msg.hdr.seq = send_seq++;
    send_msg.hdr.len = 2;
    send_msg.data[0] = 0xaa;
    send_msg.data[1] = 0x55;
    send_msg.data[2] = ~app_factorymode_msg_check_sum((unsigned char *)&send_msg, MSG_TOTAL_LEN(&send_msg) - 1);

    ret = app_factorymode_msg_uart_send((unsigned char *)&send_msg, MSG_TOTAL_LEN(&send_msg));

    return ret;
}

static int app_factorymode_msg_send_progress (uint8_t progress)
{
    int ret;

    send_msg.hdr.type = 0x88;
    send_msg.hdr.seq = send_seq++;
    send_msg.hdr.len = 2;
    send_msg.data[0] = progress;
    send_msg.data[1] = 100;
    send_msg.data[2] = ~app_factorymode_msg_check_sum((unsigned char *)&send_msg, MSG_TOTAL_LEN(&send_msg) - 1);

    ret = app_factorymode_msg_uart_send((unsigned char *)&send_msg, MSG_TOTAL_LEN(&send_msg));

    return ret;
}

static int app_factorymode_msg_send_32bitcode(uint32_t code)
{
    int ret;

    send_msg.hdr.type = 0x88;
    send_msg.hdr.seq = send_seq++;
    send_msg.hdr.len = 4;
    send_msg.data[0] = 0xf2;
    *(uint32_t *)&(send_msg.data[1]) = code;
    send_msg.data[4] = ~app_factorymode_msg_check_sum((unsigned char *)&send_msg, MSG_TOTAL_LEN(&send_msg) - 1);

    ret = app_factorymode_msg_uart_send((unsigned char *)&send_msg, MSG_TOTAL_LEN(&send_msg));

    return ret;
}

static int app_factorymode_process(APP_MESSAGE_BODY *msg_body)
{
    if (msg_body->message_id == 1){
        app_factorymode_msg_send_ping();
    }
    if (msg_body->message_id == 2){
        app_factorymode_msg_send_progress(msg_body->message_Param0);
    }
    if (msg_body->message_id == 3){
        app_factorymode_msg_send_32bitcode(msg_body->message_Param0);
    }
    return 0;
}

static int app_factorymode_uart_init(void)
{
    struct HAL_UART_CFG_T uart_cfg;

    memset(&uart_cfg, 0, sizeof(struct HAL_UART_CFG_T));
    uart_cfg.parity = HAL_UART_PARITY_NONE,
    uart_cfg.stop = HAL_UART_STOP_BITS_1,
    uart_cfg.data = HAL_UART_DATA_BITS_8,
    uart_cfg.flow = HAL_UART_FLOW_CONTROL_NONE,//HAL_UART_FLOW_CONTROL_RTSCTS,
    uart_cfg.tx_level = HAL_UART_FIFO_LEVEL_1_2,
    uart_cfg.rx_level = HAL_UART_FIFO_LEVEL_1_4,
    uart_cfg.baud = 921600,
    uart_cfg.dma_rx = false,
    uart_cfg.dma_tx = false,
    uart_cfg.dma_rx_stop_on_err = false;
    hal_uart_close(HAL_UART_ID_0);
    hal_uart_open(HAL_UART_ID_0, &uart_cfg);

    return 0;
}


static void app_factorymode_timehandler(void const *param)
{
    APP_MESSAGE_BLOCK msg;

    msg.mod_id = APP_MODUAL_OHTER;
    msg.msg_body.message_id = 1;
    app_mailbox_put(&msg);
}

static uint8_t app_factorymode_indication_init(void)
{
    struct APP_PWL_CFG_T cfg;

    memset(&cfg, 0, sizeof(struct APP_PWL_CFG_T));
    app_pwl_open();
    app_pwl_setup(APP_PWL_ID_0, &cfg);
    app_pwl_setup(APP_PWL_ID_1, &cfg);
    return 0;
}

static uint8_t app_factorymode_status_indication(APP_FACTORYMODE_STATUS_INDICATION_T status)
{
    struct APP_PWL_CFG_T cfg0;
    struct APP_PWL_CFG_T cfg1;
    APP_FACTORY_TRACE(2,"%s %d",__func__, status);
    memset(&cfg0, 0, sizeof(struct APP_PWL_CFG_T));
    memset(&cfg1, 0, sizeof(struct APP_PWL_CFG_T));
    app_pwl_stop(APP_PWL_ID_0);
    app_pwl_stop(APP_PWL_ID_1);
    switch (status) {
        case APP_FACTORYMODE_STATUS_INDICATION_RUNNING:
            cfg0.part[0].level = 0;
            cfg0.part[0].time = (300);
            cfg0.part[1].level = 1;
            cfg0.part[1].time = (300);
            cfg0.parttotal = 2;
            cfg0.startlevel = 0;
            cfg0.periodic = true;

            cfg1.part[0].level = 1;
            cfg1.part[0].time = (300);
            cfg1.part[1].level = 0;
            cfg1.part[1].time = (300);
            cfg1.parttotal = 2;
            cfg1.startlevel = 1;
            cfg1.periodic = true;

            app_pwl_setup(APP_PWL_ID_0, &cfg0);
            app_pwl_start(APP_PWL_ID_0);
            app_pwl_setup(APP_PWL_ID_1, &cfg1);
            app_pwl_start(APP_PWL_ID_1);
            break;
        case APP_FACTORYMODE_STATUS_INDICATION_PASS:
            cfg0.part[0].level = 1;
            cfg0.part[0].time = (5000);
            cfg0.parttotal = 1;
            cfg0.startlevel = 1;
            cfg0.periodic = false;

            app_pwl_setup(APP_PWL_ID_0, &cfg0);
            app_pwl_start(APP_PWL_ID_0);
            break;
        case APP_FACTORYMODE_STATUS_INDICATION_FAILED:
            cfg1.part[0].level = 1;
            cfg1.part[0].time = (5000);
            cfg1.parttotal = 1;
            cfg1.startlevel = 1;
            cfg1.periodic = false;

            app_pwl_setup(APP_PWL_ID_1, &cfg1);
            app_pwl_start(APP_PWL_ID_1);

            break;

        default:
            break;
    }
    return 0;
}

int app_factorymode_init(uint32_t factorymode)
{
    uint8_t cnt = 0;
    int nRet = 0;
    uint32_t capval = 0x00;
    struct nvrecord_env_t *nvrecord_env;
    APP_FACTORY_TRACE(1,"app_factorymode_init mode:%x\n", factorymode);

    osThreadSetPriority(osThreadGetId(), osPriorityRealtime);
    app_factorymode_uart_init();
#ifdef __WATCHER_DOG_RESET__
    app_wdt_open(60);
#endif
    app_sysfreq_req(APP_SYSFREQ_USER_APP_0, APP_SYSFREQ_52M);
    list_init();
    app_os_init();
    app_factorymode_indication_init();
    app_battery_open();
    if (app_key_open(false)){
        nRet = -1;
        goto exit;
    }
    app_set_threadhandle(APP_MODUAL_OHTER, app_factorymode_process);
    app_factory_timer = osTimerCreate (osTimer(APP_FACTORY_TIMER), osTimerPeriodic, NULL);
    osTimerStart(app_factory_timer, 300);
    app_factorymode_send_progress(10);

    app_bt_init();
    af_open();
    app_audio_open();
    app_overlay_open();

    nv_record_env_init();
    nvrec_dev_data_open();
    nv_record_env_get(&nvrecord_env);
#ifdef MEDIA_PLAYER_SUPPORT
    app_play_audio_set_lang(nvrecord_env->media_language.language);
    app_voice_report(APP_STATUS_INDICATION_POWERON, 0);
#endif
    app_status_indication_set(APP_STATUS_INDICATION_POWERON);
    app_factorymode_status_indication(APP_FACTORYMODE_STATUS_INDICATION_RUNNING);

    if (factorymode&HAL_SW_BOOTMODE_CALIB){
        btdrv_start_bt();
        app_factorymode_send_progress(20);

        do {
            nRet = app_factorymode_bt_xtalcalib_proc();
        }while(nRet && cnt++<APP_FACTORYMODE_RETRY_LIMITED);

        if (nRet)
            goto err;
        osDelay(200);
        app_factorymode_send_progress(30);
    }

    nvrec_dev_get_xtal_fcap((unsigned int*)&capval);
    app_factorymode_send_code(capval);

    btdrv_start_bt();
    bt_drv_reg_op_key_gen_after_reset(false);
    app_factorymode_send_progress(40);
    BesbtInit();
    osDelay(600);

    nRet = app_factorymode_proc();
    if (nRet)
        goto err;

    app_factorymode_test_key_init();
    //osTimerStop(app_factory_timer);
    app_factorymode_status_indication(APP_FACTORYMODE_STATUS_INDICATION_PASS);

    //wait forever
    osSignalWait(0x01, osWaitForever);
    goto exit;

err:
    osTimerStop(app_factory_timer);
    app_factorymode_status_indication(APP_FACTORYMODE_STATUS_INDICATION_FAILED);
    app_factorymode_send_code(0xff);
    osSignalWait(0x01, osWaitForever);
exit:
    app_sysfreq_req(APP_SYSFREQ_USER_APP_0, APP_SYSFREQ_32K);
    pmu_shutdown();
    return nRet;
}

int app_factorymode_calib_only(void)
{
    uint8_t cnt = 0;
    int nRet = 0;
    uint32_t capval = 0x00;

    app_factorymode_uart_init();
#ifdef __WATCHER_DOG_RESET__
    app_wdt_reopen(60);
#endif
    app_sysfreq_req(APP_SYSFREQ_USER_APP_0, APP_SYSFREQ_52M);
    list_init();
    app_os_init();
    nv_record_env_init();
    nvrec_dev_data_open();
    factory_section_open();
    app_factorymode_indication_init();

    app_set_threadhandle(APP_MODUAL_OHTER, app_factorymode_process);
    app_factory_timer = osTimerCreate(osTimer(APP_FACTORY_TIMER),osTimerPeriodic,NULL);
    osTimerStart(app_factory_timer,300);
    app_factorymode_status_indication(APP_FACTORYMODE_STATUS_INDICATION_RUNNING);
    app_factorymode_send_progress(10);
    btdrv_start_bt();
    osDelay(20);
    app_factorymode_send_progress(20);
    do {
        nRet = app_factorymode_bt_xtalcalib_proc();
    }while(nRet && ++cnt < APP_FACTORYMODE_RETRY_LIMITED);
    if(nRet)
        goto err;

    nvrec_dev_get_xtal_fcap((unsigned int*)&capval);
    app_factorymode_send_code(capval);

    app_factorymode_send_progress(50);
    osDelay(200);
    app_factorymode_send_progress(80);
    osDelay(100);
    app_factorymode_send_progress(100);
    app_factorymode_status_indication(APP_FACTORYMODE_STATUS_INDICATION_PASS);
    osSignalWait(0x01, osWaitForever);
    goto exit;

err:
    osTimerStop(app_factory_timer);
    app_factorymode_status_indication(APP_FACTORYMODE_STATUS_INDICATION_FAILED);
    app_factorymode_send_code(0xff);
    osSignalWait(0x01, osWaitForever);
exit:

    app_sysfreq_req(APP_SYSFREQ_USER_APP_0, APP_SYSFREQ_32K);
    pmu_shutdown();
    return nRet;
}

#ifdef __USB_COMM__
// for usb
#include "usb_cdc.h"
#include "hal_timer.h"
#include "hwtimer_list.h"

#include "hal_usb.h"
#include "app_factory_cdc_comm.h"
#include "sys_api_cdc_comm.h"

static const struct USB_SERIAL_CFG_T cdc_cfg = {
    .mode = USB_SERIAL_API_NONBLOCKING,
};

static void usb_serial_recv_timeout(void *param)
{
    usb_serial_cancel_recv();
}

int app_factorymode_cdc_comm(void)
{
    HWTIMER_ID timer;
    pmu_usb_config(PMU_USB_CONFIG_TYPE_DEVICE);
    usb_serial_open(&cdc_cfg);
    osDelay(500);

    hwtimer_init();
    timer = hwtimer_alloc(usb_serial_recv_timeout, NULL);
    ASSERT(timer, "Failed to alloc usb serial recv timer");

    usb_serial_flush_recv_buffer();
    usb_serial_init_xfer();
    af_open();

    comm_loop();
    return 1;
}
#endif
#endif
