/**
* @file tuya_device.c
* @author www.tuya.com
* @brief tuya_device module is used to 
* @version 0.1
* @date 2022-05-20
*
* @copyright Copyright (c) tuya.inc 2022
*
*/
#include "tuya_iot_config.h"

#if defined(ENABLE_SPI) && (ENABLE_SPI) 

#include "tuya_cloud_types.h"

#include "tal_log.h"
#include "tal_thread.h"
#include "tal_system.h"
#include "tkl_spi.h"
#include "tkl_semaphore.h"
#include "tkl_output.h"
/***********************************************************
*************************micro define***********************
***********************************************************/
#define SPI_ID                      TUYA_SPI_NUM_0
#define SPI_FREQ                    10000000
#define SPI_BUF_LEN                 1024

#define WITHOUT_DMA                 0
#define WITH_DMA                    1

#define MASTER_TO_SLAVE_MSG        "The is a blessing form master"
#define SLAVE_TO_MASTER_MSG        "The is a blessing form slave"

/***********************************************************
***********************typedef define***********************
***********************************************************/


/***********************************************************
***********************variable define**********************
***********************************************************/
STATIC TKL_SEM_HANDLE exmaple_spi_complete_sem = NULL;
STATIC UINT8_T *send_data_buf = NULL;
STATIC UINT8_T *recv_data_buf = NULL;

STATIC TUYA_SPI_BASE_CFG_T demo_spi_cfg = {
    .mode = TUYA_SPI_MODE0,
    .type = TUYA_SPI_AUTO_TYPE,
    .databits = TUYA_SPI_DATA_BIT8,
    .bitorder = TUYA_SPI_ORDER_MSB2LSB,
    .freq_hz = SPI_FREQ,
};

/***********************************************************
***********************function define**********************
***********************************************************/

STATIC VOID __example_spi_event_cb(TUYA_SPI_NUM_E port, TUYA_SPI_IRQ_EVT_E event)
{
    if ((event == TUYA_SPI_EVENT_TX_COMPLETE) || (event == TUYA_SPI_EVENT_RX_COMPLETE)) {
        tkl_log_output("post sem %d\r\n", event);
        tkl_semaphore_post(exmaple_spi_complete_sem);
    }
}

STATIC OPERATE_RET __example_spi_init(TUYA_SPI_NUM_E port, TUYA_SPI_ROLE_E role, INT_T with_dma, UINT8_T is_half_dup)
{
    OPERATE_RET rt = OPRT_OK;

    demo_spi_cfg.role = role;
    demo_spi_cfg.spi_dma_flags = with_dma;
    TUYA_CALL_ERR_GOTO(tkl_spi_init(port,  &demo_spi_cfg), __EXIT);

    if (is_half_dup)
    {
        tkl_spi_irq_init(port, __example_spi_event_cb);
        tkl_spi_irq_enable(port);
        tkl_semaphore_create_init(&exmaple_spi_complete_sem, 0, 1);
    }

    send_data_buf = (UINT8_T *)tkl_system_malloc(SPI_BUF_LEN);
    TUYA_CHECK_NULL_GOTO(send_data_buf, __EXIT);
    recv_data_buf = (UINT8_T *)tkl_system_malloc(SPI_BUF_LEN);
    TUYA_CHECK_NULL_GOTO(recv_data_buf, __EXIT);

__EXIT:
    return rt;
}

STATIC OPERATE_RET __example_spi_deinit(TUYA_SPI_NUM_E port)
{
    OPERATE_RET rt = OPRT_OK;

    TUYA_CALL_ERR_LOG(tkl_spi_deinit(port));

    if (send_data_buf)
    {
        tkl_system_free(send_data_buf);
        send_data_buf = NULL;
    }

    if (recv_data_buf)
    {
        tkl_system_free(recv_data_buf);
        recv_data_buf = NULL;
    }

    if (exmaple_spi_complete_sem)
    {
        tkl_semaphore_release(exmaple_spi_complete_sem);
        exmaple_spi_complete_sem = NULL;
    }

__EXIT:
    return rt;
}

OPERATE_RET example_spi_master_in_half_duplex(INT_T argc, CHAR_T *argv[])
{
    OPERATE_RET rt = OPRT_OK;
    UINT8_T master_to_slave[] = MASTER_TO_SLAVE_MSG;
    UINT32_T data_len = 0;

    /* init master spi */
    TUYA_CALL_ERR_GOTO(__example_spi_init(TUYA_SPI_NUM_0, TUYA_SPI_ROLE_MASTER, WITHOUT_DMA, true), __EXIT);

    /* master recv in half */
    TUYA_CHECK_NULL_GOTO(recv_data_buf, __EXIT);
    memset(recv_data_buf, 0, SPI_BUF_LEN);
    data_len = sizeof(SLAVE_TO_MASTER_MSG) - 1;
    TUYA_CALL_ERR_GOTO(tkl_spi_recv(TUYA_SPI_NUM_0, recv_data_buf, data_len), __EXIT);
    tkl_semaphore_wait(exmaple_spi_complete_sem, TKL_SEM_WAIT_FOREVER);
    TAL_PR_NOTICE("master recv data success: %s\r\n", recv_data_buf);

    /* master send in half */
    TUYA_CHECK_NULL_GOTO(send_data_buf, __EXIT);
    memset(send_data_buf, 0, SPI_BUF_LEN);
    data_len = sizeof(MASTER_TO_SLAVE_MSG) - 1;
    memcpy(send_data_buf, master_to_slave, data_len);
    TUYA_CALL_ERR_GOTO(tkl_spi_send(TUYA_SPI_NUM_0, send_data_buf, data_len), __EXIT);
    tkl_semaphore_wait(exmaple_spi_complete_sem, TKL_SEM_WAIT_FOREVER);
    TAL_PR_NOTICE("master send data success: %s\r\n", send_data_buf);

__EXIT:
    TUYA_CALL_ERR_LOG(__example_spi_deinit(TUYA_SPI_NUM_0));

    return rt;
}

OPERATE_RET example_spi_slave_in_half_duplex(INT_T argc, CHAR_T *argv[])
{
    OPERATE_RET rt = OPRT_OK;
    UINT8_T slave_to_master[] = SLAVE_TO_MASTER_MSG;
    UINT32_T data_len = 0;

    /* init slave spi */
    TUYA_CALL_ERR_GOTO(__example_spi_init(TUYA_SPI_NUM_0, TUYA_SPI_ROLE_SLAVE, WITHOUT_DMA, true), __EXIT);

    /* slave send in half */
    TUYA_CHECK_NULL_GOTO(send_data_buf, __EXIT);
    memset(send_data_buf, 0, SPI_BUF_LEN);
    data_len = sizeof(SLAVE_TO_MASTER_MSG) - 1;
    memcpy(send_data_buf, slave_to_master, data_len);
    TUYA_CALL_ERR_GOTO(tkl_spi_send(TUYA_SPI_NUM_0, send_data_buf, data_len), __EXIT);
    tkl_semaphore_wait(exmaple_spi_complete_sem, TKL_SEM_WAIT_FOREVER);
    TAL_PR_NOTICE("slave send data success: %s\r\n", send_data_buf);

    /* slave recv in half */
    TUYA_CHECK_NULL_GOTO(recv_data_buf, __EXIT);
    memset(recv_data_buf, 0, SPI_BUF_LEN);
    data_len = sizeof(MASTER_TO_SLAVE_MSG) - 1;
    TUYA_CALL_ERR_GOTO(tkl_spi_recv(TUYA_SPI_NUM_0, recv_data_buf, data_len), __EXIT);
    tkl_semaphore_wait(exmaple_spi_complete_sem, TKL_SEM_WAIT_FOREVER);
    TAL_PR_NOTICE("slave recv data success: %s\r\n", recv_data_buf);

__EXIT:
    TUYA_CALL_ERR_LOG(__example_spi_deinit(TUYA_SPI_NUM_0));

    return rt;
}

OPERATE_RET example_spi_master_in_full_duplex(INT_T argc, CHAR_T *argv[])
{
    OPERATE_RET rt = OPRT_OK;
    UINT8_T master_to_slave[] = MASTER_TO_SLAVE_MSG;
    UINT32_T data_len = 0;

    /* init master spi */
    TUYA_CALL_ERR_GOTO(__example_spi_init(TUYA_SPI_NUM_0, TUYA_SPI_ROLE_MASTER, WITH_DMA, false), __EXIT);

    /* master recv & send in full */
    TUYA_CHECK_NULL_GOTO(send_data_buf, __EXIT);
    memset(send_data_buf, 0, SPI_BUF_LEN);
    data_len = sizeof(MASTER_TO_SLAVE_MSG) - 1;
    memcpy(send_data_buf, master_to_slave, data_len);

    TUYA_CHECK_NULL_GOTO(recv_data_buf, __EXIT);
    memset(recv_data_buf, 0, SPI_BUF_LEN);
    data_len = (sizeof(SLAVE_TO_MASTER_MSG) - 1 > data_len) ? sizeof(SLAVE_TO_MASTER_MSG) - 1 : data_len;

    TUYA_CALL_ERR_GOTO(tkl_spi_transfer(TUYA_SPI_NUM_0, send_data_buf, recv_data_buf, data_len), __EXIT);

    TAL_PR_NOTICE("master send data success: %s\r\n", send_data_buf);

    TAL_PR_NOTICE("master recv data success: %s\r\n", recv_data_buf);

__EXIT:
    TUYA_CALL_ERR_LOG(__example_spi_deinit(TUYA_SPI_NUM_0));

    return rt;
}

OPERATE_RET example_spi_slave_in_full_duplex(INT_T argc, CHAR_T *argv[])
{
    OPERATE_RET rt = OPRT_OK;
    UINT8_T slave_to_master[] = SLAVE_TO_MASTER_MSG;
    UINT32_T data_len = 0;

    /* init slave spi */
    TUYA_CALL_ERR_GOTO(__example_spi_init(TUYA_SPI_NUM_0, TUYA_SPI_ROLE_SLAVE, WITH_DMA, true), __EXIT);

    /* slave recv & send in full */
    TUYA_CHECK_NULL_GOTO(send_data_buf, __EXIT);
    memset(send_data_buf, 0, SPI_BUF_LEN);
    data_len = sizeof(SLAVE_TO_MASTER_MSG) - 1;
    memcpy(send_data_buf, slave_to_master, data_len);

    TUYA_CHECK_NULL_GOTO(recv_data_buf, __EXIT);
    memset(recv_data_buf, 0, SPI_BUF_LEN);
    data_len = (sizeof(MASTER_TO_SLAVE_MSG) - 1 > data_len) ? sizeof(MASTER_TO_SLAVE_MSG) - 1 : data_len;

    TUYA_CALL_ERR_GOTO(tkl_spi_transfer(TUYA_SPI_NUM_0, send_data_buf, recv_data_buf, data_len), __EXIT);

    TAL_PR_NOTICE("slave send data success: %s\r\n", send_data_buf);

    TAL_PR_NOTICE("slave recv data success: %s\r\n", recv_data_buf);

__EXIT:
    TUYA_CALL_ERR_LOG(__example_spi_deinit(TUYA_SPI_NUM_0));

    return rt;
}
#endif