#!/usr/bin/python2
# encoding: utf-8
"""
Temperature.py

Created by Alexander Rössler on 2014-03-24.
"""

from fdm.r2temp import R2Temp

import argparse
import time
import sys

import hal

# The CRAMPS board thermistor input has one side grounded and the other side
# pulled high through a 1.00K resistor to 1.8V.  Following this is a 4.7K
# resistor, some protection diodes, and filtering capacitors.  The ADC voltage
# read is the filtered voltage across the thermistor.
def adc2r_cramps(pin,ref):
#    V_adc = pin.rawValue * 1.8 / 4096.0
#    V_adc = pin.rawValue * 3.3 / 3315.0
    V_adc = pin.rawValue * 3.3 / ref
    V_T  = 0.0  # Voltage across the thermistor
    R_PU = 2000.0 #Pull-up resistence 
    I_PU = 0.0  # Current flowing through the pull-up resistor
    R_T  = 0.0  # Resistance of the thermistor

    V_T = V_adc

    # No dividing by zero or negative voltages despite what the ADC says!
    # Clip to a small positive value
    I_PU = max((3.3 - V_T ) / R_PU, 0.000001) 
#    I_PU = max((5.0 - V_T ) / R_PU, 0.000001) 

    R_T = V_T / I_PU

    return R_T

class Pin:
    def __init__(self):
        self.pin = 0
        self.r2temp = None
        self.halValuePin = 0
        self.halRawPin = 0
        self.filterSamples = []
        self.filterSize = 10
        self.rawValue = 0.0
        self.filterSamples = []
        self.rawValue = 0.0

    def addSample(self, value):
        self.filterSamples.append(value)
        if (len(self.filterSamples) > self.filterSize):
            self.filterSamples.pop(0)
        sampleSum = 0.0
        for sample in self.filterSamples:
            sampleSum += sample
        # No dividing by zero or negative voltages despite what the ADC says!
        # Clip to a small positive value
        self.rawValue  = max(sampleSum / len(self.filterSamples), 0.000001) 


def getHalName(pin):
    return "ch-" + '{0:02d}'.format(pin.pin)


def adc2Temp(pin,ref):
#    R1 = 4700.0
#    R2 = R1 / max(4095.0 / pin.rawValue - 1.0, 0.000001)
#    return round(pin.r2temp.r2t(R2) * 10.0) / 10.0

    R = adc2r_cramps(pin,ref)
    return round(pin.r2temp.r2t(R) * 10.0) / 10.0


parser = argparse.ArgumentParser(description='HAL component to read Temperature values over I2C')
parser.add_argument('-n', '--name', help='HAL component name', required=True)
parser.add_argument('-i', '--interval', help='I2C update interval', default=0.05)
parser.add_argument('-r', '--ref', help='Calibrate Thermistor ref voltage via ref ch', default="n")
parser.add_argument('-c', '--channels', help='Komma separated list of channels and thermistors to use e.g. 01:semitec_103GT_2,02:epcos_B57560G1104', required=True)
parser.add_argument('-f', '--filter_size', help='Size of the low pass filter to use', default=10)
parser.add_argument('-d', '--delay', help='Delay before the i2c should be updated', default=0.0)

args = parser.parse_args()

updateInterval = float(args.interval)
delayInterval = float(args.delay)
filterSize = int(args.filter_size)
error = True
watchdog = True

# Create pins
pins = []

if (args.channels != ""):
    channelsRaw = args.channels.split(',')
    for channel in channelsRaw:
        pinRaw = channel.split(':')
        if (len(pinRaw) != 2):
            print(("wrong input"))
            sys.exit(1)
        pin = Pin()
        pin.pin = int(pinRaw[0])
        if ((pin.pin > 7) or (pin.pin < 0)):
            print(("Pin not available"))
            sys.exit(1)
        if (pinRaw[1] != "none"):
            pin.r2temp = R2Temp(pinRaw[1])
        pin.filterSize = filterSize
        pins.append(pin)

# Initialize HAL
h = hal.component(args.name)
for pin in pins:
    pin.halRawPin = h.newpin(getHalName(pin) + ".raw", hal.HAL_FLOAT, hal.HAL_OUT)
    if (pin.r2temp is not None):
        pin.halInputPin = h.newpin(getHalName(pin) + ".input", hal.HAL_U32, hal.HAL_IN)
        pin.halValuePin = h.newpin(getHalName(pin) + ".value", hal.HAL_FLOAT, hal.HAL_OUT)
if (args.ref == 'y'):
    halRefPin = h.newpin("voltage-ref", hal.HAL_U32, hal.HAL_IN)
halErrorPin = h.newpin("error", hal.HAL_BIT, hal.HAL_OUT)
halNoErrorPin = h.newpin("no-error", hal.HAL_BIT, hal.HAL_OUT)
halWatchdogPin = h.newpin("watchdog", hal.HAL_BIT, hal.HAL_OUT)
h.ready()

halErrorPin.value = error
halNoErrorPin.value = not error
halWatchdogPin.value = watchdog

try:
    time.sleep(delayInterval)
    while (True):
        try:
            if (args.ref == 'y'):
                ref = (halRefPin.value & 0x00000FFF)
                if (ref == 0):
                    ref = 3300
            else:
                ref = 3300
            for pin in pins:
                value = float(pin.halInputPin.value & 0x00000FFF)
                pin.addSample(value)
                pin.halRawPin.value = pin.rawValue
                if (pin.r2temp is not None):
                    pin.halValuePin.value = adc2Temp(pin,ref)
            error = False
        except IOError as e:
            error = True

        halErrorPin.value = error
        halNoErrorPin.value = not error
        watchdog = not watchdog
        halWatchdogPin.value = watchdog
        time.sleep(updateInterval)
except:
    print(("exiting HAL component " + args.name))
    h.exit()
