#!/usr/bin/env python3
"""
Modbus TCP Client - Консольное приложение для чтения holding регистров
"""

from pymodbus.client import ModbusTcpClient
import sys
import argparse

def read_holding_registers(ip_address, start_address, count, unit_id=1):
    """
    Чтение holding регистров из Modbus TCP устройства
    
    Args:
        ip_address (str): IP адрес устройства
        start_address (int): начальный адрес регистра
        count (int): количество регистров для чтения
        unit_id (int): идентификатор устройства (по умолчанию 1)
    
    Returns:
        list: список значений регистров или None в случае ошибки
    """
    client = None
    try:
        # Создание клиента Modbus TCP
        client = ModbusTcpClient(ip_address)
        
        # Подключение к устройству
        if not client.connect():
            print(f"Ошибка: Не удалось подключиться к устройству {ip_address}")
            return None
        
        # Чтение holding регистров
        print(f"Чтение регистров с адреса {start_address}, количество: {count}")
        response = client.read_holding_registers(start_address, count, slave=unit_id)
        
        if response.isError():
            print(f"Ошибка при чтении регистров: {response}")
            return None
        
        # Получение данных
        registers = response.registers
        print(f"Успешно прочитано {len(registers)} регистров")
        
        return registers
        
    except Exception as e:
        print(f"Произошла ошибка: {e}")
        return None
        
    finally:
        # Закрытие соединения
        if client:
            client.close()

def display_registers(registers, start_address):
    """
    Отображение значений регистров в табличном формате
    
    Args:
        registers (list): список значений регистров
        start_address (int): начальный адрес
    """
    if not registers:
        return
    
    print("\n" + "=" * 50)
    print("Результаты чтения holding регистров:")
    print("=" * 50)
    print(f"{'Адрес':<10} {'Значение':<10} {'HEX':<10} {'BIN':<20}")
    print("-" * 50)
    
    for i, value in enumerate(registers):
        address = start_address + i
        hex_value = f"0x{value:04X}"
        bin_value = f"0b{value:016b}"
        print(f"{address:<10} {value:<10} {hex_value:<10} {bin_value:<20}")

def main():
    """Основная функция приложения"""
    parser = argparse.ArgumentParser(
        description='Modbus TCP Client - чтение holding регистров',
        formatter_class=argparse.RawDescriptionHelpFormatter,
        epilog='''
Примеры использования:
  python modbus_client.py 192.168.1.100 0 10
  python modbus_client.py 192.168.1.100 100 5 --unit 2
  python modbus_client.py 192.168.1.50 0 20 --port 5020
        '''
    )
    
    parser.add_argument('ip_address', help='IP адрес Modbus устройства')
    parser.add_argument('start_address', type=int, help='Начальный адрес регистра')
    parser.add_argument('count', type=int, help='Количество регистров для чтения')
    parser.add_argument('--port', type=int, default=502, help='Порт Modbus (по умолчанию: 502)')
    parser.add_argument('--unit', type=int, default=1, help='ID устройства (по умолчанию: 1)')
    
    args = parser.parse_args()
    
    # Проверка входных параметров
    if args.start_address < 0:
        print("Ошибка: начальный адрес не может быть отрицательным")
        sys.exit(1)
    
    if args.count <= 0:
        print("Ошибка: количество регистров должно быть положительным числом")
        sys.exit(1)
    
    if args.count > 125:  # Ограничение Modbus протокола
        print("Предупреждение: Modbus протокол ограничивает чтение 125 регистров за один запрос")
        args.count = 125
    
    print(f"Подключение к Modbus устройству:")
    print(f"  IP адрес: {args.ip_address}:{args.port}")
    print(f"  Диапазон регистров: {args.start_address} - {args.start_address + args.count - 1}")
    print(f"  ID устройства: {args.unit}")
    
    # Чтение регистров
    registers = read_holding_registers(
        args.ip_address, 
        args.start_address, 
        args.count, 
        args.unit
    )
    
    # Отображение результатов
    if registers:
        display_registers(registers, args.start_address)
    else:
        print("Не удалось прочитать регистры")
        sys.exit(1)

def interactive_mode():
    """
    Интерактивный режим работы
    """
    print("=== Modbus TCP Client - Интерактивный режим ===")
    
    while True:
        try:
            print("\nВведите параметры для чтения регистров:")
            ip_address = input("IP адрес устройства (или 'quit' для выхода): ").strip()
            
            if ip_address.lower() in ['quit', 'exit', 'q']:
                break
            
            start_address = input("Начальный адрес регистра: ").strip()
            count = input("Количество регистров: ").strip()
            unit_id = input("ID устройства [1]: ").strip()
            
            # Проверка и преобразование параметров
            if not unit_id:
                unit_id = 1
            else:
                unit_id = int(unit_id)
            
            start_address = int(start_address)
            count = int(count)
            
            # Чтение регистров
            registers = read_holding_registers(ip_address, start_address, count, unit_id)
            
            if registers:
                display_registers(registers, start_address)
            
        except ValueError:
            print("Ошибка: Некорректный формат числа")
        except KeyboardInterrupt:
            print("\nЗавершение работы...")
            break
        except Exception as e:
            print(f"Произошла ошибка: {e}")

if __name__ == "__main__":
    if len(sys.argv) > 1:
        # Режим с аргументами командной строки
        main()
    else:
        # Интерактивный режим
        interactive_mode()