#
#           www.tctec.net
#
# Python example for Top16AT  io module
#
# 18-November-2023
#
#
# Driver install notes:
#
# sudo apt-get install libftdi-dev
#
#  From install instructions here:
#  https://pylibftdi.readthedocs.io/en/0.13/installation.html
#
# To give user access to ftdi usb device:
#
# created file /etc/udev/rules.d/99-libftdi.rules
# with the contents:
# SUBSYSTEMS=="usb", ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6001", GROUP="dialout", MODE="0660"
# SUBSYSTEMS=="usb", ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6014", 
#
#
# pip3 install pylibfti
# to install python library (depends on libftdi-dev install as above)
#
#

from pylibftdi import Device, Driver

import time


# utility function, convert value to hex and buffer with zero
#
def toHex(number):
    theString = (("0x{:X}".format(number))[2:])
    if(len(theString) == 1):
        theString = '0' + theString
        
    return(theString)


def get_top16AT_list():
    """
    return a list of lines, each a colon-separated
    vendor:product:serial summary of detected devices
    """
    dev_list = []
    for device in Driver().list_devices():
        # device must always be this triple
        
        vendor, product, serial = device
        #if we found a top16II device
        #
        if(product == 'TOP16II'):
            dev_list.append(f"{serial}")
            
    return dev_list



def setPWM(board, output, setting):
    
        if(output < 1) or (output > 8):
            return
        
        if(setting < 0) or (setting > 255):
            return
        
    
        
        commandString = "#p"+str(output)+toHex(setting).zfill(2)+"\r"
        board.write(commandString)
        time.sleep(0.03)
        # read OK response
        #
        board.read(5)
        
        
# set digital outputs
# mask : if a bit is set to '1' then the output is affected
#
#
def setDigitalOut(board, states, mask):
    
        if(states < 0) or (states > 255):
            return
        
        if(mask < 0) or (mask > 255):
            return
            
        
        commandString = "#"+toHex(states)+toHex(mask)+"\r"
        board.write(commandString)
        time.sleep(0.03)
        # read OK response
        #
        board.read(5)


def readAnalogIn(board, ain):
    
        if(ain < 1) or (ain > 8):
            return
        
            
        board.flush_input()
        
        commandString = "#z"+str(ain)+"\r"
        board.write(commandString)
        time.sleep(0.02)
        value_str = board.read(10)
        value_str = value_str.decode()
        
        #validate
        if(value_str[0] == '>'):
            reading = float(value_str[1:9])
            return(reading)
        
        return(NaN)



def main():
    
    
    
    
    top16list = get_top16AT_list()
    
    for device in top16list:
        print(device)
        
    # open the first device found
    #
    if(len(top16list) > 0):
        serialNumber = top16list[0]
        board = Device(device_id = serialNumber)
        board.baudrate = 115200
        
        # glow the PWM outputs
        #       
        
        setPWM(board, 1, 1)
        setPWM(board, 2, 20)
        setPWM(board, 3, 40)
        setPWM(board, 4, 60)
        setPWM(board, 5, 100)
        setPWM(board, 6, 200)
        setPWM(board, 7, 250)
        setPWM(board, 8, 150)
        
        time.sleep(2)
        
        # set digital outputs
        #
       
        setDigitalOut(board, 0b11111111, 0b11111111)
        time.sleep(0.3)
        # turn off half
        #
        setDigitalOut(board, 0b00000000, 0b10101010)
        time.sleep(0.3)
        
        
        for i in range(5):
          
            # toggle all
            #
            setDigitalOut(board, 0b10101010, 0b11111111)
            time.sleep(0.3)
            setDigitalOut(board, 0b01010101, 0b11111111)
            time.sleep(0.3)
            
            
            
        for i in range (1000):
            # read analog inputs
            #
            ain1 = readAnalogIn(board,1)
            ain2 = readAnalogIn(board,2)
            ain3 = readAnalogIn(board,3)
            ain4 = readAnalogIn(board,4)
            ain5 = readAnalogIn(board,5)
            ain6 = readAnalogIn(board,6)
            ain7 = readAnalogIn(board,7)
            ain8 = readAnalogIn(board,8)
            
            
            print('{A1}\t{A2}\t{A3}\t{A4}\t{A5}\t{A6}\t{A7}\t{A8}'.format(A1=ain1, A2=ain2,A3=ain3,A4=ain4,A5=ain5,A6=ain6,A7=ain7,A8=ain8))
        
            
      
        
            


        
        
main()
