import struct
import time
import serial
from modbus_tk import modbus_rtu, modbus_tcp

# import usb

class wlmodbus:
    def __init__(self, port=None, baudrate=None, slave_ip=None, tcp_callback=None) -> None:
        self._port = port
        self._baudrate = baudrate
        self._slave_ip = slave_ip
        self._is_ok = False
        self._work_data = {}
        self._rule = None
        self._tcp_callback = tcp_callback
        try:
            if baudrate and slave_ip:
                print("tcp和uart 不能同时连接")
                return 
            if baudrate:
                self._ser = serial.Serial(self._port, self._baudrate, rtscts=False, dsrdtr=False)
                time.sleep(0.5)
                self._master = modbus_rtu.RtuMaster(self._ser)
            if slave_ip:
                self._master = modbus_tcp.TcpMaster(host=self._slave_ip, port=self._port, timeout_in_sec=5.0)
            self._master.set_timeout(5, use_sw_timeout=True)
            self._is_ok = True
        except Exception as exp:
            print(self._port + ': Serial port is not connected')

    def getWtLinkOpData(self):
        return self._work_data
        
    def readWtLinkOpData(self, modbus_id, cmd, name, type, rate, addr, cnt, sensor):
        opdata = None
        data = None
        try:  
            if type != 'avg' and type != 'max' and type != 'min':
                data = self._master.execute(modbus_id, cmd, addr, cnt)
                o_data = [0, 0]
                # data = [0,10] test
                if type == 'int':
                    h_data = data[0]
                elif type == 'int1':
                    h_data = struct.unpack('>H', struct.pack('<H', data[0]))[0]
                elif type == 'long':
                    h_data = int.from_bytes(struct.pack('>HH', data[0], data[1]), 'big') 
                elif type == 'long2':
                    h_data = int.from_bytes(struct.pack('<HH', data[0], data[1]), 'little') 
                elif type == 'long3':
                    o_data[0] = struct.unpack('>H', struct.pack('<H', data[0]))[0]
                    o_data[1] = struct.unpack('>H', struct.pack('<H', data[1]))[0]
                    h_data = int.from_bytes(struct.pack('>HH', o_data[0], o_data[1]), 'big') 
                elif type == 'long4':
                    o_data[0] = struct.unpack('>H', struct.pack('<H', data[0]))[0]
                    o_data[1] = struct.unpack('>H', struct.pack('<H', data[1]))[0]
                    h_data = int.from_bytes(struct.pack('<HH', o_data[0], o_data[1]), 'little') 
                elif type == 'float':
                    h_data = struct.unpack('>f', struct.pack('>I', data[0] << 16 | data[1]))[0]
                elif type == 'float2':
                    h_data = struct.unpack('<f', struct.pack('<I', data[1] << 16 | data[0]))[0]
                elif type == 'float3':
                    o_data[0] = struct.unpack('>H', struct.pack('<H', data[0]))[0]
                    o_data[1] = struct.unpack('>H', struct.pack('<H', data[1]))[0]
                    h_data = struct.unpack('>f', struct.pack('>I', o_data[0] << 16 | o_data[1]))[0] # BA DC
                elif type == 'float4':
                    o_data[0] = struct.unpack('>H', struct.pack('<H', data[0]))[0]
                    o_data[1] = struct.unpack('>H', struct.pack('<H', data[1]))[0]
                    h_data = struct.unpack('<f', struct.pack('<I', o_data[1] << 16 | o_data[0]))[0] # DC AB
                else:
                    h_data = data[0]
                if self._tcp_callback is not None:
                    self._tcp_callback(modbus_id, cmd, addr, h_data, type)    
            else:
                if self._rule is not None:
                    for index in self._rule:
                        if index['id'] == modbus_id and index['addr'] == addr and index['sensor'] == sensor:
                            if index['name'] in self._work_data:
                                h_data = self._work_data[index['name']]
                                break
                            else:
                                return None
            if type == '418x':
                # * rate  
                if h_data < 0x8000:
                    opdata = h_data * 0.00061037 * rate  
                else:
                    opdata = (h_data - 0x10000) * 0.00061037 * rate 
                
            elif type == 'int' or type == 'int1' \
                or type == 'long' or type == 'long2' or type == 'long3' or type == 'long4' \
                or type == 'float' or type == 'float2' or type == 'float3' or type == 'float4':
                opdata = h_data * rate
            
            elif type == 'avg':
                if name in self._work_data:
                    opdata = (h_data + self._work_data[name]) / 2.0
                else:
                    opdata = (h_data + h_data) / 2.0 
            
            elif type == 'max':
                if name in self._work_data:
                    if self._work_data[name] < h_data:
                        opdata =  h_data   
                    else:
                        opdata = self._work_data[name]
                else:
                    opdata = h_data

            elif type == 'min':
                if name in self._work_data:
                    if self._work_data[name] > h_data:
                        opdata =  h_data   
                    else:
                        opdata = self._work_data[name]
                else:
                    opdata = h_data
            
            self._work_data[name] = round(opdata, 3)
            self._is_ok = True
        except Exception as exp:
            self._is_ok = False
            print(exp)

    def del_data(self):
        del self._work_data
        self._work_data = {}

    def set_rule_data(self, data):
        self._rule = data

    def com_connect_task(self):
        while True:
            if self._is_ok is True:
                time.sleep(0.1)
            else:
                try:
                    if self._baudrate:
                        self._ser.close()
                        self._master.close()
                        del self._ser
                        del self._master
                        self._ser = serial.Serial(self._port, self._baudrate, rtscts=False, dsrdtr=False)
                        self._master = modbus_rtu.RtuMaster(self._ser)
                    elif self._slave_ip:
                        self._master.close()
                        self._master = modbus_tcp.TcpMaster(host=self._slave_ip, port=self._port, timeout_in_sec=5.0)    
                    self._master.set_timeout(2, use_sw_timeout=True)
                    self._is_ok = True
                except Exception as exp:
                    print(exp)
                time.sleep(10)
    

    




           
