/*********************************************************************************************************************
* TC264 Opensourec Library TC264 Դ⣩һڹٷ SDK ӿڵĵԴ
* Copyright (c) 2022 SEEKFREE ɿƼ
*
* ļ TC264 Դһ
*
* TC264 Դ 
* Ըᷢ GPLGNU General Public License GNUͨù֤
*  GPL ĵ3棨 GPL3.0ѡģκκİ汾·/޸
*
* Դķϣܷãδκεı֤
* ûԻʺض;ı֤
* ϸμ GPL
*
* ӦյԴͬʱյһ GPL ĸ
* ûУ<https://www.gnu.org/licenses/>
*
* ע
* Դʹ GPL3.0 Դ֤Э Ϊİ汾
* Ӣİ libraries/doc ļµ GPL3_permission_statement.txt ļ
* ֤ libraries ļ ļµ LICENSE ļ
* ӭλʹò ޸ʱ뱣ɿƼİȨ
*
* ļ          zf_common_debug
* ˾          ɶɿƼ޹˾
* 汾Ϣ          鿴 libraries/doc ļ version ļ 汾˵
*           ADS v1.9.4
* ƽ̨          TC264D
*           https://seekfree.taobao.com/
*
* ޸ļ¼
*                               ע
* 2022-09-15       pudding            first version
* 2022-05-26       pudding            Դڷͺ
********************************************************************************************************************/

#include "zf_common_interrupt.h"
#include "zf_common_fifo.h"
#include "zf_driver_uart.h"
#include "zf_common_debug.h"

static debug_output_struct  debug_output_info;
static volatile uint8       zf_debug_init_flag = 0;
static volatile uint8       zf_debug_assert_enable = 1;

#if DEBUG_UART_USE_INTERRUPT                                                    //  debug uart ж
uint8                       debug_uart_buffer[DEBUG_RING_BUFFER_LEN];           // ݴ
uint8                       debug_uart_data;
fifo_struct                 debug_uart_fifo;
#endif

//-------------------------------------------------------------------------------------------------------------------
//      debug ʱ  200MHz һʱ ƬҪݸʱ
// ˵     void
// ز     void
// ʹʾ     debug_delay();
// עϢ     ļڲ ûùע Ҳ޸
//-------------------------------------------------------------------------------------------------------------------
static void debug_delay (void)
{
    vuint32 loop_1 = 0, loop_2 = 0;
    for(loop_1 = 0; loop_1 <= 0xFFF; loop_1 ++)
        for(loop_2 = 0; loop_2 <= 0x1FFF; loop_2 ++);
}

//-------------------------------------------------------------------------------------------------------------------
//      debug ӿ
// ˵     *str        Ҫַ
// ز     void
// ʹʾ     debug_uart_str_output("Log message");
// עϢ     ļڲ ûùע Ҳ޸
//-------------------------------------------------------------------------------------------------------------------
static void debug_uart_str_output (const char *str)
{
    uart_write_string(DEBUG_UART_INDEX, str);
}



//-------------------------------------------------------------------------------------------------------------------
//      debug ӿ
// ˵     *type       log 
// ˵     *file       ļ
// ˵     line        Ŀ
// ˵     *str        Ϣ
// ز     void
// ʹʾ     debug_output("Log message", file, line, str);
// עϢ     ļڲ ûùע Ҳ޸
//-------------------------------------------------------------------------------------------------------------------
static void debug_output (char *type, char *file, int line, char *str)
{
    char *file_str;
    vuint16 i = 0, j = 0;
    vint32 len_origin = 0;
    vint16 show_len = 0;
    vint16 show_line_index = 0;
    len_origin = strlen(file);

    char output_buffer[256];
    char file_path_buffer[64];

    if(debug_output_info.type_index)
    {
        debug_output_info.output_screen_clear();
    }

    if(zf_debug_init_flag)
    {
        if(debug_output_info.type_index)
        {
            // Ҫнļ·
            // <· ֻһĿ¼  src/main.c>
            //  line : xxxx
            debug_output_info.output_screen(0, show_line_index ++, type);

            file_str = file;
            len_origin = strlen(file);
            show_len = (debug_output_info.display_x_max / debug_output_info.font_x_size);

            while(*file_str++ != '\0');

            // ֻȡһĿ¼ ļ̷Ŀ¼  MDK Ĺ̸Ŀ¼ ͻֱǰĿ¼
            for(j = 0; (j < 2) && (len_origin >= 0); len_origin --)             //  '/'
            {
                file_str --;
                if((*file_str == '/') || (*file_str == 0x5C))
                {
                    j ++;
                }
            }

            // ļ·浽
            if(len_origin >= 0)
            {
                file_str ++;
                sprintf(output_buffer, "file: %s", file_str);
            }
            else
            {
                if(0 == j)
                {
                    sprintf(output_buffer, "file: mdk/%s", file_str);
                }
                else
                {
                    sprintf(output_buffer, "file: %s", file_str);
                }
            }

            // Ļʾ·
            for(i = 0; i < ((strlen(output_buffer) / show_len) + 1); i ++)
            {
                for(j = 0; j < show_len; j ++)
                {
                    if(strlen(output_buffer) < (j + i * show_len))
                    {
                        break;
                    }
                    file_path_buffer[j] = output_buffer[j + i * show_len];
                }

                file_path_buffer[j] = '\0';                                     // ĩβ\0

                debug_output_info.output_screen(0, debug_output_info.font_y_size * show_line_index ++, file_path_buffer);
            }

            // Ļʾк
            sprintf(output_buffer, "line: %d", line);
            debug_output_info.output_screen(0, debug_output_info.font_y_size * show_line_index ++, output_buffer);

            // Ļʾ Log еĻ
            if(NULL != str)
            {
                for(i = 0; i < ((strlen(str) / show_len) + 1); i ++)
                {
                    for(j = 0; j < show_len; j ++)
                    {
                        if(strlen(str) < (j + i * show_len))
                        {
                            break;
                        }
                        file_path_buffer[j] = str[j + i * show_len];
                    }

                    file_path_buffer[j] = '\0';                                 // ĩβ\0

                    debug_output_info.output_screen(0, debug_output_info.font_y_size * show_line_index ++, file_path_buffer);
                }
            }
        }
        else
        {
            char output_buffer[256];
            memset(output_buffer, 0, 256);
            debug_output_info.output_uart(type);
            if(NULL != str)
            {
                sprintf(output_buffer, "\r\nfile %s line %d: %s.\r\n", file, line, str);
            }
            else
            {
                sprintf(output_buffer, "\r\nfile %s line %d.\r\n", file, line);
            }
            debug_output_info.output_uart(output_buffer);
        }
    }
}

//-------------------------------------------------------------------------------------------------------------------
//      Դڷͻ
// ˵     *buff       ݴŵָ
// ˵     len         Ҫ͵ĳ
// ز     uint32      ʣδ͵ĳ
// ʹʾ
// עϢ     Ҫ DEBUG_UART_USE_INTERRUPT 궨ſʹ
//-------------------------------------------------------------------------------------------------------------------
uint32 debug_send_buffer(const uint8 *buff, uint32 len)
{
    uart_write_buffer(DEBUG_UART_INDEX, buff, len);
    return 0;
}

#if DEBUG_UART_USE_INTERRUPT                                                    //  ֻôжϲű

//-------------------------------------------------------------------------------------------------------------------
//      ȡ debug λ
// ˵     *buff       ݴŵָ
// ˵     len         Ҫȡĳ
// ز     uint32      ݵʵʳ
// ʹʾ
// עϢ     Ҫ DEBUG_UART_USE_INTERRUPT 궨ſʹ
//-------------------------------------------------------------------------------------------------------------------
uint32 debug_read_ring_buffer (uint8 *buff, uint32 len)
{
    fifo_read_buffer(&debug_uart_fifo, buff, &len, FIFO_READ_AND_CLEAN);
    return len;
}

//-------------------------------------------------------------------------------------------------------------------
//      debug жϴ isr.c жӦжϷ
// ˵     void
// ز     void
// ʹʾ     debug_interrupr_handler();
// עϢ     Ҫ DEBUG_UART_USE_INTERRUPT 궨ſʹ
//              ұĬϷ UART1 Ĵڽжϴ
//-------------------------------------------------------------------------------------------------------------------
void debug_interrupr_handler (void)
{
    if(zf_debug_init_flag)
    {
        uart_query_byte(DEBUG_UART_INDEX, &debug_uart_data);                    // ȡ
        fifo_write_buffer(&debug_uart_fifo, &debug_uart_data, 1);               //  FIFO
    }
}

#endif


//-------------------------------------------------------------------------     // printf ض ˲ֲû
//-------------------------------------------------------------------------------------------------------------------
//        ضprintf 
//  ˵      ch      Ҫӡֽ
//  ˵      stream  
//  עϢ       ˺ɱԴprintf
//-------------------------------------------------------------------------------------------------------------------
int fputc(int ch, FILE *stream)
{
    uart_write_byte(DEBUG_UART_INDEX, (char)ch);
    return(ch);
}
//-------------------------------------------------------------------------------------------------------------------
//        ضprintf 
//  ˵      ch      Ҫӡֽ
//  ˵      stream  
//  עϢ       ˺ɱԴprintf
//-------------------------------------------------------------------------------------------------------------------
int fgetc(FILE *f)
{
    return uart_read_byte(DEBUG_UART_INDEX);
}
//-------------------------------------------------------------------------     // printf ض ˲ֲû

//-------------------------------------------------------------------------------------------------------------------
//      ö
// ˵     void
// ز     void
// ʹʾ     debug_assert_enable();
// עϢ     ĬϿ 鿪
//-------------------------------------------------------------------------------------------------------------------
void debug_assert_enable (void)
{
    zf_debug_assert_enable = 1;
}

//-------------------------------------------------------------------------------------------------------------------
//      ö
// ˵     void
// ز     void
// ʹʾ     debug_assert_disable();
// עϢ     ĬϿ ö
//-------------------------------------------------------------------------------------------------------------------
void debug_assert_disable (void)
{
    zf_debug_assert_enable = 0;
}

//-------------------------------------------------------------------------------------------------------------------
//      debug Դ
// ˵     pass        жǷ񴥷
// ˵     *file       ļ
// ˵     line        Ŀ
// ز     void
// ʹʾ     zf_assert(0);
// עϢ     ֱӵõ ˲ֲû
//             ʹ zf_commmon_debug.h е zf_assert(x) ӿ
//-------------------------------------------------------------------------------------------------------------------
void debug_assert_handler (uint8 pass, char *file, int line)
{
    if(pass || !zf_debug_assert_enable)
    {
        return;
    }

    static uint8 assert_nest_index = 0;

    if(0 != assert_nest_index)
    {
        while(TRUE);
    }
    assert_nest_index ++;

    assert_interrupt_config();

    while(TRUE)
    {
        // תͣס
        // һĺݳ
        // Լõ zf_assert(x) ӿڴ

        //  debug_init ʼ log 
        // ڶӦȥ鿴ĸļһб

        // ûгʼ debug
        // ǾͿ file ֵַ line 
        // Ǵļ·ƺͶӦ

        // ȥԿΪʲô
        debug_output("Assert error", file, line, NULL);
        debug_delay();
    }
}

//-------------------------------------------------------------------------------------------------------------------
//      debug Ϣ
// ˵     pass        жǷ񴥷
// ˵     *str        Ϣ
// ˵     *file       ļ
// ˵     line        Ŀ
// ز     void
// ʹʾ     zf_log(0, "Log Message");
// עϢ     ֱӵõ ˲ֲû
//             ʹ zf_commmon_debug.h е zf_log(x, str) ӿ
//-------------------------------------------------------------------------------------------------------------------
void debug_log_handler (uint8 pass, char *str, char *file, int line)
{
    if(pass)
    {
        return;
    }
    if(zf_debug_init_flag)
    {
        debug_output("Log message", file, line, str);
    }
}

//-------------------------------------------------------------------------------------------------------------------
//      debug Ϣʼ
// ˵     *info       debug Ϣṹ
// ز     void
// ʹʾ     debug_output_struct_init(info);
// עϢ     һ㲻û
//-------------------------------------------------------------------------------------------------------------------
void debug_output_struct_init (debug_output_struct *info)
{
    info->type_index            = 0;                        // ĻϢ־

    info->display_x_max         = 0xFFFF;                   // ĻʾXֵ
    info->display_y_max         = 0xFFFF;                   // ĻʾYֵ

    info->font_x_size           = 0xFF;                     // Xֵ
    info->font_y_size           = 0xFF;                     // Yֵ

    info->output_uart           = NULL;                     // ϢĴ
    info->output_screen         = NULL;                     // ϢĻ
    info->output_screen_clear   = NULL;                     // Ļ
}

//-------------------------------------------------------------------------------------------------------------------
//      debug 󶨳ʼ
// ˵     *info       debug Ϣṹ
// ز     void
// ʹʾ     debug_output_init(info);
// עϢ     һ㲻û
//-------------------------------------------------------------------------------------------------------------------
void debug_output_init (debug_output_struct *info)
{
    debug_output_info.type_index            = info->type_index;

    debug_output_info.display_x_max         = info->display_x_max;
    debug_output_info.display_y_max         = info->display_y_max;

    debug_output_info.font_x_size           = info->font_x_size;
    debug_output_info.font_y_size           = info->font_y_size;

    debug_output_info.output_uart           = info->output_uart;
    debug_output_info.output_screen         = info->output_screen;
    debug_output_info.output_screen_clear   = info->output_screen_clear;

    zf_debug_init_flag = 1;
}

//-------------------------------------------------------------------------------------------------------------------
//      debug ڳʼ
// ˵     void
// ز     void
// ʹʾ     debug_init();
// עϢ     ԴʾĬϵ ĬϽжϽ
//-------------------------------------------------------------------------------------------------------------------
void debug_init (void)
{
    debug_output_struct info;                   // Ϣṹ
    debug_output_struct_init(&info);            // ʼԵϢ
    info.output_uart = debug_uart_str_output;   // ö
    debug_output_init(&info);

    uart_init(DEBUG_UART_INDEX,                 //  zf_common_debug.h в鿴Ӧֵ
              DEBUG_UART_BAUDRATE,              //  zf_common_debug.h в鿴Ӧֵ
              DEBUG_UART_TX_PIN,                //  zf_common_debug.h в鿴Ӧֵ
              DEBUG_UART_RX_PIN);               //  zf_common_debug.h в鿴Ӧֵ
#if DEBUG_UART_USE_INTERRUPT                                                    //  ֻôжϲű
    fifo_init(&debug_uart_fifo, FIFO_DATA_8BIT, debug_uart_buffer, DEBUG_RING_BUFFER_LEN);
    uart_rx_interrupt(DEBUG_UART_INDEX, 1);                                     // ʹܶӦڽж
#endif
}



