/* * lcd_th05.c * * Created on: 23 янв. 2024 г. * Author: pvvx, Shestoperd */ #include #include "types.h" #include "config.h" #if (DEV_SERVICES & SERVICE_SCREEN) && (DEVICE == DEVICE_TH05D) #include "OSAL.h" #include "gpio.h" #include "rom_sym_def.h" #include "dev_i2c.h" #include "sensors.h" #include "lcd.h" #include "thb2_peripheral.h" #define LCD_I2C_ADDR 0x3E #define I2C_WAIT_ms 1 dev_i2c_t i2c_dev1 = { //.pi2cdev = AP_I2C1, .scl = I2C_LCD_SCL, .sda = I2C_LCD_SDA, .speed = I2C_100KHZ, .i2c_num = 0 }; /* 0,1,2,3,4,5,6,7,8,9,A,b,C,d,E,F*/ const uint8_t display_numbers67[] = { // 76543210 0b011111010, // 0 0b001100000, // 1 0b011010110, // 2 0b011110100, // 3 0b001101100, // 4 0b010111100, // 5 0b010111110, // 6 0b011100000, // 7 0b011111110, // 8 0b011111100, // 9 0b011101110, // A 0b000111110, // b 0b010011010, // C 0b001110110, // d 0b010011110, // E 0b010001110 // F }; #define LCD_SYM67_b 0b000111110 // "b" #define LCD_SYM67_H 0b001101110 // "H" #define LCD_SYM67_h 0b001001110 // "h" #define LCD_SYM67_i 0b000000010 // "i" #define LCD_SYM67_L 0b000011010 // "L" #define LCD_SYM67_o 0b000110110 // "o" #define LCD_SYM67_t 0b000011110 // "t" #define LCD_SYM67_0 0b011111010 // "0" #define LCD_SYM67_A 0b011101110 // "A" #define LCD_SYM67_a 0b010110110 // "a" #define LCD_SYM67_P 0b011001110 // "P" const uint8_t display_numbers45[] = { // 76543210 0b010101111, // 0 0b000000110, // 1 0b001101101, // 2 0b001001111, // 3 0b011000110, // 4 0b011001011, // 5 0b011101011, // 6 0b000001110, // 7 0b011101111, // 8 0b011001111, // 9 0b011101110, // A 0b011000011, // b 0b010101001, // C 0b001100110, // d 0b011101001, // E 0b011101000 // F }; #define LCD_SYM45_b 0b011100011 // "b" #define LCD_SYM45_H 0b011100110 // "H" #define LCD_SYM45_h 0b011100010 // "h" #define LCD_SYM45_i 0b000100000 // "i" #define LCD_SYM45_L 0b010100001 // "L" #define LCD_SYM45_o 0b001100011 // "o" #define LCD_SYM45_t 0b011100001 // "t" #define LCD_SYM45_0 0b010101111 // "0" #define LCD_SYM45_A 0b011101110 // "A" #define LCD_SYM45_a 0b001101111 // "a" #define LCD_SYM45_P 0b011101100 // "P" const uint8_t display_numbers12[] = { // 76543210 0b001011111, // 0 0b000000110, // 1 0b001101011, // 2 0b000101111, // 3 0b000110110, // 4 0b000111101, // 5 0b001111101, // 6 0b000000111, // 7 0b001111111, // 8 0b000111111, // 9 0b001110111, // A 0b001111100, // b 0b001011001, // C 0b001101110, // d 0b001111001, // E 0b001110001 // F }; #define LCD_SYM12_b 0b001111100 // "b" #define LCD_SYM12_H 0b001110110 // "H" #define LCD_SYM12_h 0b001110100 // "h" #define LCD_SYM12_i 0b001000000 // "i" #define LCD_SYM12_L 0b001011000 // "L" #define LCD_SYM12_o 0b001101100 // "o" #define LCD_SYM12_t 0b001111000 // "t" #define LCD_SYM12_0 0b001011111 // "0" #define LCD_SYM12_A 0b001110111 // "A" #define LCD_SYM12_a 0b001101101 // "a" #define LCD_SYM12_P 0b001110011 // "P" lcd_data_t lcdd; const uint8_t lcd_init_cmd[] = { // LCD controller initialize: 0xea, // Set IC Operation(ICSET): Software Reset, Internal oscillator circuit 0xd8, // Mode Set (MODE SET): Display enable, 1/3 Bias, power saving 0xbc, // Display control (DISCTL): Power save mode 3, FRAME flip, Power save mode 1 0x80, // load data pointer 0xf0, // blink control off, 0xf2 - blink 0xfc, // All pixel control (APCTL): Normal 0x60, 0x00,0x00,000,0x00,0x00,0x00,0x00,0x00,0x00 }; /* 0x0 = " " * 0x1 = "°Г" * 0x2 = " _" * 0x3 = "°C" * 0x4 = " -" * 0x5 = "°F" * 0x6 = " =" * 0x7 = "°E" */ void show_temp_symbol(LCD_TEMP_SYMBOLS symbol) { lcdd.display_buff[5] &= ~(BIT(1) | BIT(2) | BIT(3)); if(symbol & 1) lcdd.display_buff[5] |= BIT(3); if(symbol & 2) lcdd.display_buff[5] |= BIT(1); if(symbol & 4) lcdd.display_buff[5] |= BIT(2); } /* 0 = " " off, * 1 = " ^_^ " happy * 2 = " -^- " sad * 3 = " ooo " * 4 = "( )" * 5 = "(^_^)" happy * 6 = "(-^-)" sad * 7 = "(ooo)" */ void show_smiley(LCD_SMILEY_SYMBOLS symbol) { lcdd.display_buff[0] &= ~(BIT(0) | BIT(1) | BIT(2) | BIT(3)); if(symbol & 1) lcdd.display_buff[0] |= BIT(1) | BIT(3); if(symbol & 2) lcdd.display_buff[0] |= BIT(1) | BIT(2); if(symbol & 4) lcdd.display_buff[0] |= BIT(0); } void show_ble_symbol(bool state) { if (state) lcdd.display_buff[0] |= BIT(4); else lcdd.display_buff[0] &= ~BIT(4); } void show_battery_symbol(bool state) { lcdd.display_buff[3] &= ~(BIT(1) | BIT(2) | BIT(5) | BIT(6)); lcdd.display_buff[4] &= ~(BIT(5) | BIT(6)); if (state) { lcdd.display_buff[4] |= BIT(6); if(measured_data.battery > 84) lcdd.display_buff[4] |= BIT(5); if(measured_data.battery > 68) lcdd.display_buff[3] |= BIT(2); if(measured_data.battery > 52) lcdd.display_buff[3] |= BIT(1); if(measured_data.battery > 36) lcdd.display_buff[3] |= BIT(5); if(measured_data.battery > 20) lcdd.display_buff[3] |= BIT(6); } } void show_big_number_x10(int16_t number) { lcdd.display_buff[5] &= BIT(1) | BIT(2) | BIT(3); // F/C "_" lcdd.display_buff[4] &= BIT(5) | BIT(6) | BIT(7); // bat, % if (number > 19995) { lcdd.display_buff[7] = LCD_SYM67_H; // "H" lcdd.display_buff[6] = LCD_SYM67_i; // "i" } else if (number < -995) { lcdd.display_buff[7] = LCD_SYM67_L; // "L" lcdd.display_buff[6] = LCD_SYM67_o; // "o" } else { lcdd.display_buff[6] = 0; lcdd.display_buff[7] = 0; /* number: -19995..19995 */ if (number > 1995 || number < -1995) { //lcdd.display_buff[5] &= ~BIT(0); // no point, show: -1999..1999 if (number < 0) { number = -number; lcdd.display_buff[6] = BIT(0); // "-" } number = (number + 5) / 10; // round(div 10) } else { // show: -199.9..199.9 lcdd.display_buff[5] |= BIT(0); // point, if (number < 0){ number = -number; lcdd.display_buff[6] = BIT(2); // "-" } } /* number: -1999..1999 */ if (number > 999) lcdd.display_buff[7] = BIT(0); // "1" 1000..1999 if (number > 99) lcdd.display_buff[7] |= display_numbers67[(number / 100) % 10]; if (number > 9) lcdd.display_buff[6] |= display_numbers67[(number / 10) % 10]; else lcdd.display_buff[6] |= LCD_SYM67_0; // "0" lcdd.display_buff[4] |= display_numbers45[number %10] & 0x0f; lcdd.display_buff[5] |= display_numbers45[number %10] & 0xe0; } } /* -9 .. 99 */ void show_small_number(int16_t number, bool percent) { if(percent) lcdd.display_buff[4] |= BIT(7); else lcdd.display_buff[4] &= ~BIT(7); if (number > 99) { lcdd.display_buff[1] = LCD_SYM12_H; // "H" lcdd.display_buff[2] = LCD_SYM12_i; // "i" } else if (number < -9) { lcdd.display_buff[1] = LCD_SYM12_L; // "L" lcdd.display_buff[2] = LCD_SYM12_o; // "o" } else { lcdd.display_buff[1] = 0; if (number < 0) { number = -number; lcdd.display_buff[1] = BIT(5); // "-" } if (number > 9) lcdd.display_buff[1] = display_numbers12[number / 10]; lcdd.display_buff[2] = display_numbers12[number %10]; } } void lcd_show_version(void) { lcdd.display_buff[0] &= BIT(4); // connect lcdd.display_buff[3] &= BIT(1) | BIT(2) | BIT(5) | BIT(6); // bat lcdd.display_buff[4] &= BIT(5) | BIT(6); #if OTA_TYPE lcdd.display_buff[7] = LCD_SYM67_b; lcdd.display_buff[6] = LCD_SYM67_o; lcdd.display_buff[5] = LCD_SYM45_t & 0xe0; lcdd.display_buff[4] |= LCD_SYM45_t & 0x0f; #else lcdd.display_buff[7] = LCD_SYM67_A; lcdd.display_buff[6] = LCD_SYM67_P; lcdd.display_buff[5] = LCD_SYM45_P & 0xe0; lcdd.display_buff[4] |= LCD_SYM45_P & 0x0f; #endif lcdd.display_buff[1] = display_numbers12[(APP_VERSION>>4) & 0x0f]; lcdd.display_buff[2] = display_numbers12[APP_VERSION & 0x0f]; update_lcd(); } void chow_clock(void) { uint32_t tmp = clkt.utc_time_sec / 60; uint32_t min = tmp % 60; uint32_t hrs = (tmp / 60) % 24; lcdd.display_buff[0] &= BIT(4); // connect lcdd.display_buff[3] &= BIT(1) | BIT(2) | BIT(5) | BIT(6); // bat lcdd.display_buff[4] &= BIT(5) | BIT(6); lcdd.display_buff[7] = display_numbers67[hrs / 10]; lcdd.display_buff[6] = display_numbers67[hrs % 10]; lcdd.display_buff[5] = 0; lcdd.display_buff[1] = display_numbers12[min / 10]; lcdd.display_buff[2] = display_numbers12[min % 10]; update_lcd(); } static void chow_measure(void) { #if (DEV_SERVICES & SERVICE_THS) if(cfg.flg & FLG_SHOW_TF) { show_big_number_x10(((int32_t)((int32_t)measured_data.temp * 9)/ 50) + 320); // convert C to F show_temp_symbol(LCD_TSYMBOL_F); // "°F" } else { show_big_number_x10((measured_data.temp + 5)/10); show_temp_symbol(LCD_TSYMBOL_C); } int16_t h = (measured_data.humi + 50)/100; if(h > 99) h = 99; show_small_number(h, true); show_battery_symbol(1); #if (OTA_TYPE == OTA_TYPE_APP) if(cfg.flg & FLG_SHOW_SMILEY) { #if (DEV_SERVICES & SERVICE_TH_TRG) if(cfg.flg & FLG_SHOW_TRG) { if(measured_data.flg.comfort) { if(measured_data.flg.trg_on) show_smiley(LD_SSYMBOL_HAPPY); else show_smiley(LD_SSYMBOL__HAPPY); } else { if(measured_data.flg.trg_on) show_smiley(LD_SSYMBOL_SAD); else show_smiley(LD_SSYMBOL__SAD); } } else #endif // SERVICE_TH_TRG { if(measured_data.flg.comfort) show_smiley(LD_SSYMBOL_HAPPY); else show_smiley(LD_SSYMBOL_SAD); } #if (DEV_SERVICES & SERVICE_TH_TRG) } else if(cfg.flg & FLG_SHOW_TRG) { if(measured_data.flg.trg_on) show_smiley(LD_SSYMBOL_ALL); else show_smiley(LD_SSYMBOL_OFF); } else #endif // SERVICE_TH_TRG #endif // OTA_TYPE show_smiley(LD_SSYMBOL_OFF); #else show_big_number_x10(measured_data.battery_mv/100); show_small_number((measured_data.battery > 99)? 99 : measured_data.battery, true); show_battery_symbol(1); show_smiley(LD_SSYMBOL_OFF); #endif // SERVICE_THS show_ble_symbol(gapRole_state == GAPROLE_CONNECTED); update_lcd(); } #if (OTA_TYPE == OTA_TYPE_APP) void chow_ext_data(void) { show_big_number_x10(lcdd.ext.big_number); show_small_number(lcdd.ext.small_number, lcdd.ext.flg.percent_on); show_battery_symbol(lcdd.ext.flg.battery); show_smiley(lcdd.ext.flg.smiley); show_temp_symbol(lcdd.ext.flg.temp_symbol); update_lcd(); } #endif /* flg != 0 -> chow_measure */ void chow_lcd(int flg) { #if OTA_TYPE == OTA_TYPE_BOOT if(clkt.utc_time_sec < lcdd.chow_ext_ut) return; if(flg) chow_measure(); #else if(cfg.flg & FLG_DISPLAY_OFF) return; if(clkt.utc_time_sec < lcdd.chow_ext_ut) return; if(cfg.flg & FLG_SHOW_TIME) { if(wrk.lcd_count++ & 1) chow_clock(); else chow_measure(); } else if(flg) { chow_measure(); } #endif } void send_to_lcd(uint8_t *pbuf, int len) { if (lcdd.lcd_i2c_addr) { init_i2c(&i2c_dev1); send_i2c_buf(&i2c_dev1, lcdd.lcd_i2c_addr, pbuf, len); deinit_i2c(&i2c_dev1); } } void update_lcd(void) { #if (OTA_TYPE == OTA_TYPE_APP) if(lcdd.lcd_i2c_addr == 0 || (cfg.flg & FLG_DISPLAY_OFF) != 0) return; #endif if(memcmp(&lcdd.display_out_buff[1], lcdd.display_buff, sizeof(lcdd.display_buff))) { memcpy(&lcdd.display_out_buff[1], lcdd.display_buff, sizeof(lcdd.display_buff)); send_to_lcd(lcdd.display_out_buff, sizeof(lcdd.display_out_buff)); } } void init_lcd(void) { i2c_dev1.speed = I2C_100KHZ; init_i2c(&i2c_dev1); if(!send_i2c_buf(&i2c_dev1, LCD_I2C_ADDR, (uint8_t *) lcd_init_cmd, sizeof(lcd_init_cmd))) { #if (OTA_TYPE == OTA_TYPE_APP) if(cfg.flg & FLG_DISPLAY_OFF) send_i2c_byte(&i2c_dev1, LCD_I2C_ADDR, 0xd0); // Mode Set (MODE SET): Display disable, 1/3 Bias, power saving #endif lcdd.lcd_i2c_addr = LCD_I2C_ADDR; } else lcdd.lcd_i2c_addr = 0; deinit_i2c(&i2c_dev1); i2c_dev1.speed = I2C_400KHZ; } /****************************************************/ #endif // (DEV_SERVICES & SERVICE_SCREEN)