/*********************************************************************************************************************
* 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_device_detector
* ˾          ɶɿƼ޹˾
* 汾Ϣ          鿴 libraries/doc ļ version ļ 汾˵
*           ADS v1.9.4
* ƽ̨          TC264D
*           https://seekfree.taobao.com/
*
* ޸ļ¼
*                               ע
* 2023-05-27       pudding           first version
********************************************************************************************************************/

#include "zf_driver_uart.h"
#include "zf_common_fifo.h"
#include "zf_device_wireless_uart.h"
#include "zf_device_bluetooth_ch9141.h"
#include "zf_device_wifi_uart.h"
#include "zf_device_wifi_spi.h"

#include "zf_device_detector.h"


typedef uint32 (*detector_transfer_callback_function)   (const uint8 *buff, uint32 length);
typedef uint32 (*detector_receive_callback_function)    (uint8 *buff, uint32 length);

detector_transfer_type_enum             detector_transfer_type;                             // ݴ䷽ʽ

detector_transfer_callback_function     detector_transfer_callback;                         // ݷͺָ
detector_receive_callback_function      detector_receive_callback;                          // ݽպָ

detector_oscilloscope_struct            detector_oscilloscope_data;                         // ʾ
static detector_camera_struct           detector_camera_data;                               // ͼλЭ
static detector_camera_dot_struct       detector_camera_dot_data;                           // ͼλЭ
static detector_camera_buffer_struct    detector_camera_buffer;                             // ͼԼ߽绺Ϣ

static fifo_struct                      detector_fifo;
static uint8                            detector_buffer[DETECTOR_BUFFER_SIZE];              // ݴ
float                                   detector_parameter[DETECTOR_SET_PARAMETR_COUNT];    // յĲ

////-------------------------------------------------------------------------------------------------------------------
////      δߴڷͺ
//// ˵     *buff           Ҫ͵ݵַ
//// ˵     length          Ҫ͵ĳ
//// ز     uint32          ʣδݳ
//// ʹʾ     
////-------------------------------------------------------------------------------------------------------------------
//uint32 detector_debug_uart_transfer (const uint8 *buff, uint32 length)
//{
//    uart_write_buffer(DEBUG_UART_INDEX, buff, length);
//    return 0;
//}

////-------------------------------------------------------------------------------------------------------------------
////      δߴڽպ
//// ˵     *buff           Ҫյݵַ
//// ˵     length          Ҫյĳ
//// ز     uint32          ʵʽճ
//// ʹʾ     
////-------------------------------------------------------------------------------------------------------------------
//uint32 detector_debug_uart_receive (uint8 *buff, uint32 length)
//{
//    return debug_read_ring_buffer(buff, length);
//}

//-------------------------------------------------------------------------------------------------------------------
//      δԶֽڷͺ
// ˵     data            Ҫ͵ݵַ
// ز     uint8           
// ʹʾ     
//-------------------------------------------------------------------------------------------------------------------
static uint8 detector_custom_write_byte(const uint8 data)
{
    // ʵֽڷ
    
    return 0;
}

//-------------------------------------------------------------------------------------------------------------------
//      δԶ巢ͺ
// ˵     *buff           Ҫ͵ݵַ
// ˵     length          Ҫ͵ĳ
// ز     uint32          ʣδݳ
// ʹʾ     ݴ䷽ʽַ֧Χʵ
//-------------------------------------------------------------------------------------------------------------------
uint32 detector_custom_transfer (const uint8 *buff, uint32 length)
{
    uint32 send_length;
    send_length = length;

    while(send_length--)
    {
        detector_custom_write_byte(*buff);
        buff++;
    }
    
    return send_length;
}

//-------------------------------------------------------------------------------------------------------------------
//      δԶպ ֽڽ
// ˵     *data           Ҫ͵ݵַ
// ز     uint8           0:ճɹ 1ʧ
// ע     detector_custom_receive_byte  detector_custom_receive ֻҪһ
//-------------------------------------------------------------------------------------------------------------------
uint8 detector_custom_receive_byte (uint8 data)
{
    uint8 return_state = 0;
    // ʵֽڷ
    if(FIFO_SUCCESS != fifo_write_buffer(&detector_fifo, &data, 1))
    {
        return_state = 1;
    }
    return return_state;
}

//-------------------------------------------------------------------------------------------------------------------
//      δԶպ 
// ˵     *buff           Ҫ͵ݵַ
// ˵     length          Ҫ͵ĳ
// ز     uint8           0:ճɹ 1ʧ
// ע     detector_custom_receive_byte  detector_custom_receive ֻҪһ
//-------------------------------------------------------------------------------------------------------------------
uint8 detector_custom_receive (uint8 *buff, uint32 length)
{
    uint8 return_state = 0;
    
    // յдFIFO
    if(FIFO_SUCCESS != fifo_write_buffer(&detector_fifo, buff, length))
    {
        return_state = 1;
    }

    return return_state;
}

//-------------------------------------------------------------------------------------------------------------------
//      δͷͺ
// ˵     *send_data      Ҫ͵ݵַ
// ˵     send_length     Ҫ͵ĳ
// ز     uint32          ʣδݳ
// ʹʾ     
//-------------------------------------------------------------------------------------------------------------------
static uint32 detector_transfer (void *send_data, uint32 send_length)
{
    return detector_transfer_callback((const uint8 *)send_data, send_length);
}

//-------------------------------------------------------------------------------------------------------------------
//      δͺ
// ˵     *buffer         ҪУݵַ
// ˵     length          У鳤
// ز     uint8           ֵ
// ʹʾ     
//-------------------------------------------------------------------------------------------------------------------
static uint8 detector_sum (uint8 *buffer, uint32 length)
{
    uint8 temp_sum = 0;
    
    while(length--)
    {
        temp_sum += *buffer++;
    }
    
    return temp_sum;
}



//-------------------------------------------------------------------------------------------------------------------
//      δ ͼͺ
// ˵     camera_type     ͷ
// ˵     *image_addr     ͼ׵ַ
// ˵     boundary_num    ͼа߽
// ˵     width           ͼ
// ˵     height          ͼ߶
// ز     void           
// ʹʾ     
//-------------------------------------------------------------------------------------------------------------------
void detector_camera_data_send (detector_image_type_enum camera_type, void *image_addr, uint8 boundary_num, uint16 width, uint16 height)
{
    uint32 image_size = 0;

    detector_camera_data.head           = DETECTOR_SEND_HEAD;
    detector_camera_data.function       = DETECTOR_CAMERA_FUNCTION;
    detector_camera_data.camera_type    = (camera_type << 5) | ((image_addr != NULL ? 0 : 1) << 4) | boundary_num;
    // дϢЭ鲿
    detector_camera_data.length         = sizeof(detector_camera_struct);
    detector_camera_data.image_width    = width;
    detector_camera_data.image_height   = height;

    // ȷ֡ͷܡͷ͡Լȸ߶ȵϢ
    detector_transfer(&detector_camera_data, sizeof(detector_camera_struct));
    
    // ͷͼͼС
    switch(camera_type)
    {
        case DETECTOR_OV7725_BIN:
        {
            image_size = width * height / 8;
        }break;
        
        case DETECTOR_MT9V03X:
        {
            image_size = width * height;
        }break;
        
        case DETECTOR_SCC8660:
        {
            image_size = width * height * 2;
        }break;
    }
    
    // ͼ
    if(NULL != image_addr)
    {
        detector_transfer(image_addr, image_size);
    }
    
}

//-------------------------------------------------------------------------------------------------------------------
//      δ ͼ߻ƺ
// ˵     boundary_id     ID
// ˵     dot_num         
// ˵     *dot_x          ׵ַ
// ˵     *dot_y          ׵ַ
// ˵     width           ͼ
// ˵     height          ͼ߶
// ز     void           
// ʹʾ     
//-------------------------------------------------------------------------------------------------------------------
void detector_camera_dot_send (detector_camera_buffer_struct *buffer)
{
    uint8  i;
    uint16 dot_bytes = 0;   // ֽ
    wifi_spi_send_multi_struct multi_buffer;
    
    dot_bytes = detector_camera_dot_data.dot_num;
    
    if(detector_camera_dot_data.dot_type & (1 << 5))
    {
        dot_bytes *= 2;
    }
    
    // ߷ʱ WIFI SPIöԴַͺ,Լ߷ٶ
    if(DETECTOR_WIFI_SPI == detector_transfer_type)
    {
        multi_buffer.source[0] = (uint8 *)&detector_camera_dot_data;
        multi_buffer.length[0] = sizeof(detector_camera_dot_struct);

        for(i=0; i < DETECTOR_CAMERA_MAX_BOUNDARY; i++)
        {
            multi_buffer.source[i * 2 + 1]  = buffer->boundary_x[i];
            multi_buffer.source[i * 2 + 2]  = buffer->boundary_y[i];
            
            multi_buffer.length[i * 2 + 1]      = dot_bytes;
            multi_buffer.length[i * 2 + 2]      = dot_bytes;
        }
        
        wifi_spi_send_buffer_multi(&multi_buffer);
    }
    else
    {
        // ȷ֡ͷܡ߽š곤ȡ
        detector_transfer(&detector_camera_dot_data, sizeof(detector_camera_dot_struct));
        
        for(i=0; i < DETECTOR_CAMERA_MAX_BOUNDARY; i++)
        {
            // жǷͺ
            if(NULL != buffer->boundary_x[i])
            {
                detector_transfer(buffer->boundary_x[i], dot_bytes);
            }
            
            // жǷ
            if(NULL != buffer->boundary_y[i])
            {
                // ûݣʾÿһֻһ߽
                // ָ˺ݣַʽʵͬһж߽㷨ܹ䡣
                detector_transfer(buffer->boundary_y[i], dot_bytes);
            }
        }
    }
}

//-------------------------------------------------------------------------------------------------------------------
//      δ ʾͺ
// ˵     *detector_oscilloscope  ʾݽṹ
// ز     void           
// ʹʾ     detector_oscilloscope_send(&detector_oscilloscope_data);
//-------------------------------------------------------------------------------------------------------------------
void detector_oscilloscope_send (detector_oscilloscope_struct *detector_oscilloscope)
{
    uint8 packet_size;
    
    // λ
    detector_oscilloscope->channel_num &= 0x0f;
    
    zf_assert(DETECTOR_SET_OSCILLOSCOPE_COUNT >= detector_oscilloscope->channel_num);
    
    // ֡ͷ
    detector_oscilloscope->head         = DETECTOR_SEND_HEAD;

    // дϢ
    packet_size                         = sizeof(detector_oscilloscope_struct) - (DETECTOR_SET_OSCILLOSCOPE_COUNT - detector_oscilloscope->channel_num) * 4;
    detector_oscilloscope->length       = packet_size;
    
    // д빦ͨ
    detector_oscilloscope->channel_num |= DETECTOR_CAMERA_OSCILLOSCOPE;

    // У
    detector_oscilloscope->check_sum    = 0;
    detector_oscilloscope->check_sum    = detector_sum((uint8 *)&detector_oscilloscope_data, packet_size);
    
    // ڵñ֮ǰûҪ͵дdetector_oscilloscope_data.data[]
    
    detector_transfer((uint8 *)detector_oscilloscope, packet_size);
}

//-------------------------------------------------------------------------------------------------------------------
//      δͼϢú
// ˵     camera_type     ͼ
// ˵     image_addr      ͼַ    NULLʾֻͱϢλ
// ˵     width           ͼ
// ˵     height          ͼ߶
// ز     void
// ʹʾ                     detector_camera_information_config(DETECTOR_MT9V03X, mt9v03x_image[0], MT9V03X_W, MT9V03X_H);
// עϢ     
//-------------------------------------------------------------------------------------------------------------------
void detector_camera_information_config (detector_image_type_enum camera_type, void *image_addr, uint16 width, uint16 height)
{
    detector_camera_dot_data.head       = DETECTOR_SEND_HEAD;
    detector_camera_dot_data.function   = DETECTOR_CAMERA_DOT_FUNCTION;
    // дϢ
    detector_camera_dot_data.length     = sizeof(detector_camera_dot_struct);

    detector_camera_buffer.camera_type  = camera_type;
    detector_camera_buffer.image_addr   = image_addr;
    detector_camera_buffer.width        = width;
    detector_camera_buffer.height       = height;
}

//-------------------------------------------------------------------------------------------------------------------
//      δͼ߷ú
// ˵     boundary_type   ߽
// ˵     dot_num         һ߽жٸ
// ˵     dot_x1          ű1ĵַ  NULLʾͱ1
// ˵     dot_x2          ű2ĵַ  NULLʾͱ2
// ˵     dot_x3          ű3ĵַ  NULLʾͱ3
// ˵     dot_y1          ű1ĵַ  NULLʾͱ1
// ˵     dot_y2          ű2ĵַ  NULLʾͱ2
// ˵     dot_y3          ű3ĵַ  NULLʾͱ3
// ز     void
// ʹʾ                     detector_camera_config(X_BOUNDARY, MT9V03X_H, x1_boundary, x2_boundary, x3_boundary, NULL, NULL, NULL);     // ͼʱߣֻк
// ʹʾ                     detector_camera_config(Y_BOUNDARY, MT9V03X_W, NULL, NULL, NULL, y1_boundary, y2_boundary, y3_boundary);     // ͼʱߣֻ
// ʹʾ                     detector_camera_config(XY_BOUNDARY, 160, xy_x1_boundary, xy_x2_boundary, xy_x3_boundary, xy_y1_boundary, xy_y2_boundary, xy_y3_boundary);   // ͼʱߣ߰
// עϢ     
//-------------------------------------------------------------------------------------------------------------------
void detector_camera_boundary_config (detector_boundary_type_enum boundary_type, uint16 dot_num, void *dot_x1, void *dot_x2, void *dot_x3, void *dot_y1, void *dot_y2, void *dot_y3)
{
    uint8 i = 0;
    uint8 boundary_num = 0;
    uint8 boundary_data_type = 0;
    
    // ͼͻǷ׼, ô˺֮ǰҪȵdetector_camera_configúͼϢ
    zf_assert(0 != detector_camera_buffer.camera_type);
    
    detector_camera_dot_data.dot_num    = dot_num;
    
    detector_camera_dot_data.valid_flag = 0;
    for(i = 0; i < 3; i++)
    {
        detector_camera_buffer.boundary_x[i] = NULL;
        detector_camera_buffer.boundary_y[i] = NULL;
    }
    
    switch(boundary_type)
    {
        case X_BOUNDARY:
        {
            if(NULL != dot_x1)  
            {
                boundary_num++;
                detector_camera_dot_data.valid_flag |= 1 << 0;
                detector_camera_buffer.boundary_x[i++] = dot_x1;
            }
            if(NULL != dot_x2)  
            {
                boundary_num++;
                detector_camera_dot_data.valid_flag |= 1 << 1;
                detector_camera_buffer.boundary_x[i++] = dot_x2;
            }
            if(NULL != dot_x3)  
            {
                boundary_num++;
                detector_camera_dot_data.valid_flag |= 1 << 2;
                detector_camera_buffer.boundary_x[i++] = dot_x3;
            }
            
            if(255 < detector_camera_buffer.height)
            {
                boundary_data_type = 1;
            }
        }break;
        
        case Y_BOUNDARY:
        {
            if(NULL != dot_y1)  
            {
                boundary_num++;
                detector_camera_dot_data.valid_flag |= 1 << 0;
                detector_camera_buffer.boundary_y[i++] = dot_y1;
            }
            if(NULL != dot_y2)  
            {
                boundary_num++;
                detector_camera_dot_data.valid_flag |= 1 << 1;
                detector_camera_buffer.boundary_y[i++] = dot_y2;
            }
            if(NULL != dot_y3)  
            {
                boundary_num++;
                detector_camera_dot_data.valid_flag |= 1 << 2;
                detector_camera_buffer.boundary_y[i++] = dot_y3;
            }
    
            if(255 < detector_camera_buffer.width)
            {
                boundary_data_type = 1;
            }
        }break;
        
        case XY_BOUNDARY:
        {
            if((NULL != dot_x1) && (NULL != dot_y1))  
            {
                boundary_num++;
                detector_camera_dot_data.valid_flag |= 1 << 0;
                detector_camera_buffer.boundary_x[i]   = dot_x1;
                detector_camera_buffer.boundary_y[i++] = dot_y1;
            }
            if((NULL != dot_x2) && (NULL != dot_y2))  
            {
                boundary_num++;
                detector_camera_dot_data.valid_flag |= 1 << 1;
                detector_camera_buffer.boundary_x[i]   = dot_x2;
                detector_camera_buffer.boundary_y[i++] = dot_y2;
            }
            if((NULL != dot_x3) && (NULL != dot_y3))  
            {
                boundary_num++;
                detector_camera_dot_data.valid_flag |= 1 << 2;
                detector_camera_buffer.boundary_x[i]   = dot_x3;
                detector_camera_buffer.boundary_y[i++] = dot_y3;
            }
    
            if((255 < detector_camera_buffer.width) || (255 < detector_camera_buffer.height))
            {
                boundary_data_type = 1;
            }
        }break;
        
        case NO_BOUNDARY:break;
    }
    
    detector_camera_dot_data.dot_type   = (boundary_type << 6) | (boundary_data_type << 5) | boundary_num;
}

//-------------------------------------------------------------------------------------------------------------------
//      δͷͷͼ
// ˵     void     
// ز     void
// ʹʾ     
// עϢ     ڵͼͺ֮ǰصһdetector_camera_configӦĲú
//-------------------------------------------------------------------------------------------------------------------
void detector_camera_send (void)
{
    // ͼͻǷ׼
    zf_assert(0 != detector_camera_buffer.camera_type);
    
    detector_camera_data_send(detector_camera_buffer.camera_type, detector_camera_buffer.image_addr, detector_camera_dot_data.dot_type & 0x0f, detector_camera_buffer.width, detector_camera_buffer.height);
    
    if(detector_camera_dot_data.dot_type & 0x0f)
    {
        detector_camera_dot_send(&detector_camera_buffer);
    }
}

//-------------------------------------------------------------------------------------------------------------------
//      δͽյ
// ˵     void            
// ز     void           
// ʹʾ     ֻҪŵеPITжϻѭ
//-------------------------------------------------------------------------------------------------------------------
void detector_data_analysis (void)
{
    uint8  temp_sum;
    uint32 read_length;
    detector_parameter_struct *receive_packet;

    // ʹuint32ж壬ĿΪ˱ֽ֤ڶ
    uint32  temp_buffer[DETECTOR_BUFFER_SIZE / 4];

    // Զȡ, ԶĴ䷽ʽӽջصжȡ
    if(DETECTOR_CUSTOM != detector_transfer_type)
    {
        read_length = detector_receive_callback((uint8 *)temp_buffer, DETECTOR_BUFFER_SIZE);
        if(read_length)
        {
            // ȡдFIFO
            fifo_write_buffer(&detector_fifo, (uint8 *)temp_buffer, read_length);
        }
    }
    
    while(sizeof(detector_parameter_struct) <= fifo_used(&detector_fifo))
    {
        read_length = sizeof(detector_parameter_struct);
        fifo_read_buffer(&detector_fifo, (uint8 *)temp_buffer, &read_length, FIFO_READ_ONLY);
        
        if(DETECTOR_RECEIVE_HEAD != ((uint8 *)temp_buffer)[0])
        {
            // û֡ͷFIFOȥһ
            read_length = 1;
        }
        else
        {
            // ҵ֡ͷ
            receive_packet = (detector_parameter_struct *)temp_buffer;
            temp_sum = receive_packet->check_sum;
            receive_packet->check_sum = 0;
            if(temp_sum == detector_sum((uint8 *)temp_buffer, sizeof(detector_parameter_struct)))
            {
                // Уɹ
                detector_parameter[receive_packet->channel - 1] = receive_packet->data;
            }
            else
            {
                read_length = 1;
            }
        }
        
        // ʹõ
        fifo_read_buffer(&detector_fifo, NULL, &read_length, FIFO_READ_AND_CLEAN);
    }
}

//-------------------------------------------------------------------------------------------------------------------
//      δ ʼ
// ˵     transfer_type   ѡʹַʽ
// ز     void            
// ʹʾ     
//-------------------------------------------------------------------------------------------------------------------
void detector_init (detector_transfer_type_enum transfer_type)
{
    detector_transfer_type = transfer_type;
    
    fifo_init(&detector_fifo, FIFO_DATA_8BIT, detector_buffer, DETECTOR_BUFFER_SIZE);
    
    switch(detector_transfer_type)
    {
        case DETECTOR_DEBUG_UART:
        {
            detector_transfer_callback = debug_send_buffer;
            detector_receive_callback = debug_read_ring_buffer;
        }break;
        
        case DETECTOR_WIRELESS_UART:
        {
            detector_transfer_callback = wireless_uart_send_buffer;
            detector_receive_callback = wireless_uart_read_buffer;
        }break;
        
        case DETECTOR_CH9141:
        {
            detector_transfer_callback = bluetooth_ch9141_send_buffer;
            detector_receive_callback = bluetooth_ch9141_read_buffer;
        }break;
        
        case DETECTOR_WIFI_UART:
        {
            detector_transfer_callback = wifi_uart_send_buffer;
            detector_receive_callback = wifi_uart_read_buffer;
        }break;
        
        case DETECTOR_WIFI_SPI:
        {
            detector_transfer_callback = wifi_spi_send_buffer;
            detector_receive_callback = wifi_spi_read_buffer;
        }break;
        
        case DETECTOR_CUSTOM:
        {
            // Լ ʵdetector_custom_write_byteݵĴ
            detector_transfer_callback = detector_custom_transfer;
            
            // ýջص
            
            // ںʵλõdetector_custom_receive  detector_custom_receive_byteʵݽ
            // detector_custom_receive  detector_custom_receive_byte ֻһɣԼǰֽڽݻǰݽ
            // յݻᱻдdetector_fifoУ Աʹ
            //detector_receive_callback = detector_custom_receive;
            
        }break;
    }
}
