/*
 * Copyright (c) 2022 OpenLuat & AirM2M
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of
 * this software and associated documentation files (the "Software"), to deal in
 * the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
 * the Software, and to permit persons to whom the Software is furnished to do so,
 * subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include "user.h"
#include "zbar.h"
#include "symbol.h"
#include "image.h"
#if 1
#define CAMERA_WIDTH	320
#define CAMERA_HEIGHT 240
#else
#define CAMERA_WIDTH	160
#define CAMERA_HEIGHT 80
#endif
#define GC032A_I2C_ADDRESS 0x21
#define OV2640_I2C_ADDRESS 0x30
static const I2C_CommonRegDataStruct GC032A_InitRegQueue[] =
{
        {0xf3, 0xff},
        {0xf7, 0x01},
		{0xf8, 0x03},
        {0xf9, 0xce},
        {0xfa, 0x00},
        {0xfc, 0x02},
        {0xfe, 0x02},
        {0x81, 0x03},


		{0xfe,0x00},
		{0x03,0x01},
		{0x04,0xc2},
		{0x05,0x01},
		{0x06,0xc2},
		{0x07,0x00},
		{0x08,0x08},
		{0x0a,0x04},
		{0x0c,0x04},
		{0x0d,0x01},
		{0x0e,0xe8},
		{0x0f,0x02},
		{0x10,0x88},
		//{0x17,0x55},
		{0x17,0x54},
		{0x19,0x04},
		{0x1a,0x0a},
		{0x1f,0x40},
		{0x20,0x30},
		{0x2e,0x80},
		{0x2f,0x2b},
		{0x30,0x1a},
		{0xfe,0x02},
		{0x03,0x02},
		{0x06,0x60},
		{0x05,0xd7},
		{0x12,0x89},
		{0xfe,0x00},
		{0x18,0x02},
		{0xfe,0x02},
		{0x40,0x22},
		{0x45,0x00},
		{0x46,0x00},
		{0x49,0x20},
		{0xfe,0x01},
		{0x0a,0xc5},
		{0x45,0x00},
		{0xfe,0x00},
		{0x40,0xff},
		{0x41,0x25},
		{0x42,0x83},
		{0x43,0x10},
		{0x46,0x26},
		{0x49,0x03},
		{0x4f,0x01},
		{0xde,0x84},
		{0xfe,0x02},
		{0x22,0xf6},
		{0xfe,0x01},
		{0x12,0xa0},
		{0x13,0x3a},
		{0xc1,0x3c},
		{0xc2,0x50},
		{0xc3,0x00},
		{0xc4,0x32},
		{0xc5,0x24},
		{0xc6,0x16},
		{0xc7,0x08},
		{0xc8,0x08},
		{0xc9,0x00},
		{0xca,0x20},
		{0xdc,0x8a},
		{0xdd,0xa0},
		{0xde,0xa6},
		{0xdf,0x75},
		{0xfe,0x01},
		{0x7c,0x09},
		{0x65,0x00},
		{0x7c,0x08},
		{0x56,0xf4},
		{0x66,0x0f},
		{0x67,0x84},
		{0x6b,0x80},
		{0x6d,0x12},
		{0x6e,0xb0},
		{0x86,0x00},
		{0x87,0x00},
		{0x88,0x00},
		{0x89,0x00},
		{0x8a,0x00},
		{0x8b,0x00},
		{0x8c,0x00},
		{0x8d,0x00},
		{0x8e,0x00},
		{0x8f,0x00},
		{0x90,0xef},
		{0x91,0xe1},
		{0x92,0x0c},
		{0x93,0xef},
		{0x94,0x65},
		{0x95,0x1f},
		{0x96,0x0c},
		{0x97,0x2d},
		{0x98,0x20},
		{0x99,0xaa},
		{0x9a,0x3f},
		{0x9b,0x2c},
		{0x9c,0x5f},
		{0x9d,0x3e},
		{0x9e,0xaa},
		{0x9f,0x67},
		{0xa0,0x60},
		{0xa1,0x00},
		{0xa2,0x00},
		{0xa3,0x0a},
		{0xa4,0xb6},
		{0xa5,0xac},
		{0xa6,0xc1},
		{0xa7,0xac},
		{0xa8,0x55},
		{0xa9,0xc3},
		{0xaa,0xa4},
		{0xab,0xba},
		{0xac,0xa8},
		{0xad,0x55},
		{0xae,0xc8},
		{0xaf,0xb9},
		{0xb0,0xd4},
		{0xb1,0xc3},
		{0xb2,0x55},
		{0xb3,0xd8},
		{0xb4,0xce},
		{0xb5,0x00},
		{0xb6,0x00},
		{0xb7,0x05},
		{0xb8,0xd6},
		{0xb9,0x8c},
		{0xfe,0x01},
		{0xd0,0x40},
		{0xd1,0xf8},
		{0xd2,0x00},
		{0xd3,0xfa},
		{0xd4,0x45},
		{0xd5,0x02},
		{0xd6,0x30},
		{0xd7,0xfa},
		{0xd8,0x08},
		{0xd9,0x08},
		{0xda,0x58},
		{0xdb,0x02},
		{0xfe,0x00},
		{0xfe,0x00},
		{0xba,0x00},
		{0xbb,0x04},
		{0xbc,0x0a},
		{0xbd,0x0e},
		{0xbe,0x22},
		{0xbf,0x30},
		{0xc0,0x3d},
		{0xc1,0x4a},
		{0xc2,0x5d},
		{0xc3,0x6b},
		{0xc4,0x7a},
		{0xc5,0x85},
		{0xc6,0x90},
		{0xc7,0xa5},
		{0xc8,0xb5},
		{0xc9,0xc2},
		{0xca,0xcc},
		{0xcb,0xd5},
		{0xcc,0xde},
		{0xcd,0xea},
		{0xce,0xf5},
		{0xcf,0xff},
		{0xfe,0x00},
		{0x5a,0x08},
		{0x5b,0x0f},
		{0x5c,0x15},
		{0x5d,0x1c},
		{0x5e,0x28},
		{0x5f,0x36},
		{0x60,0x45},
		{0x61,0x51},
		{0x62,0x6a},
		{0x63,0x7d},
		{0x64,0x8d},
		{0x65,0x98},
		{0x66,0xa2},
		{0x67,0xb5},
		{0x68,0xc3},
		{0x69,0xcd},
		{0x6a,0xd4},
		{0x6b,0xdc},
		{0x6c,0xe3},
		{0x6d,0xf0},
		{0x6e,0xf9},
		{0x6f,0xff},
		{0xfe,0x00},
		{0x70,0x50},
		{0xfe,0x00},
		{0x4f,0x01},
		{0xfe,0x01},
		{0x44,0x04},
		{0x1f,0x30},
		{0x20,0x40},
		{0x26,0x9a},
		{0x27,0x02},
		{0x28,0x0d},
		{0x29,0x02},
		{0x2a,0x0d},
		{0x2b,0x02},
		{0x2c,0x58},
		{0x2d,0x07},
		{0x2e,0xd2},
		{0x2f,0x0b},
		{0x30,0x6e},
		{0x31,0x0e},
		{0x32,0x70},
		{0x33,0x12},
		{0x34,0x0c},
		{0x3c,0x20},
		{0x3e,0x20},
		{0x3f,0x2d},
		{0x40,0x40},
		{0x41,0x5b},
		{0x42,0x82},
		{0x43,0xb7},
		{0x04,0x0a},
		{0x02,0x79},
		{0x03,0xc0},
		{0xcc,0x08},
		{0xcd,0x08},
		{0xce,0xa4},
		{0xcf,0xec},
		{0xfe,0x00},
		{0x81,0xb8},
		{0x82,0x12},
		{0x83,0x0a},
		{0x84,0x01},
		{0x86,0x25},
		{0x87,0x18},
		{0x88,0x10},
		{0x89,0x70},
		{0x8a,0x20},
		{0x8b,0x10},
		{0x8c,0x08},
		{0x8d,0x0a},
		{0xfe,0x00},
		{0x8f,0xaa},
		{0x90,0x9c},
		{0x91,0x52},
		{0x92,0x03},
		{0x93,0x03},
		{0x94,0x08},
		{0x95,0x44},
		{0x97,0x00},
		{0x98,0x00},
		{0xfe,0x00},
		{0xa1,0x30},
		{0xa2,0x41},
		{0xa4,0x30},
		{0xa5,0x20},
		{0xaa,0x30},
		{0xac,0x32},
		{0xfe,0x00},
		{0xd1,0x3c},
		{0xd2,0x3c},
		{0xd3,0x38},
		{0xd6,0xf4},
		{0xd7,0x1d},
		{0xdd,0x73},
		{0xde,0x84},
		{0xfe,0x01},
		{0x13,0x20},
		{0xfe,0x00},
		{0x4f,0x00},
		{0x03,0x00},
		{0x04,0xa0},
		{0x71,0x60},
		{0x72,0x40},
		{0x42,0x80},
		{0x77,0x64},
		{0x78,0x40},
		{0x79,0x60},

		{0xfe, 0x00},
//		{0x44, 0x06},	//改成RGB565输出
		{0x44,0x90},	//输出灰度
        {0x46, 0x0f},	//决定了VSYNC，HSYNC, pixclk
};
enum
{
	DECODE_DONE = USER_EVENT_ID_START + 100,
};

typedef struct
{
	HANDLE NotifyTaskHandler;
	uint8_t TestBuf[4096];
	uint8_t *DataCache;
	uint32_t TotalSize;
	uint32_t CurSize;
	uint16_t Width;
	uint16_t Height;
	uint8_t DataBytes;
	uint8_t IsDecode;
	uint8_t BufferFull;
}QR_DecodeCtrlStruct;
static QR_DecodeCtrlStruct prvDecodeQR;
static int32_t prvCamera_DCMICB(void *pData, void *pParam)
{
	Buffer_Struct *RxBuf = (Buffer_Struct *)pData;
	if (!pData)
	{
		if (!prvDecodeQR.DataCache)
		{
			prvDecodeQR.DataCache = malloc(prvDecodeQR.TotalSize);
			prvDecodeQR.BufferFull = 0;
		}
		else
		{
			if (prvDecodeQR.TotalSize != prvDecodeQR.CurSize)
			{
//				DBG_ERR("%d, %d", prvDecodeQR.CurSize, prvDecodeQR.TotalSize);
			}
			else if (!prvDecodeQR.IsDecode)
			{
				prvDecodeQR.IsDecode = 1;
				Task_SendEvent(prvDecodeQR.NotifyTaskHandler, DECODE_DONE, prvDecodeQR.DataCache, 0, 0);
				prvDecodeQR.DataCache = malloc(prvDecodeQR.TotalSize);
				prvDecodeQR.BufferFull = 0;
			}
			else
			{
				prvDecodeQR.BufferFull = 1;
			}
		}
		prvDecodeQR.CurSize = 0;
		return 0;
	}
	if (prvDecodeQR.DataCache)
	{
		if (prvDecodeQR.BufferFull)
		{
			if (!prvDecodeQR.IsDecode)
			{
				prvDecodeQR.IsDecode = 1;
				Task_SendEvent(prvDecodeQR.NotifyTaskHandler, DECODE_DONE, prvDecodeQR.DataCache, 0, 0);
				prvDecodeQR.DataCache = malloc(prvDecodeQR.TotalSize);
				prvDecodeQR.BufferFull = 0;
				prvDecodeQR.CurSize = 0;
			}
			else
			{
				return 0;
			}

		}
	}
	else
	{
		prvDecodeQR.DataCache = malloc(prvDecodeQR.TotalSize);
		prvDecodeQR.BufferFull = 0;
		prvDecodeQR.CurSize = 0;
	}
	memcpy(&prvDecodeQR.DataCache[prvDecodeQR.CurSize], RxBuf->Data, RxBuf->MaxLen * 4);
	prvDecodeQR.CurSize += RxBuf->MaxLen * 4;
	if (prvDecodeQR.TotalSize < prvDecodeQR.CurSize)
	{
		DBG_ERR("%d,%d", prvDecodeQR.TotalSize, prvDecodeQR.CurSize);
		prvDecodeQR.CurSize = 0;
	}
	return 0;
}

static int32_t prvTest_VUartCB(void *pData, void *pParam)
{
	uint32_t UartID = (uint32_t)pData;
	uint32_t State = (uint32_t)pParam;
	uint16_t ReadLen;
	switch (State)
	{

	case UART_CB_TX_BUFFER_DONE:
	case UART_CB_TX_ALL_DONE:
//		DBG("usb send ok");
//		Core_PrintMemInfo();
		break;
	case UART_CB_RX_BUFFER_FULL:
	case UART_CB_RX_TIMEOUT:
	case UART_CB_RX_NEW:
		ReadLen = Core_VUartRxBufferRead(UartID, prvDecodeQR.TestBuf, sizeof(prvDecodeQR.TestBuf));
		Core_VUartBufferTx(UartID, prvDecodeQR.TestBuf, ReadLen);
		break;
	case UART_CB_ERROR:
		DBG("usb disconnect");
		Core_VUartBufferTxStop(UartID); //也可以选择不清除，USB连上后，会自动重发，但是会有重复发送的情况，需要用户去处理
		break;
	case UART_CB_CONNECTED:
		break;
	}
}

static int32_t prvTest_VHIDCB(void *pData, void *pParam)
{
	uint32_t USB_ID = (uint32_t)pData;
	uint32_t State = (uint32_t)pParam;
	uint16_t ReadLen;
	switch (State)
	{
	case USB_HID_NOT_READY:
	case USB_HID_READY:
	case USB_HID_SEND_DONE:
		DBG("%d", State);
		break;
	}
}

static void zbar_task(void *pData)
{
	OS_EVENT Event;
	unsigned int len;
	int ret;
	char *string;
	zbar_t *zbar;
	LCD_DrawStruct *draw;
	Core_VUartInit(VIRTUAL_UART0, 0, 1, 0, 0, 0, prvTest_VUartCB);
	Core_VHIDInit(USB_ID0, prvTest_VHIDCB);
	while (1) {
		Task_GetEvent(prvDecodeQR.NotifyTaskHandler, DECODE_DONE, &Event, NULL, 0);
		draw = zalloc(sizeof(LCD_DrawStruct));
		draw->Mode = SPI_MODE_0;
		draw->Speed = 48000000;
		draw->SpiID = HSPI_ID0;
		draw->CSPin = GPIOC_14;
		draw->DCPin = 72;
		draw->x1 = 0;
		draw->x2 = prvDecodeQR.Width - 1;
		draw->y1 = 0;
		draw->y2 = prvDecodeQR.Height - 1;
		draw->xoffset = 0;
		draw->yoffset = 0;
		draw->Size = prvDecodeQR.TotalSize;
		draw->ColorMode = COLOR_MODE_GRAY;
		draw->Data = Event.Param1;
		Core_CameraDraw(draw);
		zbar = zbar_create();

		ret = zbar_run(zbar, prvDecodeQR.Width, prvDecodeQR.Height, Event.Param1);

		if (ret > 0)
		{
			string = zbar_get_data_ptr(zbar, &len);
			memcpy(prvDecodeQR.TestBuf, string, len);
			Core_VUartBufferTx(VIRTUAL_UART0, prvDecodeQR.TestBuf, len);
			DBG("%.*s", len, string);
//			Core_PrintMemInfo();
			Core_VHIDUploadData(USB_ID0, string, len);
		}
		zbar_destory(zbar);
		free(Event.Param1);
		prvDecodeQR.IsDecode = 0;
	}
}





void DecodeQR_TestInit(void)
{
	uint8_t Reg = 0xf0;
	uint8_t Data[2];
	uint32_t i;
	prvDecodeQR.DataCache = NULL;
	prvDecodeQR.Width = CAMERA_WIDTH;
	prvDecodeQR.Height = CAMERA_HEIGHT;
	prvDecodeQR.TotalSize = prvDecodeQR.Width * prvDecodeQR.Height;
	prvDecodeQR.DataBytes = 1;
	prvDecodeQR.NotifyTaskHandler = Task_Create(zbar_task, NULL, 8 * 1024, 1, "test zbar");
	GPIO_Config(GPIOD_06, 0, 0);
	GPIO_Config(GPIOD_07, 0, 0);
//	GPIO_ExtiSetHWTimerCB(GC032A_IOCB, NULL);
	GPIO_Iomux(GPIOE_01, 3);
	GPIO_Iomux(GPIOE_02, 3);
	GPIO_Iomux(GPIOE_03, 3);

	GPIO_Iomux(GPIOD_01, 3);
	GPIO_Iomux(GPIOD_02, 3);
	GPIO_Iomux(GPIOD_03, 3);
	GPIO_Iomux(GPIOD_08, 3);
	GPIO_Iomux(GPIOD_09, 3);
	GPIO_Iomux(GPIOD_10, 3);
	GPIO_Iomux(GPIOD_11, 3);
	GPIO_Iomux(GPIOE_00, 3);

	GPIO_Iomux(GPIOE_06, 2);
	GPIO_Iomux(GPIOE_07, 2);

	GPIO_Iomux(GPIOA_05, 2);
//	GPIO_Config(GPIOE_03, 1, 1);
//	GPIO_ExtiConfig(GPIOE_03, 0, 1, 0);
	HWTimer_SetPWM(HW_TIMER5, 24000000, 0, 0);
	Task_DelayMS(1);
	GPIO_Output(GPIOD_06, 1);
	GPIO_Output(GPIOD_07, 1);
	Task_DelayUS(10);
	GPIO_Output(GPIOD_07, 0);
	I2C_MasterSetup(I2C_ID0, 400000);
	Data[0] = 0xf4;
	Data[1] = 0x10;

	I2C_BlockWrite(I2C_ID0, GC032A_I2C_ADDRESS, Data, 2, 10, NULL, 0);
	I2C_BlockRead(I2C_ID0, GC032A_I2C_ADDRESS, &Reg, Data, 2, 10, NULL, 0);
	if ((0x23 == Data[0]) && (0x2a == Data[1]))
	{
		DBG("识别到GC032A控制芯片");
	}
	else
	{
		DBG("没有识别到GC032A控制芯片");
		return;
	}
//	Data[0] = 0xfe;
//	Data[1] = 0x00;
//	Reg = 0x44;
//	I2C_BlockWrite(I2C_ID0, GC032A_I2C_ADDRESS, Data, 2, 10, NULL, 0);
//	I2C_BlockRead(I2C_ID0, GC032A_I2C_ADDRESS, &Reg, Data, 2, 10, NULL, 0);
//	DBG("%x,%x", Data[0], Data[1]);
	for(i = 0; i < sizeof(GC032A_InitRegQueue)/sizeof(I2C_CommonRegDataStruct); i++)
	{
		I2C_BlockWrite(I2C_ID0, GC032A_I2C_ADDRESS, GC032A_InitRegQueue[i].Data, 2, 10, NULL, 0);
	}
//	DBG("GC032A Init Done");
//	I2C_Prepare(I2C_ID0, GC032A_I2C_ADDRESS, 1, GC032A_InitDone, 0);
//	I2C_MasterWriteRegQueue(I2C_ID0, GC032A_InitRegQueue, sizeof(GC032A_InitRegQueue)/sizeof(I2C_CommonRegDataStruct), 10, 0);
	DCMI_Setup(0, 0, 0, 8, 0);
	DCMI_SetCallback(prvCamera_DCMICB, 0);
	DCMI_SetCROPConfig(1, (480-prvDecodeQR.Height)/2, ((640-prvDecodeQR.Width)/2)*prvDecodeQR.DataBytes, prvDecodeQR.Height - 1, prvDecodeQR.DataBytes*prvDecodeQR.Width - 1);	//裁剪中间的240*320图像
	DCMI_CaptureSwitch(1, (prvDecodeQR.Width * prvDecodeQR.DataBytes * prvDecodeQR.Height) / 80, 0, 0, 0, NULL);	//240 * 2 / 4 * 12，一次DMA传输有12行数据，一共传输20次
}
