/*
 * lcd_mho_c122.c
 *
 *      Created: pvvx, 28.05.2023 
 *      Edited by: FaBjE
 *
 *  https://github.com/pvvx/ATC_MiThermometer/issues/339
 */
#include "tl_common.h"
#include "app_config.h"
#if DEVICE_TYPE == DEVICE_MHO_C122
#include "drivers.h"
#include "drivers/8258/gpio_8258.h"
#include "app.h"
#include "i2c.h"
#include "lcd.h"
/*
 *  MHO-C122 LCD buffer:  byte.bit

         --0.4--         --1.4--            --2.4--
  |    |         |     |         |        |         |
  |   0.0       0.5   1.0       1.5      2.0       2.5
  |    |         |     |         |        |         |      o 3.0
 0.3     --0.1--         --1.1--            --2.1--          +--- 3.0
  |    |         |     |         |        |         |     3.0|
  |   0.2       0.6   1.2       1.6      2.2       2.6       ---- 3.1
  |    |         |     |         |        |         |     3.0|
         --0.7--         --1.7--     *      --2.7--          ---- 3.2
                                    2.3
           --5.3--         --4.3--              1.3       1.3            
 (|)     |         |     |         |            / \       / \      
 3.6    5.6       5.2   4.6       4.2     1.3(  ___  3.1  ___  )1.3
         |         |     |         |            1.3 /3.6\ 1.3      
 BLE       --5.5--         --4.5--                  _____
 4.7     |         |     |         |                \3.5/
        5.4       5.1   4.4       4.1     	          
 BAT     |         |     |         |                  %
 5.7       --5.0--         --4.0--                   3.4

None: 3.3 ?
*/

RAM u8 lcd_i2c_addr;

#define lcd_send_i2c_byte(a)  send_i2c_byte(lcd_i2c_addr, a)
#define lcd_send_i2c_buf(b, a)  send_i2c_buf(lcd_i2c_addr, (u8 *) b, a)

#define LCD_SYM_H	0b01100111	// "H"
#define LCD_SYM_i	0b00000100	// "i"
#define LCD_SYM_L	0b10000101	// "L"
#define LCD_SYM_o	0b11000110	// "o"

#define LCD_SYM_BLE	BIT(7)	// BLE connect
#define LCD_SYM_BAT	BIT(7)	// battery

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

_attribute_ram_code_
void send_to_lcd(void){
	unsigned int buff_index;
	u8 * p = display_buff;
	if(cfg.flg2.screen_off)
		return;
	if (lcd_i2c_addr) {
		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 = lcd_i2c_addr;
		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(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);
	}
}

void init_lcd(void){
	lcd_i2c_addr = (u8) scan_i2c_addr(B14_I2C_ADDR << 1);
	if (lcd_i2c_addr) {
// 		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
		if(!cfg.flg2.screen_off) {
			pm_wait_ms(50);
			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));
		}
	}
}

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

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

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

_attribute_ram_code_
void show_ble_symbol(bool state){
	if (state)
		display_buff[4] |= LCD_SYM_BLE;
	else 
		display_buff[4] &= ~LCD_SYM_BLE;
}

_attribute_ram_code_
void show_battery_symbol(bool state){
	if (state)
		display_buff[5] |= LCD_SYM_BAT;
	else 
		display_buff[5] &= ~LCD_SYM_BAT;
}

/* number in 0.1 (-995..19995), Show: -99 .. -9.9 .. 199.9 .. 1999 */
_attribute_ram_code_
__attribute__((optimize("-Os"))) void show_big_number_x10(s16 number){
	display_buff[0] = 0;
	display_buff[1] &= BIT(3); // Clear digit (except smiley contour)
	display_buff[2] = 0;

	if (number > 19995) {
   		display_buff[0] |= LCD_SYM_H; // "H"
   		display_buff[1] |= LCD_SYM_i; // "i"
	} else if (number < -995) {
   		display_buff[0] |= LCD_SYM_L; // "L"
   		display_buff[1] |= LCD_SYM_o; // "o"
	} else {
		/* number: -995..19995 */
		if (number > 1995 || number < -95) {
			if (number < 0){
				number = -number;
				display_buff[0] |= BIT(1); // "-"
			}
			number = (number + 5) / 10; // round(div 10)
		} else { // show: -9.9..199.9
			display_buff[2] = BIT(3); // point
			if (number < 0){
				number = -number;
				display_buff[0] |= BIT(1); // "-"
			}
		}
		/* number: -99..1999 */
		if (number > 999) display_buff[0] |= BIT(3); // "1" 1000..1999
		if (number > 99) display_buff[0] |= display_numbers[number / 100 % 10];
		if (number > 9) display_buff[1] |= display_numbers[number / 10 % 10];
		else display_buff[1] |= display_numbers[0]; // "0"
	    display_buff[2] |= display_numbers[number %10];
	}
}

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

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

	if (number > 99) {
		display_buff[5] |= BIT(1) | BIT(2) | BIT(4) | BIT(5) | BIT(6) ; // "H"
		display_buff[4] |= BIT(4); // "i"
	} else if (number < -9) {
		display_buff[5] |= BIT(0) | BIT(4) | BIT(6); // "L"
		display_buff[4] |= BIT(0) | BIT(1) | BIT(4) | BIT(5); // "o"
	} else {
		if (number < 0) {
			number = -number;
			display_buff[5] |= BIT(5); // "-"
		}
		if (number > 9) 
			display_buff[5] |= display_small_numbers[number / 10 % 10];

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

void show_ota_screen(void) {
	memset(&display_buff, 0, sizeof(display_buff));
	display_buff[4] = BIT(7); // "ble"
	display_buff[0] = BIT(1); // "_"
	display_buff[1] = BIT(1); // "_"
	display_buff[2] = BIT(1); // "_"
	send_to_lcd();
}

// #define SHOW_REBOOT_SCREEN()
void show_reboot_screen(void) {
	memset(&display_buff, 0xff, sizeof(display_buff));
	send_to_lcd();
}

#if	USE_DISPLAY_CLOCK
_attribute_ram_code_
void show_clock(void) {
	u32 tmp = wrk.utc_time_sec / 60;
	u32 min = tmp % 60;
	u32 hrs = tmp / 60 % 24;

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

	display_buff[0] = display_numbers[hrs / 10 % 10];
	display_buff[1] = display_numbers[hrs % 10];
	display_buff[2] = 0;
	display_buff[3] = 0;

	display_buff[4] &= LCD_SYM_BLE; //Clear digit (except BLE symbol)
	display_buff[5] &= LCD_SYM_BAT; //Clear digit (except BAT symbol)

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

#endif // DEVICE_TYPE == DEVICE_MHO_C122