Browse Source

Работа со входами

TelenkovDmitry 1 year ago
parent
commit
cad2b8759f

BIN
doc/~$_модули_входов_выходов_редакция_4.doc


+ 13 - 1
fw/modules/io/input.c

@@ -1,11 +1,12 @@
 #include "at32f403a_407.h"
 #include "input.h"
+#include "settings_api.h"
 #include "FreeRTOS.h"
 #include "task.h"
 #include <stdio.h>
 
 
-
+// *port; pin; mode; port_source; pin_source; deb_counter; p_flag; cnt;
 din_t inputs[DI_NUMBER] = {
     {GPIOB, GPIO_PINS_11, 0, GPIO_PORT_SOURCE_GPIOB, GPIO_PINS_SOURCE11, 0, false, 0}, // 1   
     {GPIOB, GPIO_PINS_10, 0, GPIO_PORT_SOURCE_GPIOB, GPIO_PINS_SOURCE10, 0, false, 0}, // 2
@@ -75,6 +76,17 @@ void in_exint_init(void)
     nvic_irq_enable(EXINT15_10_IRQn, 5, 0);
 }
 
+//
+void in_set(void)
+{
+#if 0  
+    for (int i = 0; i < DI_NUMBER; i++)
+    {
+        if (settings.mode_bits & (1 << i) != inputs[])
+    }
+#endif    
+}
+
 //
 void io_test(void)
 {

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

@@ -337,7 +337,7 @@ eMBFuncReportSlaveID( UCHAR * pucFrame, USHORT * usLen )
 #if 1
     mb_package_flag = true;
     
-	*usLen = mb_get_info(&pucFrame[1]) + 3;
+	//*usLen = mb_get_info(&pucFrame[1]) + 3;
 #endif
 	return MB_EX_NONE;
 }

+ 17 - 191
fw/modules/modbus/modbus_params.c

@@ -20,7 +20,7 @@ void mb_init_params(void)
 {
     uint16_t index = 0;
     uint16_t addr = 0;
-  
+    
     mb_param[index].reg = 0x0100;
 	mb_param[index].size = 1;
 	mb_param[index].param = (uint8_t*)&input_state_bit;  // Текущее состояние входа
@@ -29,11 +29,13 @@ void mb_init_params(void)
     mb_param[index].check_handler = mb_check_dummy;
     
     index++;
-    
+        
     // Счетчики импульсов. Регистры 0x0102 - 0x0111
     addr = 0x0102;
     for (int i = 0; i < DI_NUMBER; i++)
     {
+        input_cnt[i] = i;
+          
         mb_param[index].reg = addr;
         mb_param[index].size = 2;
         mb_param[index].param = (uint8_t*)&input_cnt[i];  // Счетчик ипульсов
@@ -47,135 +49,24 @@ void mb_init_params(void)
     
     mb_param[index].reg = 0x0120;
 	mb_param[index].size = 1;
-	mb_param[index].param = (uint8_t*)&settings.mode_bits;  // Текущее состояние входа
+	mb_param[index].param = (uint8_t*)&settings.mode_bits;  // Режим работы входов
 	mb_param[index].set = NULL;
     mb_param[index].get = NULL;
     mb_param[index].check_handler = mb_check_dummy;
     
     index++;
     
+    // TODO Пока дублируем
+    
     mb_param[index].reg = 0x0122;
 	mb_param[index].size = 1;
-	mb_param[index].param = (uint8_t*)&settings.mode_bits;  // Текущее состояние входа
+	mb_param[index].param = (uint8_t*)&settings.norm_state_bits;  // Нормальное состояние входов
 	mb_param[index].set = NULL;
     mb_param[index].get = NULL;
     mb_param[index].check_handler = mb_check_dummy;
     
     index++;
-    
-    
-#if 0
-    mb_param[1].reg = 0x0101;
-	mb_param[1].size = 1;
-	mb_param[1].param = (uint8_t*)&input_state[1];  // Текущее состояние входа
-	mb_param[1].set_handler = NULL;
-    mb_param[1].check_handler = mb_check_dummy;
-    
-    mb_param[2].reg = 0x0102;
-	mb_param[2].size = 1;
-	mb_param[2].param = (uint8_t*)&input_state[2];  // Текущее состояние входа
-	mb_param[2].set_handler = NULL;
-    mb_param[2].check_handler = mb_check_dummy;
-    
-    mb_param[3].reg = 0x0103;
-	mb_param[3].size = 1;
-	mb_param[3].param = (uint8_t*)&input_state[3];  // Текущее состояние входа
-	mb_param[3].set_handler = NULL;
-    mb_param[3].check_handler = mb_check_dummy;
-    
-    mb_param[4].reg = 0x0104;
-	mb_param[4].size = 1;
-	mb_param[4].param = (uint8_t*)&input_state[4];  // Текущее состояние входа
-	mb_param[4].set_handler = NULL;
-    mb_param[4].check_handler = mb_check_dummy;
-    
-    mb_param[5].reg = 0x0105;
-	mb_param[5].size = 1;
-	mb_param[5].param = (uint8_t*)&input_state[5];  // Текущее состояние входа
-	mb_param[5].set_handler = NULL;
-    mb_param[5].check_handler = mb_check_dummy;
-    
-    mb_param[6].reg = 0x0106;
-	mb_param[6].size = 1;
-	mb_param[6].param = (uint8_t*)&input_state[6];  // Текущее состояние входа
-	mb_param[6].set_handler = NULL;
-    mb_param[6].check_handler = mb_check_dummy;
-    
-    mb_param[7].reg = 0x0107;
-	mb_param[7].size = 1;
-	mb_param[7].param = (uint8_t*)&input_state[7];  // Текущее состояние входа
-	mb_param[7].set_handler = NULL;
-    mb_param[7].check_handler = mb_check_dummy;
-    
-    mb_param[8].reg = 0x0110;
-	mb_param[8].size = 2;
-	mb_param[8].param = (uint8_t*)&input_cnt[0];  // Счетчик ипульсов
-	mb_param[8].set_handler = NULL;
-    mb_param[8].check_handler = mb_check_dummy;
-    
-    mb_param[9].reg = 0x0112;
-	mb_param[9].size = 2;
-	mb_param[9].param = (uint8_t*)&input_cnt[0];  // Счетчик ипульсов
-	mb_param[9].set_handler = NULL;
-    mb_param[9].check_handler = mb_check_dummy;
-    
-    mb_param[10].reg = 0x0114;
-	mb_param[10].size = 2;
-	mb_param[10].param = (uint8_t*)&input_cnt[0];  // Счетчик ипульсов
-	mb_param[10].set_handler = NULL;
-    mb_param[10].check_handler = mb_check_dummy;
-    
-    mb_param[11].reg = 0x0116;
-	mb_param[11].size = 2;
-	mb_param[11].param = (uint8_t*)&input_cnt[0];  // Счетчик ипульсов
-	mb_param[11].set_handler = NULL;
-    mb_param[11].check_handler = mb_check_dummy;
-    
-    mb_param[12].reg = 0x0118;
-	mb_param[12].size = 2;
-	mb_param[12].param = (uint8_t*)&input_cnt[0];  // Счетчик ипульсов
-	mb_param[12].set_handler = NULL;
-    mb_param[12].check_handler = mb_check_dummy;
-    
-    mb_param[13].reg = 0x011A;
-	mb_param[13].size = 2;
-	mb_param[13].param = (uint8_t*)&input_cnt[0];  // Счетчик ипульсов
-	mb_param[13].set_handler = NULL;
-    mb_param[13].check_handler = mb_check_dummy;
-    
-    mb_param[14].reg = 0x011C;
-	mb_param[14].size = 2;
-	mb_param[14].param = (uint8_t*)&input_cnt[0];  // Счетчик ипульсов
-	mb_param[14].set_handler = NULL;
-    mb_param[14].check_handler = mb_check_dummy;
-    
-    mb_param[15].reg = 0x011E;
-	mb_param[15].size = 2;
-	mb_param[15].param = (uint8_t*)&input_cnt[0];  // Счетчик ипульсов
-	mb_param[15].set_handler = NULL;
-    mb_param[15].check_handler = mb_check_dummy;
-    
-    // ---------------------------------------------------------------------- //
-    // Системные параметры
-    
-    mb_param[16].reg = 0x0800;
-	mb_param[16].size = 2;
-	mb_param[16].param = (uint8_t*)&uptime;     // Uptime
-	mb_param[16].set_handler = NULL;
-    mb_param[16].check_handler = mb_check_dummy;
-    
-    mb_param[17].reg = 0x0802;
-	mb_param[17].size = 2;
-	mb_param[17].param = (uint8_t*)&rtc_unix;   // Unix time stamp
-	mb_param[17].set_handler = NULL;
-    mb_param[17].check_handler = mb_check_dummy;
-    
-    mb_param[18].reg = 0x0804;
-	mb_param[18].size = 2;
-	mb_param[18].param = (uint8_t*)&rtc_sinhro;   // Unix time stamp
-	mb_param[18].set_handler = mb_set_time;
-    mb_param[18].check_handler = mb_check_dummy;
-#endif    
+ 
 }
 
 
@@ -254,79 +145,6 @@ void mb_get_param(uint8_t *buf, uint16_t index)
 
 
 
-//
-uint8_t mb_get_info(uint8_t *buf)
-{
-	char id_str[9] = {0};
-    char model[6] = {0};
-	uint32_t id_word;
-	uint8_t ret = 0;	// длина пакета
-	uint8_t len;
-
-    len = strlen("Hello world");
-    *buf++ = len;
-    strcpy(buf, "Hello world");
-    buf += len;
-    ret = 1 + len;
-      
-#if 0    
-	// ------------------------------------------------------------------- //
-	// Model
-	// ------------------------------------------------------------------- //
-    sprintf(model, "%u", sys_settings.model);
-    len = strlen(model); 
-    *buf++ = len; // Model len
-    memcpy(buf, model, len);
-    buf += len;
-    ret = 1 + len;
-
-	// ------------------------------------------------------------------- //
-	// FW version
-	// ------------------------------------------------------------------- //
-	*buf++ = 8; // FW version len
-	memcpy(buf, sys_settings.fw_version, 8);
-	buf += 8;
-	ret += 9;
-
-	// ------------------------------------------------------------------- //
-	// Stm ID
-	// ------------------------------------------------------------------- //
-	*buf++ = 24; // STM ID len
-	id_word = HAL_GetUIDw0();
-	sprintf(id_str, "%08X", id_word);
-	len = strlen(id_str);
-	memcpy(buf, id_str, len);
-	buf += len;
-	ret += len;
-	memset(id_str, 0, 9);
-		
-	id_word = HAL_GetUIDw1();
-	sprintf(id_str, "%08X", id_word);
-	len = strlen(id_str);
-	memcpy(buf, id_str, len);
-	buf += len;
-	ret += len;
-	memset(id_str, 0, 9);
-	
-	id_word = HAL_GetUIDw2();
-	sprintf(id_str, "%08X", id_word);
-	len = strlen(id_str);
-	memcpy(buf, id_str, len);
-	buf += len;
-	ret += len;
-
-	// ------------------------------------------------------------------- //	
-	// Серийник
-	// ------------------------------------------------------------------- //
-	id_word = sys_settings.serial;
-	sprintf(id_str, "%u", id_word);
-	len = strlen(id_str);
-	*buf++ = len;
-	memcpy(buf, id_str, len);
-	ret += len;
-#endif
-	return ret;
-}
 
 // -------------------------------------------------------------------------- //
 //                          Чтение параметров
@@ -345,6 +163,7 @@ void get_time(uint8_t* buf, uint8_t size)
 	}
 }
 
+//
 void get_din_mode(uint8_t* buf, uint8_t size)
 {
     
@@ -354,6 +173,13 @@ void get_din_mode(uint8_t* buf, uint8_t size)
 //                          Установка параметров
 // -------------------------------------------------------------------------- //
 
+//
+mb_delay_action_t set_din_mode(void)
+{
+    
+    return MB_NO_ACTION;
+}
+
 //
 mb_delay_action_t mb_set_time(void)
 {

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

@@ -9,7 +9,7 @@
 #include <stdbool.h>
 
 
-#define MB_PARAM_MAX			10
+#define MB_PARAM_MAX			11
 
 
 //
@@ -38,8 +38,6 @@ mb_delay_action_t mb_set_param(uint8_t *buf, uint16_t index);
 //
 void mb_get_param(uint8_t *buf, uint16_t index);
 
-//
-uint8_t mb_get_info(uint8_t *buf);
 
 // Установка адреса. Запрос без параметров.
 bool mb_set_addr(uint8_t *buf, uint8_t *addr);

BIN
output/fw.bin


File diff suppressed because it is too large
+ 429 - 404
project/ewarm/iap/iap.dep


File diff suppressed because it is too large
+ 561 - 605
project/ewarm/module_universal_io.dep


+ 139 - 0
tools/io_module.py

@@ -0,0 +1,139 @@
+from modbus import Modbus, MBError, NoResponseError
+import colorama
+from colorama import Fore
+import time
+import os
+
+reg_table = {'in_bits': 0x0100, 'in_cnt': 0x0102, 'in_mode': 0x0120,'uptime': 0x0800, 
+             'rtc_unix': 0x0802, 'rtc_sinhro': 0x0804}
+
+
+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()
+
+    # 0x0100 - текущее состояние входов
+    def get_inputs_bit(self) -> str:
+        data = self.read_holding_registers(reg_table['in_bits'], 1)
+        return format(data[0], '08b')
+
+    # 0x0101 - 0x0110 Счетчики импульсов
+    def get_inputs_counters(self):
+        data = []
+        for i in range(reg_table['in_cnt'], reg_table['in_cnt'] + 16, 2):
+            data.append(self.read_uint32_holding(i))
+        return data                              
+
+    # 0x0120 - режим работы входов
+    def get_inputs_mode(self):
+        data = self.read_holding_registers(reg_table['in_mode'], 1)
+        return format(data[0], '08b')
+
+    def set_inputs_mode(self, val):
+        self.write_holding_register(reg_table['in_mode'], val)
+
+    def get_uptime(self):
+        return self.read_uint32_holding(reg_table['uptime'])
+
+    def get_rtc(self):
+        return self.read_uint32_holding(reg_table['rtc_unix'])
+
+    def set_rtc(self, utc):
+        self.write_uint32(reg_table['rtc_sinhro'], utc)
+
+    
+
+def main():
+    colorama.init(autoreset=True)
+    dev = IO_Module('COM24', 115200, 1)
+    dev.MB_DEBUG = False
+    # 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}')
+    # print('Set time:', int(time.time()))
+    # dev.set_rtc(int(time.time()))
+    # time.sleep(1)
+    # unix_time = dev.get_rtc()
+    # print(f'RTC: {time.ctime(unix_time)}. Unix time stamp:  {unix_time}')
+    
+    # while True:
+    for i in range(10):
+        print('~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~')
+        print('Inputs values [bit field :', Fore.GREEN + dev.get_inputs_bit())
+        print('Inputs mode [bit field]  :', Fore.GREEN + dev.get_inputs_mode())
+        data = dev.get_inputs_counters()
+        print('Inputs counters          :', Fore.GREEN + ' | '.join(str(el) for el in data))
+        dev.set_inputs_mode(i)
+
+        time.sleep(1)
+
+    
+
+
+if __name__ == '__main__':
+    main()

+ 203 - 0
tools/modbus.py

@@ -0,0 +1,203 @@
+import time
+from serial import Serial
+import colorama
+import struct
+from colorama import Fore, Style 
+from typing import Sequence, Union
+from binascii import b2a_hex
+
+DEFAULT_MB_CRC_TABLE = (
+    00000, 49345, 49537,   320, 49921,   960,   640, 49729, 50689,  1728,  1920,
+    51009,  1280, 50625, 50305,  1088, 52225,  3264,  3456, 52545,  3840, 53185,
+    52865,  3648,  2560, 51905, 52097,  2880, 51457,  2496,  2176, 51265, 55297,
+    6_336,  6528, 55617,  6912, 56257, 55937,  6720,  7680, 57025, 57217,  8000,
+    56577,  7616,  7296, 56385,  5120, 54465, 54657,  5440, 55041,  6080,  5760,
+    54849, 53761,  4800,  4992, 54081,  4352, 53697, 53377,  4160, 61441, 12480,
+    12672, 61761, 13056, 62401, 62081, 12864, 13824, 63169, 63361, 14144, 62721,
+    13760, 13440, 62529, 15360, 64705, 64897, 15680, 65281, 16320, 16000, 65089,
+    64001, 15040, 15232, 64321, 14592, 63937, 63617, 14400, 10240, 59585, 59777,
+    10560, 60161, 11200, 10880, 59969, 60929, 11968, 12160, 61249, 11520, 60865,
+    60545, 11328, 58369,  9408,  9600, 58689,  9984, 59329, 59009,  9792,  8704,
+    58049, 58241,  9024, 57601,  8640,  8320, 57409, 40961, 24768, 24960, 41281,
+    25344, 41921, 41601, 25152, 26112, 42689, 42881, 26432, 42241, 26048, 25728,
+    42049, 27648, 44225, 44417, 27968, 44801, 28608, 28288, 44609, 43521, 27328,
+    27520, 43841, 26880, 43457, 43137, 26688, 30720, 47297, 47489, 31040, 47873,
+    31680, 31360, 47681, 48641, 32448, 32640, 48961, 32000, 48577, 48257, 31808,
+    46081, 29888, 30080, 46401, 30464, 47041, 46721, 30272, 29184, 45761, 45953,
+    29504, 45313, 29120, 28800, 45121, 20480, 37057, 37249, 20800, 37633, 21440,
+    21120, 37441, 38401, 22208, 22400, 38721, 21760, 38337, 38017, 21568, 39937,
+    23744, 23936, 40257, 24320, 40897, 40577, 24128, 23040, 39617, 39809, 23360,
+    39169, 22976, 22656, 38977, 34817, 18624, 18816, 35137, 19200, 35777, 35457,
+    19008, 19968, 36545, 36737, 20288, 36097, 19904, 19584, 35905, 17408, 33985,
+    34177, 17728, 34561, 18368, 18048, 34369, 33281, 17088, 17280, 33601, 16640,
+    33217, 32897, 16448)
+
+class NoResponseError(IOError):
+    pass
+
+class ChecksumError(IOError):
+    pass
+
+class MBError(IOError):
+    pass
+
+class ModbusMixin():
+    def print_hex(self, text: str, data: bytes):
+        print(text, *tuple(map(lambda x: '0x{:02X}'.format(x), (i for i in data))))
+
+
+class Modbus(ModbusMixin):
+
+    # MB_CRC_TABLE: Sequence[int] = DEFAULT_MB_CRC_TABLE
+    MB_TIMEOUT: float = 0.05
+    MB_CRC_TABLE: Sequence[int] = DEFAULT_MB_CRC_TABLE
+    MB_DEBUG: bool = False
+    MB_TRIES: int = 3
+
+    def __init__(self, tty: str, brate: int, address: int):
+        self.serial = Serial(port=tty, baudrate=brate, timeout=0.05, parity='N', xonxoff=False)
+        self.address = address
+
+    @classmethod
+    def test(cls):
+        print(type(cls.MB_CRC_TABLE))
+
+    @classmethod
+    def _crc(cls, data: bytes) -> bytes:
+        crc = 0xFFFF
+        crc_table = cls.MB_CRC_TABLE
+        for char in data:
+            crc = (crc >> 8) ^ crc_table[(crc ^ char) & 0xFF]
+        return crc.to_bytes(2, 'little')
+
+    def raw_communicate(self, data: bytes, predicted_length:int = -1) -> bytes:
+        """Send request and return it back with checksum"""
+        if self.MB_DEBUG:
+            self.print_hex('Request:', data)
+        self.serial.write(data)
+        response_bytes = bytearray()
+        start_time = time.time()
+        while True:
+            b = self.serial.read(1)
+            if len(b):
+                new_byte = bytearray(b)
+                response_bytes.extend(new_byte)
+            elif time.time() - start_time > self.MB_TIMEOUT:
+                break
+            if len(response_bytes) == predicted_length:
+                break
+        if self.MB_DEBUG:
+            self.print_hex('Responce:', response_bytes)
+        return response_bytes
+    
+    def communicate(self, request: bytes, predicted_length: int = -1) -> bytes:
+        """Send request and return rewponse after checksum check"""
+        pl = predicted_length + 2 if predicted_length != -1 else -1
+        response = self.raw_communicate(request + self._crc(request), pl)
+        if len(response) == 0:
+            raise NoResponseError('No response frome module')
+        crc_received = response[-2:]
+        crc_calculated = self._crc(response[:-2])
+        if crc_received != crc_calculated:
+            raise ChecksumError("CRC check dailed (got: 0x{}, calculated: 0x{})".format(
+                b2a_hex(crc_received).decode().upper(), b2a_hex(crc_calculated).decode().upper()))
+        return response
+
+    def mb_func(self, code: int, req: bytes, predicted_response_length: int = -1):
+        """Call typical MB function with address and function code check,
+        return just response, no header and checksum included"""
+        error = None
+        for i in range(self.MB_TRIES):
+            try:
+                pl = predicted_response_length + 2 if predicted_response_length != -1 else -1
+                response = self.communicate(b''.join((self.address.to_bytes(1, 'big'),
+                                                      code.to_bytes(1, 'big'), req)), pl)
+                if response[0] != self.address:
+                    raise MBError("Modbus address mismatch in request and response ({}/{})".format(
+                        self.address, response[0]))
+                elif response[1] != code:
+                    raise MBError("Modbus function opcode mismatch in request and response ({}/{})".format(
+                        code, response[1]))
+                return response[2:-2]
+            except (MBError, ChecksumError, NoResponseError) as e:
+                if self.MB_DEBUG:
+                    print(e)
+                error = e
+                time.sleep(0.5)
+        raise error
+
+    def _read_registers(self, opcode: int, address: int, count: int, raw: bool = False) -> Union[Sequence[int], bytes]:
+        """Read values of inpurt/holding registers from device"""
+        response = self.mb_func(opcode, address.to_bytes(2, 'big') + count.to_bytes(2, 'big'), 1 + 2*count)
+        try:
+            if raw:
+                return response[1:]
+            inp_count = response[0] // 2
+            return tuple(int.from_bytes(response[i:i + 2], 'big') for i in range(1, inp_count*2, 2))
+        except KeyError:
+            raise MBError("Incorrect response payload")
+
+    # 0x03
+    def read_holding_registers(self, address: int, count: int) -> Sequence[int]:
+        return self._read_registers(3, address, count)
+
+    def read_holding_registers_raw(self, address: int, count: int) -> bytes:
+        return self._read_registers(3, address, count, True)
+
+    def read_uint32_holding(self, address: int) -> int:
+        """Read 32-bit integer from holding registers"""
+        return struct.unpack('>I', self.read_holding_registers_raw(address, 2))[0]
+
+    # 0x10
+    def write_holding_registers_raw(self, address:int, values: bytes):
+        """Write 16-bit integers to holding registers on device"""
+        request = bytearray(address.to_bytes(2, 'big'))
+        request += (len(values) // 2).to_bytes(2, 'big')
+        request += len(values).to_bytes(1, 'big')
+        request += values
+        response = self.mb_func(16, bytes(request), 4)
+        if request[:4] != response:
+            raise MBError('Incorrect response payload')
+    
+    #
+    def write_holding_register(self, address: int, value: int):
+        """Write 16-bit integer to register on device"""
+        request = address.to_bytes(2, 'big') + value.to_bytes(2, 'big')
+        response = self.mb_func(6, request, len(request))
+        if request != response:
+            raise MBError('Incorrect response payload')
+
+    def write_uint32(self, address: int, value: int):
+        """Write 32-bit integer to holding register"""
+        self.write_holding_registers_raw(address, struct.pack('>I', value))
+
+    def test_send(self, data: bytes):
+        while True:
+            self.serial.write(data)
+            time.sleep(1)
+
+    def send_recv(self, data, number):
+        self.serial.write(data)
+        
+        # while True:
+        #     self.serial.write(data)
+        #     recv = self.serial.read_all()
+        #     print(recv)
+        #     print(recv.decode('utf_8'))
+        #     time.sleep(1)
+
+def main():
+    ADDR = 1
+    colorama.init()
+    dev = Modbus('COM22', 115200, ADDR)
+    
+
+    # print(dev.read_holding_registers(0x0100, 1))
+    # print(dev.read_uint32_holding(0x0100))
+    # time.sleep(1)
+
+
+if __name__ == '__main__':
+    main()
+
+

Some files were not shown because too many files changed in this diff