| 
					
				 | 
			
			
				@@ -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
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 
 
			 |