'''
Copyright 2021 Stichting Nederlandse Wetenschappelijk Onderzoek Instituten,
ASTRON Netherlands Institute for Radio Astronomy
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
 http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

Test script to write single registers of RCU2_ADC

'''
import sys
import time
sys.path.insert(0,'.')
import os
if os.name =="posix":
    from I2C_serial_pi import *
else:
    from I2C_serial import *

sleep_time=0.05
CHECK_I2C_DEVICES = False
WRITE_DATA = True
READ_BYTE = True
PWR_RST = False
SET_ADC = True

CS   = 0

SCLK = [1, 3, 5]
SDIO = [0, 2, 4]
ADC_ORDER = [0, 1, 2]


def off_on(address=0x76):
    print("Off_on")
    I2C_device = I2C(address)
    I2C_device.write_bytes(0x06, 00)
    I2C_device.write_bytes(0x07, 00)
    I2C_device.write_bytes(0x02, 0x0)
    I2C_device.write_bytes(0x03, 0x8)
    sleep(5)
    I2C_device.write_bytes(0x02, 0xF0)
    I2C_device.write_bytes(0x03, 0xF0)

def blink_led(address=0x76, times = 5):
    print("Blink LED")
    I2C_device = I2C(address)
    I2C_device.write_bytes(0x07, 00)
    for cnt in range(times):
        I2C_device.write_bytes(0x03, 0x40)
        sleep(0.5)
        I2C_device.write_bytes(0x03, 0x80)
        sleep(0.5)
    I2C_device.write_bytes(0x03, 0x40)


def Write_byte_ADC(ADC_reg_address, ADC_data, ADC_bytes=1, ADC_NR = 0, ADDRESS=0x20):
    #
    # Write Byte to the ADC
    #
    I2C_device = I2C(ADDRESS)
    ADC_rw    = 0x00 # 0 for write, 1 for read
    stri = "Write : {0:2x} to Address : {1:2x}".format(ADC_data, ADC_reg_address)
    print(stri)
    data = ( ADC_rw << 23) + ( ADC_bytes << 21 ) + (ADC_reg_address << 8) + int(ADC_data)

    I2C_device.write_bytes(0x06, 00) # Config registers IO-expander
    I2C_device.write_bytes(0x07, 00) # Config registers IO-expander
    I2C_device.write_bytes(0x03, (0x0F ^ (0x01 << ADC_NR)))

    bit_array = "{0:{fill}24b}".format(data, fill='0')
    print(bit_array)
    for bit in bit_array:
        for clk in range(2):
            Write_data = 0x00 | (clk << SCLK[ADC_NR]) | (int(bit) << SDIO[ADC_NR])
            I2C_device.write_bytes(0x02, Write_data)
    #            sleep(sleep_time)

    for extra_cylces in range(5):
        for clk in range(2):
            Write_data = 0x00 | (clk << SCLK[ADC_NR]) | (0 << SDIO[ADC_NR])
            I2C_device.write_bytes(0x02, Write_data)

    Write_data = (0x00 |  (0 << SCLK[ADC_NR]) | ( 0 << SDIO[ADC_NR] ))
    I2C_device.write_bytes(0x02, Write_data)
    I2C_device.write_bytes(0x03, 0x0F)

def Read_byte_ADC(ADC_reg_address, ADC_bytes=0, ADC_NR = 0, ADDRESS=0x20 ):
    #
    # Read Byte from the ADC
    #
    I2C_device = I2C(ADDRESS)
    ADC_rw    = 0x01 # 0 for write, 1 for read
    
    stri = "Read ADC from Address {:8x}".format(ADC_reg_address)
    print(stri)
    
    data = ( ADC_rw << 15) + ( ADC_bytes << 13 ) + ADC_reg_address
    
#    print("write read command")
    I2C_device.write_bytes(0x06, 00)
    I2C_device.write_bytes(0x07, 00)
    I2C_device.write_bytes(0x03, (0x0F ^ (0x01 << ADC_NR)))

    bit_array = "{0:{fill}16b}".format(data, fill='0')
    for bit in bit_array:
        for clk in range(2):
            Write_data = 0x00 |  (clk << SCLK[ADC_NR]) | ( int(bit) << SDIO[ADC_NR] )
            I2C_device.write_bytes(0x02, Write_data)
#            sleep(sleep_time)
    I2C_device.write_bytes(0x03, 0x0F)
#    print("read byte")
    I2C_device.write_bytes(0x06, (1 << SDIO[ADC_NR]))
    I2C_device.write_bytes(0x03, (0x0F ^ (0x01 << ADC_NR)))
    read_bit = ''
    for cnt in range(8*(ADC_bytes+1)):
        for clk in [1,0]: # Read after faling edge
            Write_data = 0x00 | (clk << SCLK[ADC_NR]) | ( int(bit) << SDIO[ADC_NR] )
            I2C_device.write_bytes(0x02, Write_data)
        ret_ack, ret_value = I2C_device.read_bytes(0x00, 1)
        if ret_ack:
            read_bit += str((int(ret_value, 16) >> SDIO[ADC_NR])  & 0x01)
        else:
            print("ACK nok")
    I2C_device.write_bytes(0x03, 0x0F)
    I2C_device.write_bytes(0x07, 00)
    Write_data = 0x00 | (0 << SCLK[ADC_NR]) | ( 0 << SDIO[ADC_NR] )
    I2C_device.write_bytes(0x02, Write_data)
    I2C_device.write_bytes(0x03, 0x0F)
    stri = "Read back data is: {0:2x} ".format(int(read_bit, 2))
    print(stri)
    return read_bit;

def rcu_sensors():
    addr = 0x14
    Vref = 3.3
    one_step = Vref/(2**(16+1))
    I2C_device = I2C(addr)
    I2C_device.write_bytes(0xB8, 0xB0)
    sleep(1)
    ret_ack, ret_value = I2C_device.read_last_reg(3)
    if ret_ack:
        stri = "Return value input 0 : 0x{0} ".format(ret_value)
        print(stri)
        if int(ret_value, 16) >= 0xC00000:
            print("over range")
        else:
            steps = (int(ret_value, 16) & 0x1FFFFF) >> 6
            voltage = one_step * steps
            string = "Voltage is {0:.4f}".format(voltage)
            print(string)
    else:
        print("ACK nok")
    sleep(1)
    temp_slope = 93.5E-6 * 2**(16+1) / Vref
    I2C_device.write_bytes(0xA0, 0xE0)
    sleep(1)
    ret_ack, ret_value = I2C_device.read_last_reg(3)
    if ret_ack:
        raw_value  = (int(ret_value, 16) & 0x1FFFFF) >> 6
        temperature_K = (raw_value/temp_slope)
        temperature = temperature_K-273
        stri = "Return value : 0x{0} Temperature : {1:.2f} gr. C".format(ret_value, temperature)
        print(stri)
    else:
        print("ACK nok")


def rw_eeprom(value=0xAB):
    ADDR = 0x50
    I2C_eeprom = I2C(0x53)
    I2C_eeprom.write_bytes(0x00, value)
    I2C_eeprom.write_pointer(0x00)
    ret_ack, ret_value = I2C_eeprom.read_last_reg(1)
    if ret_ack:
        stri = "EEPROM readback : {0} ".format(ret_value)
        print(stri)
    else:
        print("ACK nok")

def power(state):
    ADDRESS_IO = 0x76
    I2C_IO_device = I2C(ADDRESS_IO)
    I2C_IO_device.write_bytes(0x06, 00)
    if state=='ON':
        print("Switch ON")
        bits_to_set = 0x40
        I2C_IO_device.write_bytes(0x02, bits_to_set)
    else:
        I2C_IO_device.write_bytes(0x06, 0xFF)
        print("Switch OFF")
        bits_to_set = 0x0



def set_gain(gain, channel):
    string = "Set Channel {0} to a gain of {1} dB".format(channel, gain)
    print(string)
    if channel <= 1:
        ADDRESS_IO = 0x75
        max_gain = 15
        min_gain = -6
    elif channel <= 2:
        ADDRESS_IO = 0x76
        max_gain = 20
        min_gain = -4
    else:
        print(" wrong channel number 0 <= Channel <= 2 channel set to 2")
        channel = 2
        ADDRESS_IO = 0x76
        max_gain = 20
        min_gain = -4
    if min_gain <= gain <= max_gain:
        set_gain = max_gain-gain
    else:
        set_gain = max_gain-min_gain
    bits_to_set = set_gain
    I2C_IO_device = I2C(ADDRESS_IO)
    I2C_IO_device.write_bytes(0x06, 00)
    I2C_IO_device.write_bytes(0x07, 00)
    if channel == 0:
        I2C_IO_device.write_bytes(0x02, bits_to_set)
    elif channel == 1:
        I2C_IO_device.write_bytes(0x03, bits_to_set)
    elif channel == 2:
        I2C_IO_device.write_bytes(0x02, bits_to_set | 0x40)
    else:
        print("no update done")

if PWR_RST:
    power(False)
    sleep(1)
    power(True)

if CHECK_I2C_DEVICES:
    blink_led(address = 0x76, times=6)
    rw_eeprom(0xAC)
    rcu_sensors()


ADC_address = 0x3A # see address table
ADC_data    = 0x00 # 8 bits data
ADC_bytes   = 0x00 # 00 / 11 + 1 bytes
ADCNR = 1

ADCNR = 1
stri = "Set channel {} in test mode".format(ADCNR)
print(stri)
#    Write_byte_ADC(0x5F, 0x14, ADC_NR=ADCNR)  # OK  ILAS normal mode standard value
#    Write_byte_ADC(0x15, 0x07, ADC_NR=ADCNR)  # OK  CML level
#Write_byte_ADC(0x3A, 0x01, ADC_NR=ADCNR)  # SYNC / SYSREF control
#    Write_byte_ADC(0x60, 0x80, ADC_NR=ADCNR)  # Single ended SYNC pulse
#Write_byte_ADC(0xFF, 0x01, ADC_NR = ADCNR) # ILAS normal mode standard value
#Read_byte_ADC(0x3A, ADC_NR = ADCNR)
#Write_byte_ADC(0x08, 0x35, ADC_NR = 0) # ADC OFF
#Write_byte_ADC(0x08, 0x35, ADC_NR = 1) # ADC OFF
#Write_byte_ADC(0x08, 0x35, ADC_NR = 2) # ADC OFF
#Write_byte_ADC(0x08, 0x00, ADC_NR = 0) # ADC ON
#Write_byte_ADC(0x08, 0x00, ADC_NR = 1) # ADC ON
#Write_byte_ADC(0x14, 0x05, ADC_NR = 2) # Invert signal
#Write_byte_ADC(0x0D, 0x06, ADC_NR = 0) # Ramp output
#Write_byte_ADC(0xFF, 0x01, ADC_NR = 0)  # transfer settings
#Write_byte_ADC(0x0D, 0x06, ADC_NR = 1) # Ramp output
#Write_byte_ADC(0xFF, 0x01, ADC_NR = 1)  # transfer settings
#Write_byte_ADC(0x0D, 0x06, ADC_NR = 2) # Ramp output
#Write_byte_ADC(0xFF, 0x01, ADC_NR = 2)  # transfer settings
#
power('OFF')
blink_led(address=0x76, times=5)
power('ON')
blink_led(address=0x76, times=5)
power('OFF')
blink_led(address=0x76, times=5)
power('ON')