diff --git a/makefile b/makefile index e88715de..af88dd41 100644 --- a/makefile +++ b/makefile @@ -102,7 +102,7 @@ stop: go: @python3 $(PROJECT_PATH)/../TlsrPgm.py -p$(PGM_PORT) -w -m -TADDR?=0x840000 +TADDR?=0x844000 TLEN?=128 test_damp: @python3 $(PROJECT_PATH)/../TlsrPgm.py -p$(PGM_PORT) -z10 -c -g ds $(TADDR) $(TLEN) diff --git a/src/app.c b/src/app.c index ab85cebf..b3100476 100644 --- a/src/app.c +++ b/src/app.c @@ -11,6 +11,9 @@ #include "sensor.h" #include "app.h" #include "i2c.h" +#if USE_RTC +#include "rtc.h" +#endif #if USE_TRIGGER_OUT #include "trigger.h" #include "rds_count.h" @@ -39,13 +42,17 @@ RAM volatile uint8_t tx_measures; RAM volatile uint8_t start_measure; // start measure all RAM volatile uint8_t wrk_measure; RAM volatile uint8_t end_measure; +#if (DEVICE_TYPE == DEVICE_MJWSD05MMC) +RAM volatile uint8_t lcd_update; +#else +RAM uint32_t min_step_time_update_lcd; // = cfg.min_step_time_update_lcd * 0.05 sec RAM uint32_t tim_last_chow; // timer show lcd >= 1.5 sec +#endif RAM uint32_t tim_measure; // timer measurements >= 10 sec RAM uint32_t adv_interval; // adv interval in 0.625 ms // = cfg.advertising_interval * 100 RAM uint32_t connection_timeout; // connection timeout in 10 ms, Tdefault = connection_latency_ms * 4 = 2000 * 4 = 8000 ms RAM uint32_t measurement_step_time; // = adv_interval * measure_interval -RAM uint32_t min_step_time_update_lcd; // = cfg.min_step_time_update_lcd * 0.05 sec RAM uint32_t utc_time_sec; // clock in sec (= 0 1970-01-01 00:00:00) RAM uint32_t utc_time_sec_tick; @@ -54,6 +61,10 @@ RAM uint32_t utc_time_tick_step = CLOCK_16M_SYS_TIMER_CLK_1S; // adjust time clo #else #define utc_time_tick_step CLOCK_16M_SYS_TIMER_CLK_1S #endif +#ifdef GPIO_KEY2 +RAM int32_t rest_adv_int_tad; // timer event restore adv.intervals (in adv tik) +RAM uint32_t key_pressed_tik, key_pressed_tiks; // timer key_pressed (in sys tik) +#endif #if USE_SECURITY_BEACON RAM uint8_t bindkey[16]; @@ -71,14 +82,24 @@ void lcd(void); const cfg_t def_cfg = { .flg.temp_F_or_C = false, .flg.comfort_smiley = true, +#if DEVICE_TYPE != DEVICE_MJWSD05MMC .flg.blinking_time_smile = false, .flg.show_batt_enabled = false, - .flg.advertising_type = ADV_TYPE_DEFAULT, - .flg.tx_measures = false, .flg2.smiley = 0, // 0 = " " off .flg2.bt5phy = 1, // support BT5.0 - .advertising_interval = 40, // multiply by 62.5 ms = 2.5 sec -#if DEVICE_TYPE == DEVICE_LYWSD03MMC +#endif + .flg.tx_measures = false, + .flg.advertising_type = ADV_TYPE_DEFAULT, + .advertising_interval = 80, // multiply by 62.5 ms = 5 sec +#if DEVICE_TYPE == DEVICE_MJWSD05MMC + .flg.time_am_pm = true, + .flg.comfort_smiley = true, + .measure_interval = 4, // * advertising_interval = 10 sec + .hw_cfg.hwver = HW_VER_MJWSD05MMC, +#if USE_FLASH_MEMO + .averaging_measurements = 180, // * measure_interval = 10 * 180 = 1800 sec = 30 minutes +#endif +#elif DEVICE_TYPE == DEVICE_LYWSD03MMC .flg.comfort_smiley = true, .measure_interval = 4, // * advertising_interval = 10 sec .min_step_time_update_lcd = 49, //x0.05 sec, 2.45 sec @@ -134,6 +155,7 @@ const cfg_t def_cfg = { }; RAM cfg_t cfg; static const external_data_t def_ext = { +#if DEVICE_TYPE != DEVICE_MJWSD05MMC .big_number = 0, .small_number = 0, .vtime_sec = 60, // 1 minutes @@ -141,13 +163,19 @@ static const external_data_t def_ext = { .flg.percent_on = true, .flg.battery = false, .flg.temp_symbol = 5 // 5 = "°C", ... app.h +#else + .number = 1234500, + .vtime_sec = 30, // 30 sec + .flg.smiley = 7, // 7 = "(ooo)" + .flg.battery = false, + .flg.temp_symbol = LCD_SYM_N // 0 = " ", ... app.h +#endif }; RAM external_data_t ext; #if BLE_SECURITY_ENABLE RAM uint32_t pincode; #endif -__attribute__((optimize("-Os"))) void set_hw_version(void) { cfg.hw_cfg.reserved = 0; if (sensor_i2c_addr == (SHTC3_I2C_ADDR << 1)) @@ -207,12 +235,15 @@ void set_hw_version(void) { cfg.hw_cfg.hwver = HW_VER_CGDK2; #elif DEVICE_TYPE == DEVICE_MHO_C401N cfg.hw_cfg.hwver = HW_VER_MHO_C401_2022; +#elif DEVICE_TYPE == DEVICE_MJWSD05MMC + cfg.hw_cfg.hwver = HW_VER_MJWSD05MMC; #else cfg.hw_cfg.hwver = HW_VER_UNKNOWN; #endif } -__attribute__((optimize("-Os"))) void test_config(void) { +__attribute__((optimize("-Os"))) +void test_config(void) { if (cfg.flg2.longrange) cfg.flg2.bt5phy = 1; if (cfg.rf_tx_power & BIT(7)) { @@ -263,16 +294,21 @@ __attribute__((optimize("-Os"))) void test_config(void) { my_periConnParameters.latency = cfg.connect_latency; } my_periConnParameters.timeout = connection_timeout; +#if DEVICE_TYPE != DEVICE_MJWSD05MMC if (cfg.min_step_time_update_lcd < 10) // min 0.5 sec: (10*50ms) cfg.min_step_time_update_lcd = 10; min_step_time_update_lcd = cfg.min_step_time_update_lcd * (50 * CLOCK_16M_SYS_TIMER_CLK_1MS); - +#endif my_RxTx_Data[0] = CMD_ID_CFG; my_RxTx_Data[1] = VERSION; + set_hw_version(); memcpy(&my_RxTx_Data[2], &cfg, sizeof(cfg)); } void low_vbat(void) { +#if DEVICE_TYPE == DEVICE_MJWSD05MMC + show_low_bat(); +#else #if ((DEVICE_TYPE == DEVICE_MHO_C401) || (DEVICE_TYPE == DEVICE_MHO_C401N) || (DEVICE_TYPE == DEVICE_CGG1)) while(task_lcd()) pm_wait_ms(10); #endif @@ -290,13 +326,15 @@ void low_vbat(void) { update_lcd(); #if ((DEVICE_TYPE == DEVICE_MHO_C401) || (DEVICE_TYPE == DEVICE_MHO_C401N) || (DEVICE_TYPE == DEVICE_CGG1)) while(task_lcd()) pm_wait_ms(10); +#endif #endif cpu_sleep_wakeup(DEEPSLEEP_MODE, PM_WAKEUP_TIMER, clock_time() + 120 * CLOCK_16M_SYS_TIMER_CLK_1S); // go deep-sleep 2 minutes while(1); } -_attribute_ram_code_ void WakeupLowPowerCb(int par) { +_attribute_ram_code_ +void WakeupLowPowerCb(int par) { (void) par; if (wrk_measure) { #if USE_TRIGGER_OUT && defined(GPIO_RDS) @@ -339,7 +377,9 @@ _attribute_ram_code_ void WakeupLowPowerCb(int par) { } #endif end_measure = 1; - +#if (DEVICE_TYPE == DEVICE_MJWSD05MMC) + lcd_update = 1; +#endif wrk_measure = 0; } timer_measure_cb = 0; @@ -349,7 +389,8 @@ _attribute_ram_code_ void WakeupLowPowerCb(int par) { low_vbat(); } -_attribute_ram_code_ static void suspend_exit_cb(u8 e, u8 *p, int n) { +_attribute_ram_code_ +static void suspend_exit_cb(u8 e, u8 *p, int n) { (void) e; (void) p; (void) n; if (timer_measure_cb) init_i2c(); @@ -357,10 +398,22 @@ _attribute_ram_code_ static void suspend_exit_cb(u8 e, u8 *p, int n) { } #if USE_WK_RDS_COUNTER -_attribute_ram_code_ static void suspend_enter_cb(u8 e, u8 *p, int n) { +_attribute_ram_code_ +static void suspend_enter_cb(u8 e, u8 *p, int n) { (void) e; (void) p; (void) n; if (rds.type) // rds: switch or counter rds_suspend(); +#ifdef GPIO_KEY2 + if (1) { // !ble_connected) { + /* TODO: if connection mode, gpio wakeup throws errors in sdk libs! + Work options: bls_pm_setSuspendMask(SUSPEND_ADV | DEEPSLEEP_RETENTION_ADV | SUSPEND_CONN); + No DEEPSLEEP_RETENTION_CONN */ + cpu_set_gpio_wakeup(GPIO_KEY2, BM_IS_SET(reg_gpio_in(GPIO_KEY2), GPIO_KEY2 & 0xff)? Level_Low : Level_High, 1); // pad wakeup deepsleep enable + bls_pm_setWakeupSource(PM_WAKEUP_PAD | PM_WAKEUP_TIMER); // gpio pad wakeup suspend/deepsleep + } else { + cpu_set_gpio_wakeup(GPIO_KEY2, Level_Low, 0); // pad wakeup suspend/deepsleep disable + } +#endif } #endif @@ -370,25 +423,89 @@ _attribute_ram_code_ void check_battery(void) { measured_data.battery_level = get_battery_level(measured_data.battery_mv); } -#if DEVICE_TYPE == DEVICE_LYWSD03MMC +#if (DEVICE_TYPE == DEVICE_LYWSD03MMC) || (DEVICE_TYPE == DEVICE_MJWSD05MMC) +#if DEVICE_TYPE == DEVICE_MJWSD05MMC +extern unsigned char *_icload_size_div_16_; +extern unsigned char *_bin_size_; + +#define MI_OTA2_FADDR 0x40000 // Big OTA2 +// Current OTA header: +static const uint32_t head_id[4] = { + 0x00008026, // asm("tj __reset") + 0x025d0000, // id OTA + 0x544c4e4b, // id "bootable" = "KNLT" + (uint32_t)(&_icload_size_div_16_ ) + 0x00880000 }; +/* Reformat Big OTA to Low OTA */ +void test_first_ota(void) { + // find the real FW flash address + uint32_t buf_blk[64], id, size, faddrw = 0x20000, faddrr = MI_OTA2_FADDR; + flash_unlock(FLASH_TYPE_GD); + flash_read_page(faddrr, 0x20, (unsigned char *) &buf_blk); + if(buf_blk[0] == MEMO_SEC_ID) + return; + if(memcmp(&buf_blk, &head_id, sizeof(head_id)) == 0) { + // calculate size OTA + size = (uint32_t)(&_bin_size_); + size += 15; + size &= ~15; + size += 4; + if(buf_blk[6] == size) { // OTA bin size +// bls_ota_clearNewFwDataArea(); + flash_erase_sector(faddrw); // 45 ms, 4 mA + flash_read_page(faddrr, sizeof(buf_blk), (unsigned char *) &buf_blk); + buf_blk[2] &= 0xffffffff; // clear id "bootable" + faddrr += sizeof(buf_blk); + flash_write_page(faddrw, sizeof(buf_blk), (unsigned char *) &buf_blk); + size += faddrw; + faddrw += sizeof(buf_blk); + while(faddrw < size) { + if((faddrw & (FLASH_SECTOR_SIZE - 1)) == 0) + flash_erase_sector(faddrw); // 45 ms, 4 mA + // rd-wr 4kB - 20 ms, 4 mA + flash_read_page(faddrr, sizeof(buf_blk), (unsigned char *) &buf_blk); + faddrr += sizeof(buf_blk); + flash_write_page(faddrw, sizeof(buf_blk), (unsigned char *) &buf_blk); + faddrw += sizeof(buf_blk); + } + // set id "bootable" to new segment + id = head_id[2]; // = "KNLT" + flash_write_page(0x20008, sizeof(id), (unsigned char *) &id); + // clear the "bootable" identifier on the current OTA segment + id = 0; + flash_write_page(MI_OTA2_FADDR + 8, 1, (unsigned char *) &id); + //flash_erase_sector(CFG_ADR_BIND); // Pair & Security info + while(1) + start_reboot(); + } + } +} +#endif /* * Read HW version - * Flash: + * Flash LYWSD03MMC: * 00055000: 42 31 2E 34 46 31 2E 30 2D 43 46 4D 4B 2D 4C 42 B1.4F1.0-CFMK-LB * 00055010: 2D 5A 43 58 54 4A 2D 2D FF FF FF FF FF FF FF FF -ZCXTJ-- + * Flash MJWSD05MMC: + * 0007D000: 56 32 2E 33 46 32 2E 30 2D 43 46 4D 4B 2D 4C 42 V2.3F2.0-CFMK-LB + * 0007D010: 2D 54 4D 44 5A 2D 2D 2D FF FF FF FF FF FF FF FF -TMDZ---   */ uint32_t get_mi_hw_version(void) { uint32_t hw; - flash_read_page(0x55000, sizeof(hw), (unsigned char *) &hw); - if ((hw & 0xf0fff0ff) != 0x302E3042) { - if (flash_read_cfg(&hw, EEP_ID_HWV, sizeof(hw)) != sizeof(hw)) - hw = 0; - else if ((hw & 0xf0fff0ff) != 0x302E3042) + flash_read_page(MI_HW_VER_FADDR, sizeof(hw), (unsigned char *) &hw); +#if (DEVICE_TYPE == DEVICE_MJWSD05MMC) + if ((hw & 0xf0fff0ff) != 0x302E3056) +#else + if ((hw & 0xf0fff0ff) != 0x302E3042) +#endif + { +// if (flash_read_cfg(&hw, EEP_ID_HWV, sizeof(hw)) != sizeof(hw)) +// hw = 0; +// else if ((hw & 0xf0fff0ff) != 0x302E3042) hw = 0; } return hw; } -#endif // DEVICE_TYPE == DEVICE_LYWSD03MMC +#endif // DEVICE_TYPE == DEVICE_LYWSD03MMC / DEVICE_TYPE == DEVICE_MJWSD05MMC #if USE_SECURITY_BEACON void bindkey_init(void) { @@ -426,15 +543,20 @@ void user_init_normal(void) {//this will get executed one time after power up unsigned int old_ver; adc_power_on_sar_adc(0); // - 0.4 mA lpc_power_down(); + blc_ll_initBasicMCU(); //must if (get_battery_mv() < MIN_VBAT_MV) { // 2.2V + init_sensor(); sensor_go_sleep(); // SHTC3 go SLEEP cpu_sleep_wakeup(DEEPSLEEP_MODE, PM_WAKEUP_TIMER, clock_time() + 120 * CLOCK_16M_SYS_TIMER_CLK_1S); // go deep-sleep 2 minutes } random_generator_init(); //must -#if DEVICE_TYPE == DEVICE_LYWSD03MMC +#if (DEVICE_TYPE == DEVICE_MJWSD05MMC) + test_first_ota(); // Correct FW OTA address? Reformat Big OTA to Low OTA +#endif // (DEVICE_TYPE == DEVICE_MJWSD05MMC) +#if (DEVICE_TYPE == DEVICE_LYWSD03MMC) uint32_t hw_ver = get_mi_hw_version(); -#endif +#endif // (DEVICE_TYPE == DEVICE_LYWSD03MMC) || (DEVICE_TYPE == DEVICE_MJWSD05MMC) // Read config if(flash_read_cfg(&old_ver, EEP_ID_VER, sizeof(old_ver)) != sizeof(old_ver)) old_ver = 0; @@ -477,7 +599,7 @@ void user_init_normal(void) {//this will get executed one time after power up #if USE_TRIGGER_OUT memcpy(&trg, &def_trg, FEEP_SAVE_SIZE_TRG); #endif -#if DEVICE_TYPE == DEVICE_LYWSD03MMC +#if (DEVICE_TYPE == DEVICE_LYWSD03MMC) if (hw_ver) flash_write_cfg(&hw_ver, EEP_ID_HWV, sizeof(hw_ver)); #endif @@ -485,13 +607,23 @@ void user_init_normal(void) {//this will get executed one time after power up #if USE_WK_RDS_COUNTER rds_init(); #endif -#if BLE_EXT_ADV +#if (DEVICE_TYPE == DEVICE_MJWSD05MMC) || (USE_RTC) || (BLE_EXT_ADV) || (defined(SHOW_REBOOT_SCREEN) && SHOW_REBOOT_SCREEN) if(analog_read(DEEP_ANA_REG0) != 0x55) { +#if BLE_EXT_ADV cfg.flg2.longrange = 0; +#endif // BLE_EXT_ADV analog_write(DEEP_ANA_REG0, 0x55); +#if (defined(SHOW_REBOOT_SCREEN) && SHOW_REBOOT_SCREEN) || (USE_RTC) +#if (defined(SHOW_REBOOT_SCREEN) && SHOW_REBOOT_SCREEN) + init_lcd(); + show_reboot_screen(); +#endif // SHOW_REBOOT_SCREEN + // RTC wakes up after powering on > 1 second. + cpu_sleep_wakeup(DEEPSLEEP_MODE, PM_WAKEUP_TIMER, + clock_time() + 1500*CLOCK_16M_SYS_TIMER_CLK_1MS); // go deep-sleep 1.5 sec +#endif // SHOW_REBOOT_SCREEN || (USE_RTC) +#endif // (DEVICE_TYPE == DEVICE_MJWSD05MMC) || (USE_RTC) || (BLE_EXT_ADV) || SHOW_REBOOT_SCREEN } -#endif - test_config(); memcpy(&ext, &def_ext, sizeof(ext)); init_ble(); @@ -502,6 +634,9 @@ void user_init_normal(void) {//this will get executed one time after power up init_sensor(); #if USE_FLASH_MEMO memo_init(); +#endif +#if USE_RTC + init_rtc(); #endif init_lcd(); set_hw_version(); @@ -517,11 +652,11 @@ void user_init_normal(void) {//this will get executed one time after power up check_battery(); WakeupLowPowerCb(0); lcd(); -#if (DEVICE_TYPE == DEVICE_LYWSD03MMC) || (DEVICE_TYPE == DEVICE_CGDK2) +#if (DEVICE_TYPE == DEVICE_LYWSD03MMC) || (DEVICE_TYPE == DEVICE_CGDK2) || (DEVICE_TYPE == DEVICE_MJWSD05MMC) update_lcd(); #endif if (!next_start) { // first start? - if (!cfg.hw_cfg.shtc3) // sensor SHT4x ? + if(!cfg.hw_cfg.shtc3) cfg.flg.lp_measures = 1; flash_write_cfg(&cfg, EEP_ID_CFG, sizeof(cfg)); } @@ -530,13 +665,16 @@ void user_init_normal(void) {//this will get executed one time after power up } //------------------ user_init_deepRetn ------------------- -_attribute_ram_code_ void user_init_deepRetn(void) {//after sleep this will get executed +_attribute_ram_code_ +void user_init_deepRetn(void) {//after sleep this will get executed blc_ll_initBasicMCU(); rf_set_power_level_index(cfg.rf_tx_power); blc_ll_recoverDeepRetention(); bls_ota_registerStartCmdCb(app_enter_ota_mode); } +#if(DEVICE_TYPE != DEVICE_MJWSD05MMC) + _attribute_ram_code_ uint8_t is_comfort(int16_t t, uint16_t h) { uint8_t ret = SMILE_SAD; if (t >= cmf.t[0] && t <= cmf.t[1] && h >= cmf.h[0] && h <= cmf.h[1]) @@ -546,13 +684,8 @@ _attribute_ram_code_ uint8_t is_comfort(int16_t t, uint16_t h) { _attribute_ram_code_ __attribute__((optimize("-Os"))) void lcd(void) { bool set_small_number_and_bat = true; - while (chow_tick_sec && clock_time() - chow_tick_clk - > CLOCK_16M_SYS_TIMER_CLK_1S) { - chow_tick_clk += CLOCK_16M_SYS_TIMER_CLK_1S; - chow_tick_sec--; - } show_stage++; - if (chow_tick_sec && (show_stage & 2)) { // show ext data + if (chow_tick_sec >= utc_time_sec && (show_stage & 2)) { // show ext data if (show_stage & 1) { // stage blinking or show battery or clock if (cfg.flg.show_batt_enabled #if (DEVICE_TYPE == DEVICE_CGG1) || (DEVICE_TYPE == DEVICE_CGDK2) @@ -678,21 +811,60 @@ _attribute_ram_code_ __attribute__((optimize("-Os"))) void lcd(void) { } show_ble_symbol(ble_connected); } +#endif // (DEVICE_TYPE != DEVICE_MJWSD05MMC) + +#ifdef GPIO_KEY2 +void set_default_cfg(void) { + memcpy(&cfg, &def_cfg, sizeof(cfg)); + if(!cfg.hw_cfg.shtc3) + cfg.flg.lp_measures = 1; + flash_write_cfg(&cfg, EEP_ID_CFG, sizeof(cfg)); +#if (defined(SHOW_REBOOT_SCREEN) && SHOW_REBOOT_SCREEN) + show_reboot_screen(); +#endif + cpu_sleep_wakeup(DEEPSLEEP_MODE, PM_WAKEUP_TIMER, + clock_time() + 2*CLOCK_16M_SYS_TIMER_CLK_1S); // go deep-sleep 2 sec + while(1) + start_reboot(); +} +#endif // GPIO_KEY2 +//============================================= //----------------------- main_loop() -_attribute_ram_code_ void main_loop(void) { +_attribute_ram_code_ +void main_loop(void) { blt_sdk_main_loop(); while (clock_time() - utc_time_sec_tick > utc_time_tick_step) { utc_time_sec_tick += utc_time_tick_step; utc_time_sec++; // + 1 sec +#if USE_RTC + if(++rtc.seconds >= 60) { + rtc.seconds = 0; + if(++rtc.minutes >= 60) { + rtc.minutes = 0; + rtc_sync_utime = utc_time_sec; + } +#if (DEVICE_TYPE == DEVICE_MJWSD05MMC) + lcd_update = 1; +#endif + } +#endif } // instability workaround bls_pm_setAppWakeupLowPower() if(timer_measure_cb && clock_time() - timer_measure_cb > SENSOR_MEASURING_TIMEOUT) WakeupLowPowerCb(0); if (ota_is_working) { - bls_pm_setSuspendMask (SUSPEND_ADV | SUSPEND_CONN); // SUSPEND_DISABLE - if ((ble_connected&2)==0) - bls_pm_setManualLatency(0); +#if USE_EXT_OTA + if(ota_is_working == 0xff) { + bls_pm_setManualLatency(3); + clear_ota_area(); + } else +#endif + { + if ((ble_connected & 2)==0) + bls_pm_setManualLatency(0); + } + bls_pm_setSuspendMask (SUSPEND_ADV | SUSPEND_CONN); } else { #if USE_WK_RDS_COUNTER if (rds.type) // rds: switch or counter @@ -713,12 +885,13 @@ _attribute_ram_code_ void main_loop(void) { WakeupLowPowerCb(0); #else if (cfg.flg.lp_measures) { + // sensor SHT4x or cfg.flg.lp_measures if (cfg.hw_cfg.shtc3) { start_measure_sensor_low_power(); check_battery(); WakeupLowPowerCb(0); - } else { // sensor SHT4x - // no callback, data read sensor is next cycle + } else { + // if sensor SHT4x - > no callback, data read sensor is next cycle WakeupLowPowerCb(0); check_battery(); start_measure_sensor_deep_sleep(); @@ -736,7 +909,9 @@ _attribute_ram_code_ void main_loop(void) { } #endif } else { + bls_pm_setAppWakeupLowPower(0, 0); // clear callback if ((blc_ll_getCurrentState() & BLS_LINK_STATE_CONN) && blc_ll_getTxFifoNumber() < 9) { + // connect, TxFifo ready if (end_measure) { end_measure = 0; if (RxTxValueInCCC) { @@ -746,6 +921,7 @@ _attribute_ram_code_ void main_loop(void) { ble_send_measures(); } if (lcd_flg.b.new_update) { + // LCD for send notify lcd_flg.b.new_update = 0; ble_send_lcd(); } @@ -766,24 +942,74 @@ _attribute_ram_code_ void main_loop(void) { #endif } } +#if USE_RTC + else if(rtc_sync_utime) { + rtc_sync_utime = 0; + utc_time_sec = rtc_get_utime(); + } +#endif // USE_RTC +#ifdef GPIO_KEY2 + if(!get_key2_pressed()) { + if(!trg.flg.key2pressed) { + // key2 on + trg.flg.key2pressed = 1; + key_pressed_tik = new; + key_pressed_tiks = new; + set_adv_con_time(0); +#if (DEVICE_TYPE == DEVICE_MJWSD05MMC) + lcd_update = 1; +#endif + } + else { + if(new - key_pressed_tik > 1750*CLOCK_16M_SYS_TIMER_CLK_1MS) { + key_pressed_tik = new; + if(++cfg.flg2.screen_type > SCR_TYPE_EXT) + cfg.flg2.screen_type = SCR_TYPE_TIME; +#if (DEVICE_TYPE == DEVICE_MJWSD05MMC) + lcd_update = 1; +#endif + } + if(new - key_pressed_tiks > 5*CLOCK_16M_SYS_TIMER_CLK_1S) { + if((reg_gpio_in(GPIO_KEY1) & (GPIO_KEY1 & 0xff))==0) + set_default_cfg(); + } + } + } + else { + // key2 off + trg.flg.key2pressed = 0; + key_pressed_tik = new; + key_pressed_tiks = new; + if(rest_adv_int_tad < -80) { + set_adv_con_time(1); +#if (DEVICE_TYPE == DEVICE_MJWSD05MMC) + lcd_update = 1; +#endif + } + } +#endif // GPIO_KEY2 if (new - tim_measure >= measurement_step_time) { tim_measure = new; start_measure = 1; } #if ((DEVICE_TYPE == DEVICE_MHO_C401) || (DEVICE_TYPE == DEVICE_MHO_C401N) || (DEVICE_TYPE == DEVICE_CGG1)) - else - if ((!stage_lcd) && (new - tim_last_chow >= min_step_time_update_lcd)) { + else if ((!stage_lcd) && (new - tim_last_chow >= min_step_time_update_lcd)) { +#elif (DEVICE_TYPE == DEVICE_MJWSD05MMC) + if (lcd_update) { + lcd_update = 0; #else if (new - tim_last_chow >= min_step_time_update_lcd) { #endif - if (!lcd_flg.b.ext_data) { + if (!lcd_flg.b.ext_data) { // Not LCD show external data + // set flag LCD for send notify lcd_flg.b.new_update = lcd_flg.b.notify_on; lcd(); } update_lcd(); +#if (DEVICE_TYPE != DEVICE_MJWSD05MMC) tim_last_chow = new; +#endif } - bls_pm_setAppWakeupLowPower(0, 0); // clear callback } } #if ((DEVICE_TYPE == DEVICE_MHO_C401) || (DEVICE_TYPE == DEVICE_MHO_C401N) || (DEVICE_TYPE == DEVICE_CGG1)) diff --git a/src/app.h b/src/app.h index 578a768b..d9d2a652 100644 --- a/src/app.h +++ b/src/app.h @@ -10,14 +10,15 @@ enum { HW_VER_LYWSD03MMC_B14 = 0, - HW_VER_MHO_C401, - HW_VER_CGG1, - HW_VER_LYWSD03MMC_B19, - HW_VER_LYWSD03MMC_B16, - HW_VER_LYWSD03MMC_B17, - HW_VER_CGDK2, - HW_VER_CGG1_2022, - HW_VER_MHO_C401_2022, + HW_VER_MHO_C401, //1 + HW_VER_CGG1, //2 + HW_VER_LYWSD03MMC_B19, //3 + HW_VER_LYWSD03MMC_B16, //4 + HW_VER_LYWSD03MMC_B17, //5 + HW_VER_CGDK2, //6 + HW_VER_CGG1_2022, //7 + HW_VER_MHO_C401_2022, //8 + HW_VER_MJWSD05MMC, //9 HW_VER_UNKNOWN = 15 } HW_VERSION_ID; @@ -41,15 +42,27 @@ enum { } ADV_TYPE_ENUM; #define ADV_TYPE_DEFAULT ADV_TYPE_PVVX +#if (DEVICE_TYPE != DEVICE_MJWSD05MMC) #define MASK_FLG2_REBOOT 0xe0 #define MASK_FLG2_EXT_ADV 0xc0 +#else +#define MASK_FLG2_REBOOT 0x60 +#endif typedef struct __attribute__((packed)) _cfg_t { struct __attribute__((packed)) { uint8_t advertising_type : 2; // 0 - atc1441, 1 - Custom (pvvx), 2 - Mi, 3 - HA_BLE uint8_t comfort_smiley : 1; +#if (DEVICE_TYPE == DEVICE_MJWSD05MMC) + uint8_t x100 : 1; +#else uint8_t blinking_time_smile : 1; //(USE_CLOCK = 0 - smile, =1 time) +#endif uint8_t temp_F_or_C : 1; +#if (DEVICE_TYPE == DEVICE_MJWSD05MMC) + uint8_t time_am_pm : 1; +#else uint8_t show_batt_enabled : 1; +#endif uint8_t tx_measures : 1; // Send all measurements in connected mode uint8_t lp_measures : 1; // Sensor measurements in "Low Power" mode } flg; @@ -77,10 +90,29 @@ typedef struct __attribute__((packed)) _cfg_t { * ------------------- * CGG1: * 0 = " " off, - * &1 = "---" Line */ + * &1 = "---" Line + * ------------------- + * MJWSD05MMC + * screen_type: + * 0 = Time + * 1 = Temperature + * 2 = Humidity + * 3 = Battery % + * 4 = Battery V + * 5 = External number & symbols + * */ +#if (DEVICE_TYPE == DEVICE_MJWSD05MMC) + uint8_t screen_type : 3; +// uint8_t reserved1 : 1; +#else uint8_t smiley : 3; // 0..7 +#endif uint8_t adv_crypto : 1; // advertising uses crypto beacon +#if (DEVICE_TYPE == DEVICE_MJWSD05MMC) + uint8_t reserved1 : 1; +#else uint8_t adv_flags : 1; // advertising add flags +#endif uint8_t bt5phy : 1; // support BT5.0 All PHY uint8_t longrange : 1; // advertising in LongRange mode (сбрасывается после отключения питания) uint8_t reserved : 1; @@ -91,7 +123,11 @@ typedef struct __attribute__((packed)) _cfg_t { uint8_t measure_interval; // measure_interval = advertising_interval * x (2..25) uint8_t rf_tx_power; // RF_POWER_N25p18dBm .. RF_POWER_P3p01dBm (130..191) uint8_t connect_latency; // +1 x0.02 sec ( = connection interval), Tmin = 1*20 = 20 ms, Tmax = 256 * 20 = 5120 ms +#if (DEVICE_TYPE == DEVICE_MJWSD05MMC) + uint8_t rezerved; +#else uint8_t min_step_time_update_lcd; // x0.05 sec, 0.5..12.75 sec (10..255) +#endif struct __attribute__((packed)) { uint8_t hwver : 4; // 0 - LYWSD03MMC B1.4, 1 - MHO-C401, 2 - CGG1-M, 3 - LYWSD03MMC B1.9, 4 - LYWSD03MMC B1.6, 5 - LYWSD03MMC B1.7, 6 - CGDK2, 7 - CGG1-M-2022, 8 - MHO-C401-2022 uint8_t reserved : 3; // reserved @@ -103,6 +139,32 @@ extern cfg_t cfg; extern const cfg_t def_cfg; /* Warning: MHO-C401 Symbols: "%", "°Г", "( )", "." have one control bit! */ typedef struct __attribute__((packed)) _external_data_t { +#if(DEVICE_TYPE == DEVICE_MJWSD05MMC) + int32_t number; // -999.50..19995.50, x0.01 + uint16_t vtime_sec; // validity time, in sec + struct __attribute__((packed)) { + /* 0 = " " off, + * 1 = " ^-^ " + * 2 = " -^- " + * 3 = " ooo " + * 4 = "( )" + * 5 = "(^-^)" happy + * 6 = "(-^-)" sad + * 7 = "(ooo)" */ + uint8_t smiley : 3; + uint8_t battery : 1; + /* 0x00 = " " + * 0x01 = "°г" + * 0x02 = " -" + * 0x03 = "°c" + * 0x04 = " |" + * 0x05 = "°Г" + * 0x06 = " г" + * 0x07 = "°F" + * 0x08 = "%" */ + uint8_t temp_symbol : 4; + } flg; +#else int16_t big_number; // -995..19995, x0.1 int16_t small_number; // -9..99, x1 uint16_t vtime_sec; // validity time, in sec @@ -128,6 +190,7 @@ typedef struct __attribute__((packed)) _external_data_t { * 7 = "°E", shr 0xe0 */ uint8_t temp_symbol : 3; } flg; +#endif } external_data_t, * pexternal_data_t; extern external_data_t ext; extern uint32_t chow_tick_clk; // count chow validity time, in clock @@ -137,6 +200,7 @@ extern uint32_t utc_time_sec; // clock in sec (= 0 1970-01-01 00:00:00) #if USE_TIME_ADJUST extern uint32_t utc_time_tick_step; // adjust time clock (in 1/16 us for 1 sec) #endif +extern int32_t rest_adv_int_tad; // timer event restore adv.intervals #if BLE_SECURITY_ENABLE extern uint32_t pincode; // pincode (if = 0 - not used) @@ -165,6 +229,17 @@ extern volatile uint8_t tx_measures; // connect notify send measure flag extern volatile uint8_t start_measure; // start measure all extern volatile uint8_t wrk_measure; extern volatile uint8_t end_measure; +#if (DEVICE_TYPE == DEVICE_MJWSD05MMC) +extern volatile uint8_t lcd_update; +#endif + +#if (DEVICE_TYPE == DEVICE_MJWSD05MMC) +#define MI_HW_VER_FADDR 0x7D000 // Mi HW version +#else +#define MI_HW_VER_FADDR 0x55000 // Mi HW version +#endif + + extern uint32_t tim_measure; // timer measurements >= 10 sec typedef union _lcd_flg_t { @@ -196,7 +271,10 @@ extern uint32_t adv_interval; extern uint32_t connection_timeout; extern uint32_t measurement_step_time; extern uint32_t tim_last_chow; // timer show lcd >= 1.5 sec + +#if DEVICE_TYPE != DEVICE_MJWSD05MMC extern uint32_t min_step_time_update_lcd; // = cfg.min_step_time_update_lcd * (50 * CLOCK_16M_SYS_TIMER_CLK_1MS) +#endif void ev_adv_timeout(u8 e, u8 *p, int n); void test_config(void); @@ -205,5 +283,6 @@ void reset_cache(void); void blc_newMacAddress(int flash_addr, u8 *mac_pub, u8 *mac_rand); void SwapMacAddress(u8 *mac_out, u8 *mac_in); +void flash_erase_mac_sector(u32 faddr); #endif /* MAIN_H_ */ diff --git a/src/app_att.c b/src/app_att.c index 2b838807..986f5f04 100644 --- a/src/app_att.c +++ b/src/app_att.c @@ -85,7 +85,13 @@ static const u8 my_ManCharVal[5] = { U16_LO(CHARACTERISTIC_UUID_MANUFACTURER_NAME), U16_HI(CHARACTERISTIC_UUID_MANUFACTURER_NAME) }; static const u8 my_FirmStr[] = {"github.com/pvvx"}; -#if DEVICE_TYPE == DEVICE_MHO_C401 +#if DEVICE_TYPE == DEVICE_MJWSD05MMC +static const u8 my_ModelStr[] = {"MJWSD05MMC"}; +static const u8 my_SerialStr[] = {"F2.0-CFMK-LB-TMDZ---"}; +static const u8 my_HardStr[] = {"2022"}; // V2.3 +static const u8 my_SoftStr[] = {'V','0'+(VERSION>>4),'.','0'+(VERSION&0x0f)}; // "0026" +static const u8 my_ManStr[] = {"miaomiaoce.com"}; +#elif DEVICE_TYPE == DEVICE_MHO_C401 static const u8 my_ModelStr[] = {"MHO-C401"}; static const u8 my_SerialStr[] = {"0000-0000-0000-0001"}; // "0000-0000-0000-00000" static const u8 my_HardStr[] = {"2020"}; @@ -129,7 +135,7 @@ static const u8 my_ManStr[] = {"Qingping Technology (Beijing) Co., Ltd."}; #ifdef CHG_CONN_PARAM RAM gap_periConnectParams_t my_periConnParameters = {DEF_CON_INERVAL, DEF_CON_INERVAL, 0, DEF_CON_INERVAL*250}; #else -static const gap_periConnectParams_t def_periConnParameters = {CON_INERVAL_LAT, CON_INERVAL_LAT*2, 0, CON_INERVAL_LAT*125}; +static const gap_periConnectParams_t def_periConnParameters = {DEF_CON_INERVAL, DEF_CON_INERVAL, DEF_CONNECT_LATENCY , DEF_CON_INERVAL*(DEF_CONNECT_LATENCY)*3}; RAM gap_periConnectParams_t my_periConnParameters = {DEF_CON_INERVAL, DEF_CON_INERVAL+3, 0, DEF_CON_INERVAL*125}; #endif @@ -159,7 +165,7 @@ static const u8 my_OtaName[] = {'O', 'T', 'A'}; // RxTx Char static const u16 my_RxTxUUID = 0x1f1f; static const u16 my_RxTx_ServiceUUID = 0x1f10; -RAM u8 my_RxTx_Data[16]; +RAM u8 my_RxTx_Data[sizeof(cfg) + 2]; RAM u16 RxTxValueInCCC; //0x95FE diff --git a/src/app_config.h b/src/app_config.h index 259f6465..79d00a2c 100644 --- a/src/app_config.h +++ b/src/app_config.h @@ -11,11 +11,14 @@ extern "C" { #define DEVICE_MHO_C401 0x0387 // E-Ink display MHO-C401 2020 #define DEVICE_MHO_C401N 0x0008 // E-Ink display MHO-C401 2022 #define DEVICE_CGG1 0x0B48 // E-Ink display CGG1-M "Qingping Temp & RH Monitor" +#ifndef DEVICE_CGG1_ver #define DEVICE_CGG1_ver 2022 // =2022 - CGG1-M version 2022, or = 0 - CGG1-M version 2020,2021 +#endif #define DEVICE_CGDK2 0x066F // LCD display "Qingping Temp & RH Monitor Lite" +#define DEVICE_MJWSD05MMC 0x2832 // LCD display MJWSD05MMC #ifndef DEVICE_TYPE -#define DEVICE_TYPE DEVICE_LYWSD03MMC // DEVICE_LYWSD03MMC or DEVICE_MHO_C401 or DEVICE_CGG1 (+ set DEVICE_CGG1_ver) or DEVICE_CGDK2 or DEVICE_MHO_C401N +#define DEVICE_TYPE DEVICE_LYWSD03MMC // DEVICE_LYWSD03MMC or DEVICE_MHO_C401 or DEVICE_CGG1 (+ set DEVICE_CGG1_ver) or DEVICE_CGDK2 or DEVICE_MHO_C401N or DEVICE_MJWSD05MMC #endif #define BLE_SECURITY_ENABLE 1 // = 1 support pin-code @@ -26,11 +29,14 @@ extern "C" { #define USE_FLASH_MEMO 1 // = 1 flash logger enable #define USE_TRIGGER_OUT 1 // = 1 use trigger out (GPIO_PA5) #define USE_WK_RDS_COUNTER USE_TRIGGER_OUT // = 1 wake up when the reed switch is triggered + pulse counter +#define USE_RTC 0 // = 1 RTC enabled #define USE_SECURITY_BEACON 1 // = 1 support encryption beacon (bindkey) #define USE_HA_BLE_BEACON 1 // = 1 https://github.com/custom-components/ble_monitor/issues/548 #define USE_MIHOME_BEACON 1 // = 1 Compatible with MiHome beacon +#define USE_EXT_OTA 0 // = 1 Compatible BigOTA + #define USE_DEVICE_INFO_CHR_UUID 1 // = 1 enable Device Information Characteristics /* Special DIY version - Voltage Logger: @@ -67,6 +73,8 @@ extern "C" { #define I2C_SCL GPIO_PC2 #define I2C_SDA GPIO_PC3 #define I2C_GROUP I2C_GPIO_GROUP_C2C3 +#define PULL_WAKEUP_SRC_PC2 PM_PIN_PULLUP_10K +#define PULL_WAKEUP_SRC_PC3 PM_PIN_PULLUP_10K #define EPD_SHD GPIO_PC4 // should be high #define PULL_WAKEUP_SRC_PC4 PM_PIN_PULLUP_10K @@ -159,6 +167,8 @@ extern "C" { #define I2C_SCL GPIO_PC2 #define I2C_SDA GPIO_PC3 #define I2C_GROUP I2C_GPIO_GROUP_C2C3 +#define PULL_WAKEUP_SRC_PC2 PM_PIN_PULLUP_10K +#define PULL_WAKEUP_SRC_PC3 PM_PIN_PULLUP_10K #define EPD_RST2 GPIO_PB7 // should be high #define PULL_WAKEUP_SRC_PB7 PM_PIN_PULLUP_1M @@ -258,6 +268,8 @@ extern "C" { #define I2C_SCL GPIO_PC0 #define I2C_SDA GPIO_PC1 #define I2C_GROUP I2C_GPIO_GROUP_C0C1 +#define PULL_WAKEUP_SRC_PC0 PM_PIN_PULLUP_10K +#define PULL_WAKEUP_SRC_PC1 PM_PIN_PULLUP_10K #define EPD_SHD GPIO_PA1 // should be high #define PULL_WAKEUP_SRC_PA1 PM_PIN_PULLUP_10K @@ -342,7 +354,16 @@ extern "C" { #endif #elif DEVICE_TYPE == DEVICE_LYWSD03MMC - +/* Original Flash markup: + 0x00000 Old Firmware bin + 0x20000 OTA New bin storage Area + 0x55000 SerialStr: "B1.5F2.0-CFMK-LB-JHBD---" + 0x74000 Pair & Security info (CFG_ADR_BIND)? + 0x76000 MAC address (CFG_ADR_MAC) + 0x77000 Customize freq_offset adjust cap value (CUST_CAP_INFO_ADDR) + 0x78000 Mijia key-code + 0x80000 End Flash (FLASH_SIZE) + */ // TLSR8251F512ET24 // GPIO_PA5 - DM, free, pcb mark "reset" (TRG) // GPIO_PA6 - DP, free, pcb mark "P8" (RDS) @@ -365,6 +386,8 @@ extern "C" { #define I2C_SCL GPIO_PC2 #define I2C_SDA GPIO_PC3 #define I2C_GROUP I2C_GPIO_GROUP_C2C3 +#define PULL_WAKEUP_SRC_PC2 PM_PIN_PULLUP_10K +#define PULL_WAKEUP_SRC_PC3 PM_PIN_PULLUP_10K #if USE_TRIGGER_OUT @@ -436,6 +459,8 @@ extern "C" { #define I2C_SCL GPIO_PC0 #define I2C_SDA GPIO_PC1 #define I2C_GROUP I2C_GPIO_GROUP_C0C1 +#define PULL_WAKEUP_SRC_PC0 PM_PIN_PULLUP_10K +#define PULL_WAKEUP_SRC_PC1 PM_PIN_PULLUP_10K // PC4 - key #define GPIO_KEY GPIO_PC4 @@ -486,6 +511,98 @@ extern "C" { #define PB6_FUNC AS_GPIO #endif +#elif DEVICE_TYPE == DEVICE_MJWSD05MMC +/* Original Flash markup: + 0x00000 Old Firmware bin + 0x40000 OTA New bin storage Area + 0x66000 Logger, saving measurements ? + 0x74000 Pair & Security info (CFG_ADR_BIND) + 0x76000 MAC address (CFG_ADR_MAC) + 0x77000 Customize freq_offset adjust cap value (CUST_CAP_INFO_ADDR) + 0x78000 Mijia key-code + 0x7D000 Ver+SerialStr: "V2.3F2.0-CFMK-LB-TMDZ---" + 0x7E000 ? 5A 07 00 02 CE 0C 5A 07 00 02 CB 0C 5A 07 00 02 CD 0C + 0x80000 End Flash (FLASH_SIZE) + */ +// ### TLSR8250F512ET32 +// GPIO_PA0 - UART_RX +// GPIO_PA1 +// GPIO_PA7 - SWS + +// GPIO_PB1 +// GPIO_PB4 +// GPIO_PB5 - R5 -> +BAT +// GPIO_PB6 - key1 +// GPIO_PB7 - R10 -> /INT AT85163T + +// GPIO_PC0 - SDA, used I2C +// GPIO_PC1 - SCL, used I2C +// GPIO_PC2 +// GPIO_PC3 +// GPIO_PC4 - key2 + +// GPIO_PD2 +// GPIO_PD3 +// GPIO_PD4 +// GPIO_PD7 - UART_TX + +// scan i2c: 0x7c, 0x88, 0xa2 + +#define SHL_ADC_VBAT 6 // "B5P" in adc.h +#define GPIO_VBAT GPIO_PB5 // R5 -> +Vbat +//#define PULL_WAKEUP_SRC_PB5 PM_PIN_PULLUP_1M +//#define PB5_INPUT_ENABLE 1 +//#define PB5_DATA_OUT 1 +//#define PB5_OUTPUT_ENABLE 1 + +#define I2C_SCL GPIO_PC1 +#define I2C_SDA GPIO_PC0 +#define I2C_GROUP I2C_GPIO_GROUP_C0C1 +#define PULL_WAKEUP_SRC_PC0 PM_PIN_PULLUP_10K +#define PULL_WAKEUP_SRC_PC1 PM_PIN_PULLUP_10K + +#define PULL_WAKEUP_SRC_PD7 PM_PIN_PULLUP_1M // UART TX + +#define SHL_ADC_VBAT 6 // "B5P" in adc.h +#define GPIO_VBAT GPIO_PB5 // R5 -> +Vbat +//#define PULL_WAKEUP_SRC_PB5 PM_PIN_PULLUP_1M +//#define PB5_INPUT_ENABLE 1 +//#define PB5_DATA_OUT 1 +//#define PB5_OUTPUT_ENABLE 1 + +#undef USE_TIME_ADJUST +#define USE_TIME_ADJUST 0 // disabled -> used RTC + Quartz 32.768 kHz +#undef USE_RTC +#define USE_RTC 1 +#undef USE_EXT_OTA +#define USE_EXT_OTA 1 // = 1 Compatible BigOTA +#undef USE_TRIGGER_OUT +#define USE_TRIGGER_OUT 1 + +#define GPIO_TRG GPIO_PA0 // none +#define PA0_INPUT_ENABLE 1 +#define PA0_DATA_OUT 0 +#define PA0_OUTPUT_ENABLE 0 +#define PA0_FUNC AS_GPIO +#define PULL_WAKEUP_SRC_PA0 PM_PIN_PULLDOWN_100K + +#define GPIO_RDS GPIO_PC4 +#define PC4_INPUT_ENABLE 1 +#define PC4_DATA_OUT 0 +#define PC4_OUTPUT_ENABLE 0 +#define PC4_FUNC AS_GPIO +#define PULL_WAKEUP_SRC_PC4 PM_PIN_PULLDOWN_100K + +#define GPIO_KEY1 GPIO_PC4 +#define GPIO_KEY2 GPIO_PB6 +#define PB6_INPUT_ENABLE 1 +#define PB6_DATA_OUT 0 +#define PB6_OUTPUT_ENABLE 0 +#define PB6_FUNC AS_GPIO +#define PULL_WAKEUP_SRC_PB6 PM_PIN_PULLUP_10K + +#else // DEVICE_TYPE +#error ("DEVICE_TYPE = ?") #endif // DEVICE_TYPE == ? #if UART_PRINT_DEBUG_ENABLE @@ -536,7 +653,8 @@ enum{ #define BLE_HOST_SMP_ENABLE BLE_SECURITY_ENABLE -#define CHG_CONN_PARAM // test +//#define CHG_CONN_PARAM // test +#define DEV_NAME "ble_th" #include "vendor/common/default_config.h" diff --git a/src/battery.c b/src/battery.c index f1f34aaf..e778f646 100644 --- a/src/battery.c +++ b/src/battery.c @@ -74,7 +74,11 @@ _attribute_ram_code_ uint16_t get_adc_mv(uint32_t p_ain) { // ADC_InputPchTypeDe adc_power_on_sar_adc(0); // - 0.4 mA adc_average = (adc_sample[2] + adc_sample[3] + adc_sample[4] + adc_sample[5]) / 4; - return ((adc_average * 1175) >> 10); // adc_vref default: 1175 (mV) +#if DEVICE_TYPE == DEVICE_MJWSD05MMC + return (adc_average * 1686) >> 10; // adc_vref default: 1175 (mV) +#else + return (adc_average * 1175) >> 10; // adc_vref default: 1175 (mV) +#endif } // 2200..3100 mv - 0..100% diff --git a/src/ble.c b/src/ble.c index 1618930b..a9a474c8 100644 --- a/src/ble.c +++ b/src/ble.c @@ -23,6 +23,7 @@ #if USE_HA_BLE_BEACON #include "ha_ble_beacon.h" #endif +#include "stack/ble/service/ble_ll_ota.h" void bls_set_advertise_prepare(void *p); // add ll_adv.h @@ -60,22 +61,30 @@ RAM uint8_t ble_name[32] = { 11, 0x09, 'C', 'G', 'G', '_', '0', '0', '0', '0', '0', '0' }; #elif DEVICE_TYPE == DEVICE_CGDK2 'C', 'G', 'D', '_', '0', '0', '0', '0', '0', '0' }; +#elif DEVICE_TYPE == DEVICE_MJWSD05MMC + 'B', 'T', 'H', '_', '0', '0', '0', '0', '0', '0' }; #else 'A', 'T', 'C', '_', '0', '0', '0', '0', '0', '0' }; #endif RAM uint8_t mac_public[6], mac_random_static[6]; RAM adv_buf_t adv_buf; -uint8_t ota_is_working = 0; +RAM uint8_t ota_is_working = 0; // =1 ota enabled, = 0xff flag ext.ota void app_enter_ota_mode(void) { #if USE_NEW_OTA bls_ota_clearNewFwDataArea(); #endif - ota_is_working = 1; +#if USE_EXT_OTA + if(ota_is_working != 0xff) +#endif + ota_is_working = 1; ble_connected &= ~2; bls_pm_setManualLatency(0); - bls_ota_setTimeout(45 * 1000000); // set OTA timeout 45 seconds + bls_ota_setTimeout(16 * 1000000); // set OTA timeout 16 seconds +#if (defined(SHOW_OTA_SCREEN) && SHOW_OTA_SCREEN) + show_ota_screen(); +#endif } void ble_disconnect_callback(uint8_t e, uint8_t *p, int n) { @@ -94,24 +103,34 @@ void ble_disconnect_callback(uint8_t e, uint8_t *p, int n) { else tx_measures = 0; #if (BLE_EXT_ADV) +#if (DEVICE_TYPE == DEVICE_MJWSD05MMC) + set_adv_con_time(1); +#else + test_config(); if(ext_adv_init) { // patch: restart ext_adv after 1 second ll_ext_adv_t *pea = (ll_ext_adv_t *)&app_adv_set_param; blt_advExpectTime = clock_time() + CLOCK_16M_SYS_TIMER_CLK_1S; // set time next ext.adv pea->advInt_use = adv_interval; // restore next ext.adv. interval pea->extAdv_en = 1; + } else { + ev_adv_timeout(0,0,0); } -#endif +#endif // DEVICE_TYPE == DEVICE_MJWSD05MMC +#endif // BLE_EXT_ADV #ifdef LCD_CONN_SYMBOL show_connected_symbol(false); #else - tim_last_chow = clock_time() - min_step_time_update_lcd - (CLOCK_16M_SYS_TIMER_CLK_1S); +#if (DEVICE_TYPE == DEVICE_MJWSD05MMC) + lcd_update = 1; +#else // DEVICE_TYPE != DEVICE_MJWSD05MMC + tim_last_chow = clock_time() - min_step_time_update_lcd - (8*CLOCK_16M_SYS_TIMER_CLK_1MS); #endif +#endif // LCD_CONN_SYMBOL } void ble_connect_callback(uint8_t e, uint8_t *p, int n) { (void) e; (void) p; (void) n; - // bls_l2cap_setMinimalUpdateReqSendingTime_after_connCreate(1000); ble_connected = 1; if(cfg.connect_latency > DEF_CONNECT_LATENCY && measured_data.battery_mv < 2800) cfg.connect_latency = DEF_CONNECT_LATENCY; @@ -125,9 +144,16 @@ void ble_connect_callback(uint8_t e, uint8_t *p, int n) { #ifdef LCD_CONN_SYMBOL show_connected_symbol(true); #else - tim_last_chow = clock_time() - min_step_time_update_lcd - (CLOCK_16M_SYS_TIMER_CLK_1S); +#if (DEVICE_TYPE == DEVICE_MJWSD05MMC) + lcd_update = 1; +#else + tim_last_chow = clock_time() - min_step_time_update_lcd - (8*CLOCK_16M_SYS_TIMER_CLK_1MS); +#endif #endif -// bls_l2cap_setMinimalUpdateReqSendingTime_after_connCreate(2600); +#ifdef GPIO_KEY2 + rest_adv_int_tad = 0; +#endif + bls_l2cap_setMinimalUpdateReqSendingTime_after_connCreate(1000); } #ifdef CHG_CONN_PARAM @@ -154,12 +180,16 @@ int app_conn_param_update_response(u8 id, u16 result) { if (result == CONN_PARAM_UPDATE_ACCEPT) ble_connected |= 2; else if (result == CONN_PARAM_UPDATE_REJECT) { - bls_l2cap_requestConnParamUpdate(160, 200, 0, 2500); // (200 ms, 250 ms, 0, 2.5 s) + // TODO: необходимо подбирать другие параметры соединения если внешний адаптер не согласен или плюнуть и послать, + // что является лучшим решением для OTA, т.к. использовать плохие и сверх медленные адаптеры типа ESP32 для OTA нет смысла. + bls_l2cap_requestConnParamUpdate(my_periConnParameters.intervalMin, my_periConnParameters.intervalMax, my_periConnParameters.latency, my_periConnParameters.timeout); + } return 0; } -extern u32 blt_ota_start_tick; +//extern u32 blt_ota_start_tick; // in "stack/ble/service/ble_ll_ota.h" + int otaWritePre(void * p) { blt_ota_start_tick = clock_time() | 1; return otaWrite(p); @@ -186,6 +216,15 @@ int app_advertise_prepare_handler(rf_packet_adv_t * p) { if (++adv_buf.call_count > adv_buf.update_count) // refresh adv_buf.data ? set_adv_data(); } +#ifdef GPIO_KEY2 + if(rest_adv_int_tad) { +#if (DEVICE_TYPE == DEVICE_MJWSD05MMC) + if ((rest_adv_int_tad & 1) == 0) + lcd_update = 1; +#endif + rest_adv_int_tad--; + } +#endif } #if USE_WK_RDS_COUNTER else { @@ -350,6 +389,11 @@ void ble_get_name(void) { ble_name[3] = 'G'; ble_name[4] = 'D'; ble_name[5] = '_'; +#elif DEVICE_TYPE == DEVICE_MJWSD05MMC + ble_name[2] = 'B'; + ble_name[3] = 'T'; + ble_name[4] = 'H'; + ble_name[5] = '_'; #else ble_name[2] = 'A'; ble_name[3] = 'T'; @@ -389,7 +433,7 @@ __attribute__((optimize("-Os"))) void init_ble(void) { /// if bls_ll_setAdvParam( OWN_ADDRESS_RANDOM ) -> blc_ll_setRandomAddr(mac_random_static); ble_get_name(); ////// Controller Initialization ////////// - blc_ll_initBasicMCU(); //must + //blc_ll_initBasicMCU(); // -> app.c user_init_normal() blc_ll_initStandby_module(mac_public); //must blc_ll_initAdvertising_module(mac_public); // adv module: must for BLE slave, blc_ll_initConnection_module(); // connection module must for BLE slave/master @@ -558,7 +602,12 @@ void set_adv_data(void) { memcpy(&adv_buf.data[adv_buf.data_size], ble_name, ble_name[0] + 1); size += ble_name[0] + 1; } - if (cfg.flg2.adv_flags) { +#if DEVICE_TYPE == DEVICE_MJWSD05MMC + if(1) +#else + if (cfg.flg2.adv_flags) +#endif + { p = adv_buf.flag; size += sizeof(adv_buf.flag); } else { @@ -568,7 +617,12 @@ void set_adv_data(void) { } else #endif { - if (cfg.flg2.adv_flags) { +#if DEVICE_TYPE == DEVICE_MJWSD05MMC + if(1) +#else + if (cfg.flg2.adv_flags) +#endif + { bls_ll_setAdvData((u8 *)&adv_buf.flag, adv_buf.data_size + sizeof(adv_buf.flag)); } else { bls_ll_setAdvData((u8 *)&adv_buf.data, adv_buf.data_size); diff --git a/src/ble.h b/src/ble.h index cae7064e..7eda140c 100644 --- a/src/ble.h +++ b/src/ble.h @@ -37,7 +37,7 @@ extern u16 RxTxValueInCCC; #define SEND_BUFFER_SIZE (ATT_MTU_SIZE-3) // = 20 extern uint8_t send_buf[SEND_BUFFER_SIZE]; -extern u8 my_RxTx_Data[16]; +extern u8 my_RxTx_Data[sizeof(cfg) + 2]; #if DEVICE_TYPE == DEVICE_LYWSD03MMC extern u8 my_HardStr[4]; @@ -184,6 +184,7 @@ typedef enum }ATT_HANDLE; +void app_enter_ota_mode(void); void set_adv_data(void); void my_att_init(); @@ -232,5 +233,6 @@ inline void ble_send_battery(void) { } inline void ble_send_cfg(void) { + memcpy(&my_RxTx_Data[2], &cfg, sizeof(cfg)); bls_att_pushNotifyData(RxTx_CMD_OUT_DP_H, my_RxTx_Data, sizeof(cfg) + 3); } diff --git a/src/blt_common.c b/src/blt_common.c index 27f79db1..d45ac66e 100644 --- a/src/blt_common.c +++ b/src/blt_common.c @@ -39,6 +39,17 @@ void SwapMacAddress(u8 *mac_out, u8 *mac_in) { mac_out[5] = mac_in[0]; } +extern void flash_write_all_size(unsigned int addr, unsigned int len, unsigned char *buf); + +/* Erase Flash sector CFG_ADR_MAC + * Save CUST_CAP_INFO_ADDR (Customize freq_offset adjust cap value) */ +void flash_erase_mac_sector(u32 faddr) { + u8 buf[16]; + flash_read_page(faddr+0xff8, sizeof(buf), (unsigned char *) &buf); + flash_erase_sector(faddr); + flash_write_all_size(faddr+0xff8, sizeof(buf), (unsigned char *)&buf); +} + __attribute__((optimize("-Os"))) void blc_newMacAddress(int flash_addr, u8 *mac_pub, u8 *mac_rand) { #if ((DEVICE_TYPE == DEVICE_CGG1) && (DEVICE_CGG1_ver == 2022)) @@ -54,12 +65,12 @@ void blc_newMacAddress(int flash_addr, u8 *mac_pub, u8 *mac_rand) { #else #if DEVICE_TYPE == DEVICE_CGDK2 u8 mac_flash[13]; - flash_erase_sector(flash_addr); + flash_erase_mac_sector(flash_addr); SwapMacAddress(&mac_flash[1], mac_pub); SwapMacAddress(&mac_flash[7], mac_pub); #else // DEVICE_TYPE != DEVICE_CGDK2 u8 mac_flash[8]; - flash_erase_sector(flash_addr); + flash_erase_mac_sector(flash_addr); #if DEVICE_TYPE == DEVICE_CGG1 SwapMacAddress(mac_flash, mac_pub); #else // DEVICE_TYPE != DEVICE_CGG1 diff --git a/src/cmd_parser.c b/src/cmd_parser.c index 9c09577f..b050f80f 100644 --- a/src/cmd_parser.c +++ b/src/cmd_parser.c @@ -3,8 +3,12 @@ #include "stack/ble/ble.h" #include "vendor/common/blt_common.h" #include "ble.h" - +#if USE_RTC +#include "rtc.h" +#endif +#include "i2c.h" #include "lcd.h" +#include "sensor.h" #include "app.h" #include "flash_eep.h" #if USE_TRIGGER_OUT @@ -18,12 +22,11 @@ #include "mi_beacon.h" #endif #include "cmd_parser.h" - - +#include "stack/ble/service/ble_ll_ota.h" #define _flash_read(faddr,len,pbuf) flash_read_page(FLASH_BASE_ADDR + (uint32_t)faddr, len, (uint8_t *)pbuf) -#define TX_MAX_SIZE (ATT_MTU_SIZE-3) // = 20 +//#define SEND_BUFFER_SIZE (ATT_MTU_SIZE-3) // = 20 #define FLASH_MIMAC_ADDR CFG_ADR_MAC // 0x76000 #define FLASH_MIKEYS_ADDR 0x78000 //#define FLASH_SECTOR_SIZE 0x1000 // in "flash_eep.h" @@ -49,6 +52,134 @@ enum { RAM blk_mi_keys_t keybuf; +#if USE_EXT_OTA // Compatible BigOTA + + +void ota_result_cb(int result) { + uint8_t id = 0; + if(result == OTA_SUCCESS) { + // clear the "bootable" identifier on the current work segment + flash_read_page(0x20008, sizeof(id), (unsigned char *) &id); + if(id == 'K') { + id = 0; + flash_write_page(0x20008, 1, (unsigned char *) &id); + } + } +} + +typedef struct _ext_ota_t { + uint32_t start_addr; + uint32_t ota_size; // in kbytes + uint32_t check_addr; +} ext_ota_t; + +RAM ext_ota_t ext_ota; + +uint32_t check_sector_clear(uint32_t addr) { + uint32_t faddr = addr, efaddr, fbuf; + faddr &= ~(FLASH_SECTOR_SIZE-1); + efaddr = faddr + FLASH_SECTOR_SIZE; + while(faddr < efaddr) { + flash_read_page(faddr, sizeof(fbuf), (unsigned char *) &fbuf); + if(fbuf != 0xffffffff) { +#if 1 + flash_erase_sector(faddr & (~(FLASH_SECTOR_SIZE-1))); +#else + unsigned char r = irq_disable(); + sleep_us(287*1000); + irq_restore(r); +#endif + break; + } + faddr += 1024; + } + return efaddr; +} + + +// Ext.OTA return code +enum { + EXT_OTA_OK = 0, //0 + EXT_OTA_WORKS, //1 + EXT_OTA_BUSY, //2 + EXT_OTA_READY, //3 + EXT_OTA_EVENT, //4 + EXT_OTA_ERR_PARM = 0xfe +} EXT_OTA_ENUM; + +uint8_t check_ext_ota(uint32_t ota_addr, uint32_t ota_size) { + if(ota_is_working == 0xff) + return EXT_OTA_BUSY; + if(ota_is_working) + return EXT_OTA_WORKS; + if(ota_addr < 0x40000 && ota_size <= ota_firmware_size_k) + return EXT_OTA_OK; + if(ota_size >= 208 + || ota_size < 4 + || ota_addr & (FLASH_SECTOR_SIZE-1)) + return EXT_OTA_ERR_PARM; +#if (defined(SHOW_OTA_SCREEN) && SHOW_OTA_SCREEN) + show_ota_screen(); +#endif + ble_connected |= 0x80; + ota_is_working = 0xff; // flag ext.ota + ext_ota.start_addr = ota_addr; + ext_ota.check_addr = ota_addr; + ext_ota.ota_size = (ota_size + 3) & 0xfffffc; + bls_ota_registerResultIndicateCb(ota_result_cb); + bls_pm_setManualLatency(3); + return EXT_OTA_BUSY; +} + +#if (DEVICE_TYPE == DEVICE_MJWSD05MMC) +static const uint8_t _mi_hw_vers[] = "V2.3F2.0-CFMK-LB-TMDZ---"; +#else +#error "Define MI_HW_VER_FADDR & _mi_hw_vers!" +#endif + +void clear_ota_area(void) { + union { + uint8_t b[24]; + struct __attribute__((packed)) { + uint16_t id_ok; + uint32_t start_addr; + uint32_t ota_size; + } msg; + } buf; +// if(bls_pm_getSystemWakeupTick() - clock_time() < 512*CLOCK_16M_SYS_TIMER_CLK_1MS) +// return; + if(bls_ll_requestConnBrxEventDisable() < 256 || ext_ota.check_addr == 0) + return; + if (ext_ota.check_addr >= ext_ota.start_addr + (ext_ota.ota_size << 10)) { +#if (DEVICE_TYPE == DEVICE_MJWSD05MMC) + check_sector_clear(MI_HW_VER_FADDR); + memcpy(buf.b, &_mi_hw_vers, 24); + flash_write_page(MI_HW_VER_FADDR, 24, (unsigned char *)buf.b); +#else +#error "Define MI_HW_VER_FADDR & _mi_hw_vers!" +#endif + ota_firmware_size_k = ext_ota.ota_size; + ota_program_offset = ext_ota.start_addr; + buf.msg.id_ok = (EXT_OTA_READY << 8) + CMD_ID_SET_OTA; + buf.msg.start_addr = ext_ota.start_addr; + buf.msg.ota_size = ext_ota.ota_size; + ota_is_working = 0x02; // flag ext.ota end + ext_ota.check_addr = 0; + } + else { + bls_ll_disableConnBrxEvent(); + ext_ota.check_addr = check_sector_clear(ext_ota.check_addr); + bls_ll_restoreConnBrxEvent(); + buf.msg.id_ok = (EXT_OTA_EVENT << 8) + CMD_ID_SET_OTA; + buf.msg.start_addr = ext_ota.check_addr; + buf.msg.ota_size = 0; + } + bls_att_pushNotifyData(RxTx_CMD_OUT_DP_H, (u8 *)&buf.msg, sizeof(buf.msg)); + bls_pm_setSuspendMask( + SUSPEND_ADV | DEEPSLEEP_RETENTION_ADV | SUSPEND_CONN | DEEPSLEEP_RETENTION_CONN); // MCU_STALL); +} +#endif // USE_EXT_OTA + #if ((DEVICE_TYPE == DEVICE_MHO_C401) || (DEVICE_TYPE == DEVICE_MHO_C401N)) uint32_t find_mi_keys(uint16_t chk_id, uint8_t cnt) { uint32_t faddr = FLASH_MIKEYS_ADDR; @@ -75,7 +206,7 @@ uint32_t find_mi_keys(uint16_t chk_id, uint8_t cnt) { } while (id != 0xffff || len != 0xff || faddr < faend); return 0; } -#else // DEVICE_LYWSD03MMC & DEVICE_CGG1 & DEVICE_CGDK2 +#else // DEVICE_LYWSD03MMC & DEVICE_CGG1 & DEVICE_CGDK2 & DEVICE_MJWSD05MMC /* if return != 0 -> keybuf = keys */ uint32_t find_mi_keys(uint16_t chk_id, uint8_t cnt) { uint32_t faddr = FLASH_MIKEYS_ADDR; @@ -102,11 +233,11 @@ uint32_t find_mi_keys(uint16_t chk_id, uint8_t cnt) { uint8_t send_mi_key(void) { if (blc_ll_getTxFifoNumber() < 9) { - while (keybuf.klen > TX_MAX_SIZE - 2) { - bls_att_pushNotifyData(RxTx_CMD_OUT_DP_H, (u8 *) &keybuf, TX_MAX_SIZE); - keybuf.klen -= TX_MAX_SIZE - 2; + while (keybuf.klen > SEND_BUFFER_SIZE - 2) { + bls_att_pushNotifyData(RxTx_CMD_OUT_DP_H, (u8 *) &keybuf, SEND_BUFFER_SIZE); + keybuf.klen -= SEND_BUFFER_SIZE - 2; if (keybuf.klen) - memcpy(&keybuf.data, &keybuf.data[TX_MAX_SIZE - 2], keybuf.klen); + memcpy(&keybuf.data, &keybuf.data[SEND_BUFFER_SIZE - 2], keybuf.klen); }; if (keybuf.klen) bls_att_pushNotifyData(RxTx_CMD_OUT_DP_H, (u8 *) &keybuf, @@ -266,7 +397,9 @@ static int32_t erase_mikeys(void) { return tmp; } -__attribute__((optimize("-Os"))) void cmd_parser(void * p) { +__attribute__((optimize("-Os"))) +void cmd_parser(void * p) { + uint8_t send_buf[32]; rf_packet_att_data_t *req = (rf_packet_att_data_t*) p; uint32_t len = req->l2cap - 3; if (len) { @@ -286,8 +419,10 @@ __attribute__((optimize("-Os"))) void cmd_parser(void * p) { if (--len > sizeof(ext)) len = sizeof(ext); if (len) { memcpy(&ext, &req->dat[1], len); - chow_tick_sec = ext.vtime_sec; - chow_tick_clk = clock_time(); + chow_tick_sec = utc_time_sec + ext.vtime_sec; +#if (DEVICE_TYPE == DEVICE_MJWSD05MMC) + lcd_update = 1; +#endif } ble_send_ext(); } else if (cmd == CMD_ID_CFG || cmd == CMD_ID_CFG_NS) { // Get/set config @@ -295,9 +430,12 @@ __attribute__((optimize("-Os"))) void cmd_parser(void * p) { u8 tmp = ((volatile u8 *)&cfg.flg2)[0]; if (len) { memcpy(&cfg, &req->dat[1], len); +#if (DEVICE_TYPE == DEVICE_MJWSD05MMC) + lcd_update = 1; +#endif } test_config(); - set_hw_version(); +// set_hw_version(); ev_adv_timeout(0, 0, 0); if (cmd != CMD_ID_CFG_NS) { // Get/set config (not save to Flash) flash_write_cfg(&cfg, EEP_ID_CFG, sizeof(cfg)); @@ -312,7 +450,9 @@ __attribute__((optimize("-Os"))) void cmd_parser(void * p) { } memcpy(&cfg, &def_cfg, sizeof(cfg)); test_config(); - set_hw_version(); +// set_hw_version(); + if (!cfg.hw_cfg.shtc3) // sensor SHT4x ? + cfg.flg.lp_measures = 1; ev_adv_timeout(0, 0, 0); flash_write_cfg(&cfg, EEP_ID_CFG, sizeof(cfg)); ble_send_cfg(); @@ -336,7 +476,7 @@ __attribute__((optimize("-Os"))) void cmd_parser(void * p) { #endif // USE_TRIGGER_OUT } else if (cmd == CMD_ID_DEV_MAC) { // Get/Set mac if (len == 2 && req->dat[1] == 0) { // default MAC - flash_erase_sector(FLASH_MIMAC_ADDR); + flash_erase_mac_sector(FLASH_MIMAC_ADDR); blc_initMacAddress(FLASH_MIMAC_ADDR, mac_public, mac_random_static); ble_connected |= 0x80; // reset device on disconnect } else if (len == sizeof(mac_public)+2 && req->dat[1] == sizeof(mac_public)) { @@ -396,11 +536,14 @@ __attribute__((optimize("-Os"))) void cmd_parser(void * p) { #endif olen = 2; } else if (cmd == CMD_ID_LCD_DUMP) { // Get/set lcd buf - if (--len > sizeof(display_buff)) len = sizeof(display_buff); + if (--len > sizeof(display_buff)) + len = sizeof(display_buff); if (len) { memcpy(display_buff, &req->dat[1], len); - //update_lcd(); - lcd_flg.b.ext_data = 1; + lcd_flg.b.ext_data = 1; // update_lcd(); +#if (DEVICE_TYPE == DEVICE_MJWSD05MMC) + lcd_update = 1; +#endif } else lcd_flg.b.ext_data = 0; ble_send_lcd(); } else if (cmd == CMD_ID_LCD_FLG) { // Start/stop notify lcd dump and ... @@ -431,7 +574,7 @@ __attribute__((optimize("-Os"))) void cmd_parser(void * p) { flash_write_cfg(&cmf, EEP_ID_CMF, sizeof(cmf)); ble_send_cmf(); } else if (cmd == CMD_ID_DNAME) { // Get/Set device name - if (--len > sizeof(ble_name) - 2) len = sizeof(ble_name) - 2; + if (--len > SEND_BUFFER_SIZE - 1) len = SEND_BUFFER_SIZE - 1; if (len) { flash_write_cfg(&req->dat[1], EEP_ID_DVN, (req->dat[1] != 0)? len : 0); ble_get_name(); @@ -455,6 +598,12 @@ __attribute__((optimize("-Os"))) void cmd_parser(void * p) { memcpy(&utc_time_sec, &req->dat[1], len); #if USE_TIME_ADJUST utc_set_time_sec = utc_time_sec; +#endif +#if USE_RTC + rtc_set_utime(utc_time_sec); +#endif +#if (DEVICE_TYPE == DEVICE_MJWSD05MMC) + lcd_update = 1; #endif } memcpy(&send_buf[1], &utc_time_sec, sizeof(utc_time_sec)); @@ -501,13 +650,65 @@ __attribute__((optimize("-Os"))) void cmd_parser(void * p) { } else if (cmd == CMD_ID_REBOOT) { // Set Reboot on disconnect ble_connected |= 0x80; // reset device on disconnect olen = 2; + } else if (cmd == CMD_ID_SET_OTA) { // Set OTA address and size +#if USE_EXT_OTA // Compatible BigOTA + uint32_t ota_addr, ota_size; + if (len > 8) { + memcpy(&ota_addr, &req->dat[1], 4); + memcpy(&ota_size, &req->dat[5], 4); + send_buf[1] = check_ext_ota(ota_addr, ota_size); + } // else send_buf[1] = 0; +#endif + memcpy(&send_buf[2], &ota_program_offset, 4); + memcpy(&send_buf[2+4], &ota_firmware_size_k, 4); + olen = 2 + 8; + } else if (cmd == CMD_ID_GDEVS) { // Get address devises + send_buf[1] = sensor_i2c_addr; +#if ((DEVICE_TYPE == DEVICE_LYWSD03MMC) || (DEVICE_TYPE == DEVICE_CGDK2) || (DEVICE_TYPE == DEVICE_MJWSD05MMC)) + send_buf[2] = lcd_i2c_addr; +#else + send_buf[2] = 1; // SPI +#endif +#if (DEVICE_TYPE == DEVICE_MJWSD05MMC) + send_buf[3] = rtc_i2c_addr; + olen = 3 + 1; +#else + olen = 2 + 1; +#endif + } else if (cmd == CMD_ID_I2C_SCAN) { // Universal I2C/SMBUS read-write + len = 0; + olen = 1; + while(len < 0x100 && olen < SEND_BUFFER_SIZE) { + send_buf[olen] = (uint8_t)scan_i2c_addr(len); + if(send_buf[olen]) + olen++; + len += 2; + } + } else if (cmd == CMD_ID_I2C_UTR) { // Universal I2C/SMBUS read-write + i2c_utr_t * pbufi = (i2c_utr_t *)&req->dat[1]; + olen = pbufi->rdlen & 0x7f; + if(len > sizeof(i2c_utr_t) + && olen <= SEND_BUFFER_SIZE - 3 // = 17 + && I2CBusUtr(&send_buf[3], + pbufi, + len - sizeof(i2c_utr_t) - 1) == 0 // wrlen: - addr + ) { + send_buf[1] = len - 1 - sizeof(i2c_utr_t); // write data len + send_buf[2] = pbufi->wrdata[0]; // i2c addr + olen += 3; + } else { + send_buf[1] = 0xff; // Error cmd + olen = 2; + } // Debug commands (unsupported in different versions!): - } else if (cmd == CMD_ID_DEBUG && len > 3) { // test/debug _flash_read((req->dat[1] | (req->dat[2]<<8) | (req->dat[3]<<16)), 18, &send_buf[4]); memcpy(send_buf, req->dat, 4); olen = 18+4; + } else { + send_buf[1] = 0xff; // Error cmd + olen = 2; } if (olen) bls_att_pushNotifyData(RxTx_CMD_OUT_DP_H, send_buf, olen); diff --git a/src/cmd_parser.h b/src/cmd_parser.h index 6f2c0d2c..133ed2e2 100644 --- a/src/cmd_parser.h +++ b/src/cmd_parser.h @@ -1,6 +1,9 @@ #pragma once enum { CMD_ID_DNAME = 0x01, // Get/Set device name, "\0" - default: ATC_xxxx + CMD_ID_GDEVS = 0x02, // Get address devises + CMD_ID_I2C_SCAN = 0x03, // I2C scan + CMD_ID_I2C_UTR = 0x04, // Universal I2C/SMBUS read-write CMD_ID_DEV_MAC = 0x10, // Get/Set MAC [+RandMAC], [size][mac[6][randmac[2]]] CMD_ID_MI_DNAME = 0x11, // Get/Set Mi key: DevNameId, [size]["\0"+miDevName] CMD_ID_MI_TBIND = 0x12, // Get/Set Mi keys: Token & Bind, [size][keys] @@ -28,6 +31,8 @@ enum { CMD_ID_PINCODE = 0x70, // Set new PinCode 0..999999 CMD_ID_MTU = 0x71, // Request Mtu Size Exchange (23..255) CMD_ID_REBOOT = 0x72, // Set Reboot on disconnect + CMD_ID_SET_OTA = 0x73, // Extension BigOTA: Get/set address and size OTA, erase sectors + // Debug commands (unsupported in different versions!): CMD_ID_DEBUG = 0xDE // Test/Debug } CMD_ID_KEYS; @@ -46,6 +51,10 @@ typedef struct __attribute__((packed)) _blk_mi_keys_t { } blk_mi_keys_t, * pblk_mi_keys_t; extern blk_mi_keys_t keybuf; +#if USE_EXT_OTA // Compatible BigOTA + void clear_ota_area(void); +#endif + uint32_t find_mi_keys(uint16_t chk_id, uint8_t cnt); uint8_t mi_key_stage; diff --git a/src/epd_cgg1n.c b/src/epd_cgg1n.c new file mode 100644 index 00000000..35606203 --- /dev/null +++ b/src/epd_cgg1n.c @@ -0,0 +1,426 @@ +#include +#include "tl_common.h" +#include "app_config.h" +#if ((DEVICE_TYPE == DEVICE_CGG1) && (DEVICE_CGG1_ver == 2022)) + +#include "app.h" +//#include "epd.h" +#include "lcd.h" +#include "battery.h" +#include "drivers/8258/pm.h" +#include "drivers/8258/timer.h" + +#define LOW 0 +#define HIGH 1 + +/* + CGG1-2022 LCD buffer: byte.bit + + @ ---------5.0------------- O :--4.2--- + 7.6 | | 4.3 | + || | | | | | | 4.2 + BLE || 5.5 5.4 5.3 5.2 5.1 | | + 9.6 || | | | | | | :--4.1--- + | | | + ------------------------- 4.2 + | + :--4.0--- + + 12.4 11.4--10.7--10.4 7.4---6.7---6.4 3.4---2.7---2.4 + | | | | | | | + 12.3 11.3 10.3 7.3 6.3 3.3 2.3 + | | | | | | | + 12.2 11.2--10.6--10.2 7.2---6.6---6.2 3.2---2.6-- 2.2 + | | | | | | | + 12.1 11.1 10.1 7.1 6.1 3.1 2.1 + | | | | | 4.5 | | + 12.0 11.0--10.5--10.0 7.0---6.5---6.0 * 3.0---2.5---2.0 + + ------------------------------4.4-------------------------- + + 14.4--13.7--13.4 9.4---8.7---8.4 % 1.4---0.7---0.4 + | | | | 1.6 | | + 14.3 13.3 9.3 8.3 1.3 0.3 + | | | | | | + 14.2--13.6--13.2 9.2---8.6---8.2 1.2---0.6---0.2 + | | | | | | + 14.1 13.1 9.1 8.1 1.1 0.1 + | | | | 4.6 | | + 14.0--13.5--13.0 9.0---8.5---8.0 * 1.0---0.5---0.0 + + 0 1 2 3 4 5 6 7 8 9 a b c d e f +60ff5fff1f7f3fff5fff5fff1f1fff1f00 +*/ +#define DEF_EPD_SUMBOL_SIGMENTS 13 +#define DEF_EPD_REFRESH_CNT 255 +//---------------------------------- +// define segments +// the data in the arrays consists of {byte, bit} pairs of each segment +//---------------------------------- +const uint8_t top_left[DEF_EPD_SUMBOL_SIGMENTS*2] = {10, 7, 10, 4, 10, 3, 10, 2, 10, 1, 10, 0, 10, 5, 11, 0, 11, 1, 11, 2, 11, 3, 11, 4, 10, 6}; +const uint8_t top_middle[DEF_EPD_SUMBOL_SIGMENTS*2] = {6, 7, 6, 4, 6, 3, 6, 2, 6, 1, 6, 0, 6, 5, 7, 0, 7, 1, 7, 2, 7, 3, 7, 4, 6, 6}; +const uint8_t top_right[DEF_EPD_SUMBOL_SIGMENTS*2] = {2, 7, 2, 4, 2, 3, 2, 2, 2, 1, 2, 0, 2, 5, 3, 0, 3, 1, 3, 2, 3, 3, 3, 4, 2, 6}; +const uint8_t bottom_left[DEF_EPD_SUMBOL_SIGMENTS*2] = {13, 7, 13, 4, 13, 3, 13, 2, 13, 1, 13, 0, 13, 5, 14, 0, 14, 1, 14, 2, 14, 3, 14, 4, 13, 6}; +const uint8_t bottom_middle[DEF_EPD_SUMBOL_SIGMENTS*2] = {8, 7, 8, 4, 8, 3, 8, 2, 8, 1, 8, 0, 8, 5, 9, 0, 9, 1, 9, 2, 9, 3, 9, 4, 8, 6}; +const uint8_t bottom_right[DEF_EPD_SUMBOL_SIGMENTS*2] = {0, 7, 0, 4, 0, 3, 0, 2, 0, 1, 0, 0, 0, 5, 1, 0, 1, 1, 1, 2, 1, 3, 1, 4, 0, 6}; +/* +Now define how each digit maps to the segments: + 1 + 12 :-----------: 2 + | | + 11 | | 3 + | 13 | + 10 :-----------: 4 + | | + 9 | | 5 + | 7 | + 8 :-----------: 6 +*/ +const uint8_t digits[16][DEF_EPD_SUMBOL_SIGMENTS + 1] = { + {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 0, 0}, // 0 + {2, 3, 4, 5, 6, 0, 0, 0, 0, 0, 0, 0, 0}, // 1 + {1, 2, 3, 4, 6, 7, 8, 9, 10, 12, 13, 0, 0, 0}, // 2 + {1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 13, 0, 0, 0}, // 3 + {2, 3, 4, 5, 6, 10, 11, 12, 13, 0, 0, 0, 0, 0}, // 4 + {1, 2, 4, 5, 6, 7, 8, 10, 11, 12, 13, 0, 0, 0}, // 5 + {1, 2, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 0, 0}, // 6 + {1, 2, 3, 4, 5, 6, 12, 0, 0, 0, 0, 0, 0, 0}, // 7 + {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 0}, // 8 + {1, 2, 3, 4, 5, 6, 7, 8, 10, 11, 12, 13, 0, 0}, // 9 + {1, 2, 3, 4, 5, 6, 8, 9, 10, 11, 12, 13, 0, 0}, // A + {4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 0, 0, 0, 0}, // b + {1, 2, 6, 7, 8, 9, 10, 11, 12, 0, 0, 0, 0, 0}, // C + {2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 0, 0, 0}, // d + {1, 2, 4, 6, 7, 8, 9, 10, 11, 12, 0, 0, 0, 0}, // E + {1, 2, 8, 9, 10, 11, 12, 13, 0, 0, 0, 0, 0, 0} // F +}; + +RAM uint8_t display_buff[16]; +RAM uint8_t display_cmp_buff[16]; +RAM uint8_t stage_lcd; +//RAM uint8_t flg_lcd_init; +RAM uint8_t lcd_refresh_cnt; +RAM uint8_t epd_updated; +//---------------------------------- +// T_LUT_ping, T_LUT_init, T_LUT_work values taken from the actual device with a +// logic analyzer +//---------------------------------- +const uint8_t T_LUT_ping[5] = {0x07B, 0x081, 0x0E4, 0x0E7, 0x008}; +const uint8_t T_LUT_init[14] = {0x082, 0x068, 0x050, 0x0E8, 0x0D0, 0x0A8, 0x065, 0x07B, 0x081, 0x0E4, 0x0E7, 0x008, 0x0AC, 0x02B }; +const uint8_t T_LUT_work[9] = {0x082, 0x080, 0x000, 0x0C0, 0x080, 0x080, 0x062, 0x0AC, 0x02B}; +//const uint8_t T_LUT_test[16] = {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00}; + +#define delay_SPI_end_cycle() cpu_stall_wakeup_by_timer0((CLOCK_SYS_CLOCK_1US*15)/10) // real clk 4.4 + 4.4 us : 114 kHz) +#define delay_EPD_SCL_pulse() cpu_stall_wakeup_by_timer0((CLOCK_SYS_CLOCK_1US*15)/10) // real clk 4.4 + 4.4 us : 114 kHz) +/* 0x00 = " " + * 0x20 = "°Г" + * 0x40 = " -" + * 0x60 = "°F" + * 0x80 = " _" + * 0xA0 = "°C" + * 0xC0 = " =" + * 0xE0 = "°E" */ +_attribute_ram_code_ void show_temp_symbol(uint8_t symbol) { + if (symbol & 0x20) + display_buff[4] |= BIT(2) | BIT(3); // "°Г" + else + display_buff[4] &= ~(BIT(2) | BIT(3)); // "°Г" + if (symbol & 0x40) + display_buff[4] |= BIT(1); //"-" + else + display_buff[4] &= ~BIT(1); //"-" + if (symbol & 0x80) + display_buff[4] |= BIT(0); // "_" + else + display_buff[4] &= ~BIT(0); // "_" +} + +/* CGG1 no symbol 'smiley' ! + * =5 -> "---" happy, != 5 -> " " sad */ +_attribute_ram_code_ void show_smiley(uint8_t state){ + if (state & 1) + display_buff[4] |= BIT(4); + else + display_buff[4] &= ~BIT(4); +/* + display_buff[7] |= BIT(6); + else + display_buff[7] &= ~BIT(6); +*/ +} + +_attribute_ram_code_ void show_battery_symbol(bool state){ + display_buff[5] = 0; + if (state) { + display_buff[5] |= BIT(0); + if (measured_data.battery_level >= 16) { + display_buff[5] |= BIT(1); + if (measured_data.battery_level >= 33) { + display_buff[5] |= BIT(2); + if (measured_data.battery_level >= 49) { + display_buff[5] |= BIT(3); + if (measured_data.battery_level >= 67) { + display_buff[5] |= BIT(4); + if (measured_data.battery_level >= 83) { + display_buff[5] |= BIT(5); + } + } + } + } + } + } +} + +_attribute_ram_code_ void show_ble_symbol(bool state){ + if (state) + display_buff[9] |= BIT(6); // "ble" + else + display_buff[9] &= ~BIT(6); +} + +_attribute_ram_code_ __attribute__((optimize("-Os"))) static void epd_set_digit(uint8_t *buf, uint8_t digit, const uint8_t *segments) { + // set the segments, there are up to 11 segments in a digit + int segment_byte; + int segment_bit; + for (int i = 0; i < DEF_EPD_SUMBOL_SIGMENTS; i++) { + // get the segment needed to display the digit 'digit', + // this is stored in the array 'digits' + int segment = digits[digit][i] - 1; + // segment = -1 indicates that there are no more segments to display + if (segment >= 0) { + segment_byte = segments[2 * segment]; + segment_bit = segments[1 + 2 * segment]; + buf[segment_byte] |= (1 << segment_bit); + } + else + // there are no more segments to be displayed + break; + } +} + +/* number in 0.1 (-995..19995), Show: -99 .. -9.9 .. 199.9 .. 1999 */ +_attribute_ram_code_ __attribute__((optimize("-Os"))) void show_big_number_x10(int16_t number){ + display_buff[2] = 0; + display_buff[3] = 0; + display_buff[4] &= ~(BIT(5)); // point + display_buff[6] = 0; + display_buff[7] &= BIT(6); // @ + display_buff[10] = 0; + display_buff[11] = 0; + display_buff[12] = 0; + if (number > 19995) { + // "Hi" + display_buff[11] |= BIT(0) | BIT(1) | BIT(2) | BIT(3) | BIT(4); + display_buff[10] |= BIT(0) | BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(6); + display_buff[7] |= BIT(0) | BIT(1) | BIT(2) | BIT(4); + } else if (number < -995) { + // "Lo" + display_buff[11] |= BIT(0) | BIT(1) | BIT(2) | BIT(3) | BIT(4); + display_buff[10] |= BIT(0) | BIT(5); + display_buff[7] |= BIT(0) | BIT(1) | BIT(2); + display_buff[6] |= BIT(0) | BIT(1) | BIT(2) | BIT(5) | BIT(6); + } else { + /* number: -995..19995 */ + if (number > 1995 || number < -95) { + // no point, show: -99..1999 + if (number < 0){ + number = -number; + display_buff[10] |= BIT(6); // "-" + } + number = (number / 10) + ((number % 10) > 5); // round(div 10) + } else { // show: -9.9..199.9 + display_buff[4] |= BIT(5); // point + if (number < 0){ + number = -number; + display_buff[10] |= BIT(6); // "-" + } + } + /* number: -99..1999 */ + if (number > 999) display_buff[12] |= BIT(0) | BIT(1) | BIT(2) | BIT(3) | BIT(4); // "1" 1000..1999 + if (number > 99) epd_set_digit(display_buff, number / 100 % 10, top_left); + if (number > 9) epd_set_digit(display_buff, number / 10 % 10, top_middle); + else epd_set_digit(display_buff, 0, top_middle); + epd_set_digit(display_buff, number % 10, top_right); + } +} + +/* number in 0.1 (-99..999) -> show: -9.9 .. 99.9 */ +_attribute_ram_code_ __attribute__((optimize("-Os"))) void show_small_number_x10(int16_t number, bool percent){ + display_buff[0] = 0; + display_buff[1] = 0; + display_buff[4] &= ~(BIT(6)); + display_buff[8] = 0; + display_buff[9] &= BIT(6); // BLE + display_buff[13] = 0; + display_buff[14] = 0; + if (percent) + display_buff[1] |= BIT(6); // "%" + if (number > 9995) { + // "Hi" + display_buff[14] |= BIT(0) | BIT(1) | BIT(2) | BIT(3) | BIT(4); + display_buff[13] |= BIT(0) | BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(6); + display_buff[9] |= BIT(0) | BIT(1) | BIT(2) | BIT(4); + } else if (number < -995) { + // "Lo" + display_buff[14] |= BIT(0) | BIT(1) | BIT(2) | BIT(3) | BIT(4); + display_buff[13] |= BIT(0) | BIT(5); + display_buff[9] |= BIT(0) | BIT(1) | BIT(2); + display_buff[8] |= BIT(0) | BIT(1) | BIT(2) | BIT(5) | BIT(6); + } else { + /* number: -99..999 */ + if (number > 995 || number < -95) { + // no point, show: -99..999 + if (number < 0){ + number = -number; + display_buff[13] |= BIT(6); // "-" + } + number = (number / 10) + ((number % 10) > 5); // round(div 10) + } else { // show: -9.9..99.9 + display_buff[4] |= BIT(6); // point + if (number < 0){ + number = -number; + display_buff[13] |= BIT(6); // "-" + } + } + /* number: -99..999 */ + if (number > 99) epd_set_digit(display_buff, number / 100 % 10, bottom_left); + if (number > 9) epd_set_digit(display_buff, number / 10 % 10, bottom_middle); + else epd_set_digit(display_buff, 0, bottom_middle); + epd_set_digit(display_buff, number % 10, bottom_right); + } +} + +void show_batt_cgg1(void) { + uint16_t battery_level = 0; + if (measured_data.battery_mv > MIN_VBAT_MV) { + battery_level = ((measured_data.battery_mv - MIN_VBAT_MV)*10)/((MAX_VBAT_MV - MIN_VBAT_MV)/100); + if (battery_level > 995) + battery_level = 995; + } + show_small_number_x10(battery_level, false); +} + +#if USE_CLOCK +_attribute_ram_code_ void show_clock(void) { + uint32_t tmp = utc_time_sec / 60; + uint32_t min = tmp % 60; + uint32_t hrs = tmp / 60 % 24; + memset(display_buff, 0, sizeof(display_buff)); + epd_set_digit(display_buff, min / 10 % 10, bottom_left); + epd_set_digit(display_buff, min % 10, bottom_middle); + epd_set_digit(display_buff, hrs / 10 % 10, top_left); + epd_set_digit(display_buff, hrs % 10, top_middle); +} +#endif // USE_CLOCK + +_attribute_ram_code_ __attribute__((optimize("-Os"))) static void transmit(uint8_t cd, uint8_t data_to_send) { + gpio_write(EPD_SCL, LOW); + gpio_write(EPD_CSB, LOW); + delay_EPD_SCL_pulse(); + + // send the first bit, this indicates if the following is a command or data + gpio_write(EPD_SDA, cd); + delay_EPD_SCL_pulse(); + gpio_write(EPD_SCL, HIGH); + delay_EPD_SCL_pulse(); + + // send 8 bits + for (int i = 0; i < 8; i++) { + // start the clock cycle + gpio_write(EPD_SCL, LOW); + // set the MOSI according to the data + if (data_to_send & 0x80) + gpio_write(EPD_SDA, HIGH); + else + gpio_write(EPD_SDA, LOW); + // prepare for the next bit + data_to_send = (data_to_send << 1); + delay_EPD_SCL_pulse(); + // the data is read at rising clock (halfway the time MOSI is set) + gpio_write(EPD_SCL, HIGH); + delay_EPD_SCL_pulse(); + } + + // finish by ending the clock cycle and disabling SPI + gpio_write(EPD_SCL, LOW); + delay_SPI_end_cycle(); + gpio_write(EPD_CSB, HIGH); + delay_SPI_end_cycle(); +} + +_attribute_ram_code_ static void transmit_blk(uint8_t cd, const uint8_t * pdata, size_t size_data) { + for (int i = 0; i < size_data; i++) + transmit(cd, pdata[i]); +} + +_attribute_ram_code_ void update_lcd(void){ + if (!stage_lcd) { + if (memcmp(&display_cmp_buff, &display_buff, sizeof(display_buff))) { + memcpy(&display_cmp_buff, &display_buff, sizeof(display_buff)); + if (lcd_refresh_cnt) { + lcd_refresh_cnt--; + } else { + init_lcd(); // pulse RST_N low for 110 microseconds +// lcd_refresh_cnt = DEF_EPD_REFRESH_CNT; +// epd_updated = 0; + } + stage_lcd = 1; + } + } +} + +void init_lcd(void) { + // pulse RST_N low for 110 microseconds + gpio_write(EPD_RST, LOW); + pm_wait_us(110); + lcd_refresh_cnt = DEF_EPD_REFRESH_CNT; + stage_lcd = 1; + epd_updated = 0; + gpio_write(EPD_RST, HIGH); + display_buff[15] = 0; +} + +_attribute_ram_code_ __attribute__((optimize("-Os"))) int task_lcd(void) { + if (gpio_read(EPD_BUSY)) { + switch (stage_lcd) { + case 1: // Update/Init, stage 1 + transmit_blk(0, T_LUT_ping, sizeof(T_LUT_ping)); + stage_lcd = 2; + break; + case 2: // Update/Init, stage 2 + if (epd_updated == 0) { + transmit_blk(0, T_LUT_init, sizeof(T_LUT_init)); + } else { + transmit_blk(0, T_LUT_work, sizeof(T_LUT_work)); + } + stage_lcd = 3; + break; + case 3: // Update/Init, stage 3 + transmit(0, 0x040); + transmit(0, 0x0A9); + transmit(0, 0x0A8); + transmit_blk(1, display_buff, sizeof(display_buff)); + transmit(0, 0x0AB); + transmit(0, 0x0AA); + transmit(0, 0x0AF); + if (epd_updated) { + stage_lcd = 4; + // EPD_BUSY: ~500 ms + } else { + epd_updated = 1; + stage_lcd = 2; + // EPD_BUSY: ~1000 ms + } + break; + case 4: // Update, stage 4 + transmit(0, 0x0AE); + transmit(0, 0x028); + transmit(0, 0x0AD); + default: + stage_lcd = 0; + } + } + return stage_lcd; +} + +#endif // ((DEVICE_TYPE == DEVICE_CGG1) && (DEVICE_CGG1_ver == 2022)) diff --git a/src/epd_mho_c401n.c b/src/epd_mho_c401n.c index 13320c6e..3267fc9f 100644 --- a/src/epd_mho_c401n.c +++ b/src/epd_mho_c401n.c @@ -189,7 +189,7 @@ void show_connected_symbol(bool state){ display_buff[0] |= BIT(0); else display_buff[0] &= ~BIT(0); - tim_last_chow = clock_time() - min_step_time_update_lcd - (CLOCK_16M_SYS_TIMER_CLK_1S); + tim_last_chow = clock_time() - min_step_time_update_lcd - (8*CLOCK_16M_SYS_TIMER_CLK_1MS); } _attribute_ram_code_ __attribute__((optimize("-Os"))) static void epd_set_digit(uint8_t *buf, uint8_t digit, const uint8_t *segments) { diff --git a/src/ext_ota.c b/src/ext_ota.c new file mode 100644 index 00000000..e8caadb6 --- /dev/null +++ b/src/ext_ota.c @@ -0,0 +1,52 @@ +/* + * ext_ota.c + * + * Created on: 04.03.2023 + * Author: pvvx + */ +#include +#include "tl_common.h" + +#if USE_EXT_OTA // Compatible BigOTA + +typedef struct _ext_ota_t { + uint32_t start_addr; + uint32_t ota_size; + uint32_t check_addr; +} ext_ota_t; + +RAM ext_ota_t ext_ota; + +// check_ext_ota(ota_addr, ota_size); +uint8_t check_ext_ota(uint32_t ota_addr, uint32_t ota_size) { + uint32_t faddr, efaddr; + uint32_t fbuf; + if(ota_size >= 208) // 208 kbytes + return -2; + if(ota_addr & (FLASH_SECTOR_SIZE-1) || ota_size < FLASH_SECTOR_SIZE) + return -3; + if(ota_addr == ota_program_offset && ota_size < ota_firmware_size_k) + return 0; + if(ota_addr < 0x40000) + return -4; + ext_ota.start_addr = ota_addr; + ext_ota.ota_size = ota_size; + efaddr = ota_addr + (ota_size<<10); + while(faddr < efaddr) { + flash_read_page(faddr, sizeof(fbuf), (unsigned char *) &fbuf); + if(fbuf != -1) { + ext_ota.check_addr = ota_addr; + return 1; + } + faddr += 1024; + } + ota_program_offset = ext_ota.start_addr; + ota_firmware_size_k = ext_ota.ota_size >> 10; // in kbytes + + ota_is_working = 0xff; + ble_connected &= ~2; + bls_pm_setManualLatency(0); + return 0; +} + +#endif // USE_EXT_OTA diff --git a/src/flash_eep.c b/src/flash_eep.c index 191814b7..4dcbe557 100644 --- a/src/flash_eep.c +++ b/src/flash_eep.c @@ -110,6 +110,17 @@ inline unsigned int _flash_memcmp(unsigned int addr, unsigned int len, unsigned } #endif +/* +void flash_erase_sector_bt(unsigned int addr) { + if(bls_ll_requestConnBrxEventDisable() > 256) { + bls_ll_disableConnBrxEvent(); + flash_erase_sector(addr); + bls_ll_restoreConnBrxEvent(); + } else + flash_erase_sector(addr); +} +*/ + // error flash write: patch (переход границы в 256 байт) _attribute_ram_code_ void flash_write_all_size(unsigned int addr, unsigned int len, unsigned char *buf) { uint32_t xlen; @@ -134,7 +145,7 @@ _attribute_ram_code_ void flash_write_all_size(unsigned int addr, unsigned int l // ret < FMEM_ERROR_MAX - ошибка //----------------------------------------------------------------------------- FEEP_CODE_ATTR -LOCAL unsigned int get_addr_bscfg() +LOCAL unsigned int get_addr_bscfg(void) { unsigned int x1 = 0xFFFFFFFF, x2; unsigned int faddr = FMEMORY_SCFG_BASE_ADDR; @@ -424,6 +435,7 @@ bool flash_supported_eep_ver(unsigned int min_ver, unsigned int new_ver) { unsigned int tmp; unsigned int faddr = FMEMORY_SCFG_BASE_ADDR; _flash_mutex_lock(); + flash_unlock(FLASH_TYPE_GD); // Flash Unprotect if (flash_read_cfg(&tmp, EEP_ID_VER, sizeof(tmp)) == sizeof(tmp) && tmp >= min_ver) { if(tmp != new_ver) { tmp = new_ver; diff --git a/src/i2c.c b/src/i2c.c index 506b520a..0bcdd2e7 100644 --- a/src/i2c.c +++ b/src/i2c.c @@ -3,13 +3,15 @@ #include "drivers.h" #include "vendor/common/user_config.h" #include "app_config.h" +#include "i2c.h" #include "app.h" #include "drivers/8258/gpio_8258.h" -_attribute_ram_code_ void init_i2c(void){ +_attribute_ram_code_ +void init_i2c(void){ i2c_gpio_set(I2C_GROUP); // I2C_GPIO_GROUP_C0C1, I2C_GPIO_GROUP_C2C3, I2C_GPIO_GROUP_B6D7, I2C_GPIO_GROUP_A3A4 -#if (DEVICE_TYPE == DEVICE_CGDK2) - reg_i2c_speed = (uint8_t)(CLOCK_SYS_CLOCK_HZ/(4*450000)); // 450 kHz +#if (DEVICE_TYPE == DEVICE_CGDK2) || (DEVICE_TYPE == DEVICE_MJWSD05MMC) + reg_i2c_speed = (uint8_t)(CLOCK_SYS_CLOCK_HZ/(4*400000)); // 400 kHz #elif (DEVICE_TYPE == DEVICE_LYWSD03MMC) if(cfg.hw_cfg.hwver == 3) // HW:B1.9 reg_i2c_speed = (uint8_t)(CLOCK_SYS_CLOCK_HZ/(4*500000)); // 500 kHz @@ -34,3 +36,149 @@ int scan_i2c_addr(int address) { while (reg_i2c_status & FLD_I2C_CMD_BUSY); return ((reg_i2c_status & FLD_I2C_NAK)? 0 : address); } + +int send_i2c_byte(uint8_t i2c_addr, uint8_t cmd) { + if ((reg_clk_en0 & FLD_CLK0_I2C_EN)==0) + init_i2c(); + reg_i2c_id = i2c_addr; + reg_i2c_adr = cmd; + reg_i2c_ctrl = FLD_I2C_CMD_START | FLD_I2C_CMD_ID | FLD_I2C_CMD_ADDR | FLD_I2C_CMD_STOP; + while (reg_i2c_status & FLD_I2C_CMD_BUSY); + return (reg_i2c_status & FLD_I2C_NAK); +} + +int send_i2c_word(uint8_t i2c_addr, uint16_t cmd) { + if ((reg_clk_en0 & FLD_CLK0_I2C_EN)==0) + init_i2c(); + reg_i2c_id = i2c_addr; + reg_i2c_adr_dat = cmd; + reg_i2c_ctrl = FLD_I2C_CMD_START | FLD_I2C_CMD_ID | FLD_I2C_CMD_DO | FLD_I2C_CMD_ADDR | FLD_I2C_CMD_STOP; + while (reg_i2c_status & FLD_I2C_CMD_BUSY); + return (reg_i2c_status & FLD_I2C_NAK); +} + +int send_i2c_buf(uint8_t i2c_addr, uint8_t * dataBuf, uint32_t dataLen) { + int err = 0; + if ((reg_clk_en0 & FLD_CLK0_I2C_EN)==0) + init_i2c(); + uint8_t * p = dataBuf; + reg_i2c_id = i2c_addr; + reg_i2c_ctrl = FLD_I2C_CMD_START | FLD_I2C_CMD_ID; + while (reg_i2c_status & FLD_I2C_CMD_BUSY); + err = reg_i2c_status & FLD_I2C_NAK; + if(!err) { + while (dataLen--) { + reg_i2c_do = *p++; + reg_i2c_ctrl = FLD_I2C_CMD_DO; + while (reg_i2c_status & FLD_I2C_CMD_BUSY); + err = reg_i2c_status & FLD_I2C_NAK; + if(err) + break; + } + } + reg_i2c_ctrl = FLD_I2C_CMD_STOP; + while (reg_i2c_status & FLD_I2C_CMD_BUSY); + return err; +} + +#if USE_RTC +_attribute_ram_code_ +#endif +int read_i2c_byte_addr(uint8_t i2c_addr, uint8_t reg_addr, uint8_t * dataBuf, uint32_t dataLen) { + int ret = -1; + int size = dataLen; + uint8_t *p = dataBuf; + if ((reg_clk_en0 & FLD_CLK0_I2C_EN)==0) + init_i2c(); + //unsigned char r = irq_disable(); + //reg_i2c_speed = (uint8_t)(CLOCK_SYS_CLOCK_HZ/(4*125000)); // 125 kHz + reg_i2c_id = i2c_addr; + reg_i2c_adr = reg_addr; + reg_i2c_ctrl = FLD_I2C_CMD_START | FLD_I2C_CMD_ID | FLD_I2C_CMD_ADDR; + while (reg_i2c_status & FLD_I2C_CMD_BUSY); + ret = reg_i2c_status & FLD_I2C_NAK; + if (ret == 0) { + // Start By Master Read, Write Slave Address, Read data first byte + reg_rst0 = FLD_RST0_I2C; + reg_rst0 = 0; + //while(reg_i2c_status & FLD_I2C_CMD_BUSY); + //reg_i2c_speed = (uint8_t)(CLOCK_SYS_CLOCK_HZ/(4*125000)); // 125 kHz + reg_i2c_id = i2c_addr | FLD_I2C_WRITE_READ_BIT; + reg_i2c_ctrl = FLD_I2C_CMD_START | FLD_I2C_CMD_ID | FLD_I2C_CMD_READ_ID; + while(reg_i2c_status & FLD_I2C_CMD_BUSY); + ret = reg_i2c_status & FLD_I2C_NAK; + if(ret == 0) { + while(size) { + size--; + if(!size) + reg_i2c_ctrl = FLD_I2C_CMD_DI | FLD_I2C_CMD_READ_ID | FLD_I2C_CMD_ACK; + else + reg_i2c_ctrl = FLD_I2C_CMD_DI | FLD_I2C_CMD_READ_ID; + while(reg_i2c_status & FLD_I2C_CMD_BUSY); + *p++ = reg_i2c_di; + } + } + } + reg_i2c_ctrl = FLD_I2C_CMD_STOP; + while(reg_i2c_status & FLD_I2C_CMD_BUSY); + //irq_restore(r); + return ret; +} + +/* Universal I2C/SMBUS read-write transaction + * wrlen = 0..127 ! */ +int I2CBusUtr(void * outdata, i2c_utr_t * tr, unsigned int wrlen) { + unsigned char * pwrdata = (unsigned char *) &tr->wrdata; + unsigned char * poutdata = (unsigned char *) outdata; + unsigned int cntstart = wrlen - (tr->mode & 0x7f); + unsigned int rdlen = tr->rdlen & 0x7f; + + if ((reg_clk_en0 & FLD_CLK0_I2C_EN)==0) + init_i2c(); + unsigned char r = irq_disable(); + + reg_i2c_id = *pwrdata++; + reg_i2c_ctrl = FLD_I2C_CMD_START | FLD_I2C_CMD_ID; + while(reg_i2c_status & FLD_I2C_CMD_BUSY); + + int ret = reg_i2c_status & FLD_I2C_NAK; + while(ret == 0 && wrlen) { + // write data + reg_i2c_do = *pwrdata++; + reg_i2c_ctrl = FLD_I2C_CMD_DO; + while(reg_i2c_status & FLD_I2C_CMD_BUSY); + ret = reg_i2c_status & FLD_I2C_NAK; + + if(--wrlen == cntstart && ret == 0) { // + send start & id + if(tr->mode & 0x80) { + reg_i2c_ctrl = FLD_I2C_CMD_STOP; + while(reg_i2c_status & FLD_I2C_CMD_BUSY); + } + else { + // hw reset I2C + reg_rst0 = FLD_RST0_I2C; + reg_rst0 = 0; + } + reg_i2c_id = tr->wrdata[0] | FLD_I2C_WRITE_READ_BIT; + // start + id + reg_i2c_ctrl = FLD_I2C_CMD_START | FLD_I2C_CMD_ID; + while(reg_i2c_status & FLD_I2C_CMD_BUSY); + ret = reg_i2c_status & FLD_I2C_NAK; + } + } + if(ret == 0) { + while(rdlen) { + rdlen--; + if(rdlen == 0 && (tr->rdlen & 0x80) == 0) + reg_i2c_ctrl = FLD_I2C_CMD_DI | FLD_I2C_CMD_READ_ID | FLD_I2C_CMD_ACK; + else + reg_i2c_ctrl = FLD_I2C_CMD_DI | FLD_I2C_CMD_READ_ID; + while(reg_i2c_status & FLD_I2C_CMD_BUSY); + *poutdata++ = reg_i2c_di; + } + } + reg_i2c_ctrl = FLD_I2C_CMD_STOP; // launch start/stop cycle + while(reg_i2c_status & FLD_I2C_CMD_BUSY); + irq_restore(r); + return ret; +} diff --git a/src/i2c.h b/src/i2c.h index 41e78708..bcdee7c3 100644 --- a/src/i2c.h +++ b/src/i2c.h @@ -2,7 +2,19 @@ #include +/* Universal I2C/SMBUS read-write transaction struct */ +typedef struct _i2c_utr_t { + unsigned char mode; // bit0..6: number wr_byte for new START (bit7: =1 - generate STOP/START) + unsigned char rdlen; // bit0..6: number rd_byte (bit7: =0 - old read byte generate NACK, =1 - ACK) + unsigned char wrdata[1]; // i2c_addr_wr, wr_byte1, wr_byte2, wr_byte3, ... wr_byte126 +} i2c_utr_t; + void init_i2c(); //void send_i2c(uint8_t device_id, uint8_t *buffer, int dataLen); int scan_i2c_addr(int address); +int send_i2c_byte(uint8_t i2c_addr, uint8_t cmd); +int send_i2c_word(uint8_t i2c_addr, uint16_t cmd); +int send_i2c_buf(uint8_t i2c_addr, uint8_t * dataBuf, uint32_t dataLen); +int read_i2c_byte_addr(uint8_t i2c_addr, uint8_t reg_addr, uint8_t * dataBuf, uint32_t dataLen); +int I2CBusUtr(void * outdata, i2c_utr_t *tr, unsigned int wrlen); diff --git a/src/lcd.h b/src/lcd.h index 90389974..02dbfef5 100644 --- a/src/lcd.h +++ b/src/lcd.h @@ -3,7 +3,7 @@ #include #include #include "app_config.h" - +#if (DEVICE_TYPE != DEVICE_MJWSD05MMC) /* CGG1 no symbol 'smiley' ! */ #define SMILE_HAPPY 5 // "(^-^)" happy #define SMILE_SAD 6 // "(-^-)" sad @@ -92,3 +92,81 @@ void show_small_number_x10(int16_t number, bool percent); // -9 .. 99 #else #error "Set DEVICE_TYPE!" #endif + +#else // (DEVICE_TYPE == DEVICE_MJWSD05MMC) + +#define SHOW_OTA_SCREEN 1 +#define SHOW_REBOOT_SCREEN 1 + +enum { + SCR_TYPE_TIME = 0, //0 Time (default) + SCR_TYPE_TEMP, //1 Temperature + SCR_TYPE_HUMI, //2 Humidity + SCR_TYPE_BAT_P, //3 Battery % + SCR_TYPE_BAT_V, //4 Battery V + SCR_TYPE_EXT //5 External number & symbols +} SCR_TYPE_ENUM; + +#define MJWSD05MMC_LCD_I2C_ADDR 0x3E +#define min_step_time_update_lcd (500 * CLOCK_16M_SYS_TIMER_CLK_1MS) + +#define LCD_SYM_SMILEY_NONE 0 // "(^-^)" happy +#define LCD_SYM_SMILEY_HAPPY 5 // "(^-^)" happy +#define LCD_SYM_SMILEY_SAD 6 // "(-^-)" sad +/* 0 = " " off, + * 1 = " ^-^ " + * 2 = " -^- " + * 3 = " ooo " + * 4 = "( )" + * 5 = "(^-^)" happy + * 6 = "(-^-)" sad + * 7 = "(ooo)" */ +void show_smiley(uint8_t state); + +#define LCD_SYM_N 0x00 // " " +#define LCD_SYM_C 0x03 // "°C" +#define LCD_SYM_F 0x07 // "°F" +#define LCD_SYM_P 0x08 // "%" +#define LCD_SYM_T 0x10 // ":" +/* 0x00 = " " + * 0x01 = "°г" + * 0x02 = " -" + * 0x03 = "°c" + * 0x04 = " |" + * 0x05 = "°Г" + * 0x06 = " г" + * 0x07 = "°F" + * 0x08 = "%" + * 0x10 = ":" */ +void show_symbol_s1(uint8_t symbol); + +extern uint8_t lcd_i2c_addr; + +#if (defined(SHOW_OTA_SCREEN) && SHOW_OTA_SCREEN) +void show_ota_screen(void); +#endif +#if (defined(SHOW_REBOOT_SCREEN) && SHOW_REBOOT_SCREEN) +void show_reboot_screen(void); +#endif + +void init_lcd(void); +void lcd(void); +void update_lcd(void); +void show_battery_symbol(bool state); +void show_ble_symbol(bool state); + +void show_s1_number_x100(int32_t number, uint8_t atr); +void show_s3_number_x10(int32_t number, uint8_t atr); +void show_s4_number_x10(int32_t number, uint8_t atr); +void show_clock_s1(void); +void show_clock_s3(void); +void show_battery_s1(uint8_t level); +void show_data_s2(void); +void show_low_bat(void); + +#define LCD_BUF_SIZE 18 +//extern uint32_t min_step_time_update_lcd; // = cfg.min_step_time_update_lcd * 0.05 sec +//extern uint32_t tim_last_chow; // timer show lcd >= 1.5 sec +extern uint8_t display_buff[LCD_BUF_SIZE]; + +#endif // (DEVICE_TYPE == DEVICE_MJWSD05MMC) diff --git a/src/lcd_cgdk2.c b/src/lcd_cgdk2.c index 5f0d8eae..b35ae6d2 100644 --- a/src/lcd_cgdk2.c +++ b/src/lcd_cgdk2.c @@ -9,6 +9,14 @@ #include "lcd.h" #include "battery.h" +RAM uint8_t lcd_i2c_addr; +RAM uint8_t display_buff[18]; +RAM uint8_t display_cmp_buff[18]; + +#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, (uint8_t *) b, a) + + /* CGDK2 LCD buffer: byte.bit @@ -100,10 +108,7 @@ const uint8_t bottom_right[DEF_CGDK22_SUMBOL_SIGMENTS*2] = {9, 3, 17, 7, 10, 7, */ const uint8_t lcd_init_cmd[] = {0xea,0xbe,0xf0,0xfc}; -RAM uint8_t lcd_i2c_addr; -RAM uint8_t display_buff[18]; -RAM uint8_t display_cmp_buff[18]; - +/* static void lcd_send_i2c_buf(uint8_t * dataBuf, uint32_t dataLen) { if ((reg_clk_en0 & FLD_CLK0_I2C_EN)==0) init_i2c(); @@ -119,7 +124,7 @@ static void lcd_send_i2c_buf(uint8_t * dataBuf, uint32_t dataLen) { reg_i2c_ctrl = FLD_I2C_CMD_STOP; while (reg_i2c_status & FLD_I2C_CMD_BUSY); } - +*/ _attribute_ram_code_ void send_to_lcd(void){ unsigned int buff_index; diff --git a/src/lcd_lywsd03mmc.c b/src/lcd_lywsd03mmc.c new file mode 100644 index 00000000..feb577ca --- /dev/null +++ b/src/lcd_lywsd03mmc.c @@ -0,0 +1,337 @@ +#include +#include "tl_common.h" +#include "app_config.h" +#if DEVICE_TYPE == DEVICE_LYWSD03MMC +#include "drivers.h" +#include "drivers/8258/gpio_8258.h" +#include "app.h" +#include "i2c.h" +#include "lcd.h" + +RAM uint8_t 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, (uint8_t *) b, a) + +/* t,H,h,L,o,i 0xe2,0x67,0x66,0xe0,0xC6,0x40 */ +#define LCD_SYM_H 0x67 // "H" +#define LCD_SYM_i 0x40 // "i" +#define LCD_SYM_L 0xE0 // "L" +#define LCD_SYM_o 0xC6 // "o" + +#define LCD_SYM_BLE 0x10 // connect +#define LCD_SYM_BAT 0x08 // battery + +const uint8_t 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 uint8_t lcd_init_clr_b14[] = {0x80,0x40,0xC0,0,0xC0,0,0xC0,0,0xC0,0,0xC0,0,0xC0,0,0xC0,0,0xC0,0}; +const uint8_t lcd_init_clr_b19[] = {0x00,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00}; + +RAM uint8_t display_buff[6]; +RAM uint8_t display_cmp_buff[6]; + +typedef struct __attribute__((packed)) _dma_uart_buf_t { + volatile uint32_t dma_len; + uint32_t head; + uint8_t start; + uint8_t data[6]; + uint8_t chk; + uint8_t end; +} dma_uart_buf_t; + +RAM dma_uart_buf_t utxb; + +/* 0,1,2,3,4,5,6,7,8,9,A,b,C,d,E,F*/ +const uint8_t display_numbers[] = {0xf5,0x05,0xd3,0x97,0x27,0xb6,0xf6,0x15,0xf7,0xb7, 0x77,0xe6,0xf0,0xc7,0xf2,0x72}; + +static _attribute_ram_code_ uint8_t reverse(uint8_t revByte) { + revByte = (revByte & 0xF0) >> 4 | (revByte & 0x0F) << 4; + revByte = (revByte & 0xCC) >> 2 | (revByte & 0x33) << 2; + revByte = (revByte & 0xAA) >> 1 | (revByte & 0x55) << 1; + return revByte; +} +/* +static void lcd_send_i2c_byte(uint8_t cmd) { + if ((reg_clk_en0 & FLD_CLK0_I2C_EN)==0) + init_i2c(); + reg_i2c_id = lcd_i2c_addr; + reg_i2c_adr = cmd; + reg_i2c_ctrl = FLD_I2C_CMD_START | FLD_I2C_CMD_ID | FLD_I2C_CMD_ADDR | FLD_I2C_CMD_STOP; + while (reg_i2c_status & FLD_I2C_CMD_BUSY); +} + +static void lcd_send_i2c_buf(uint8_t * dataBuf, uint32_t dataLen) { + if ((reg_clk_en0 & FLD_CLK0_I2C_EN)==0) + init_i2c(); + uint8_t * p = dataBuf; + reg_i2c_id = lcd_i2c_addr; + reg_i2c_ctrl = FLD_I2C_CMD_START | FLD_I2C_CMD_ID; + while (reg_i2c_status & FLD_I2C_CMD_BUSY); + while (dataLen--) { + reg_i2c_do = *p++; + reg_i2c_ctrl = 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); +} +*/ + +// UART 38400 BAUD +#define UART_BAUD 38400 +#if CLOCK_SYS_CLOCK_HZ == 16000000 +#define uartCLKdiv 51 // 16000000/(7+1)/(51+1)=38461.538... +#define bwpc 7 +#elif CLOCK_SYS_CLOCK_HZ == 24000000 +#define uartCLKdiv 124 // 24000000/(4+1)/(124+1)=38400 +#define bwpc 4 +#elif CLOCK_SYS_CLOCK_HZ == 32000000 +#define uartCLKdiv 103 // 32000000/(7+1)/(103+1)=38461.538... +#define bwpc 7 +#elif CLOCK_SYS_CLOCK_HZ == 48000000 +#define uartCLKdiv 124 // 48000000/(9+1)/(124+1)=38400 +#define bwpc 9 +#endif + +_attribute_ram_code_ void lcd_send_uart(void) { + // init uart + reg_clk_en0 |= FLD_CLK0_UART_EN; + ///reg_clk_en1 |= FLD_CLK1_DMA_EN; + uart_reset(); + // reg_uart_clk_div/reg_uart_ctrl0 + REG_ADDR32(0x094) = MASK_VAL(FLD_UART_CLK_DIV, uartCLKdiv, FLD_UART_CLK_DIV_EN, 1) + | ((MASK_VAL(FLD_UART_BPWC, bwpc) | (FLD_UART_TX_DMA_EN)) << 16) // set bit width, enable UART DMA mode + | ((MASK_VAL(FLD_UART_CTRL1_STOP_BIT, 0)) << 24) // 00: 1 bit, 01: 1.5bit 1x: 2bits; + ; + // reg_dma1_addr/reg_dma1_ctrl + REG_ADDR32(0xC04) = (unsigned short)((u32)(&utxb)) //set tx buffer address + | (((sizeof(utxb)+15)>>4) << 16); //set tx buffer size + ///reg_dma1_addrHi = 0x04; (in sdk init?) + reg_dma_chn_en |= FLD_DMA_CHN_UART_TX; + ///reg_dma_chn_irq_msk |= FLD_DMA_IRQ_UART_TX; + + // GPIO_PD7 set TX UART pin + REG_ADDR8(0x5AF) = (REG_ADDR8(0x5AF) & (~(BIT(7)|BIT(6)))) | BIT(7); + BM_CLR(reg_gpio_func(UART_TX_PD7), UART_TX_PD7 & 0xff); + /// gpio_set_input_en(UART_TX_PD7, 1); ??? + + // start send DMA + reg_dma_tx_rdy0 |= FLD_DMA_CHN_UART_TX; // start tx + // wait send (3.35 ms), sleep? + pm_wait_us(3330); // 13 bytes * 10 bits / 38400 baud = 0.0033854 sec = 3.4 ms power ~3 mA + //while (reg_dma_tx_rdy0 & FLD_DMA_CHN_UART_TX); ? + while (!(reg_uart_status1 & FLD_UART_TX_DONE)); + // set low/off power UART + reg_uart_clk_div = 0; +} + + +_attribute_ram_code_ void send_to_lcd(void){ + unsigned int buff_index; + uint8_t * p = display_buff; + 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; + + if (lcd_i2c_addr == (B14_I2C_ADDR << 1)) { + // B1.4, B1.7, B2.0 + 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; + } else { // (lcd_i2c_addr == (B19_I2C_ADDR << 1)) + // B1.9 + reg_i2c_adr = 0x04; + reg_i2c_do = reverse(*p++); + reg_i2c_di = reverse(*p++); + reg_i2c_ctrl = FLD_I2C_CMD_ID | FLD_I2C_CMD_ADDR | FLD_I2C_CMD_DO | FLD_I2C_CMD_DI | FLD_I2C_CMD_START; + while (reg_i2c_status & FLD_I2C_CMD_BUSY); + reg_i2c_adr_dat = 0; + reg_i2c_ctrl = FLD_I2C_CMD_ADDR | FLD_I2C_CMD_DO; + while (reg_i2c_status & FLD_I2C_CMD_BUSY); + reg_i2c_adr = reverse(*p++); + reg_i2c_do = reverse(*p++); + reg_i2c_ctrl = FLD_I2C_CMD_ADDR | FLD_I2C_CMD_DO; + while (reg_i2c_status & FLD_I2C_CMD_BUSY); + reg_i2c_adr_dat = 0; + reg_i2c_ctrl = FLD_I2C_CMD_ADDR | FLD_I2C_CMD_DO; + while (reg_i2c_status & FLD_I2C_CMD_BUSY); + reg_i2c_adr = reverse(*p++); + reg_i2c_do = reverse(*p); + reg_i2c_ctrl = FLD_I2C_CMD_ADDR | FLD_I2C_CMD_DO | FLD_I2C_CMD_STOP; + } + while (reg_i2c_status & FLD_I2C_CMD_BUSY); + } else { + // B1.6 (UART LCD) + utxb.data[5] = *p++; + utxb.data[4] = *p++; + utxb.data[3] = *p++; + utxb.data[2] = *p++; + utxb.data[1] = *p++; + utxb.data[0] = *p; + utxb.chk = utxb.data[0]^utxb.data[1]^utxb.data[2]^utxb.data[3]^utxb.data[4]^utxb.data[5]; + utxb.dma_len = sizeof(utxb) - sizeof(utxb.dma_len); + lcd_send_uart(); + } +} + +void init_lcd(void){ + lcd_i2c_addr = (uint8_t) scan_i2c_addr(B14_I2C_ADDR << 1); + if (lcd_i2c_addr) { // B1.4, B1.7, B2.0 +// 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_send_i2c_buf((uint8_t *) lcd_init_cmd_b14, sizeof(lcd_init_cmd_b14)); + lcd_send_i2c_buf((uint8_t *) lcd_init_clr_b14, sizeof(lcd_init_clr_b14)); + return; + } + lcd_i2c_addr = (uint8_t) scan_i2c_addr(B19_I2C_ADDR << 1); + if (lcd_i2c_addr) { // B1.9 + lcd_send_i2c_byte(0xEA); // Set IC Operation(ICSET): Software Reset, Internal oscillator circuit + sleep_us(240); + lcd_send_i2c_byte(0xA4); // Display control (DISCTL): Normal mode, FRAME flip, Power save mode 1 + lcd_send_i2c_byte(0x9C); // ? Address set (ADSET): 0x1C ? + lcd_send_i2c_byte(0xAC); // Display control (DISCTL): Power save mode 1, FRAME flip, Power save mode 1 + lcd_send_i2c_byte(0xBC); // Display control (DISCTL): Power save mode 3, FRAME flip, Power save mode 1 + lcd_send_i2c_byte(0xF0); // Blink control (BLKCTL): Off + lcd_send_i2c_byte(0xFC); // All pixel control (APCTL): Normal + lcd_send_i2c_buf((uint8_t *) lcd_init_clr_b19, sizeof(lcd_init_clr_b19)); + lcd_send_i2c_byte(0xC8); // Mode Set (MODE SET): Display ON, 1/3 Bias + return; + } + // B1.6 (UART), lcd_i2c_addr = 0 + // utxb.dma_len = 0; + // utxb.head = 0; + utxb.start = 0xAA; + // utxb.data = {0}; + utxb.end = 0x55; +} + +_attribute_ram_code_ void update_lcd(){ + if (memcmp(&display_cmp_buff, &display_buff, sizeof(display_buff))) { + send_to_lcd(); + memcpy(&display_cmp_buff, &display_buff, sizeof(display_buff)); + } +} +/* 0x00 = " " + * 0x20 = "°Г" + * 0x40 = " -" + * 0x60 = "°F" + * 0x80 = " _" + * 0xA0 = "°C" + * 0xC0 = " =" + * 0xE0 = "°E" */ +_attribute_ram_code_ void show_temp_symbol(uint8_t symbol) { + display_buff[2] &= ~0xE0; + display_buff[2] |= symbol & 0xE0; +} +/* 0 = " " off, + * 1 = " ^-^ " + * 2 = " -^- " + * 3 = " ooo " + * 4 = "( )" + * 5 = "(^-^)" happy + * 6 = "(-^-)" sad + * 7 = "(ooo)" */ +_attribute_ram_code_ void show_smiley(uint8_t state){ + display_buff[2] &= ~0x07; + display_buff[2] |= state & 0x07; +} + +_attribute_ram_code_ void show_ble_symbol(bool state){ + if (state) + display_buff[2] |= LCD_SYM_BLE; + else + display_buff[2] &= ~LCD_SYM_BLE; +} + +_attribute_ram_code_ void show_battery_symbol(bool state){ + if (state) + display_buff[1] |= LCD_SYM_BAT; + else + display_buff[1] &= ~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(int16_t number){ +// display_buff[4] = point?0x08:0x00; + if (number > 19995) { + display_buff[3] = 0; + display_buff[4] = LCD_SYM_i; // "i" + display_buff[5] = LCD_SYM_H; // "H" + } else if (number < -995) { + display_buff[3] = 0; + display_buff[4] = LCD_SYM_o; // "o" + display_buff[5] = LCD_SYM_L; // "L" + } else { + display_buff[5] = 0; + /* number: -995..19995 */ + if (number > 1995 || number < -95) { + display_buff[4] = 0; // no point, show: -99..1999 + if (number < 0){ + number = -number; + display_buff[5] = 2; // "-" + } + number = (number / 10) + ((number % 10) > 5); // round(div 10) + } else { // show: -9.9..199.9 + display_buff[4] = 0x08; // point, + if (number < 0){ + number = -number; + display_buff[5] = 2; // "-" + } + } + /* number: -99..1999 */ + if (number > 999) display_buff[5] |= 0x08; // "1" 1000..1999 + if (number > 99) display_buff[5] |= display_numbers[number / 100 % 10]; + if (number > 9) display_buff[4] |= display_numbers[number / 10 % 10]; + else display_buff[4] |= 0xF5; // "0" + display_buff[3] = display_numbers[number %10]; + } +} + +/* -9 .. 99 */ +_attribute_ram_code_ __attribute__((optimize("-Os"))) void show_small_number(int16_t number, bool percent){ + display_buff[1] = display_buff[1] & 0x08; // and battery + display_buff[0] = percent?0x08:0x00; + if (number > 99) { + display_buff[0] |= LCD_SYM_i; // "i" + display_buff[1] |= LCD_SYM_H; // "H" + } else if (number < -9) { + display_buff[0] |= LCD_SYM_o; // "o" + display_buff[1] |= LCD_SYM_L; // "L" + } else { + if (number < 0) { + number = -number; + display_buff[1] = 2; // "-" + } + if (number > 9) display_buff[1] |= display_numbers[number / 10 % 10]; + display_buff[0] |= display_numbers[number %10]; + } +} + +#if USE_CLOCK +_attribute_ram_code_ void show_clock(void) { + uint32_t tmp = utc_time_sec / 60; + uint32_t min = tmp % 60; + uint32_t hrs = tmp / 60 % 24; + display_buff[0] = display_numbers[min % 10]; + display_buff[1] = display_numbers[min / 10 % 10]; + display_buff[2] = 0; + display_buff[3] = display_numbers[hrs % 10]; + display_buff[4] = display_numbers[hrs / 10 % 10]; + display_buff[5] = 0; +} +#endif // USE_CLOCK + +#endif // DEVICE_TYPE == DEVICE_LYWSD03MMC diff --git a/src/lcd_mjwsd05mmc.c b/src/lcd_mjwsd05mmc.c new file mode 100644 index 00000000..42b559cf --- /dev/null +++ b/src/lcd_mjwsd05mmc.c @@ -0,0 +1,888 @@ +#include +#include "tl_common.h" +#include "app_config.h" +#if DEVICE_TYPE == DEVICE_MJWSD05MMC +#include "drivers.h" +#include "drivers/8258/gpio_8258.h" +#include "app.h" +#include "i2c.h" +#if USE_RTC +#include "rtc.h" +#endif +#include "lcd.h" +#include "ble.h" +#include "battery.h" + +#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, (uint8_t *) b, a) + +RAM uint8_t lcd_i2c_addr; +RAM uint8_t display_buff[LCD_BUF_SIZE]; +RAM uint8_t display_cmp_buff[LCD_BUF_SIZE]; + + +/* MJWSD05MMC LCD buffer: byte.bit + __ __ + AM PM BLE BAT 17.5( ^__^ ^ )17.5 + 3.0 2.0 0.0 [|17.4]# 17.6 17.7 + + + --3.4-- --2.4-- --1.4-- -17.0-- o 0.4 + | | | | | 1.0 | | | | +--- 0.4 + | 3.1 3.5 2.1 2.5 o 1.1 1.5 0.1 17.1 | + | | | | | | | | | ---- 0.5 + 4.4 --3.2-- --2.2-- 1.0 --1.2-- --0.2-- | + | | | | | o | | | | | + | 3.3 3.6 2.3 2.6 1.3 1.6 0.3 17.2 0.6 + | | | | | | | | | o/ 0.7 + --3.7-- --2.7-- * --1.7-- -17.3-- /o + 13.0 + + Воскресенье Понедельник Вторник Среда Четверг Пятница Суббота + Sunday Monday Tuesday Wednesday Thursday Friday Saturday + 4.5 4.6 4.7 4.3 4.2 4.1 4.0 + + --6.0-- --6.4-- --7.4-- --8.4-- + | | | | | | | | + 5.4 5.5 5.1 6.5 / 6.1 7.5 7.1 8.5 + | | | | / | | | | + --5.6-- --5.2-- 5.0 --6.2-- --7.2-- + | | | | / | | | | + 6.0 5.7 5.3 6.6 / 6.3 7.6 7.3 8.6 + | | | | | | | | + --6.0-- --6.7-- --7.7-- --8.7-- + + + --9.4-- -10.4-- 10.0 -11.4-- -12.4-- o 9.0 + | | | | o | | | | +--- 9.0 + 8.1 9.5 9.1 10.5 10.1 11.5 11.1 12.5 | + | | | | 10.0 | | | | ---- 8.0 + --8.2-- --9.2-- o -10.2-- -11.2-- | + | | | | | | | | | + 8.3 9.6 9.3 10.6 10.3 11.6 11.3 12.6 7.0 + | | | | | | * | | + --9.7-- -10.7-- -11.7-- 11.0 -12.7-- + + + -13.4-- -14.4-- -15.4-- o 15.0 + | | | | | | | +--- 15.0 + | 12.1 13.5 13.1 14.5 14.1 15.5 | + | | | | | | | ---- 15.1 + 12.0 -12.2-- -13.2-- -14.2-- | + | | | | | | | | + | 12.3 13.6 13.3 14.6 14.3 15.6 15.2 + | | | | | * | | o/ 15.3 + -13.7-- -14.7-- 14.0 -15.7-- /o + +none: 16.0..16.7 +*/ + +#define DEF_MJWSD05MMC_SUMBOL_SIGMENTS 7 +/* +Now define how each digit maps to the segments: + -----1----- + | | + 6 2 + | | + -----7----- + | | + 5 3 + | | + -----4----- +*/ + +const uint8_t digits[16][DEF_MJWSD05MMC_SUMBOL_SIGMENTS + 1] = { + {1, 2, 3, 4, 5, 6, 0, 0}, // 0 + {2, 3, 0, 0, 0, 0, 0, 0}, // 1 + {1, 2, 4, 5, 7, 0, 0, 0}, // 2 + {1, 2, 3, 4, 7, 0, 0, 0}, // 3 + {2, 3, 6, 7, 0, 0, 0, 0}, // 4 + {1, 3, 4, 6, 7, 0, 0, 0}, // 5 + {1, 3, 4, 5, 6, 7, 0, 0}, // 6 + {1, 2, 3, 0, 0, 0, 0, 0}, // 7 + {1, 2, 3, 4, 5, 6, 7, 0}, // 8 + {1, 2, 3, 4, 6, 7, 0, 0}, // 9 + {1, 2, 3, 5, 6, 7, 0, 0}, // A + {3, 4, 5, 6, 7, 0, 0, 0}, // b + {1, 4, 5, 6, 0, 0, 0, 0}, // C + {2, 3, 4, 5, 7, 0, 0, 0}, // d + {1, 4, 5, 6, 7, 0, 0, 0}, // E + {1, 5, 6, 7, 0, 0, 0, 0} // F +}; + +//---------------------------------- +// define segments +// the data in the arrays consists of {byte, bit} pairs of each segment +//---------------------------------- +//const uint8_t sb_s1_0[2] = {4,0x10}; +const uint8_t sb_s1[4][DEF_MJWSD05MMC_SUMBOL_SIGMENTS*2] = { + {3,0x10, 3,0x20, 3,0x40, 3,0x80, 3,0x08, 3,0x02, 3,0x04}, + {2,0x10, 2,0x20, 2,0x40, 2,0x80, 2,0x08, 2,0x02, 2,0x04}, + // "." 13,0x01 + // ":" 1,0x01 + {1,0x10, 1,0x20, 1,0x40, 1,0x80, 1,0x08, 1,0x02, 1,0x04}, + {17,0x01, 17,0x02, 17,0x04, 17,0x08, 0,0x08, 0,0x02, 0,0x04} + // "°Г" 0,0x10 + // "-" 0,0x20 + // "|" 0,0x40 + // "%" 0,0x80 +}; + +// Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday +// display_buff[4] |= sb_dnd(n) +const uint8_t sb_dnd[7] = {0x20, 0x40, 0x80, 0x08, 0x04, 0x02, 0x01}; + +const uint8_t sb_s2[4][DEF_MJWSD05MMC_SUMBOL_SIGMENTS*2] = { + {6,0x01, 5,0x20, 5,0x80, 6,0x01, 6,0x01, 5,0x10, 5,0x40}, + {6,0x10, 6,0x20, 6,0x40, 6,0x80, 5,0x08, 5,0x02, 5,0x04}, + // "/" 5,0x01 + {7,0x10, 7,0x20, 7,0x40, 7,0x80, 6,0x08, 6,0x02, 6,0x04}, + {8,0x10, 8,0x20, 8,0x40, 8,0x80, 7,0x08, 7,0x02, 7,0x04} +}; +const uint8_t sb_s3[4][DEF_MJWSD05MMC_SUMBOL_SIGMENTS*2] = { + {9,0x10, 9,0x20, 9,0x40, 9,0x80, 8,0x08, 8,0x02, 8,0x04}, + {10,0x10, 10,0x20, 10,0x40, 10,0x80, 9,0x08, 9,0x02, 9,0x04}, + // ":" 10,0x01 + {11,0x10, 11,0x20, 11,0x40, 11,0x80, 10,0x08, 10,0x02, 10,0x04}, + // "." 11,0x01 + {12,0x10, 12,0x20, 12,0x40, 12,0x80, 11,0x08, 11,0x02, 11,0x04} +}; + +//const uint8_t sb_s4_0[2] = {12,0x01}; +const uint8_t sb_s4[4][DEF_MJWSD05MMC_SUMBOL_SIGMENTS*2] = { + {13,0x10, 13,0x20, 13,0x40, 13,0x80, 12,0x08, 12,0x02, 12,0x04}, + {14,0x10, 14,0x20, 14,0x40, 14,0x80, 13,0x08, 13,0x02, 13,0x04}, + // "." 14,0x01 + {15,0x10, 15,0x20, 15,0x40, 15,0x80, 14,0x08, 14,0x02, 14,0x04} + // "°Г" 15,0x01 + // "-" 15,0x02 + // "|" 15,0x04 + // "%" 15,0x08 +}; + +/* LCD controller initialize: +1. 0xea - Set IC Operation(ICSET): Software Reset, Internal oscillator circuit +2. 0xbe - Display control (DISCTL): Power save mode3, FRAME flip 1, Normal mode // (0xb6) Power save mode2 +3. 0xf0 - Blink control (BLKCTL): Off +4. 0xfc - All pixel control (APCTL): Normal +*/ +const uint8_t lcd_init_cmd[] = {0xea,0xbe,0xf0,0xfc}; +const uint8_t lcd_init_clr_b19[] = {0x00,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00}; + +// runtime: 600 us if I2C 450 kHz +_attribute_ram_code_ void send_to_lcd(void){ + unsigned int buff_index; + uint8_t * p = display_buff; + if (lcd_i2c_addr) { + if ((reg_clk_en0 & FLD_CLK0_I2C_EN)==0) + init_i2c(); + reg_i2c_id = lcd_i2c_addr; + reg_i2c_adr_dat = 0xE800; // 0xe8 - Set IC Operarion(ICSET): Do not execute Software Reset, Internal oscillator circuit; 0x00 - ADSET + 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); + + for(buff_index = 0; buff_index < sizeof(display_buff) - 1; buff_index++) { + reg_i2c_do = *p++; + reg_i2c_ctrl = FLD_I2C_CMD_DO; + while (reg_i2c_status & FLD_I2C_CMD_BUSY); + } + reg_i2c_do = *p; + reg_i2c_ctrl = FLD_I2C_CMD_DO | FLD_I2C_CMD_STOP; + while (reg_i2c_status & FLD_I2C_CMD_BUSY); + + reg_i2c_adr = 0xC8; // 0xc8 - Mode Set (MODE SET): Display ON, 1/3 Bias + reg_i2c_ctrl = FLD_I2C_CMD_START | FLD_I2C_CMD_ID | FLD_I2C_CMD_ADDR | FLD_I2C_CMD_STOP; + while (reg_i2c_status & FLD_I2C_CMD_BUSY); + } +} + +/* LCD controller initialize +1. 0xea - Set IC Operation(ICSET): Software Reset, Internal oscillator circuit +2. 0xf0 - Blink control (BLKCTL): Off +4. 0xc0 - Mode Set (MODE SET): Display ON ? +2. 0xbc - Display control (DISCTL): Power save mode 3, FRAME flip, Power save mode 1 +*/ +const uint8_t lcd_init1_cmd[] = {0xea,0xf0, 0xc0, 0xbc}; + +void init_lcd(void){ + lcd_i2c_addr = (uint8_t) scan_i2c_addr(MJWSD05MMC_LCD_I2C_ADDR << 1); + if (lcd_i2c_addr) { // LCD CGDK2_I2C_ADDR ? +#if 1 // sleep: 15.5 uA + lcd_send_i2c_buf((uint8_t *) lcd_init1_cmd, sizeof(lcd_init1_cmd)); +#else // sleep: 15.5 uA + lcd_send_i2c_byte(0xEA); // Set IC Operation(ICSET): Software Reset, Internal oscillator circuit + sleep_us(240); + lcd_send_i2c_byte(0xA4); // Display control (DISCTL): Normal mode, FRAME flip, Power save mode 1 + lcd_send_i2c_byte(0x9C); // ? Address set (ADSET): 0x1C ? + lcd_send_i2c_byte(0xAC); // Display control (DISCTL): Power save mode 1, FRAME flip, Power save mode 1 + lcd_send_i2c_byte(0xBC); // Display control (DISCTL): Power save mode 3, FRAME flip, Power save mode 1 + lcd_send_i2c_byte(0xF0); // Blink control (BLKCTL): Off + lcd_send_i2c_byte(0xFC); // All pixel control (APCTL): Normal + lcd_send_i2c_buf((uint8_t *) lcd_init_clr_b19, sizeof(lcd_init_clr_b19)); + lcd_send_i2c_byte(0xC8); // Mode Set (MODE SET): Display ON, 1/3 Bias +#endif + pm_wait_us(200); + //memset(display_buff, 0xff, sizeof(display_buff)); + send_to_lcd(); + } +} + +_attribute_ram_code_ void update_lcd(void){ + if (memcmp(&display_cmp_buff, &display_buff, sizeof(display_buff))) { + send_to_lcd(); + memcpy(&display_cmp_buff, &display_buff, sizeof(display_buff)); + } +} + +_attribute_ram_code_ __attribute__((optimize("-Os"))) static void lcd_set_digit(uint8_t *buf, uint8_t digit, const uint8_t *segments) { + // set the segments, there are up to 11 segments in a digit + int segment_byte; + int segment_bit; + for (int i = 0; i < DEF_MJWSD05MMC_SUMBOL_SIGMENTS; i++) { + // get the segment needed to display the digit 'digit', + // this is stored in the array 'digits' + int segment = digits[digit][i] - 1; + // segment = -1 indicates that there are no more segments to display + if (segment >= 0) { + segment_byte = segments[2 * segment]; + segment_bit = segments[1 + 2 * segment]; + buf[segment_byte] |= segment_bit; + } + else + // there are no more segments to be displayed + break; + } +} + +/* 0x00 = " " + * 0x01 = "°г" + * 0x02 = " -" + * 0x03 = "°c" + * 0x04 = " |" + * 0x05 = "°Г" + * 0x06 = " г" + * 0x07 = "°F" + * 0x08 = "%" + * 0x10 = ":" */ +void show_symbol_s1(uint8_t symbol) { +/* o 0.4 + +--- 0.4 + | + ---- 0.5 + | + | + 0.6 + o/ 0.7 + /o +*/ + if (symbol & 1) + display_buff[0] |= BIT(4); // "°г" + else + display_buff[0] &= ~BIT(4); // "°г" + if (symbol & 2) + display_buff[0] |= BIT(5); //"-" + else + display_buff[0] &= ~BIT(5); //"-" + if (symbol & 4) + display_buff[0] |= BIT(6); // "|" + else + display_buff[0] &= ~BIT(6); // "|" + if (symbol & 8) + display_buff[0] |= BIT(7); // "%" + else + display_buff[0] &= ~BIT(7); // "%" + if (symbol & 0x10) + display_buff[1] |= BIT(0); // ":" + else + display_buff[1] &= ~BIT(0); // ":" +} + +void show_symbol_s3(uint8_t symbol) { +/* o 9.0 + +--- 9.0 + | + ---- 8.0 + | + | + 7.0 + */ + if (symbol & 1) + display_buff[9] |= BIT(0); // "°г" + else + display_buff[9] &= ~BIT(0); // "°г" + if (symbol & 2) + display_buff[8] |= BIT(0); //"-" + else + display_buff[8] &= ~BIT(0); //"-" + if (symbol & 4) + display_buff[7] |= BIT(0); // "|" + else + display_buff[7] &= ~BIT(0); // "|" + if (symbol & 0x10) + display_buff[10] |= BIT(0); // ":" + else + display_buff[10] &= ~BIT(0); // ":" +} + +void show_symbol_s4(uint8_t symbol) { +/* o 15.0 + +--- 15.0 + | + ---- 15.1 + | + | + 15.2 + o/ 15.3 + /o + */ + if (symbol & 1) + display_buff[15] |= BIT(0); // "°г" + else + display_buff[15] &= ~BIT(0); // "°г" + if (symbol & 2) + display_buff[15] |= BIT(1); //"-" + else + display_buff[15] &= ~BIT(1); //"-" + if (symbol & 4) + display_buff[15] |= BIT(2); // "|" + else + display_buff[15] &= ~BIT(2); // "|" + if (symbol & 8) + display_buff[15] |= BIT(3); // "%" + else + display_buff[15] &= ~BIT(3); // "%" +} + +/* 0 = " " off, + * 1 = " ^-^ " + * 2 = " -^- " + * 3 = " ooo " + * 4 = "( )" + * 5 = "(^-^)" happy + * 6 = "(-^-)" sad + * 7 = "(ooo)" */ + +void show_smiley(uint8_t state){ +/* __ __ +17.5( ^__^ ^ )17.5 + 17.6 17.7 */ + if (state & 1) + display_buff[17] |= BIT(6); + else + display_buff[17] &= ~(BIT(6)); + if (state & 2) + display_buff[17] |= BIT(7); + else + display_buff[17] &= ~(BIT(7)); + if (state & 4) + display_buff[17] |= BIT(5); + else + display_buff[17] &= ~(BIT(5)); +} + +void show_ble_symbol(bool state){ + if (state) + display_buff[0] |= BIT(0); + else + display_buff[0] &= ~(BIT(0)); +} + +void show_battery_symbol(bool state){ + if (state) + display_buff[17] |= BIT(4); + else + display_buff[17] &= ~(BIT(4)); +} + +static void clear_s1(void) { + display_buff[0] &= BIT(0); // "ble" + display_buff[1] = 0; // ":" + display_buff[2] &= BIT(0); //"PM" + display_buff[3] &= BIT(0); //"AM" + display_buff[4] &= ~(BIT(4)); // "1" + display_buff[13] &= ~(BIT(0)); // "." + display_buff[17] &= ~(BIT(0) | BIT(1) | BIT(2) | BIT(3)); // bat, smile +} + +static void clear_s2(void) { + display_buff[5] = 0; + display_buff[6] = 0; + display_buff[7] &= BIT(0); // "i" от "°F" + display_buff[8] &= ~(BIT(4) | BIT(5) | BIT(6) | BIT(7)); // "-" от "°F" + s3 +} + +static void clear_s3(void) { + display_buff[7] &= ~(BIT(0)); // "i" от "°F" + display_buff[8] &= ~(BIT(0) | BIT(1) | BIT(2) | BIT(3)); // "-" от "°F" + s2 + display_buff[9] = 0; // "°F" + display_buff[10] = 0; // ":" + display_buff[11] = 0; + display_buff[12] &= ~(BIT(4) | BIT(5) | BIT(6) | BIT(7)); // s4 +} + +static void clear_s4(void) { + display_buff[12] &= ~(BIT(0) | BIT(1) | BIT(2) | BIT(3)); // s3 + display_buff[13] &= BIT(0); //s1: "." + display_buff[14] = 0; + display_buff[15] = 0; +} + +/* number: -999.50 .19999.50, in 0.01: -99950..1999950 + *012345 + * -999 (-9.99) [ -999][ -9.99] + * -99 (-0.99) [ -99 ][ -0.99] + * -9 (-0.09) [ -9 ][ -0.09] + * 9 (0.09) [ 9 ][ 0.09] + * 99 (0.09) [ 99 ][ 0.99] + * 999 (9.99) [ 999 ][ 9.99] + * 9999 (99.99) [ 9999][ 99.99] + * 19999 (199.99)[19999][199.99] */ +void show_s1_number_x100(int32_t number, uint8_t atr){ + uint8_t buf[6] = {0}; + clear_s1(); + show_symbol_s1(atr); + if (number >= 1999950) { + // "Hi" + display_buff[1] |= BIT(3); + display_buff[2] |= BIT(1) | BIT(2) | BIT(3) | BIT(5) | BIT(6); + } else if (number <= -99950) { + // "Lo" + display_buff[1] |= BIT(2) | BIT(3) | BIT(6) | BIT(7); + display_buff[2] |= BIT(1) | BIT(3) | BIT(7); + } else if (number > 19999 || number < -999) { + // no point, show: -999..19999 + if (number < 0){ + number = -number; + buf[0] = 1; + } + number = (number / 100) + ((number % 100) >= 50); // round(div 100) + if (number > 9999) buf[1] = 1; // "1" 10000..19999 + if (number > 999) buf[2] = number / 1000 % 10; + if (number > 99) buf[3] = number / 100 % 10; + if (number > 9) buf[4] = number / 10 % 10; + buf[5] = number % 10; + /* + *012345 + *- -999 [ -999] + *- -99 [ -99 ] + *- -9 [ -9 ] + * 9 [ 9 ] + * 99 [ 99 ] + * 999 [ 999 ] + * 9999 [ 9999] + * 19999 [19999] */ + if(buf[1] || buf[2]) { + // 1000..19999 + if(buf[1]) display_buff[4] |= BIT(4); // "1" 10000..19999 + lcd_set_digit(display_buff, buf[2], sb_s1[0]); + lcd_set_digit(display_buff, buf[3], sb_s1[1]); + lcd_set_digit(display_buff, buf[4], sb_s1[2]); + lcd_set_digit(display_buff, buf[5], sb_s1[3]); + } else { // -999..999 + if(buf[0]) { + if(buf[3]) { // -999..-100 + display_buff[3] |= BIT(2); // "-" + lcd_set_digit(display_buff, buf[3], sb_s1[1]); + lcd_set_digit(display_buff, buf[4], sb_s1[2]); + lcd_set_digit(display_buff, buf[5], sb_s1[3]); + } else { // -99..-10 + if(buf[4]) { + display_buff[3] |= BIT(2); // "-" + lcd_set_digit(display_buff, buf[4], sb_s1[1]); + } else // -9..-1 + display_buff[2] |= BIT(2); // "-" + lcd_set_digit(display_buff, buf[5], sb_s1[2]); + } + } else { // 0..999 + if(buf[3]) { // 10000..19999 + lcd_set_digit(display_buff, buf[3], sb_s1[1]); + lcd_set_digit(display_buff, buf[4], sb_s1[2]); + } else if(buf[4]) + lcd_set_digit(display_buff, buf[4], sb_s1[2]); + lcd_set_digit(display_buff, buf[5], sb_s1[3]); + } + } + } else { // show: -9.99..199.99 + display_buff[13] |= BIT(0); // point + if (number < 0){ + number = -number; + buf[0] = 1; + display_buff[3] |= BIT(2); // "-" + } + if (number > 9999) buf[1] = 1; // "1" 10000..19999 + if (number > 999) buf[2] = number / 1000 % 10; + if (number > 99) buf[3] = number / 100 % 10; + if (number > 9) buf[4] = number / 10 % 10; + buf[5] = number % 10; + /* + *012345 + *- -999 (-9.99) [ -9.99] + *- -99 (-0.99) [ -0.99] + *- -9 (-0.09) [ -0.09] + * 9 (0.09) [ 0.09] + * 99 (0.09) [ 0.99] + * 999 (9.99) [ 9.99] + * 9999 (99.99) [ 99.99] + * 19999 (199.99)[199.99] */ + if(!buf[0]) { // 0..199.99 + if(buf[1]) { + display_buff[4] |= BIT(4); // "1" 100.00..199.99 + lcd_set_digit(display_buff, buf[2], sb_s1[0]); + } else if(buf[2]) + lcd_set_digit(display_buff, buf[2], sb_s1[0]); + } + lcd_set_digit(display_buff, buf[3], sb_s1[1]); + lcd_set_digit(display_buff, buf[4], sb_s1[2]); + if(buf[5]) lcd_set_digit(display_buff, buf[5], sb_s1[3]); + } +} + +/* number in 0.1 (-995..1995) show: -99..-9.9..199.9..1999 */ +void show_s1_number_x10(int32_t number, uint8_t atr){ + clear_s1(); + show_symbol_s1(atr); + if (number > 99995) { + // "Hi" + display_buff[1] |= BIT(3); + display_buff[2] |= BIT(1) | BIT(2) | BIT(3) | BIT(5) | BIT(6); + } else if (number < -9995) { + // "Lo" + display_buff[1] |= BIT(2) | BIT(3) | BIT(6) | BIT(7); + display_buff[2] |= BIT(1) | BIT(3) | BIT(7); + } else { + if (number > 1999 || number < -99) { + // no point, show: -99..1999 + if (number < 0){ + number = -number; + display_buff[3] |= BIT(2); // "-" + } + number = (number / 10) + ((number % 10) >= 5); // round(div 10) + } else { // show: -9.9..199.9 + display_buff[13] |= BIT(0); // point + if (number < 0){ + number = -number; + display_buff[3] |= BIT(2); // "-" + } + } + /* number: -99..1999 */ + if (number > 999) display_buff[4] |= BIT(4); // "1" 1000..1999 + if (number > 99) lcd_set_digit(display_buff, number / 100 % 10, sb_s1[0]); + if (number > 9) lcd_set_digit(display_buff, number / 10 % 10, sb_s1[1]); + else lcd_set_digit(display_buff, 0, sb_s1[1]); + lcd_set_digit(display_buff, number % 10, sb_s1[2]); + } +} + + +/* number in 0.1 (-9995..99995) show: -999..-99.9..999.9..9999 */ +void show_s3_number_x10(int32_t number, uint8_t atr){ + clear_s3(); + show_symbol_s3(atr); + if (number > 99995) { + // "Hi" + display_buff[8] |= BIT(1) | BIT(2) | BIT(3); + display_buff[9] |= BIT(3) | BIT(5) | BIT(6); + } else if (number < -9995) { + // "Lo" + display_buff[8] |= BIT(1) | BIT(3); + display_buff[9] |= BIT(2) | BIT(3) | BIT(7); + display_buff[10] |= BIT(6) | BIT(7); + } else { + if (number > 9999 || number < -999) { + // no point, show: -999..9999 + if (number < 0){ + number = -number; + display_buff[8] |= BIT(2); // "-" + } + number = (number / 10) + ((number % 10) >= 5); // round(div 10) + } else { // show: -99.9..999.9 + display_buff[11] |= BIT(0); // point + if (number < 0){ + number = -number; + display_buff[8] |= BIT(2); // "-" + } + } + /* number: -999..9999 */ + if (number > 999) lcd_set_digit(display_buff, number / 1000 % 10, sb_s3[0]); + if (number > 99) lcd_set_digit(display_buff, number / 100 % 10, sb_s3[1]); + if (number > 9) lcd_set_digit(display_buff, number / 10 % 10, sb_s3[2]); + else lcd_set_digit(display_buff, 0, sb_s3[2]); + lcd_set_digit(display_buff, number % 10, sb_s3[3]); + } +} + +/* number in 0.1 (-99.5 .1999.5) -99..-9.9..199.9..1999 */ +void show_s4_number_x10(int32_t number, uint8_t atr){ + clear_s4(); + show_symbol_s4(atr); + if (number > 19995) { + // "Hi" + display_buff[13] |= BIT(1) | BIT(2) | BIT(3); + display_buff[14] |= BIT(3) | BIT(5) | BIT(6); + } else if (number < -9995) { + // "Lo" + display_buff[13] |= BIT(1) | BIT(3) | BIT(7); + display_buff[14] |= BIT(2) | BIT(3); + display_buff[15] |= BIT(6) | BIT(7); + } else { + if (number > 999 || number < -1999) { + // no point, show: -99..1999 + if (number < 0){ + number = -number; + display_buff[12] |= BIT(2); // "-" + } + number = (number / 10) + ((number % 10) >= 5); // round(div 10) + } else { // show: -9.99..199.99 + display_buff[14] |= BIT(0); // point + if (number < 0){ + number = -number; + display_buff[12] |= BIT(2); // "-" + } + } + /* number: -9999..19999 */ + if (number > 999) display_buff[12] |= BIT(0); // "1" 10000..19999 + if (number > 99) lcd_set_digit(display_buff, number / 100 % 10, sb_s4[0]); + if (number > 9) lcd_set_digit(display_buff, number / 10 % 10, sb_s4[1]); + else lcd_set_digit(display_buff, 0, sb_s4[1]); + lcd_set_digit(display_buff, number % 10, sb_s4[2]); + } +} + +void show_clock_s3(void) { +#if USE_RTC + uint8_t hrs = rtc.hours; + if(cfg.flg.time_am_pm) { + if(hrs > 12) + hrs -= 12; + else if(!hrs) + hrs = 12; + } + clear_s3(); + display_buff[10] = BIT(0); // ":" + lcd_set_digit(display_buff, hrs / 10 % 10, sb_s3[0]); + lcd_set_digit(display_buff, hrs % 10, sb_s3[1]); + lcd_set_digit(display_buff, rtc.minutes / 10 % 10, sb_s3[2]); + lcd_set_digit(display_buff, rtc.minutes % 10, sb_s3[3]); +#else + uint32_t tmp = utc_time_sec / 60; + uint32_t min = tmp % 60; + uint32_t hrs = tmp / 60 % 24; + + clear_s3(); + display_buff[10] = BIT(0); // ":" + + lcd_set_digit(display_buff, hrs / 10 % 10, sb_s3[0]); + lcd_set_digit(display_buff, hrs % 10, sb_s3[1]); + lcd_set_digit(display_buff, min / 10 % 10, sb_s3[2]); + lcd_set_digit(display_buff, min % 10, sb_s3[3]); +#endif +} + +void show_weekday(void) { + display_buff[4] &= BIT(4); // "1" + display_buff[4] |= sb_dnd[rtc.weekday & 7]; +} + +void show_clock_s1(void) { +#if USE_RTC + clear_s1(); + display_buff[1] = BIT(0); // ":" + uint8_t hrs = rtc.hours; + if(cfg.flg.time_am_pm) { + if(hrs > 12) + hrs -= 12; + else if(!hrs) + hrs = 12; + } + lcd_set_digit(display_buff, hrs / 10 % 10, sb_s1[0]); + lcd_set_digit(display_buff, hrs % 10, sb_s1[1]); + lcd_set_digit(display_buff, rtc.minutes / 10 % 10, sb_s1[2]); + lcd_set_digit(display_buff, rtc.minutes % 10, sb_s1[3]); +#else + uint32_t tmp = utc_time_sec / 60; + uint32_t min = tmp % 60; + uint32_t hrs = tmp / 60 % 24; + + clear_s1(); + display_buff[1] = BIT(0); // ":" + + lcd_set_digit(display_buff, hrs / 10 % 10, sb_s1[0]); + lcd_set_digit(display_buff, hrs % 10, sb_s1[1]); + lcd_set_digit(display_buff, min / 10 % 10, sb_s1[2]); + lcd_set_digit(display_buff, min % 10, sb_s1[3]); +#endif +} + +void show_data_s2(void) { + uint8_t mh, ml, dh, dl; + clear_s2(); + display_buff[5] = BIT(0); // "/" + + display_buff[4] &= BIT(4); // s1: "1" + display_buff[4] |= sb_dnd[rtc.weekday]; + + if (rtc.month >= 10) { + mh = 1; + ml = rtc.month - 10; + } else { + mh = 0; + ml = rtc.month; + } + dh = 0; + dl = rtc.days; + while(dl >= 10) { + dl -= 10; + dh++; + } + if(cfg.flg.time_am_pm) { + lcd_set_digit(display_buff, mh, sb_s2[0]); + lcd_set_digit(display_buff, ml, sb_s2[1]); + lcd_set_digit(display_buff, dh, sb_s2[2]); + lcd_set_digit(display_buff, dl, sb_s2[3]); + } else { + lcd_set_digit(display_buff, dh, sb_s2[0]); + lcd_set_digit(display_buff, dl, sb_s2[1]); + lcd_set_digit(display_buff, mh, sb_s2[2]); + lcd_set_digit(display_buff, ml, sb_s2[3]); + } +} + +void show_battery_s1(uint8_t level) { + clear_s1(); + display_buff[0] |= BIT(7); // "%" + if(level > 99) + lcd_set_digit(display_buff, 1, sb_s1[0]); + lcd_set_digit(display_buff, level / 10 % 10, sb_s1[1]); + lcd_set_digit(display_buff, level % 10, sb_s1[2]); +} + +void show_low_bat(void) { + memset(&display_buff, 0, sizeof(display_buff)); + // s1 "Lo" + display_buff[1] |= BIT(2) | BIT(3) | BIT(6) | BIT(7); + display_buff[2] |= BIT(1) | BIT(3) | BIT(7); + // "bat" + display_buff[17] |= BIT(4); + //show_s1_number_x100(measured_data.battery_mv * 10, 0); + send_to_lcd(); +} + +#if (defined(SHOW_OTA_SCREEN) && SHOW_OTA_SCREEN) +void show_ota_screen(void) { + memset(&display_buff, 0, sizeof(display_buff)); + display_buff[0] = BIT(0) | BIT(2); // "ble", "-" + display_buff[1] = BIT(2); // "-" + display_buff[2] = BIT(2); // "-" + display_buff[3] = BIT(2); // "-" + send_to_lcd(); +} +#endif // SHOW_OTA_SCREEN +#if (defined(SHOW_REBOOT_SCREEN) && SHOW_REBOOT_SCREEN) +void show_reboot_screen(void) { + memset(&display_buff, 0xff, sizeof(display_buff)); + send_to_lcd(); +} +#endif // SHOW_REBOOT_SCREEN + +_attribute_ram_code_ +uint8_t is_comfort(int16_t t, uint16_t h) { + uint8_t ret = LCD_SYM_SMILEY_SAD; + if (t >= cmf.t[0] && t <= cmf.t[1] && h >= cmf.h[0] && h <= cmf.h[1]) + ret = LCD_SYM_SMILEY_HAPPY; + return ret; +} + +_attribute_ram_code_ +__attribute__((optimize("-O2"))) +void lcd(void) { + uint8_t screen_type = cfg.flg2.screen_type; + if(chow_tick_sec >= utc_time_sec) + screen_type = SCR_TYPE_EXT; +// else chow_tick_sec = 0; + + show_ble_symbol(ble_connected || (rest_adv_int_tad & 2)); + + show_battery_symbol(measured_data.battery_mv < 2400); + switch(screen_type) { + case SCR_TYPE_TEMP: + if (cfg.flg.temp_F_or_C) { + if(cfg.flg.x100) + show_s1_number_x100(((measured_data.temp / 5) * 9) + 3200, LCD_SYM_F); // convert C to F + else + show_s1_number_x10(((measured_data.temp_x01 / 5) * 9) + 320, LCD_SYM_F); // convert C to F + } else { + if(cfg.flg.x100) + show_s1_number_x100(measured_data.temp, LCD_SYM_C); + else + show_s1_number_x10(measured_data.temp_x01, LCD_SYM_C); + } + show_clock_s3(); + show_s4_number_x10(measured_data.humi_x01, LCD_SYM_P); + break; + case SCR_TYPE_HUMI: + if(cfg.flg.x100) + show_s1_number_x100(measured_data.humi, LCD_SYM_P); + else + show_s1_number_x10(measured_data.humi_x01, LCD_SYM_P); + show_clock_s3(); + if (cfg.flg.temp_F_or_C) + show_s4_number_x10((((measured_data.temp / 5) * 9) + 3200) / 10, LCD_SYM_F); // convert C to F + else + show_s4_number_x10(measured_data.temp_x01, LCD_SYM_C); + break; + case SCR_TYPE_BAT_P: + show_battery_s1(measured_data.battery_level); + show_battery_symbol(1); + if (cfg.flg.temp_F_or_C) + show_s3_number_x10((((measured_data.temp / 5) * 9) + 3200) / 10, LCD_SYM_F); // convert C to F + else + show_s3_number_x10(measured_data.temp_x01, LCD_SYM_C); + show_s4_number_x10(measured_data.humi_x01, LCD_SYM_P); + break; + case SCR_TYPE_BAT_V: + show_s1_number_x100((measured_data.battery_mv / 10), 0); + show_battery_symbol(1); + if (cfg.flg.temp_F_or_C) + show_s3_number_x10((((measured_data.temp / 5) * 9) + 3200) / 10, LCD_SYM_F); // convert C to F + else + show_s3_number_x10(measured_data.temp_x01, LCD_SYM_C); + show_s4_number_x10(measured_data.humi_x01, LCD_SYM_P); + break; + case SCR_TYPE_EXT: + show_s1_number_x100(ext.number, ext.flg.temp_symbol); + show_battery_symbol(ext.flg.battery); + show_smiley(ext.flg.smiley); + if (cfg.flg.temp_F_or_C) + show_s3_number_x10((((measured_data.temp / 5) * 9) + 3200) / 10, LCD_SYM_F); // convert C to F + else + show_s3_number_x10(measured_data.temp_x01, LCD_SYM_C); + show_s4_number_x10(measured_data.humi_x01, LCD_SYM_P); + break; + default: // SCR_TYPE_TIME + show_clock_s1(); + if (cfg.flg.temp_F_or_C) + show_s3_number_x10((((measured_data.temp / 5) * 9) + 3200) / 10, LCD_SYM_F); // convert C to F + else + show_s3_number_x10(measured_data.temp_x01, LCD_SYM_C); + show_s4_number_x10(measured_data.humi_x01, LCD_SYM_P); + } + display_buff[3] &= ~(BIT(0)); + display_buff[2] &= ~(BIT(0)); + if(cfg.flg.time_am_pm) { + if(rtc.hours >= 12) { + display_buff[2] |= BIT(0); + } else { + display_buff[3] |= BIT(0); + } + } + if (screen_type != SCR_TYPE_EXT) { + if (cfg.flg.comfort_smiley) // smiley = comfort + show_smiley(is_comfort(measured_data.temp, measured_data.humi)); + else + show_smiley(LCD_SYM_SMILEY_NONE); + } + show_data_s2(); +} + + +#endif // DEVICE_TYPE == DEVICE_MJWSD05MMC diff --git a/src/logger.c b/src/logger.c index 600f54bf..891be6cd 100644 --- a/src/logger.c +++ b/src/logger.c @@ -14,15 +14,10 @@ #include "logger.h" #include "ble.h" -#define FLASH_ADDR_START_MEMO 0x40000 -#define FLASH_ADDR_END_MEMO 0x74000 // 49 sectors - #define MEMO_SEC_COUNT ((FLASH_ADDR_END_MEMO - FLASH_ADDR_START_MEMO) / FLASH_SECTOR_SIZE) // 49 sectors #define MEMO_SEC_RECS ((FLASH_SECTOR_SIZE-sizeof(memo_head_t))/sizeof(memo_blk_t)) // - sector: 409 records //#define MEMO_REC_COUNT (MEMO_SEC_RECS*(MEMO_SEC_COUNT-1))// max 48*409 = 20041 records -#define MEMO_SEC_ID 0x55AAC0DE // sector head - #define _flash_erase_sector(a) flash_erase_sector(FLASH_BASE_ADDR + a) #define _flash_write_dword(a,d) { unsigned int _dw = d; flash_write_all_size(FLASH_BASE_ADDR + a, 4, (unsigned char *)&_dw); } #define _flash_write(a,b,c) flash_write_all_size(FLASH_BASE_ADDR + a, b, (unsigned char *)c) @@ -82,7 +77,8 @@ void memo_init_count(void) { } #endif -__attribute__((optimize("-Os"))) void memo_init(void) { +__attribute__((optimize("-Os"))) +void memo_init(void) { memo_head_t mhs; uint32_t tmp, fsec_end; uint32_t faddr = FLASH_ADDR_START_MEMO; @@ -173,6 +169,8 @@ void write_memo(void) { summ_data.count++; if (cfg.averaging_measurements > summ_data.count) return; + if(ble_connected && bls_pm_getSystemWakeupTick() - clock_time() < 125*CLOCK_16M_SYS_TIMER_CLK_1MS) + return; mblk.temp = (int16_t)(summ_data.temp/(int32_t)summ_data.count); mblk.humi = (uint16_t)(summ_data.humi/summ_data.count); mblk.vbat = (uint16_t)(summ_data.battery_mv/summ_data.count); diff --git a/src/logger.h b/src/logger.h index 459febaf..24f29884 100644 --- a/src/logger.h +++ b/src/logger.h @@ -11,6 +11,10 @@ #if USE_FLASH_MEMO +#define MEMO_SEC_ID 0x55AAC0DE // sector head +#define FLASH_ADDR_START_MEMO 0x40000 +#define FLASH_ADDR_END_MEMO 0x74000 // 49 sectors + typedef struct _memo_blk_t { uint32_t time; // time (UTC) int16_t temp; // x0.01 C diff --git a/src/mi_beacon.h b/src/mi_beacon.h index 176b627e..1a9068c8 100644 --- a/src/mi_beacon.h +++ b/src/mi_beacon.h @@ -31,17 +31,20 @@ enum { XIAOMI_DEV_ID_YM_K1501EU = 0x0113, XIAOMI_DEV_ID_V_SK152 = 0x045C, XIAOMI_DEV_ID_SJWS01LM = 0x0863, + XIAOMI_DEV_ID_MJWSD05MMC = 0x2832, XIAOMI_DEV_ID_MJYD02YL = 0x07F6 }XIAOMI_DEV_ID; #if DEVICE_TYPE == DEVICE_LYWSD03MMC -#define XIAOMI_DID XIAOMI_DEV_ID_LYWSD03MMC // 0x055B LCD display LYWSD03MMC +#define XIAOMI_DID XIAOMI_DEV_ID_LYWSD03MMC // 0x055B LCD display LYWSD03MMC +#elif DEVICE_TYPE == DEVICE_MJWSD05MMC +#define XIAOMI_DID XIAOMI_DEV_ID_MJWSD05MMC // 0x2832 LCD display MJWSD05MMC #elif DEVICE_TYPE == DEVICE_MHO_C401 -#define XIAOMI_DID XIAOMI_DEV_ID_MHO_C401 // 0x0387 E-Ink display MHO-C401 +#define XIAOMI_DID XIAOMI_DEV_ID_MHO_C401 // 0x0387 E-Ink display MHO-C401 #elif DEVICE_TYPE == DEVICE_MHO_C401N -#define XIAOMI_DID XIAOMI_DEV_ID_MHO_C401 // 0x0387 E-Ink display MHO-C401 +#define XIAOMI_DID XIAOMI_DEV_ID_MHO_C401 // 0x0387 E-Ink display MHO-C401 #elif DEVICE_TYPE == DEVICE_CGG1 -#define XIAOMI_DID XIAOMI_DEV_ID_CGG1_ENCRYPTED // 0x0B48 E-Ink display CGG1-M "Qingping Temp & RH Monitor" +#define XIAOMI_DID XIAOMI_DEV_ID_CGG1_ENCRYPTED // 0x0B48 E-Ink display CGG1-M "Qingping Temp & RH Monitor" #elif DEVICE_TYPE == DEVICE_CGDK2 #define XIAOMI_DID XIAOMI_DEV_ID_CGDK2 // 0x066F LCD display "Qingping Temp & RH Monitor Lite" #else diff --git a/src/project.mk b/src/project.mk index 37abef7e..132644b1 100644 --- a/src/project.mk +++ b/src/project.mk @@ -4,13 +4,15 @@ OUT_DIR += /src OBJS += \ $(OUT_PATH)/src/utils.o \ $(OUT_PATH)/src/app.o \ -$(OUT_PATH)/src/lcd.o \ +$(OUT_PATH)/src/lcd_lywsd03mmc.o \ $(OUT_PATH)/src/lcd_cgdk2.o \ +$(OUT_PATH)/src/lcd_mjwsd05mmc.o \ $(OUT_PATH)/src/epd_cgg1.o \ -$(OUT_PATH)/src/epd_cgg1_2022.o \ +$(OUT_PATH)/src/epd_cgg1n.o \ $(OUT_PATH)/src/epd_mho_c401.o \ $(OUT_PATH)/src/epd_mho_c401n.o \ $(OUT_PATH)/src/sensors.o \ +$(OUT_PATH)/src/rtc_pcf85163.o \ $(OUT_PATH)/src/trigger.o \ $(OUT_PATH)/src/rds_count.o \ $(OUT_PATH)/src/app_att.o \ diff --git a/src/rds_count.c b/src/rds_count.c index f7c9d765..6183ea1e 100644 --- a/src/rds_count.c +++ b/src/rds_count.c @@ -14,6 +14,7 @@ #include "sensor.h" #include "trigger.h" #include "ble.h" +#include "lcd.h" #include "custom_beacon.h" #if USE_MIHOME_BEACON #include "mi_beacon.h" @@ -97,19 +98,27 @@ void set_rds_adv_data(void) { adv_buf.update_count = 0; // refresh adv_buf.data in next set_adv_data() #if (BLE_EXT_ADV) if (ext_adv_init) { // support extension advertise +#if (DEVICE_TYPE == DEVICE_MJWSD05MMC) + blc_ll_setExtAdvData(ADV_HANDLE0, DATA_OPER_COMPLETE, DATA_FRAGM_ALLOWED, adv_buf.data_size + sizeof(adv_buf.flag), (u8 *)&adv_buf.flag); +#else if (cfg.flg2.adv_flags) blc_ll_setExtAdvData(ADV_HANDLE0, DATA_OPER_COMPLETE, DATA_FRAGM_ALLOWED, adv_buf.data_size + sizeof(adv_buf.flag), (u8 *)&adv_buf.flag); else blc_ll_setExtAdvData(ADV_HANDLE0, DATA_OPER_COMPLETE, DATA_FRAGM_ALLOWED, adv_buf.data_size, (u8 *)&adv_buf.data); +#endif } else #endif { +#if (DEVICE_TYPE == DEVICE_MJWSD05MMC) + bls_ll_setAdvData((u8 *)&adv_buf.flag, adv_buf.data_size + sizeof(adv_buf.flag)); +#else if (cfg.flg2.adv_flags) { bls_ll_setAdvData((u8 *)&adv_buf.flag, adv_buf.data_size + sizeof(adv_buf.flag)); } else { bls_ll_setAdvData((u8 *)&adv_buf.data, adv_buf.data_size); } +#endif } } @@ -140,6 +149,28 @@ static void start_ext_adv(void) { } } +#ifdef GPIO_KEY2 +void set_adv_con_time(int restore) { + if(restore) { + test_config(); + rest_adv_int_tad = 0; + } else { + adv_interval = 1600; // 1 sec + rest_adv_int_tad = -1; + } + if((!ble_connected) && (!blta.adv_duraton_en)) { +#if (BLE_EXT_ADV) + if (ext_adv_init) { // support extension advertise + ll_ext_adv_t *pea = (ll_ext_adv_t *)&app_adv_set_param; + pea->advInt_use = adv_interval; // set next ext.adv. interval + } + else +#endif + ev_adv_timeout(0,0,0); + } +} +#endif // GPIO_KEY2 + _attribute_ram_code_ void rds_suspend(void) { if (!ble_connected) { /* TODO: if connection mode, gpio wakeup throws errors in sdk libs! @@ -154,7 +185,8 @@ _attribute_ram_code_ void rds_suspend(void) { /* if (rds.type) // rds.type: switch or counter */ -_attribute_ram_code_ __attribute__((optimize("-Os"))) +_attribute_ram_code_ +__attribute__((optimize("-Os"))) void rds_task(void) { // rds_input_on(); // in "app_config.h" and WakeupLowPowerCb() if (get_rds_input()) { diff --git a/src/rds_count.h b/src/rds_count.h index 92a02124..a7961625 100644 --- a/src/rds_count.h +++ b/src/rds_count.h @@ -64,6 +64,16 @@ void set_rds_adv_data(void); #endif // defined GPIO_RDS +#ifdef GPIO_KEY2 + +void set_adv_con_time(int restore); + +static inline uint8_t get_key2_pressed(void) { + return BM_IS_SET(reg_gpio_in(GPIO_KEY2), GPIO_KEY2 & 0xff); +} + +#endif // GPIO_KEY2 + #endif // USE_TRIGGER_OUT #endif /* RDS_COUNT_H_ */ diff --git a/src/rtc.h b/src/rtc.h new file mode 100644 index 00000000..11f16e03 --- /dev/null +++ b/src/rtc.h @@ -0,0 +1,64 @@ +/* + * rtc.h + * + * Created on: 02.03.2023 + * Author: pvvx + */ + +#ifndef RTC_H_ +#define RTC_H_ + +#if USE_RTC + +typedef struct { + uint8_t hours; // RTC Time Hours: 0-12 / 0-23 range if H12 (AM/PM) + uint8_t minutes; // RTC Time Minutes: 0-59 range. + uint8_t seconds; // RTC Time Seconds: 0-59 range. + uint8_t weekday; // RTC Date WeekDay: 0-6 range. + uint8_t month; // RTC Date Month + uint8_t days; // RTC Date Days: 1-31 range. + uint8_t year; // RTC Date Year: 0-99 range. +} rtc_time_t; + + +typedef struct _rtc_pcf_reg_t{ + uint8_t sec; + uint8_t min; + uint8_t hrs; + uint8_t days; + uint8_t wkds; + uint8_t cmnths; + uint8_t years; +} rtc_pcf_reg_t; + +typedef union _rtc_registers_t{ + rtc_pcf_reg_t r; + uint8_t uc[7]; +} rtc_registers_t; + +typedef struct __attribute__((packed)) _rtc_regs_t { + uint8_t reg_addr; + rtc_registers_t reg; +} rtc_regs_t; + +extern uint8_t rtc_i2c_addr; +extern rtc_regs_t rtc_reg; +extern rtc_time_t rtc; +extern uint32_t rtc_sync_utime; + +void init_rtc(void); +int rtc_read_all(void); +uint32_t rtc_get_utime(void); +void rtc_set_utime(uint32_t ut); + +// Conversion Utilities +uint32_t rtc_to_utime(rtc_time_t *r); // convert RTC date/time structures to unix time (sec) +void utime_to_rtc(uint32_t ut, rtc_time_t *r); // convert unix time to RTC date/time +uint8_t bcd_to_byte(uint8_t bcd); +uint8_t byte_to_bcd(uint8_t b); +void rtc_to_regs(rtc_time_t *r); +void rtc_regs(rtc_time_t *r); + +#endif // USE_RTC + +#endif /* RTC_H_ */ diff --git a/src/rtc_pcf85163.c b/src/rtc_pcf85163.c new file mode 100644 index 00000000..d17aa871 --- /dev/null +++ b/src/rtc_pcf85163.c @@ -0,0 +1,178 @@ +/* + * rtc_pcf85163.c + * + * Created on: 01.03.2023 + * Author: pvvx + */ +#include +#include "tl_common.h" +#include "app_config.h" +#if USE_RTC +#include "drivers.h" +#include "drivers/8258/gpio_8258.h" +#include "i2c.h" +#include "rtc.h" +#include "app.h" +#define PCF85163_I2C_ADDR 0x51 +RAM uint8_t rtc_i2c_addr; +RAM rtc_regs_t rtc_reg; +RAM rtc_time_t rtc; +RAM uint32_t rtc_sync_utime; + +#define rtc_send_i2c_rega(a) send_i2c_byte(rtc_i2c_addr, a) +#define rtc_set_reg(a, d) send_i2c_word(rtc_i2c_addr, a | (d << 8)) +#define rtc_send_i2c_buf(b, s) send_i2c_buf(rtc_i2c_addr, (uint8_t *) b, s) + +int rtc_read_all(void) { + int ret = -1; + if (rtc_i2c_addr) { + // runtime: 240 us if I2C 450 kHz + ret = read_i2c_byte_addr(rtc_i2c_addr, 2, rtc_reg.reg.uc, + sizeof(rtc_reg.reg.uc)); + } + return ret; +} + +void rtc_set_regs(void) { + if (rtc_i2c_addr) { + rtc_reg.reg_addr = 2; + rtc_send_i2c_buf(&rtc_reg, sizeof(rtc_reg)); + } +} + +// set regs: control_1, control_2 +static const uint8_t rtc_init_b1[3] = { 0, 0, 0 }; +// disable alarm, clk_out, timer +static const uint8_t rtc_init_b2[7] = { 9, 0x80, 0x80, 0x80, 0x80, 0x03, 0x03 }; + +void init_rtc(void) { + // set regs: control_1, control_2 + rtc_i2c_addr = (uint8_t) scan_i2c_addr(PCF85163_I2C_ADDR << 1); + if (rtc_i2c_addr) { + // set regs: control_1, control_2 + rtc_send_i2c_buf(rtc_init_b1, sizeof(rtc_init_b1)); + // disable alarm, clk_out, timer + rtc_send_i2c_buf(rtc_init_b2, sizeof(rtc_init_b2)); + + uint32_t utime = rtc_get_utime(); + + if (rtc_reg.reg.r.sec & 0x80) { +// && utc_time_sec > utime +// && utc_time_sec > 946684800) // Sat Jan 01 2000 00:00:00 + rtc_set_utime(utc_time_sec); + } else { + utc_time_sec = utime; + rtc_sync_utime = 0; + } + } +} + +//------------------------- Conversion Utilities +#define RTC_UNIX_DAYS ((uint32_t)2440588) // 01 Jan 1970 12:00:00 (Unix time) +/* Convert Date/Time structures to unix time (sec) */ +uint32_t rtc_to_utime(rtc_time_t *r) { + uint8_t a, m; + uint16_t y; + uint32_t ut; + // Calculate some coefficients + a = (uint8_t)(14U - r->month) / 12; + y = (uint16_t)(r->year + 6800) - a; // years since 1 March, 4801 BC (2000+4800) + m = (uint8_t)(r->month + (12 * a) - 3); + // Compute Julian day number (from Gregorian calendar date) + ut = r->days; + ut += ((153 * m) + 2) / 5; // Number of days since 1 march + ut += 365 * y; + ut += y / 4; + ut -= y / 100; + ut += y / 400; + ut -= 32045; + // Subtract number of days passed before base date from Julian day number + ut -= RTC_UNIX_DAYS; + // Convert days to seconds + ut *= 86400; + // Increase epoch time by specified time (in seconds) + ut += r->hours * 3600; + ut += r->minutes * 60; + ut += r->seconds; + // Number of seconds passed since the base date + return ut; +} + +/* Convert unix time to RTC date/time */ +void utime_to_rtc(uint32_t ut, rtc_time_t *r) { + uint32_t a, b, c, d; + // calculate utime (Julian day number) from a specified epoch value + a = (ut / 86400) + RTC_UNIX_DAYS; + // day of week + r->weekday = (uint8_t)((a + 1) % 7); + // calculate intermediate values + a += 32044; + b = ((4 * a) + 3) / 146097; + a -= (146097 * b) / 4; + c = ((4 * a) + 3) / 1461; + a -= (1461 * c) / 4; + d = ((5 * a) + 2) / 153; + // date and time + r->days = (uint8_t)(a - (((153 * d) + 2) / 5) + 1); + r->month = (uint8_t)(d + 3 - (12 * (d / 10))); + r->year = (uint8_t)((100 * b) + c - 6800 + (d / 10)); + r->hours = (uint8_t)((ut / 3600) % 24); + r->minutes = (uint8_t)((ut / 60) % 60); + r->seconds = (uint8_t)(ut % 60); +} + +_attribute_ram_code_ uint8_t byte_to_bcd(uint8_t b) { +#if 1 + uint8_t bcd = 0; + while (b >= 10) { + b -= 10; + bcd += 0x10; + } + return bcd + b; +#else + return ((b / 10) << 4) | (b % 10); +#endif +} + +_attribute_ram_code_ uint8_t bcd_to_byte(uint8_t bcd) { + return ((bcd & 0xf0) >> 4) * 10 + (bcd & 0x0f); +} + +void rtc_to_regs(rtc_time_t *r) { + rtc_reg.reg.r.sec = byte_to_bcd(r->seconds); + rtc_reg.reg.r.min = byte_to_bcd(r->minutes); + rtc_reg.reg.r.hrs = byte_to_bcd(r->hours); + rtc_reg.reg.r.wkds = r->weekday & 0x7; + rtc_reg.reg.r.days = byte_to_bcd(r->days); + rtc_reg.reg.r.cmnths = byte_to_bcd(r->month); + rtc_reg.reg.r.years = byte_to_bcd(r->year); +} + +void rtc_regs(rtc_time_t *r) { + r->seconds = bcd_to_byte(rtc_reg.reg.r.sec & 0x7f); + r->minutes = bcd_to_byte(rtc_reg.reg.r.min & 0x7f); + r->hours = bcd_to_byte(rtc_reg.reg.r.hrs & 0x3f); + r->weekday = rtc_reg.reg.r.wkds & 0x07; + r->days = bcd_to_byte(rtc_reg.reg.r.days & 0x3f); + r->month = bcd_to_byte(rtc_reg.reg.r.cmnths & 0x1f); + r->year = bcd_to_byte(rtc_reg.reg.r.years); +} + +// ----------------------- + +void rtc_set_utime(uint32_t ut) { + utime_to_rtc(ut, &rtc); + rtc_to_regs(&rtc); + rtc_set_regs(); + rtc_sync_utime = 0; +} + +uint32_t rtc_get_utime(void) { + if(rtc_read_all() == 0) + rtc_regs(&rtc); + else + utime_to_rtc(utc_time_sec, &rtc); + return rtc_to_utime(&rtc); +} + +#endif // USE_RTC diff --git a/src/sensors.c b/src/sensors.c index d5219807..8656be18 100644 --- a/src/sensors.c +++ b/src/sensors.c @@ -116,8 +116,8 @@ _attribute_ram_code_ __attribute__((optimize("-Os"))) int read_sensor_cb(void) { 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); + //gpio_setup_up_down_resistor(I2C_SCL, PM_PIN_PULLUP_10K); + //gpio_setup_up_down_resistor(I2C_SDA, PM_PIN_PULLUP_10K); } if (sensor_i2c_addr == 0) { if(check_sensor()) @@ -204,8 +204,8 @@ _attribute_ram_code_ void start_measure_sensor_deep_sleep(void) { send_sensor_byte(SHT4x_MEASURE_HI); } else return; - gpio_setup_up_down_resistor(I2C_SCL, PM_PIN_PULLUP_1M); - gpio_setup_up_down_resistor(I2C_SDA, PM_PIN_PULLUP_1M); + //gpio_setup_up_down_resistor(I2C_SCL, PM_PIN_PULLUP_1M); + //gpio_setup_up_down_resistor(I2C_SDA, PM_PIN_PULLUP_1M); timer_measure_cb = clock_time() | 1; } diff --git a/src/trigger.c b/src/trigger.c index 25de3973..99ac2b35 100644 --- a/src/trigger.c +++ b/src/trigger.c @@ -12,6 +12,7 @@ #include "drivers.h" #include "sensor.h" #include "trigger.h" +#include "rds_count.h" const trigger_t def_trg = { .temp_threshold = 2100, // 21 °C @@ -20,6 +21,9 @@ const trigger_t def_trg = { .humi_hysteresis = 0 // disable #if USE_WK_RDS_COUNTER ,.rds_time_report = 3600 // 1 hours +#if DEVICE_TYPE == DEVICE_MJWSD05MMC + ,.rds.type = RDS_SWITCH +#endif #endif }; diff --git a/src/trigger.h b/src/trigger.h index 5c9feb63..a086c1f7 100644 --- a/src/trigger.h +++ b/src/trigger.h @@ -17,6 +17,9 @@ typedef struct __attribute__((packed)) _trigger_flg_t { uint8_t trigger_on : 1; // Output GPIO_TRG pin is controlled according to the set parameters threshold temperature or humidity uint8_t temp_out_on : 1; // Temperature trigger event uint8_t humi_out_on : 1; // Humidity trigger event +#if (DEVICE_TYPE == DEVICE_MJWSD05MMC) + uint8_t key2pressed : 1; // Key2 pressed +#endif }trigger_flg_t; typedef struct __attribute__((packed)) _rds_type_t {