/*
 * Copyright 2022 MindMotion Microelectronics Co., Ltd.
 * All rights reserved.
 *
 * SPDX-License-Identifier: BSD-3-Clause
 */

#include "board_init.h"

/*
 * Macros.
 */

/* the cmd of spiflash. */
#define APP_SPIFLASH_ENABLE_WRITE           0x06 /* enable write func. */
#define APP_SPIFLASH_DISABLE_WRITE          0x04 /* disable write func. */
#define APP_SPIFLASH_READ_REGISTER_1        0x05 /* get spiflash register-1 status. */
#define APP_SPIFLASH_READ_REGISTER_2        0x35 /* get spiflash register-2 status. */
#define APP_SPIFLASH_WRITE_REGISTER_1       0x01 /* set spiflash register-1 status. */
#define APP_SPIFLASH_WRITE_REGISTER_2       0x31 /* set spiflash register-2 status. */

/* the bit mask of spiflash register. */
#define APP_SPIFLASH_REGISTER2_QE_MASK      0x02 /* the qe(quad enable) bit mask on spiflash register-2. */
#define APP_SPIFLASH_REGISTER1_BUSY_MASK    0x01 /* the busy bit mask on spiflash register-1. */

/*
 * Variables.
 */

/* help string. */
const char str_help[] = "a. get spiflash 4line status.\r\n"
                        "b. unlock 4line mode.\r\n"
                        "c. lock 4line mode.\r\n";

/*
 * Declerations.
 */

bool app_read_4line_status(void); /* get spiflash 4line status. */
void app_enable_4line_mode(bool enable); /* enable or disable 4line mode. */

/*
 * Functions.
 */

int main(void)
{
    uint8_t ch = 0u;
    BOARD_Init();

    printf("spi_flash_unlock_4line_mode.\r\n");
    printf("%s", str_help);

    while (1)
    {
        ch = getchar();
        switch (ch)
        {
            case 'a': /* get spiflash 4line status. */
                if (app_read_4line_status())
                {
                    printf("4line unlocked.\r\n");
                }
                else
                {
                    printf("4line locked.\r\n");
                }
                break;
            case 'b': /* unlock 4line mode. */
                app_enable_4line_mode(true); /* unlock. */
                if (app_read_4line_status()) /* check unlocked. */
                {
                    printf("4line unlock succ.\r\n");
                }
                else
                {
                    printf("4line unlock faild.\r\n");
                }
                break;
            case 'c': /* lock 4line mode. */
                app_enable_4line_mode(false); /* lock. */
                if (!app_read_4line_status()) /* check locked. */
                {
                    printf("4line lock succ.\r\n");
                }
                else
                {
                    printf("4line lock faild.\r\n");
                }
                break;
            default: /* print help. */
                printf("%s", str_help);
                break;
        }
    }
}

/* get spiflash 4line status. */
bool app_read_4line_status(void)
{
    uint8_t cmd_buf[1] = {APP_SPIFLASH_READ_REGISTER_2}; /* send "get register-2 status" cmd. */
    uint8_t status_buf[1] = {0}; /* recv status. */
    softspi_xfer(cmd_buf, sizeof(cmd_buf), status_buf, sizeof(status_buf)); /* xfer. */
    return (0 != (status_buf[0] & APP_SPIFLASH_REGISTER2_QE_MASK)); /* 'true' to unlocked 4line mode, 'false' to locked 4line mode. */
}

/* enable or disable 4line mode. */
void app_enable_4line_mode(bool enable)
{
    uint8_t enable_write_cmd_buf[]    = {APP_SPIFLASH_ENABLE_WRITE};
    uint8_t disable_write_cmd_buf[]   = {APP_SPIFLASH_DISABLE_WRITE};
    uint8_t read_register1_cmd_buf[]  = {APP_SPIFLASH_READ_REGISTER_1};
    uint8_t read_register2_cmd_buf[]  = {APP_SPIFLASH_READ_REGISTER_2};
    uint8_t write_register2_cmd_buf[] = {APP_SPIFLASH_WRITE_REGISTER_2, 0};
    uint8_t status_buf[] = {0};

    /* send "get register-2 status" cmd. */
    softspi_xfer(read_register2_cmd_buf, sizeof(read_register1_cmd_buf), status_buf, sizeof(status_buf)); /* read regsiter-2 status. */

    /* set or reset qe bit. */
    if (enable)
    {
        status_buf[0] |= APP_SPIFLASH_REGISTER2_QE_MASK;
        write_register2_cmd_buf[1] = status_buf[0];
    }
    else
    {
        status_buf[0] &= ~APP_SPIFLASH_REGISTER2_QE_MASK;
        write_register2_cmd_buf[1] = status_buf[0];
    }

    softspi_xfer(enable_write_cmd_buf, sizeof(enable_write_cmd_buf), NULL, 0); /* enable write. */

    softspi_xfer(write_register2_cmd_buf, sizeof(write_register2_cmd_buf), NULL, 0); /* write register-2. */

    for (uint32_t i = 0; i < BOARD_SPIFLASH_WRITE_TIMEOUT; i++) /* wait for set qe bit done. */
    {
        softspi_xfer(read_register1_cmd_buf, sizeof(read_register1_cmd_buf), status_buf, sizeof(status_buf)); /* read regsiter-1 status. */
        if (0 == (status_buf[0] & APP_SPIFLASH_REGISTER1_BUSY_MASK)) /* check busy. */
        {
            break;
        }
    }

    softspi_xfer(disable_write_cmd_buf, sizeof(disable_write_cmd_buf), NULL, 0); /* disable write. */
}

/* EOF. */
