/*
 * lcd_mho_c122.c
 * Created: pvvx, 28.05.2023 
 * Edited by: FaBjE
 *
 *  https://github.com/pvvx/ATC_MiThermometer/issues/339
 */
#include "tl_common.h"
#if BOARD == BOARD_MHO_C122
#include "chip_8258/timer.h"

#include "i2c_drv.h"
#include "lcd.h"
#include "device.h"

#define _SCR_CODE_SEC_

RAM scr_data_t scr;

#define lcd_send_i2c_byte(a)  send_i2c_byte(scr.i2c_address, a)
#define lcd_send_i2c_buf(b, a)  send_i2c_bytes(scr.i2c_address, (u8 *) b, a)

#define LCD_SYM_Top_E	0b10010111	// "E"
#define LCD_SYM_Top_H	0b01100111	// "H"
#define LCD_SYM_Top_i	0b00000100	// "i"
#define LCD_SYM_Top_L	0b10000101	// "L"
#define LCD_SYM_Top_o	0b11000110	// "o"

#define LCD_SYM_Top_t	0b10000111	// "t"
#define LCD_SYM_Top_a	0b11110110	// "a"

#define LCD_SYM_Bot_E	0b01111001	// "E"
#define LCD_SYM_Bot_H   0b01110110	// "H"
#define LCD_SYM_Bot_i	0b00010000	// "i"
#define LCD_SYM_Bot_L	0b01010001	// "L"
#define LCD_SYM_Bot_o	0b00110011	// "o"


const u8 lcd_init_cmd_b14[] =	{0x80,0x3B,0x80,0x02,0x80,0x0F,0x80,0x95,0x80,0x88,0x80,0x88,0x80,0x88,0x80,0x88,0x80,0x19,0x80,0x28,0x80,0xE3,0x80,0x11};
								//	{0x80,0x40,0xC0,byte1,0xC0,byte2,0xC0,byte3,0xC0,byte4,0xC0,byte5,0xC0,byte6};
const u8 lcd_init_clr_b14[] =	{0x80,0x40,0xC0,0,0xC0,0,0xC0,0,0xC0,0,0xC0,0,0xC0,0,0xC0,0,0xC0,0};

/* 0,1,2,3,4,5,6,7,8,9,A,b,C,d,E,F*/
const u8 display_numbers[] = {
		0b11110101, // 0
		0b01100000, // 1
		0b10110110, // 2
		0b11110010, // 3
		0b01100011, // 4
		0b11010011, // 5
		0b11010111, // 6
		0b01110000, // 7
		0b11110111, // 8
		0b11110011, // 9
		0b01110111, // A
		0b11000111, // b
		0b10010101, // C
		0b11100110, // d
		0b10010111, // E
		0b00010111};  // F
const u8 display_small_numbers[] = {
		0b01011111, // 0
		0b00000110, // 1
		0b00111101, // 2
		0b00101111, // 3
		0b01100110, // 4
		0b01101011, // 5
		0b01111011, // 6
		0b00001110, // 7
		0b01111111, // 8
		0b01101111, // 9
		0b01111110, // A
		0b01110011, // b
		0b01011001, // C
		0b00110111, // d
		0b01111001, // E
		0b01111000};  // F

_SCR_CODE_SEC_
static void send_to_lcd(void){
	unsigned int buff_index;
	u8 * p = scr.display_cmp_buff;
	if (scr.i2c_address) {
		unsigned char r = irq_disable();
		if ((reg_clk_en0 & FLD_CLK0_I2C_EN)==0)
			init_i2c();
		else {
			gpio_setup_up_down_resistor(I2C_SCL, PM_PIN_PULLUP_10K);
			gpio_setup_up_down_resistor(I2C_SDA, PM_PIN_PULLUP_10K);
		}
		reg_i2c_id = scr.i2c_address;
		reg_i2c_adr_dat = 0x4080;
		reg_i2c_ctrl = FLD_I2C_CMD_START | FLD_I2C_CMD_ID | FLD_I2C_CMD_ADDR | FLD_I2C_CMD_DO;
		while (reg_i2c_status & FLD_I2C_CMD_BUSY);
		reg_i2c_adr = 0xC0;
		for(buff_index = 0; buff_index < sizeof(scr.display_buff); buff_index++) {
			reg_i2c_do = *p++;
			reg_i2c_ctrl = FLD_I2C_CMD_ADDR | FLD_I2C_CMD_DO;
			while (reg_i2c_status & FLD_I2C_CMD_BUSY);
		}
		reg_i2c_ctrl = FLD_I2C_CMD_STOP;
		while (reg_i2c_status & FLD_I2C_CMD_BUSY);
		irq_restore(r);
	}
}

void init_lcd(void){
	scr.display_off = g_zcl_thermostatUICfgAttrs.display_off;
	scr.i2c_address = scan_i2c_addr(B14_I2C_ADDR << 1);
	if (scr.i2c_address) {
// 		GPIO_PB6 set in app_config.h!
//		gpio_setup_up_down_resistor(GPIO_PB6, PM_PIN_PULLUP_10K); // LCD on low temp needs this, its an unknown pin going to the LCD controller chip
//		pm_wait_ms(50); // LCD_INIT_DELAY()
		lcd_send_i2c_buf((u8 *) lcd_init_cmd_b14, sizeof(lcd_init_cmd_b14));
		lcd_send_i2c_buf((u8 *) lcd_init_clr_b14, sizeof(lcd_init_clr_b14));
		memset(&scr.display_buff, 0xff, sizeof(scr.display_buff));
		send_to_lcd();
	} else
		scr.display_off = 1;
}

_SCR_CODE_SEC_
void update_lcd(void){
	if(scr.display_off)
		return;
	if (memcmp(scr.display_cmp_buff, scr.display_buff, sizeof(scr.display_buff))) {
		memcpy(scr.display_cmp_buff, scr.display_buff, sizeof(scr.display_buff));
		send_to_lcd();
	}
}

/* 0x00 = "  "
 * 0x20 = "°Г"
 * 0x40 = " -"
 * 0x60 = "°F"
 * 0x80 = " _"
 * 0xA0 = "°C"
 * 0xC0 = " ="
 * 0xE0 = "°E" */
_SCR_CODE_SEC_
void show_temp_symbol(u8 symbol) {
	scr.display_buff[3] &= ~(BIT(0) | BIT(1) | BIT(2));
	if (symbol & 0x20)
		scr.display_buff[3] |= BIT(0);
	if (symbol & 0x40)
		scr.display_buff[3] |= BIT(1); //"-"
	if (symbol & 0x80)
		scr.display_buff[3] |= BIT(2); // "_"
}

/* 0 = "     " off,
 * 1 = " ^-^ "
 * 2 = " -^- "
 * 3 = " ooo "
 * 4 = "(   )"
 * 5 = "(^-^)" happy
 * 6 = "(-^-)" sad
 * 7 = "(ooo)" */
_SCR_CODE_SEC_
void show_smiley(u8 state){
	scr.display_buff[1] &= ~BIT(3);
	scr.display_buff[3] &= ~(BIT(5) | BIT(6));

	if(state & 1)
		scr.display_buff[3] |= BIT(5); // Happy mouth
	if(state & 2)
		scr.display_buff[3] |= BIT(6); // Sad mouth
	if(state & 4)
		scr.display_buff[1] |= BIT(3); // Smiley contour
}

_SCR_CODE_SEC_
void show_ble_symbol(bool state){
	if (state)
		scr.display_buff[4] |= BIT(7);
	else 
		scr.display_buff[4] &= ~BIT(7);
}

_SCR_CODE_SEC_
void show_connected_symbol(bool state){
 	if (state)
		scr.display_buff[3] |= BIT(7); // "*"
	else
		scr.display_buff[3] &= ~BIT(7);
}

_SCR_CODE_SEC_
void show_battery_symbol(bool state){
	if (state)
		scr.display_buff[5] |= BIT(7);
	else 
		scr.display_buff[5] &= ~BIT(7);
}

/* number:
 * in 0.1 (-995..19995), Show: -99..-9.9 .. 199.9 .. 1999
 * symbol:
 * 0x00 = "  "
 * 0x20 = "°Г"
 * 0x40 = " -"
 * 0x60 = "°F"
 * 0x80 = " _"
 * 0xA0 = "°C"
 * 0xC0 = " ="
 * 0xE0 = "°E" */
_SCR_CODE_SEC_
__attribute__((optimize("-Os")))
void show_big_number_x10(s16 number, u8 symbol){

	scr.display_buff[3] &= ~(BIT(0) | BIT(1) | BIT(2));
	if (symbol & 0x20)
		scr.display_buff[3] |= BIT(0);
	if (symbol & 0x40)
		scr.display_buff[3] |= BIT(1); //"-"
	if (symbol & 0x80)
		scr.display_buff[3] |= BIT(2); // "_"

	scr.display_buff[0] = 0;
	scr.display_buff[1] &= BIT(3); // Clear digit (except smiley contour)
	scr.display_buff[2] = 0;

	if (number > 19995) {
   		scr.display_buff[0] |= LCD_SYM_Top_H; // "H"
   		scr.display_buff[1] |= LCD_SYM_Top_i; // "i"
	} else if (number < -995) {
   		scr.display_buff[0] |= LCD_SYM_Top_L; // "L"
   		scr.display_buff[1] |= LCD_SYM_Top_o; // "o"
	} else {
		/* number: -995..19995 */
		if (number > 1999 || number < -99) {
			/* number: -995..-100, 2000..19995 */
			// round(div 10)
			number += 5;
			number /= 10;
			// show no point: -99..-10, 200..1999
		} else {
			// show point: -9.9..199.9
			scr.display_buff[2] = BIT(3); // point top
		}
		/* show: -99..1999 */
		if (number < 0) {
			number = -number;
			scr.display_buff[0] |= BIT(1); // "-"
		}
		/* number: -99..1999 */
		if (number > 999) scr.display_buff[0] |= BIT(3); // "1" 1000..1999
		if (number > 99) scr.display_buff[0] |= display_numbers[number / 100 % 10];
		if (number > 9) scr.display_buff[1] |= display_numbers[number / 10 % 10];
		else scr.display_buff[1] |= display_numbers[0]; // "0"
	    scr.display_buff[2] |= display_numbers[number %10];
	}
}

/* -9 .. 99 */
_SCR_CODE_SEC_
__attribute__((optimize("-Os")))
void show_small_number(s16 number, bool percent){
	scr.display_buff[4] &= BIT(7); //Clear digit (except BLE symbol)
	scr.display_buff[5] &= BIT(7); //Clear digit (except BAT symbol)

	if (percent)
		scr.display_buff[3] |= BIT(4); // %
	else
		scr.display_buff[3] &= ~BIT(4); // %

	if (number > 99) {
		scr.display_buff[5] |= LCD_SYM_Bot_H;  // "H"
		scr.display_buff[4] |= LCD_SYM_Bot_i;  // "i"
	} else if (number < -9) {
		scr.display_buff[5] |= LCD_SYM_Bot_L; // "L"
		scr.display_buff[4] |= LCD_SYM_Bot_o; // "o"
	} else {
		if (number < 0) {
			number = -number;
			scr.display_buff[5] |= BIT(5); // "-"
		}
		if (number > 9) 
			scr.display_buff[5] |= display_small_numbers[number / 10 % 10];

		scr.display_buff[4] |= display_small_numbers[number %10];
	}
}

void show_ble_ota(void) {
	scr.display_buff[0] = LCD_SYM_Top_o; // "o"
	scr.display_buff[1] = LCD_SYM_Top_t; // "t"
	scr.display_buff[2] = LCD_SYM_Top_a; // "a"
	scr.display_buff[3] &= BIT(7); // "(|)"
	scr.display_buff[4] = BIT(7); // "ble"
	scr.display_buff[5] &= BIT(7); // "bat"
	update_lcd();
}

void show_err_sensors(void) {
	scr.display_buff[0] = LCD_SYM_Bot_E; // E
	scr.display_buff[1] = LCD_SYM_Bot_E; // E
	scr.display_buff[2] = 0;
	scr.display_buff[3] &= BIT(7); // "(|)"
	scr.display_buff[4] &= BIT(7); // "ble"
	scr.display_buff[5] &= BIT(7); // "bat"
	scr.display_buff[4] |= LCD_SYM_Top_E; // E
	scr.display_buff[5] |= LCD_SYM_Top_E; // E
}

void show_reset_screen(void) {
	scr.display_buff[0] = LCD_SYM_Top_o; // "o"
	scr.display_buff[1] = LCD_SYM_Top_o; // "o"
	scr.display_buff[2] = 0;
	scr.display_buff[3] = 0;
	scr.display_buff[4] = LCD_SYM_Bot_o; // "o"
	scr.display_buff[5] = LCD_SYM_Bot_o; // "o"
	update_lcd();
}

#if	USE_CLOCK
void show_clock(void) {
	uint32_t tmp = utc_time_sec / 60;
	uint32_t min = tmp % 60;
	uint32_t hrs = tmp / 60 % 24;

	scr.display_buff[0] = 0;
	scr.display_buff[1] &= BIT(3); //Clear digit (except smiley contour)

	scr.display_buff[0] = display_numbers[hrs / 10 % 10];
	scr.display_buff[1] = display_numbers[hrs % 10];
	scr.display_buff[2] = 0;
	scr.display_buff[3] &= BIT(7);

	scr.display_buff[4] &= BIT(7); //Clear digit (except BLE symbol)
	scr.display_buff[5] &= BIT(7); //Clear digit (except BAT symbol)

	scr.display_buff[4] |= display_small_numbers[min % 10];
	scr.display_buff[5] |= display_small_numbers[min / 10 % 10];
}
#endif // USE_CLOCK

#endif // BOARD == BOARD_MHO_C122