'''
Create a Modbus TCP server (slave) which can be requested for data or set with
specific values by a host device.
'''

# system packages
import time
import network

# import modbus server classes
from tcp import ModbusTCP

# ===============================================
# connect to a network
station = network.WLAN(network.STA_IF)
if station.active() and station.isconnected():
    station.disconnect()
    time.sleep(1)
station.active(False)
time.sleep(1)
station.active(True)

# station.connect('SSID', 'PASSWORD')
station.connect('Wokwi-GUEST', '')
time.sleep(1)

while True:
    print('Waiting for WiFi connection...')
    if station.isconnected():
        print('Connected to WiFi.')
        print(station.ifconfig())
        break
    time.sleep(2)

# ===============================================
# TCP Slave setup
tcp_port = 502
local_ip = station.ifconfig()[0]

# ModbusTCP can get TCP requests from a client device to provide/set data
server = ModbusTCP()

# check whether server has been bound to an IP and port
is_bound = server.get_bound_status()
if not is_bound:
    server.bind(local_ip=local_ip, local_port=tcp_port)

letras = ["B", "C", "D", "E"]
max_len = 5  # max length of any register sub-group
# define register values as a dictionary
register_definitions = {
    "COILS": {
        0: {
            "register": 0,
            "val": [0, 0, 0],
            "key": ["PM", "PP", "PA"]
        },
        max_len: {
            "register": max_len,
            "val": [0],
            "key": ["Set Receta"]
        }
    },
    "HREGS": {
        0: {
            "register": 0,
            "val": [2, 3, 4, 5],
            "key": [f"Receta Tipo {letra}" for letra in letras]
        },
        max_len: {
            "register": max_len,
            "val": [4, 3, 2, 1],
            "key": [f"Receta Numero {letra}" for letra in letras]
        }
    },
    "ISTS": {
        0: {
            "register": 0,
            "val": [0, 0],
            "key": ["Marcha", "Emerge"]
        }
    },
    "IREGS": {
        0: {
            "register": 0,
            "val": [2, 2, 2, 2],
            "key": [f"Receta Tipo {letra}" for letra in letras]
        },
        max_len: {
            "register": max_len,
            "val": [1, 1, 1, 1],
            "key": [f"Receta Numero {letra}" for letra in letras]
        }
    }
}

print('Setting up registers ...')
# use the defined values of each register type provided by register_definitions
server.setup_registers(register_definitions)
print('Register setup done')
print('Serving as TCP server on {}:{}'.format(local_ip, tcp_port))


# Show registers
def show_regs():
    print("> Reading REGISTERS...")
    reg_dic = server._register_dict
    print(reg_dic)
    for reg_type in reg_dic:
        print(f"> Showing {reg_type}...")
        reg_def = register_definitions[reg_type]
        for addr, item in reg_dic[reg_type].items():
            init_addr = max_len * (addr // max_len)
            index = addr - init_addr
            val = item["val"]
            key = reg_def[init_addr]["key"][index]
            print(f"{key}: {val}")


# Show modified registers
def show_mod_regs():
    reg_dic = server._register_dict
    mod_regs = {}
    for reg_type in reg_dic:
        reg_def = register_definitions[reg_type]
        for addr, item in reg_dic[reg_type].items():
            init_addr = max_len * (addr // max_len)
            index = addr - init_addr
            group = reg_def[init_addr]
            val = item["val"]
            if group["val"][index] != val:
                group["val"] = val
                key = group["key"][index]
                mod_regs[reg_type] = m_r = {}
                m_r[key] = val
    if mod_regs:
        print(mod_regs)


show_regs()

#  Modificar algunos registros una vez
print(server._register_dict["ISTS"][0]["val"])
# server._register_dict["ISTS"][0]["val"] = 1

show_mod_regs()

while True:
    try:
        server.process()
        # show_mod_regs()

    except KeyboardInterrupt:
        print('KeyboardInterrupt, stopping TCP server...')
        break
    except Exception as e:
        print('Exception during execution: {}'.format(e))

print("Finished providing/accepting data as server")