from modbus import Modbus
from updater import Updater
from sys_params import IO_SysParams
import colorama
from colorama import Fore
import time
import os
import struct
import random


class SysUtils:

    @staticmethod
    def set_bit(word, number, bit):
        """Установка/снятие бита"""
        if bit not in (0, 1):
            return None
        if bit == 1:
            word |= 0b1 << number
        else:
            word &= ~(0b1 << number)
        # print(word)
        return word



class IO_Module:
    def __init__(self, modbus: Modbus):
        self.modbus = modbus
        self.updater = Updater(self.modbus)
        self.sys = IO_SysParams(self.modbus)
        self.DBG = False

'''
    
    def set_inputs_norm_state(self, val):
        self.write_holding_register(reg_table['in_norm'], val)



    def set_debounce_channel(self, input, val):
        self.write_holding_register(reg_table['in_deb_start'] + input - 1, val)

    # 0x0200 - текущее состояние выходов в обычно режиме
    def get_outputs(self):
        data = self.read_holding_registers(reg_table['out_cur'], 1)
        return format(data[0], '08b')

    # 0x0202 - режим работы выходов; 0 - обычный, 1 - ШИМ
    def get_outputs_mode(self):
        data = self.read_holding_registers(reg_table['out_mode'], 1)
        return format(data[0], '08b')
    
    def set_outputs_mode(self, val):
        self.write_holding_register(reg_table['out_mode'], val)

    def set_output_mode(self, output, val):
        ret = self.read_holding_registers(reg_table['out_mode'], 1)
        if val == 1:
            data = ret[0] | (0b1 << (output - 1))
        else:
            data = ret[0] & ~(0b1 << (output - 1))
        self.set_outputs_mode(data)

    # 0x0203 - состояние выходов (режим обычного выхода) в безопасном режиме работы
    def get_outputs_mode_save(self):
        data = self.read_holding_registers(reg_table['out_mode_save'], 1)
        return format(data[0], '08b')

    def set_outputs_mode_save(self, val):
        self.write_holding_register(reg_table['out_mode_save'], val)

    def set_output_mode_save(self, output, val):
        ret = self.read_holding_registers(reg_table['out_mode_save'], 1)
        if val == 1:
            data = ret[0] | (0b1 << (output - 1))
        else:
            data = ret[0] & ~(0b1 << (output - 1))
        self.set_outputs_mode_save(data)

    # 0x0210 - заполнение PWM (%)
    def get_pwm_duty(self, output):
        data = self.read_holding_registers(reg_table['pwm_duty'] + output - 1, 1)
        return data[0]
    
    def get_pwm_duty_all(self):
        return self.read_holding_registers(reg_table['pwm_duty'], 8)

    def set_pwm_duty(self, output, val):
        self.write_holding_register(reg_table['pwm_duty'] + output - 1, val)

    # 0x0220 - заполнение PWM (%)
    def get_pwm_duty_all_save(self):
        return self.read_holding_registers(reg_table['pwm_duty_save'], 8)

    def set_pwm_duty_save(self, output, val):
        self.write_holding_register(reg_table['pwm_duty_save'] + output - 1, val)

    # 0x0230 - период PWM (0.1 сек)
    def get_pwm_period_all(self):
        return self.read_holding_registers(reg_table['pwm_per'], 8)

    def set_pwm_period(self, output, val):
        self.write_holding_register(reg_table['pwm_per'] + output - 1, val)

    # 0x0240 - период PWM в безопасном режиме (0.1 сек)
    def get_pwm_period_all_save(self):
        return self.read_holding_registers(reg_table['pwm_per_save'], 8)

    def set_pwm_period_save(self, output, val):
        self.write_holding_register(reg_table['pwm_per_save'] + output - 1, 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, 15)
    # dev.MB_DEBUG = False
    
    print(format(SysUtils.set_bit(0b1111_0000_0000, 0, 1), '12b'))
    


    return

    for i in range(1, 9):
        dev.set_input_mode(i, 1)
        print('Inputs mode [bit field]   :', Fore.GREEN + dev.get_inputs_mode())

    for i in range(1, 9):
        dev.set_debounce_channel(i, 100 + i)
        # dev.set_output(i, 1)
        # dev.set_output_mode(i, 1)
        
    # 0x0203 - состояние выходов (режим обычного выхода) в безопасном режиме работы
    # for i in range(1, 9):
    #     dev.set_output_mode_save(i, 0)

    # 0x0210 - заполнение PWM (ms)
    # 0x0220 - заполнение PWM (%)
    # 0x0230 - период PWM (0.1 сек)
    # 0x0240 - период PWM в безопасном режиме (0.1 сек)
    # for i in range(1, 9):
    #     dev.set_pwm_duty(i, 10 + i)    
    #     dev.set_pwm_duty_save(i, 20 + i)
    #     dev.set_pwm_period(i, 10 + i)
    #     dev.set_pwm_period_save(i, 20 + i)

    # -----------------------------------------------------------------------------
    # Тесты PWM
    # Установить 1-ый выход в режим PWM
    # for i in range(3, 9):    
        # dev.set_output_mode(i, 0)
    
    # dev.set_output_mode(1, 1)
    # dev.set_pwm_period(1, 30)

    # dev.set_pwm_period(1, 50)
    # dev.set_pwm_duty(2, 10)
        
    # return

    # Установить нормальное состояние входов
    # dev.set_inputs_norm_state(0b00110101)

    # print(dev.get_pwm_duty_all())

    while True:
        print('~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~')
        # Значения входов (битовое поле)
        print('Inputs values [bit field] :', Fore.GREEN + dev.get_inputs_bit())

        # Режим работы входов (битовое поле)
        print('Inputs mode [bit field]   :', Fore.GREEN + dev.get_inputs_mode())

        # Нормальное состояние входов (битовое поле)
        print('Inputs norm [bit field]   :', Fore.GREEN + dev.get_inputs_norm_state())

        # Период антидребезга (ms)
        print('Debounce input (ms)       :', Fore.GREEN + ' | '.join(str(el) for el in dev.get_debounce_channels()))

        # Значение счетчиков
        data = dev.get_inputs_counters()
        print('Inputs counters           :', Fore.GREEN + ' | '.join(str(el) for el in data))

        # Текущее состояние выходов в обычном режиме
        print('Outputs norm [bit field]  :', Fore.GREEN + dev.get_outputs())

        # Состояние выходов в безопасном режиме
        print('Outputs save [bit field]  :', Fore.GREEN + dev.get_outputs_mode_save())

        # Режим работы выходов
        print('Outputs mode [bit field]  :', Fore.GREEN + dev.get_outputs_mode())

        # 0x0210 - заполнение PWM (ms)
        print('PWM duty cycle [%]        :', Fore.GREEN + ' | '.join(str(el) for el in dev.get_pwm_duty_all()))

        # 0x0220 - заполнение PWM в безопасном режиме (ms)
        print('PWM duty cycle (save) [%] :', Fore.GREEN + ' | '.join(str(el) for el in dev.get_pwm_duty_all_save()))

        # 0x0230 - период PWM (0.1 сек)
        print('PWM period [0.1 sec]      :', Fore.GREEN + ' | '.join(str(el) for el in dev.get_pwm_period_all()))
        
        # 0x0240 - период PWM в безопасном режиме (0.1 сек)
        print('PWM period save [0.1 sec] :', Fore.GREEN + ' | '.join(str(el) for el in dev.get_pwm_period_all_save()))

        # Дергаем одним выходом        
        # dev.set_output(2, trigger)
        # trigger = not trigger

        # # Для проверки выходов в обычном режиме
        # for i in range(1, 9):
        #     dev.set_output(i, 1)
        #     print('Outputs norm [bit field]  :', Fore.GREEN + dev.get_output())
        #     time.sleep(0.1)

        # for i in range(1, 9):
        #     dev.set_output(i, 0)
        #     print('Outputs norm [bit field]  :', Fore.GREEN + dev.get_output())
        #     time.sleep(0.1)

        # # Режим работы выходов
        # for i in range(1, 9):
        #     dev.set_output_mode(i, 1)
        #     print('Outputs mode [bit field]  :', Fore.GREEN + dev.get_outputs_mode())
        #     time.sleep(0.1)

        # for i in range(1, 9):
        #     dev.set_output_mode(i, 0)
        #     print('Outputs mode [bit field]  :', Fore.GREEN + dev.get_outputs_mode())
        #     time.sleep(0.1)

        # break
        time.sleep(1)



    # for i in range(1, 9):
    #     dev.set_input_mode(i, 1)
    #     print('Inputs mode [bit field]  :', Fore.GREEN + dev.get_inputs_mode())
    

    # for i in range(8, 0, -1):
    #     dev.set_input_mode(i, 0)
    #     print('Inputs mode [bit field]  :', Fore.GREEN + dev.get_inputs_mode())
        

if __name__ == '__main__':
    main()