瀏覽代碼

Системные настройки, переменные, скрипты.

TelenkovDmitry 9 月之前
父節點
當前提交
afc7ceeb21

+ 13 - 5
fw/modules/log/log.c

@@ -22,6 +22,8 @@ SemaphoreHandle_t log_mutex;
 uint16_t log_entries_capacity;
 uint16_t archive_entries_capacity;
 
+void log_task(void *params);
+
 
 
 //
@@ -113,8 +115,8 @@ void log_init(bool format)
     log_entries_capacity = ringfs_capacity(&fs_log);
     
     archive_entries_capacity = ringfs_capacity(&fs_archive);
-      
-	//xTaskCreate(log_task, ( char * ) "log_task", configMINIMAL_STACK_SIZE * 2, NULL, tskIDLE_PRIORITY, NULL);
+    
+	xTaskCreate(log_task, "log_task", 2*configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY, NULL);
 }
 
 //
@@ -247,13 +249,13 @@ void log_info(uint8_t val)
     
     if (val == 0)
     {
-        DBG printf("Log partition capasity: %u\r\n", capacity_flash);
+        DBG printf("Log partition capacity: %u\r\n", capacity_flash);
         DBG printf("Count log entry: %u\r\n", count_flash);
         DBG printf("Estimate count: %u\r\n", count_estimate);
     }
     else 
     {
-        DBG printf("Archive partition capasity: %u\r\n", capacity_flash);
+        DBG printf("Archive partition capacity: %u\r\n", capacity_flash);
         DBG printf("Count archive entry: %u\r\n", count_flash);
         DBG printf("Estimate count: %u\r\n", count_estimate);
     }
@@ -326,8 +328,14 @@ void test_fetch(void)
 
 
 
+void log_task(void *params)
+{
+    for (;;)
+    {
+        vTaskDelay(1000);
 
-
+    }
+}
 
 
 

+ 2 - 2
fw/modules/log/log.h

@@ -14,11 +14,11 @@ extern "C" {
 
 #define LOG_FLASH_SECTOR_OFFSET         4
 
-#define LOG_FLASH_SECTOR_COUNT          252
+#define LOG_FLASH_SECTOR_COUNT          51 //252
 
 #define ARCHIVE_FLASH_SECTOR_OFFSET     260
 
-#define ARCHIVE_FLASH_SECTOR_COUNT      252
+#define ARCHIVE_FLASH_SECTOR_COUNT      38 //252
 
 #define SECTOR_COUNT (spi_flash_desc.sector_count/2 - LOG_FLASH_SECTOR_OFFSET)
 

+ 9 - 8
fw/modules/modbus/modbus.c

@@ -157,18 +157,19 @@ void modbus_params(void *params)
                 
                   
                 case MB_SAVE_SETTINGS :
-#if 0                
-                    settings_save();
-#endif                  
+                    
+                    settings_save(&settings);
+
                 break;
                 
                 case MB_SAVE_SYS_SETTINGS :
-#if 0
-                    if (set_sys_settings_flag) {
+
+                    if (save_sys_cmd) {
+                        save_sys_cmd = 0;
                         memcpy(&sys_settings, &temp_sys_settings, sizeof(sys_settings));
-                        sys_settings_save();
+                        sys_save(&sys_settings);
                     }
-#endif                  
+
                 break;
                 
                 case MB_RESET :
@@ -490,6 +491,6 @@ eMBFuncReadFileRecordCB( UCHAR * pucFrame, USHORT * usLen )
 //
 void cb_settings_timer(TimerHandle_t timer)
 {
-    printf("Settings timer callback\r\n");
+    DBG printf("Settings timer callback\r\n");
     psw_ok = false;
 }

+ 72 - 1
fw/modules/modbus/modbus_params.c

@@ -20,6 +20,8 @@ uint32_t rtc_sinhro;
 uint16_t psw;   
 bool psw_ok = false;
 uint8_t fw_version[8];
+uint16_t save_sys_cmd = 0;  // Команда сохранения системных настроек
+uint16_t system_cmd = 0;	// Команда управления контроллером
 
 void get_time(uint8_t* buf, uint8_t size);
 void get_din_mode(uint8_t* buf, uint8_t size);
@@ -185,7 +187,23 @@ void mb_init_params(void)
         index++;
     }
     
+    // ---------------------------------------------------------------------- //
+	//	Управление контроллером. Разные параметры.
+	// ---------------------------------------------------------------------- //
+    
+    // Управление контроллером
+    mb_param[index].reg = 0x0800;
+	mb_param[index].size = 1;
+	mb_param[index].param = (uint8_t*)&system_cmd; // 
+	mb_param[index].set = mb_control;
+    mb_param[index].get = NULL;
+    mb_param[index].check_handler = mb_check_dummy;
+    
+    index++;
+    
+    // ---------------------------------------------------------------------- //
     // Журналы/рахивы
+    // ---------------------------------------------------------------------- //
     
     // Емкость журнала (максимальная)
     mb_param[index].reg = 0x0900;
@@ -225,6 +243,16 @@ void mb_init_params(void)
     mb_param[index].get = get_archive_entries_number;
     mb_param[index].check_handler = mb_check_dummy;
     
+    index++;
+    
+    // Период архива
+    mb_param[index].reg = 0x0904;
+	mb_param[index].size = 1;
+	mb_param[index].param = (uint8_t*)&settings.period_archive;
+	mb_param[index].set = NULL;
+    mb_param[index].get = NULL;
+    mb_param[index].check_handler = mb_check_archiv_per;
+    
     index++;
     
 	// ---------------------------------------------------------------------- //
@@ -292,7 +320,15 @@ void mb_init_params(void)
     
     index++;
     
+    // Команда на сохранение системных настроек
+    mb_param[index].reg = 0x008B;
+	mb_param[index].size = 1;
+	mb_param[index].param = (uint8_t*)&save_sys_cmd; // 
+	mb_param[index].set = mb_sys_settings_save;
+    mb_param[index].get = NULL;
+    mb_param[index].check_handler = mb_check_dummy;
     
+    index++;
 }
 
 
@@ -459,6 +495,36 @@ mb_delay_action_t mb_password(void)
     }
 }
 
+//
+mb_delay_action_t mb_sys_settings_save(void)
+{
+    if (save_sys_cmd == 1)
+        return MB_SAVE_SYS_SETTINGS;
+    else
+        return MB_NO_ACTION;
+}
+
+//
+mb_delay_action_t mb_control(void)
+{
+    if (system_cmd == 1)
+        return MB_SAVE_SETTINGS;
+  
+    return MB_NO_ACTION;
+    
+#if 0
+    if (system_cmd == 1)
+        return MB_SAVE_SETTINGS;
+    else if (system_cmd == 2)
+        return MB_DEF_SETTINGS;
+    else if (system_cmd == 3)
+        return MB_RESET;
+    else if (system_cmd == 4)
+        return MB_PART_DEF_SETTINGS;
+
+    return MB_NO_ACTION;
+#endif    
+}
 
 // -------------------------------------------------------------------------- //
 //                      Проверка параметров                                   //
@@ -469,6 +535,11 @@ void mb_check_dummy(void)
 {
 }
 
-
+//
+void mb_check_archiv_per(void)
+{
+    if (settings.period_archive > (uint16_t)MAX_ARCHIVE_PERIOD)
+        settings.period_archive = (uint16_t)MAX_ARCHIVE_PERIOD;
+}
 
 

+ 15 - 1
fw/modules/modbus/modbus_params.h

@@ -14,7 +14,7 @@ extern "C" {
 
 #define SWAP_16(x, y)   {x[0] = y >> 8; x[1] = y & 0x0FF;}
   
-#define MB_PARAM_MAX			66 //54
+#define MB_PARAM_MAX			69 //54
 
 
 //
@@ -73,6 +73,13 @@ mb_delay_action_t mb_set_do_mode(void);
 //
 mb_delay_action_t mb_password(void);
 
+//
+mb_delay_action_t mb_sys_settings_save(void);
+
+//
+mb_delay_action_t mb_control(void);
+
+
 // -------------------------------------------------------------------------- //
 //                      Проверка параметров                                   //
 // -------------------------------------------------------------------------- //
@@ -80,6 +87,13 @@ mb_delay_action_t mb_password(void);
 //
 void mb_check_dummy(void);
 
+//
+void mb_check_archiv_per(void);
+
+
+
+extern uint16_t save_sys_cmd;  // Команда сохранения системных настроек
+
 #ifdef __cplusplus
 }
 #endif

+ 5 - 0
fw/modules/settings/settings_api.h

@@ -15,6 +15,11 @@
 #define SETTINGS_VERSION    0x01
 
 
+// ------------------------------------------------------------------- //
+//					 	Граничные значения
+// ------------------------------------------------------------------- //
+
+#define MAX_ARCHIVE_PERIOD  43200
 
 // ------------------------------------------------------------------- //
 //					 		Draft

+ 4 - 2
fw/user/main.cpp

@@ -89,7 +89,7 @@ int main(void)
     
     xTaskCreate(test_gpio, "gpio_task", 2*configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY, NULL);
     
-    //xTaskCreate(input_task, "input_task", 2*configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY, NULL);
+    xTaskCreate(input_task, "input_task", 2*configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY, NULL);
     
     xTaskCreate(misc_task, "misc_task", 2*configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY, NULL);
     
@@ -183,7 +183,7 @@ void init_task(void *argument)
 // Базовая инициализация входов/выходов
 // TODO потом брать значения из настроек
 
-    //io_init();
+    io_init();
     
 // -------------------------------------------------------------------------- //        
 // Сброс счетчика попыток загрузок
@@ -208,8 +208,10 @@ void init_task(void *argument)
     
 // -------------------------------------------------------------------------- //    
 // DAC    
+/*    
     dac_gpio_init();
     dac_test(CH_DAC_1, 30000);  
+*/    
 /*    
     dac_test(CH_DAC_2, 10000);  
     dac_test(CH_DAC_3, 10000);

+ 2 - 2
libs/thirdparty/ringfs/ringfs.c

@@ -151,12 +151,12 @@ int ringfs_init(struct ringfs *fs, struct ringfs_flash_partition *flash, uint32_
     fs->object_size = object_size;
 
     /* Precalculate commonly used values. */
-#if 0    
+#if 1    
     fs->slots_per_sector = (fs->flash->sector_size - sizeof(struct sector_header)) /
                            (sizeof(struct slot_header) + fs->object_size);
 #endif
     
-    fs->slots_per_sector = 20;
+    //fs->slots_per_sector = 20;
     
     return 0;
 }

二進制
output/fw.bin


文件差異過大導致無法顯示
+ 474 - 475
project/ewarm/iap/iap.dep


文件差異過大導致無法顯示
+ 720 - 738
project/ewarm/module_universal_io.dep


二進制
tools/__pycache__/io_module.cpython-310.pyc


二進制
tools/__pycache__/log_reader.cpython-310.pyc


二進制
tools/__pycache__/mb_registers.cpython-310.pyc


二進制
tools/__pycache__/sys_params.cpython-310.pyc


二進制
tools/__pycache__/updater.cpython-310.pyc


+ 38 - 0
tools/digital_io.py

@@ -0,0 +1,38 @@
+from io_module import IO_Module
+from modbus import Modbus, MBError, NoResponseError
+from log_reader import DigitalLogReader
+import log_reader
+import colorama
+from colorama import Fore
+from time import sleep
+
+
+class IO_Digital(IO_Module):
+    def __init__(self, tty: str, brate: int, address: int):
+        self.modbus = Modbus(tty, brate, address)
+        super().__init__(self.modbus)
+        self.log = DigitalLogReader(self.modbus)
+ 
+    
+
+
+def main():
+    colorama.init(autoreset=True)
+    dev = IO_Digital('COM24', 115200, 15)
+    dev.MB_DEBUG = False
+
+    '''Системные переменные и параметры'''
+    # dev.sys.set_system_vars(1234)
+    dev.sys.get_system_vars()
+    
+    '''Лог и архив. Настройки лога.'''
+    dev.log.get_log_info()
+    dev.log.get_random_entries()
+    # dev.log.set_archive_period(10)
+    
+    '''Сохранение настроек'''
+    # dev.sys.save_sattings()
+    
+    
+if __name__ == '__main__':
+    main()

+ 12 - 136
tools/io_module.py

@@ -1,4 +1,6 @@
-from modbus import Modbus, MBError, NoResponseError
+from modbus import Modbus
+from updater import Updater
+from sys_params import IO_SysParams
 import colorama
 from colorama import Fore
 import time
@@ -6,90 +8,14 @@ import os
 import struct
 import random
 
-models = {0x100: 'MDIO_88', 0x200: 'MAO_8', 0x300: 'MAI_12'}
-
-MODEL_MDIO_88 = 0x0100
-MODEL_MAO_8 = 0x0200
-MODEL_MAI_12 = 0x0300
-
-SYS_TEST_OK = 0x0001
-
-
-
-reg_table = {'in_bits': 0x0100, 'in_cnt': 0x0102, 'in_mode': 0x0120, 'in_norm': 0x0122, 'in_deb_start': 0x124,
-             'out_cur': 0x0200, 'out_mode': 0x0202, 'out_mode_save': 0x0203, 'pwm_duty': 0x0210,
-             'pwm_duty_save': 0x0220, 'pwm_per': 0x0230, 'pwm_per_save': 0x0240, 
-             'rtc_unix': 0x0802, 'rtc_sinhro': 0x0804, 'uptime': 0x0800, 'log_info': 0x0900, 
-             'log_ent': 0x0901, 'arch_cap': 0x0902, 'arch_ent': 0x0903,
-             'model': 0x0080, 'prod_date': 0x0081, 'serial_number': 0x0083, 'fw_ver': 0x0085, 
-             'test_status': 0x0089, 'password': 0x008A}
-
-
-class IO_Module(Modbus):
-    def __init__(self, tty: str, brate: int, address: int):
-        super().__init__(tty, brate, address)
-        self.update_segment_number = 0
-
-    def iap_start(self):
-        """Reboot device in IAP mode"""
-        request = bytes((self.address, 0x41, 0x01))
-        response = self.raw_communicate(request + self._crc(request))
-
-    def write_fw_start(self, size: int):
-        """Ask device to start update"""
-        self.update_segment_number = 0
-        request = bytes((self.address, 0x41, 0x01, 0xEF, 0xBE, 0xAD, 0xDE)) + size.to_bytes(4, 'big')
-        response = self.raw_communicate(request + self._crc(request), 5)
-        if len(response) == 0:
-            raise NoResponseError('No response on WRITE_START command')
-        if len(response) != 5:
-            raise MBError('Incorrect response length')
-        if response[:3] != bytes((self.address, 0x41, 0x01)):
-            raise MBError('Incorrect response')
-
-    def write_fw_part(self, data: bytes):
-        """Write piece of FW data in IAP mode"""
-        header = bytes((self.address, 0x41, 0x02))
-        request = b''.join((header, self.update_segment_number.to_bytes(2, 'big'), data))
-        response = self.raw_communicate(request + self._crc(request), 5)
-        # self.print_hex(response)
-        if len(response) != 5:
-            raise MBError('Incorrect response length')
-        if (response[:3]) != header:
-            raise MBError('Incorrect response')
-        self.update_segment_number += 1
-
-    def iap_finish(self):
-        """Complete FW transmission and check response"""
-        header = request = bytes((self.address, 0x41, 0x03))
-        response = self.raw_communicate(request + self._crc(request), 5)
-        if len(response) != 5:
-            raise MBError('Incorrect response length')
-        if response[:3] != header:
-            raise MBError('Incorrect response')
-
-    def update(self, path):
-        self.MB_TIMEOUT = 3
-        size = os.path.getsize('fw.bin')
-        print('Switch to IAP mode')
-        self.iap_start()
-        time.sleep(4)
-        print(f'Start writing {size} bytes of FW')
-        self.write_fw_start(size)
-        time.sleep(2)
-        print(f'Open FW file "{path}"...')
-        with open(path, 'rb') as f:
-            done = progress_cur = progress_pre = 0
-            while True:
-                buf = f.read(128)
-                if len(buf):
-                    self.write_fw_part(buf)
-                    progress_cur = done / size
-                else:
-                    break
-        print('End of transmission')
-        self.iap_finish()
 
+class IO_Module:
+    def __init__(self, modbus: Modbus):
+        self.modbus = modbus
+        self.updater = Updater(self.modbus)
+        self.sys = IO_SysParams(self.modbus)
+
+'''
     # 0x0100 - текущее состояние входов
     def get_inputs_bit(self) -> str:
         data = self.read_holding_registers(reg_table['in_bits'], 1)
@@ -227,55 +153,10 @@ class IO_Module(Modbus):
 
     def set_rtc(self, utc):
         self.write_uint32(reg_table['rtc_sinhro'], utc)
+'''
 
 
-
-def set_system_vars(dev: IO_Module, password: int):
-    # Отправка пароля для разблокирования доступа к системным настройкам
-    dev.write_holding_register(reg_table['password'], password)
-
-    # time.sleep(0.1)
-    # Модель
-    # dev.write_holding_register(reg_table['model'], SYS_MODEL_MDIO_88)
-    # Дата производства
-    # dev.write_holding_register(reg_table['prod_time'], int(time.time()) - 3600*24)
-    # Серийный номер
-    # dev.write_holding_register(reg_table['serial'], random.randint(10000, 1000000))
-
-    # Статус тестирования
-    # dev.write_holding_register(reg_table['test_status'], SYS_TEST_OK)
-
-
-def get_system_vars(dev: IO_Module):
-    """Запрос системных настроек и параметров"""
-    # Модель
-    model = dev.read_holding_registers(reg_table['model'], 1)[0]
-    print("Model:       ", models[model])
-
-    # Дата производства    
-    prod_date = dev.read_uint32_holding(reg_table['prod_date'])
-    print("Prod date:   ", prod_date)
-
-    # Серийный номер
-    serial_number = dev.read_uint32_holding(reg_table['serial_number'])
-    print("SN:          ", serial_number)
-
-    # Версия ПО
-    fw_bytes = b''
-    data = dev.read_holding_registers(reg_table['fw_ver'], 4)
-    fw_raw = list(data)
-    fw_raw.reverse()
-    for i in fw_raw:
-        fw_bytes += i.to_bytes(2, 'little')
-
-    fw = fw_bytes.decode('utf-8')
-    print("FW version:  ", fw)
-
-    # Статус тестирования
-    test_status = dev.read_holding_registers(reg_table['test_status'], 1)[0]
-    print("Test status: ", test_status)
-
-    
+   
 
 
 def main():
@@ -285,8 +166,6 @@ def main():
     
     # dev.update('fw.bin')
 
-    # Запрос системных параметров, установка времени
-    
     # print('Device uptime:', dev.get_uptime())
     # unix_time = dev.get_rtc()
     # print(f'RTC: {time.ctime(unix_time)}. Unix time stamp:  {unix_time}')
@@ -296,9 +175,6 @@ def main():
     # unix_time = dev.get_rtc()
     # print(f'RTC: {time.ctime(unix_time)}. Unix time stamp:  {unix_time}')
     
-    set_system_vars(dev, 1234)
-
-    # get_system_vars(dev)
     
     return
 

+ 34 - 14
tools/log_reader.py

@@ -1,5 +1,5 @@
-from io_module import IO_Module
-from io_module import reg_table
+from modbus import Modbus
+from mb_registers import reg_table
 from colorama import Fore
 from random import randint
 from time import sleep
@@ -10,46 +10,63 @@ ARCHIVE_ENTRY = 0x06
 LOG_ENTRY = 0x07
 
 
-class LogReader(IO_Module):
-    def __init__(self, tty: str, brate: int, address: int):
-        super().__init__(tty, brate, address)
-        colorama.init(autoreset=True)
+class LogReader():
+    def __init__(self, modbus: Modbus):
+        self.modbus = modbus
         self.log_capacity = 0
         self.log_entries_number = 0
         self.archive_capacity = 0
         self.archive_entries_number = 0    
+        self.archive_period = 0
+        colorama.init(autoreset=True)
 
     def get_archive(self):
         print("LogReader")
 
     def get_log_info(self):
-        data = self.read_holding_registers(reg_table['log_info'], 4)
+        data = self.modbus.read_holding_registers(reg_table['log_info'], 5)
         self.log_capacity = data[0]
         self.log_entries_number = data[1]
         self.archive_capacity = data[2]
         self.archive_entries_number = data[3]
+        self.archive_period = data[4]
+
+        print(Fore.CYAN + "Log and archive params:\n")
         print('Log capacity           :', Fore.CYAN + str(self.log_capacity))
         print('Log entries number     :', Fore.CYAN + str(self.log_entries_number))
         print('Archive capacity       :', Fore.CYAN + str(self.archive_capacity))
         print('Archive entries number :', Fore.CYAN + str(self.archive_entries_number))
+        print('Archive period         :', Fore.CYAN + str(self.archive_period), end='\n')
 
+    def set_archive_period(self, value):
+        self.modbus.write_holding_register(reg_table['archive_per'], value)
 
 class DigitalLogReader(LogReader):
-    def __init__(self, tty: str, brate: int, address: int):
-        super().__init__(tty, brate, address)
+    def __init__(self, modbus: Modbus):
+        super().__init__(modbus)
 
     def get_archive(self):
         print("DigitalLogReader")
 
     def get_random_archive_entry(self):
-        data = self.read_file_record(ARCHIVE_ENTRY, randint(1, self.archive_entries_number), 1)
+        data = self.modbus.read_file_record(ARCHIVE_ENTRY, randint(1, self.archive_entries_number), 1)
         entry = struct.unpack('<QBB', data[5:15])
-        print(entry)
+        print(Fore.CYAN + str(entry))
 
     def get_random_log_entry(self):
-        data = self.read_file_record(LOG_ENTRY, randint(1, self.log_entries_number), 1)
+        data = self.modbus.read_file_record(LOG_ENTRY, randint(1, self.log_entries_number), 1)
         entry = struct.unpack('<QBBBfB', data[5:21])
-        print(entry)
+        print(Fore.CYAN + str(entry))
+
+    def get_random_entries(self):
+        '''Читаем лог и архив'''
+        print(Fore.CYAN + "\nEntries:\n")
+        while (1):
+            self.get_random_archive_entry()
+            sleep(0.1)
+            self.get_random_log_entry()
+            sleep(0.1)
+
 
 
 class AnalogInputLogReader(LogReader):
@@ -66,7 +83,10 @@ def main():
     module = DigitalLogReader('COM24', 115200, 15)
 
     module.get_log_info()
-    module.get_archive()
+    # module.get_archive()
+    # module.set_archive_period(10)
+
+    return
 
     # for i in range(500):
     while (1):

+ 7 - 0
tools/mb_registers.py

@@ -0,0 +1,7 @@
+reg_table = {'in_bits': 0x0100, 'in_cnt': 0x0102, 'in_mode': 0x0120, 'in_norm': 0x0122, 'in_deb_start': 0x124,
+             'out_cur': 0x0200, 'out_mode': 0x0202, 'out_mode_save': 0x0203, 'pwm_duty': 0x0210,
+             'pwm_duty_save': 0x0220, 'pwm_per': 0x0230, 'pwm_per_save': 0x0240,
+             'param_manager': 0x0800, 'rtc_unix': 0x0802, 'rtc_sinhro': 0x0804, 'uptime': 0x0800, 'log_info': 0x0900, 
+             'log_ent': 0x0901, 'arch_cap': 0x0902, 'arch_ent': 0x0903, 'archive_per': 0x0904,
+             'model': 0x0080, 'prod_date': 0x0081, 'serial_number': 0x0083, 'fw_ver': 0x0085, 
+             'test_status': 0x0089, 'password': 0x008A, 'save_sys_settings': 0x008B}

+ 102 - 0
tools/sys_params.py

@@ -0,0 +1,102 @@
+"""Модуль для работы с сис"""
+from modbus import Modbus
+from mb_registers import reg_table
+from colorama import Fore
+import time
+import random
+
+models = {0x100: 'MDIO_88', 0x200: 'MAO_8', 0x300: 'MAI_12'}
+test_state = {0: 'No Test', 1: 'Test OK', 2: 'Test FAIL'}
+
+
+class IO_SysParams:
+    def __init__(self, modbus: Modbus):
+        self.modbus = modbus
+
+        self.MODEL_MDIO_88 = 0x0100
+        self.MODEL_MAO_8 = 0x0200
+        self.MODEL_MAI_12 = 0x0300
+
+        self.SYS_TEST_OK = 0x0001
+        self.SAVE_SYS_SETTINGS = 0x0001
+        self.SAVE_SETTIGNS = 0x0001
+
+    def get_system_vars(self):
+        """Запрос системных настроек и параметров"""
+
+        print(Fore.LIGHTMAGENTA_EX + "\nSystem settings and params:\n")
+
+        # Модель
+        model = self.modbus.read_holding_registers(reg_table['model'], 1)[0]
+        print("Model:       ", Fore.LIGHTMAGENTA_EX + models[model])
+
+        # Дата производства    
+        prod_date = self.modbus.read_uint32_holding(reg_table['prod_date'])
+        t = time.gmtime(prod_date)
+        print("Prod date:   ", Fore.LIGHTMAGENTA_EX + "{}.{}.{} {}:{}:{}".format(t.tm_mday, t.tm_mon, t.tm_year,
+                                                      t.tm_hour, t.tm_min, t.tm_sec))
+
+        # Серийный номер
+        serial_number = self.modbus.read_uint32_holding(reg_table['serial_number'])
+        print("SN:          ", Fore.LIGHTMAGENTA_EX + str(serial_number))
+
+        # Версия ПО
+        fw_bytes = b''
+        data = self.modbus.read_holding_registers(reg_table['fw_ver'], 4)
+        fw_raw = list(data)
+        fw_raw.reverse()
+        for i in fw_raw:
+            fw_bytes += i.to_bytes(2, 'little')
+
+        fw = fw_bytes.decode('utf-8')
+        print("FW version:  ", Fore.LIGHTMAGENTA_EX + fw)
+
+        # Статус тестирования
+        status = self.modbus.read_holding_registers(reg_table['test_status'], 1)[0]
+        print("Test status: ", Fore.LIGHTMAGENTA_EX + test_state[status])
+        print('\n')
+
+    def set_system_vars(self, password: int):
+        """Установка системных настроек"""
+        # Отправка пароля для разблокирования доступа к системным настройкам
+        print("Send password...")
+        self.modbus.write_holding_register(reg_table['password'], password)
+        time.sleep(0.1)
+
+        # Дата производства. На день назад от текущего момента.
+        prod_time = int(time.time()) - time.timezone - 3600*24
+        print("Set production date: ", prod_time)
+        self.modbus.write_uint32(reg_table['prod_date'], prod_time)
+
+        # Серийный номер
+        sn = random.randint(10000, 1000000)
+        print("Set SN: ", sn)
+        self.modbus.write_uint32(reg_table['serial_number'], sn)
+
+        # Статус тестирования
+        print("Set test status: Test OK")
+        self.modbus.write_holding_register(reg_table['test_status'], self.SYS_TEST_OK)
+
+        # Команда сохранения системных настроек
+        print("Save system settings...")
+        self.modbus.write_holding_register(reg_table['save_sys_settings'], self.SAVE_SYS_SETTINGS)
+
+
+    def save_sattings(self):
+        self.modbus.write_holding_register(reg_table['param_manager'], self.SAVE_SETTIGNS)
+
+
+# def set_manager_register(dev: IO_Module, commands: list):
+#     foo = 0
+#     for command in commands:
+#         foo |= command
+#     print(foo)
+    
+#     # dev.write_holding_register(reg_table['param_manager'])
+
+
+def main():
+    pass
+
+if __name__ == '__main__':
+    main()

+ 77 - 0
tools/updater.py

@@ -0,0 +1,77 @@
+from modbus import Modbus, MBError, NoResponseError
+import time
+import os
+
+class Updater:
+
+    def __init__(self, modbus: Modbus):
+        self.modbus = modbus
+        self.update_segment_number = 0
+
+    def iap_start(self):
+        """Reboot device in IAP mode"""
+        request = bytes((self.modbus.address, 0x41, 0x01))
+        response = self.modbus.raw_communicate(request + self.modbus._crc(request))
+
+    def write_fw_start(self, size: int):
+        """Ask device to start update"""
+        self.update_segment_number = 0
+        request = bytes((self.modbus.address, 0x41, 0x01, 0xEF, 0xBE, 0xAD, 0xDE)) + size.to_bytes(4, 'big')
+        response = self.modbus.raw_communicate(request + self._crc(request), 5)
+        if len(response) == 0:
+            raise NoResponseError('No response on WRITE_START command')
+        if len(response) != 5:
+            raise MBError('Incorrect response length')
+        if response[:3] != bytes((self.modbus.address, 0x41, 0x01)):
+            raise MBError('Incorrect response')
+
+    def write_fw_part(self, data: bytes):
+        """Write piece of FW data in IAP mode"""
+        header = bytes((self.modbus.address, 0x41, 0x02))
+        request = b''.join((header, self.update_segment_number.to_bytes(2, 'big'), data))
+        response = self.modbus.raw_communicate(request + self.modbus._crc(request), 5)
+        # self.print_hex(response)
+        if len(response) != 5:
+            raise MBError('Incorrect response length')
+        if (response[:3]) != header:
+            raise MBError('Incorrect response')
+        self.update_segment_number += 1
+
+    def iap_finish(self):
+        """Complete FW transmission and check response"""
+        header = request = bytes((self.modbus.address, 0x41, 0x03))
+        response = self.modbus.raw_communicate(request + self.modbus._crc(request), 5)
+        if len(response) != 5:
+            raise MBError('Incorrect response length')
+        if response[:3] != header:
+            raise MBError('Incorrect response')
+
+    def update(self, path):
+        self.modbus.MB_TIMEOUT = 3
+        size = os.path.getsize('fw.bin')
+        print('Switch to IAP mode')
+        self.iap_start()
+        time.sleep(4)
+        print(f'Start writing {size} bytes of FW')
+        self.write_fw_start(size)
+        time.sleep(2)
+        print(f'Open FW file "{path}"...')
+        with open(path, 'rb') as f:
+            done = progress_cur = progress_pre = 0
+            while True:
+                buf = f.read(128)
+                if len(buf):
+                    self.write_fw_part(buf)
+                    progress_cur = done / size
+                else:
+                    break
+        print('End of transmission')
+        self.iap_finish()
+
+
+def main():
+    pass
+
+
+if '__name__' == '__main__':
+    main()

部分文件因文件數量過多而無法顯示