import struct
import sys
import time
import modbus_tk.defines as cst
from module.wtserial import wtserial
from i2c_io.i2c_gpio import i2c_gpio
from modbus.wtmodbus import wtmodbus
from module.wtserial import wtserial


_operate = sys.argv[1]
_addr = sys.argv[2]
updataAddr = int(_addr)




sensorDict = {
    1: {'comNum': '/dev/ttyS2', 'wakeup': 495},
    2: {'comNum': '/dev/ttyS3', 'wakeup': 496},
    3: {'comNum': '/dev/ttyS4', 'wakeup': 497},
    4: {'comNum': '/dev/ttyS9', 'wakeup': 498},
    5: {'comNum': '/dev/ttyS7', 'wakeup': 499},
    6: {'comNum': '/dev/ttyS5', 'wakeup': 500},
    7: {'comNum': '/dev/ttyS5', 'wakeup': 501},
    8: {'comNum': '/dev/ttyS5', 'wakeup': 502},
    9: {'comNum': '/dev/ttyS5', 'wakeup': 503},
    10: {'comNum': '/dev/ttyS5', 'wakeup': 504},
    11: {'comNum': '/dev/ttyS5', 'wakeup': 505},
    12: {'comNum': '/dev/ttyS5', 'wakeup': 506}
}

updating_com = sensorDict[updataAddr]["comNum"]
wakeup_gpio_num = sensorDict[updataAddr]["wakeup"] # 495~506
updating_img = 'WTS4V3C_v2.62.bin'
update_data = None

def update(self, bin_data, per_package_size=120, version="2.99"):
    if self._wakeup_callback is not None:
        self._wakeup_callback(str(self._wakeup), '1')
        time.sleep(0.01) 
    total_bin_size = len(bin_data)
    rest_size = total_bin_size
    update_index = 0

    update_addr = 0x5000
    update_index_addr = 0x5078
    update_pwd_addr = 0x5079
    self.__stop_update = False
    
    try:
        if int(version[0]) >= 2 and int(version[2]) >= 4 and int(version[3]) >= 1:
            check_sum = 0
            for each in bin_data:
                check_sum += each
            check_sum = check_sum & 0xFF
            data = check_sum << 8
            self._master.execute(self._slave_id, cst.WRITE_MULTIPLE_REGISTERS,0x5080,
                                output_value=[data])    
        # write index to 0
        self._master.execute(self._slave_id, cst.WRITE_MULTIPLE_REGISTERS, update_index_addr,
                                output_value=[0])
        while rest_size:
            if self.__stop_update:
                return False

            if rest_size >= per_package_size * 2:
                update_data = struct.unpack('<' + 'H' * per_package_size,
                                            bin_data[update_index * per_package_size * 2:
                                                        (update_index + 1) * per_package_size * 2])

                rest_size -= per_package_size * 2
            else:
                # 补全
                update_data = struct.unpack('<' + 'H' * per_package_size,
                                            bin_data[update_index * per_package_size * 2:
                                                        (update_index + 1) * per_package_size * 2] +
                                            b'\x00' * (per_package_size * 2 - rest_size))
                rest_size = 0

            
            self._master.execute(self._slave_id, cst.WRITE_MULTIPLE_REGISTERS, update_addr,
                                    output_value=update_data)

            update_index += 1

            # read index
            try_cnts = 10000
            while try_cnts:
                index = self._master.execute(self._slave_id, cst.READ_HOLDING_REGISTERS,
                                                update_index_addr, 1)
                if index[0] == update_index:
                    break
                try_cnts -= 1
            if try_cnts == 0:
                if self._wakeup_callback is not None:
                    self._wakeup_callback(str(self._wakeup), '0')
                    time.sleep(0.01) 
                return False

        password_data = struct.unpack('>HHH', b'WITIUM')
        self._master.execute(self._slave_id, cst.WRITE_MULTIPLE_REGISTERS, update_pwd_addr,
                                output_value=password_data)

        if self._wakeup_callback is not None:
            self._wakeup_callback(str(self._wakeup), '0')
            time.sleep(0.01)     
        return True
    except Exception as exp:
        print("update error:{}".format(exp))
    if self._wakeup_callback is not None:
        self._wakeup_callback(str(self._wakeup), '0')
        time.sleep(0.1) 
    return False

def main():

    if _operate == 'update':
        print("Update Sensor Start.")
        print("addr:" ,updataAddr)
        iic_gpio = i2c_gpio()
        #iic_gpio.write_gpio(str(wakeup_gpio_num), "1")
        #time.sleep(15)

        try:
            with open(updating_img, 'rb') as files:
                update_data = files.read()
        except IOError as e:
            print(f"Exception occurred: {e}")

        print("Read File Ok.")


        ser = wtserial(str(updating_com), 115200)
        smodbus = wtmodbus(None, None, None, 1, ser, iic_gpio.write_gpio)
        sensor_info = smodbus.get_sensor_base_parameter()
        print(sensor_info)
        print("Start Update.")
        smodbus.update(update_data)
        iic_gpio.write_gpio(str(wakeup_gpio_num), "0")
        print("Update Finished.")

    elif _operate == 'read':
        print(f"Read addr {updataAddr} <START>")
        iic_gpio = i2c_gpio()
        iic_gpio.write_gpio(str(wakeup_gpio_num), "1")
        ser = wtserial(str(updating_com), 115200)
        smodbus = wtmodbus(None, None, None, 1, ser, iic_gpio.write_gpio)
        time.sleep(1)
        sensor_info = smodbus.get_sensor_base_parameter()
        print(sensor_info)
        print("Start Update.")
        iic_gpio.write_gpio(str(wakeup_gpio_num), "0")
        print(f"Read addr {updataAddr} <END>")

if __name__ == "__main__":
    main()
    exit(0)