#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Wed Jan 10 15:56:30 2018

Driver class for MCP4822: 12-Bit, 2-Channel DAC.

SPI DATA FORMAT (MSB First):
Byte #1                                              Byte #2
Data In  :  !A/B  BUF  !GA  !SHDN  D11  D10  D9  D8  D7  D6  D5  D4  D3  D2  D1  D0

@author: jan
"""

import pin as GPIO
GPIO.config('./config.json')
import time

class MCP4822:
    '''
    Constructor of the class, setup the GPIO pin for SPI-communication
    '''
    def __init__(self, CLK_Pin, MOSI_Pin, CS_Pin, LDAC_Pin, nullVoltage=0, vref=None):
        GPIO.setmode(GPIO.BCM)
        
        self.clkPin = CLK_Pin
        self.mosiPin = MOSI_Pin
        self.csPin = CS_Pin
        self.ldacPin = LDAC_Pin
        
        if vref is None:
            self.vref = 2.048
        else:
            self.vref = vref

        GPIO.setup(self.clkPin,  GPIO.OUT)
        GPIO.setup(self.mosiPin, GPIO.OUT)
        GPIO.setup(self.csPin,   GPIO.OUT)
        GPIO.setup(self.ldacPin,   GPIO.OUT)

        GPIO.output(self.csPin, GPIO.HIGH)
        GPIO.output(self.clkPin, GPIO.LOW)
        GPIO.output(self.mosiPin, GPIO.LOW)
        GPIO.output(self.ldacPin, GPIO.LOW)

        self.nullVoltage = nullVoltage
        self.write(self.nullVoltage,1)

    def U2dac(self,U,DAC):
        #U: voltage (V) [0V-4.096V]
        #DAC: DACA -> 0
        #     DACB -> 1
        #calculate binary data
        if U > 2*self.vref:
            print('maximum output voltage overshot')
            SPIdata = 666
        elif U > self.vref:
            U = U/2
            #buffered, gain=2x, enabled, data
            SPIdata = DAC<<15 | 1<<14         | 1<<12 | int(U/self.vref * ((1<<12)-1))
        elif U >= 0:
            #buffered, gain=1x, enabled, data
            SPIdata = DAC<<15 | 1<<14 | 1<<13 | 1<<12 | int(U/self.vref * ((1<<12)-1))
        else:
            print('minimum output voltage undershot')
            SPIdata = -666
        return SPIdata


    def write(self,voltage,channel):
        #Convert voltage to spi command
        command = self.U2dac(voltage,channel)

        # Start communication
        GPIO.output(self.csPin, GPIO.LOW)

        #Commucation consists of 16 transfered bits
        for bit in range(16):
            #Set outgoing bit
            if command & 0x8000:
                GPIO.output(self.mosiPin, GPIO.HIGH)
            else:
                GPIO.output(self.mosiPin, GPIO.LOW)

            #Shift command by 1 bit for next tick
            command <<= 1

            # Toggle clock pin
            GPIO.output(self.clkPin, GPIO.HIGH)
            #time.sleep(0.00001)
            GPIO.output(self.clkPin, GPIO.LOW)
            #time.sleep(0.00001)

        # Set chip select high to end the write process
        GPIO.output(self.csPin, GPIO.HIGH)
