import dwfpy as dwf
import numpy as np

F_SYSCLK_ANALOG_DISCOVERY=100e6
BITS_PER_FRAME=32
F_BITCLK=640e3
F_FRAMECLK=20e3

print(f'DWF Version: {dwf.Application.get_version()}')

def gen_pcm(device, data, f_bitclk=F_BITCLK, words_per_frame=1, bits_per_word=16):

    
    # Convert data to a list of bits
    bits_list = []
    for word in data:
        # Check if word violates the 16-bit signed integer range
        assert -32768 <= word <= 32767, 'Word value is out of range.'

        # Convert word to binary representation
        binary = bin(word & 0xFFFF)[2:].zfill(bits_per_word)

        # Add binary representation to bits_list
        bits_list.extend([int(bit) for bit in binary])


    print(f'Found device: {device.name} ({device.serial_number})')

    do_channels = device.digital_output
    
    f_sysclk=do_channels[0]._module.clock_frequency

    # Setup bitclock
    counter_bitclk=round(f_sysclk/f_bitclk)
    print(f"Set f bitclk to :{round(f_sysclk/counter_bitclk, 2)}Hz")
    assert counter_bitclk % 2 == 0, 'Counter must be even.'
    high_counter_bitclk=int(counter_bitclk/2)
    low_counter_bitclk=int(counter_bitclk/2)
    do_channels[0].setup(output_type=dwf.DigitalOutputType.PULSE, initial_counter=1, high_counter=high_counter_bitclk, low_counter=low_counter_bitclk)

    # Setup frameclock
    counter_frameclk= counter_bitclk*bits_per_word*words_per_frame
    assert counter_frameclk % counter_bitclk  == 0, 'Counter frameclk must be multiple of bit clock.'
    do_channels[1].setup(output_type=dwf.DigitalOutputType.PULSE, high_counter=counter_bitclk, low_counter=counter_frameclk-counter_bitclk)

    #setup data
    do_channels[2].setup(output_type=dwf.DigitalOutputType.CUSTOM, divider=counter_bitclk, high_counter=1, low_counter=1)
    do_channels[2].set_custom_bits(bits_list)

    return do_channels


if __name__ == '__main__':
    
    # Generate sine wave
    f_sine = 1e3
    t = np.arange(0, 1/f_sine, 1/F_FRAMECLK)
    sine_wave = np.sin(2 * np.pi * f_sine * t)*0.5

    # Convert sine wave to PCM data
    pcm_data = (sine_wave * 32767).astype(int)

    # Generate PCM channels
    with dwf.Device() as device:
        channels = gen_pcm(device, pcm_data, f_bitclk=F_BITCLK, words_per_frame=1, bits_per_word=16)
        channels.configure(start=True)
        input('Press Enter key to continue.')
        channels.reset()
