#include "includes.h"

// 是否自检屏状态
u8 self_check_state = 0;

// 显示缓冲区
TVideoBuf VideoBuf = {0};
TVideoBuf Last_VideoBuf = {0};

// 定义7段字库编码
//  |-A-|
//  F   B
//  |-G-|
//  E   C
//  |-D-|

typedef struct
{
	unsigned A : 1;
	unsigned B : 1;
	unsigned C : 1;
	unsigned D : 1;
	unsigned E : 1;
	unsigned F : 1;
	unsigned G : 1;
	unsigned : 1;
} TChar;

// 字库，不带小数点或单位
const TChar CLib[] = 
{
	{0, 0, 0, 0, 0, 0, 0}, // ' '
	{0, 0, 0, 0, 0, 0, 1}, // '-'
	{0, 1, 1, 0, 0, 0, 1}, // '+' = '-|'
	{1, 0, 0, 0, 0, 0, 0}, // '^'
	
	{1, 1, 1, 0, 1, 1, 1}, // 'A'
	{0, 0, 1, 1, 1, 1, 1}, // 'b'
	{0, 0, 0, 1, 1, 0, 1}, // 'c'
	{0, 1, 1, 1, 1, 0, 1}, // 'd'
	{1, 0, 0, 1, 1, 1, 1}, // 'E'
	{1, 0, 0, 0, 1, 1, 1}, // 'F'
	{1, 0, 1, 1, 1, 1, 0}, // 'G'
	{0, 0, 1, 0, 1, 1, 1}, // 'h'
	{0, 0, 0, 0, 1, 1, 0}, // 'I'
	{0, 1, 1, 1, 0, 0, 0}, // 'J'
	{0, 0, 0, 1, 0, 0, 0}, // 'K' = '_'
	{0, 0, 0, 1, 1, 1, 0}, // 'L'
	{0, 0, 0, 1, 0, 0, 0}, // 'M' = '_'
	{0, 0, 1, 0, 1, 0, 1}, // 'n'
	{0, 0, 1, 1, 1, 0, 1}, // 'o'
	{1, 1, 0, 0, 1, 1, 1}, // 'P'
	{1, 1, 1, 0, 0, 1, 1}, // 'q'
	{0, 0, 0, 0, 1, 0, 1}, // 'r'
	{1, 0, 1, 1, 0, 1, 1}, // 'S'
	{0, 0, 1, 0, 0, 0, 1}, // 't'
	{0, 1, 1, 1, 1, 1, 0}, // 'U'
	{0, 1, 0, 0, 1, 1, 1}, // 'V'
	{0, 0, 0, 1, 0, 0, 0}, // 'W' = '_'
	{0, 0, 0, 1, 0, 0, 0}, // 'X' = '_'
	{0, 1, 1, 1, 0, 1, 1}, // 'y'
	{0, 0, 0, 1, 0, 0, 0}, // 'Z' = '_'
	
	{1, 1, 1, 1, 1, 1, 0}, // '0'
	{0, 1, 1, 0, 0, 0, 0}, // '1'
	{1, 1, 0, 1, 1, 0, 1}, // '2'
	{1, 1, 1, 1, 0, 0, 1}, // '3'
	{0, 1, 1, 0, 0, 1, 1}, // '4'
	{1, 0, 1, 1, 0, 1, 1}, // '5'
	{1, 0, 1, 1, 1, 1, 1}, // '6'
	{1, 1, 1, 0, 0, 0, 0}, // '7'
	{1, 1, 1, 1, 1, 1, 1}, // '8'
	{1, 1, 1, 1, 0, 1, 1}, // '9'
};

// 字符在字库中的编码
typedef enum 
{
	CODE_SPACE, CODE_MINUS, CODE_PLUS, CODE_EXP,
	CODE_A, CODE_B, CODE_C, CODE_D, CODE_E, CODE_F, CODE_G, 
	CODE_H, CODE_I, CODE_J, CODE_K, CODE_L, CODE_M, CODE_N,
	CODE_O, CODE_P, CODE_Q, CODE_R, CODE_S, CODE_T,
	CODE_U, CODE_V, CODE_W, CODE_X, CODE_Y, CODE_Z,
  	CODE_0, CODE_1, CODE_2, CODE_3, CODE_4, CODE_5, CODE_6, CODE_7, CODE_8, CODE_9
} TCode;

TCode HT1621_Char2Code(char c)
{
	if(c >= '0' && c <= '9')
		return CODE_0 + (c - '0');
	
	if(c >= 'a' && c <= 'z')
		return CODE_A + (c - 'a');
	
	if(c >= 'A' && c <= 'Z')
		return CODE_A + (c - 'A');
	
	if(c == '-')
		return CODE_MINUS;
	
	if(c == '+')
		return CODE_PLUS;
	
	if(c == '^')
		return CODE_EXP;
	
	return CODE_SPACE;
}

// pin_no: 1~41
// com_no: 1~4
void HT1621_WriteBuf(u16 pin_com, u8 bit_val)
{
	uint8_t byte_index, bit_index;
	uint8_t pin_no = pin_com / 10;
	uint8_t com_no = pin_com % 10;
	
	if(pin_no < 1 || pin_no > 41)
		return;
	if(com_no < 1 || com_no > 4)
		return;
		
	byte_index = (pin_no - 1) / 2;
	bit_index = com_no - 1; 		// COM4高位，COM1低位
	if((pin_no - 1) % 2)
		bit_index += 4;				// 奇数pin高4位，偶数pin低4位
	if(bit_val)
		VideoBuf.buf[byte_index] |= (1 << bit_index);
	else
		VideoBuf.buf[byte_index] &= ~(1 << bit_index);
}
	
// 写一个七段码字符
// pin_comA = (A段的pin_no) * 10 + (A段的com_no)
void HT1621_WriteChar(char c, u16 pin_comA, u16 pin_comB, u16 pin_comC, u16 pin_comD, u16 pin_comE, u16 pin_comF, u16 pin_comG)
{
	TCode code = HT1621_Char2Code(c);
	   
	HT1621_WriteBuf(pin_comA, CLib[code].A);
	HT1621_WriteBuf(pin_comB, CLib[code].B);
	HT1621_WriteBuf(pin_comC, CLib[code].C);
	HT1621_WriteBuf(pin_comD, CLib[code].D);
	HT1621_WriteBuf(pin_comE, CLib[code].E);
	HT1621_WriteBuf(pin_comF, CLib[code].F);
	HT1621_WriteBuf(pin_comG, CLib[code].G);
}

// 写一个七段码数据
// pin_comA = (A段的pin_no) * 10 + (A段的com_no)
void HT1621_Write7Seg(u8 val, u16 pin_comA, u16 pin_comB, u16 pin_comC, u16 pin_comD, u16 pin_comE, u16 pin_comF, u16 pin_comG)
{
	HT1621_WriteBuf(pin_comA, val & 1);
	val >>= 1;
	HT1621_WriteBuf(pin_comB, val & 1);
	val >>= 1;
	HT1621_WriteBuf(pin_comC, val & 1);
	val >>= 1;
	HT1621_WriteBuf(pin_comD, val & 1);
	val >>= 1;
	HT1621_WriteBuf(pin_comE, val & 1);
	val >>= 1;
	HT1621_WriteBuf(pin_comF, val & 1);
	val >>= 1;
	HT1621_WriteBuf(pin_comG, val & 1);
}

///////////////////////////////////////////////////////////////////////////////////
// 以下定义适用于HT16C23驱动芯片
#define HT16C23_ADDR	(0x7C) // 0111110(r/w)

//命令
#define  WRITE_LCD       0x80
#define  DRIVE_MODE_CMD  0x82
#define  SYS_MODE_CMD    0x84
#define  FRQ_CMD         0x86
#define  BLINK_FRQ_CMD   0x88
#define  VOL_SET_CMD     0x8a

//参数定义
#define  BIAS_LCD        0x00  // 驱动模式 SEG55*4com显示段位模式  1/4duty  1/3bias
#define  SYS_MODE_LCD    0x03  //显示和内部晶振都打开
#define  FRQ_LCD         0x00  //0--80HZ  1--160HZ
#define  BLINK_FRQ_LCD   0x00  //blinking off
#define  VOL_LCD         0x30  //1--内部V  电压3.3v
///////////////////////////////////////////////////////////////////////////////////

// I2C写数据
uint8_t I2C_WriteBytes(uint8_t len, uint8_t *buf)
{
	uint8_t idx = 0;
	uint8_t try_count = 2;
	int32_t loop;
	
	// I2C不允许打断。
	__disable_irq();
	
	do
	{
		idx = 0;
		LL_I2C_HandleTransfer(I2C1, HT16C23_ADDR, LL_I2C_ADDRSLAVE_7BIT, len, LL_I2C_MODE_AUTOEND, LL_I2C_GENERATE_START_WRITE);
		// 发送数据
		loop = 3000;
		while(!LL_I2C_IsActiveFlag_STOP(I2C1) && idx < len && loop > 0)
		{
			if(LL_I2C_IsActiveFlag_TXIS(I2C1))
				LL_I2C_TransmitData8(I2C1, buf[idx++]);
			loop--;
		}
		LL_I2C_ClearFlag_STOP(I2C1);
	} while((--try_count) && idx < len);

	__enable_irq();
	
	return (idx == len);
}

// 写命令
void HT1621_Cmd(u8 cmd, u8 val)
{
	uint8_t buf[2] = {cmd, val};
	
	I2C_WriteBytes(2, buf);
}

// 设置参数
void HT1621_SetParams()
{
	HT1621_Cmd(DRIVE_MODE_CMD, BIAS_LCD);
	HT1621_Cmd(VOL_SET_CMD, VOL_LCD);    //使用内部振荡器
	HT1621_Cmd(FRQ_CMD, FRQ_LCD);
	HT1621_Cmd(BLINK_FRQ_CMD, BLINK_FRQ_LCD);
	HT1621_Cmd(SYS_MODE_CMD, SYS_MODE_LCD);
}

// 刷新整个显示屏内容
void HT1621_Refresh()
{
	u8 i;

	// 每次刷新都设置参数（有一定几率参数丢失导致熄屏）
	HT1621_SetParams();
	
	// 写显示数据命令
	VideoBuf.cmd = WRITE_LCD;
	VideoBuf.addr = 0;
	
	// 比较显示内容和标志位，如无改变则不操作
	if(memcmp(&VideoBuf, &Last_VideoBuf, sizeof(VideoBuf)) == 0)
		return;

	// 保存显示内容和标志位
	Last_VideoBuf = VideoBuf;
	
	// 处理闪烁，根据标志位临时改变显示内容
	if(!self_check_state && !VideoBuf.blink_visible)
	{
		// 隐藏数字（显示界面）
		if(VideoBuf.fld1_blink)			// 显示1
		{
			Disp_Fld1Text("    ");
			Disp_Fld1PointOff();
		}
		if(VideoBuf.fld2_blink)			// 显示2
		{
			Disp_Fld2Text("    ");
			Disp_Fld2PointOff();
		}
		if(VideoBuf.fld3_blink)			// 显示3
		{
			Disp_Fld3Text("    ");
			Disp_Fld3PointOff();
		}
		if(VideoBuf.fld4_blink)			// 显示4
		{
			Disp_Fld4Text("    ");
			Disp_Fld4PointOff();
		}
		if(VideoBuf.battery_blink) 		// 电池
			Disp_WriteBattery(0);
		
		// 光标闪烁（配置界面）
		for(i = 0; i < VideoBuf.cursor_width; i++)
			Disp_DispChar(VideoBuf.cursor_pos + i, ' ');
	}
	
	// 写命令和数据
	I2C_WriteBytes(2 + sizeof(VideoBuf.buf), &VideoBuf.cmd);

	// 恢复显示内容和标志位
	VideoBuf = Last_VideoBuf;
}	

// 整个屏幕全熄灭
void HT1621_AllOff()
{
	self_check_state = 1;
	memset(VideoBuf.buf, 0x00, sizeof(VideoBuf.buf)); // 不影响最后的状态
	HT1621_Refresh();
	self_check_state = 0;
}
	
// 整个屏幕全点亮
void HT1621_AllOn()
{
	self_check_state = 1;
	memset(VideoBuf.buf, 0xFF, sizeof(VideoBuf.buf)); // 不影响最后的状态
	HT1621_Refresh();
	self_check_state = 0;
}

void LCD_Init()
{
	LL_GPIO_InitTypeDef GPIO_InitStruct = {0};

	LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOB);
	/**I2C1 GPIO Configuration  
	PB8   ------> I2C1_SCL
	PB9   ------> I2C1_SDA 
	*/
	GPIO_InitStruct.Pin = LL_GPIO_PIN_8|LL_GPIO_PIN_9;
	GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;
	GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_MEDIUM;
	GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_OPENDRAIN;
	GPIO_InitStruct.Pull = LL_GPIO_PULL_UP;
	GPIO_InitStruct.Alternate = LL_GPIO_AF_4;
	LL_GPIO_Init(GPIOB, &GPIO_InitStruct);
}
 
void LCD_MyOpen()
{
	LL_I2C_InitTypeDef I2C_InitStruct = {0};

	/* Peripheral clock enable */
	LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_I2C1);

	/** I2C Initialization 
	*/
	LL_I2C_EnableAutoEndMode(I2C1);
	LL_I2C_DisableOwnAddress2(I2C1);
	LL_I2C_DisableGeneralCall(I2C1);
	LL_I2C_EnableClockStretching(I2C1);
	I2C_InitStruct.PeripheralMode = LL_I2C_MODE_I2C;
	I2C_InitStruct.Timing = 0x00503D5A;
	I2C_InitStruct.AnalogFilter = LL_I2C_ANALOGFILTER_ENABLE;
	I2C_InitStruct.DigitalFilter = 0;
	I2C_InitStruct.OwnAddress1 = 0;
	I2C_InitStruct.TypeAcknowledge = LL_I2C_ACK;
	I2C_InitStruct.OwnAddrSize = LL_I2C_OWNADDRESS1_7BIT;
	LL_I2C_Init(I2C1, &I2C_InitStruct);
	LL_I2C_SetOwnAddress2(I2C1, 0, LL_I2C_OWNADDRESS2_NOMASK);
	LL_I2C_Enable(I2C1);
}

// 熄屏
void HT1621_ScreenOff()
{
	// 内部振荡器off，显示off
	HT1621_Cmd(SYS_MODE_CMD, 0);
}

// 任务主体
void Lcd_Task(void *p_arg)
{
	static uint32_t halfSeconds = 0;
	uint16_t interval;
	uint8_t key;

	delay_ms(10);
	while(1)
	{
		// 等待信号量
		xSemaphoreTake(Key_Semaphore, 500);

		// 喂狗
		Watchdog_Feed();
		
		// 判断防过充电磁阀动作是否超时
		if(dcBuff.configDisplay.op_ANTI_OVERFILL && !dcBuff.configDisplay.op_ANTI_SINGLE_CTRL &&
			IS_CHARGE_ENABLE_HIGH() && IsTickOut(Charge_Pulse_Time))
		{
			KZ_CHARGE_ENABLE_LOW();
		}
		if(IS_CHARGE_DISABLE_HIGH() && IsTickOut(Charge_Pulse_Time))
			KZ_CHARGE_DISABLE_LOW();
		// 判断常开电磁阀闭合是否超时
		if(dcBuff.configDisplay.op_ANTI_NORM_OPEN && !IS_NORM_OPEN_ENABLED() && IsTickOut(Anti_Pulse_Time))
		{
			KZ_NORM_OPEN_ENABLE();
		}
	
		// 判断GPS定位是否超时
		if(GPS_Waiting && IsTickOut(GPS_waitTick))
			GPS_Waiting = 0;
		
		// 判断是否发送GPS数据
		if(IsTickOut(GPS_tranTick))
		{
			GPS_tranTick = GetDelayTick(dcBuff.configData.intervalGPSTrans * 1000);
			DTU_semGPS = 1;
		}

		// 默认刷屏周期
		interval = 30;

		if(MeterInSamplePage() && interval > 3)
			interval = 3;
		if(dcBuff.configDisplay.op_ANTI_OVERFILL && Charge_Enabled && interval > 10)
			interval = 10;
		if(Manual_Charing && interval > 10)
			interval = 10;
		if(dcBuff.configDisplay.op_ALARM_OUTPUT && interval > 10)
			interval = 10;
		if(dcBuff.configDisplay.op_ANTI_NORM_OPEN && Anti_Enabled && interval > 10)
			interval = 10;

		// 有外供电，刷新频率提高到5秒
		if(VCC_POWER_STATUS() && (!dcBuff.configDisplay.op_USE_SOLAR || dcBuff.dtuData.batVoltage > 4500) && interval > 5)
			interval = 5;
		
		// 有外供电，且1秒钟采集，刷新频率提高到1秒
		if(VCC_POWER_STATUS() && (!dcBuff.configDisplay.op_USE_SOLAR || dcBuff.dtuData.batVoltage > 4500) && dcBuff.configDisplay.op_LOCAL_DISP_1S && interval > 1)
			interval = 1;

		// 判断是否采集数据
		if(Wakeup_GetWorkMode() == WORK_MODE_NORMAL && ++halfSeconds >= interval * 2)
		{
			// 定时采集
			halfSeconds = 0;
			// 发送消息给任务
			Sample_Notify();
		}
		
		// 处理按键
		while(LoopBuff_GetCount(&Key_TaskM) > 0)
		{
			// 取出按键
			memmove(&key, LoopBuff_GetDataPtr(&Key_TaskM, Key_TaskM.info.rdPtr), 1);
			LoopBuff_RemoveItems(&Key_TaskM, 1);
			// 处理按键
			Form_OnKey(key);
		}
	
		// 刷新显示
		Form_OnTimer();
	}
}
