#!/usr/bin/python
#===============================================================================
# CERN (BE-CO-HT)
# Read the CONV-TTL-BLO board ID and current temperature from DS18B20 chip
#===============================================================================
# author: Theodor Stana (t.stana@cern.ch)
#
# date of creation:
#
# version: 1.0
#
# description:
#   The script implements some classes to communicate to the OpenCores One-Wire
#   master core implemented inside the CONV-TTL-BLO and uses these classes to
#   retrieve the board ID and the current temperature on-board the CONV-TTL-BLO.
#
#===============================================================================
# GNU LESSER GENERAL PUBLIC LICENSE
#===============================================================================
# This source file is free software; you can redistribute it and/or modify it
# under the terms of the GNU Lesser General Public License as published by the
# Free Software Foundation; either version 2.1 of the License, or (at your
# option) any later version. This source is distributed in the hope that it
# will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
# of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# See the GNU Lesser General Public License for more details. You should have
# received a copy of the GNU Lesser General Public License along with this
# source; if not, download it from http://www.gnu.org/licenses/lgpl-2.1.html
#===============================================================================
# last changes:
#===============================================================================
#  TODO: - 
#===============================================================================
# Import system modules
import sys
import time
import os

# Import common modules
sys.path.append("../ei2c")
from ei2c import *
import ei2cdefine


##------------------------------------------------------------------------------
## DS18B20 class
##------------------------------------------------------------------------------
class CDS18B20:
    OFFSET_UIDLR = 0xA8
    OFFSET_UIDHR = 0xAC
    OFFSET_TEMPR = 0xB0

    def __init__(self, elma, slot):
        self.elma = elma
        self.slot = slot

    def read_serial_number(self):
        l = self.elma.read(self.slot, self.OFFSET_UIDHR)
        h = self.elma.read(self.slot, self.OFFSET_UIDLR)
        return (h << 32 | l)

    def read_temp(self):
        temp = self.elma.read(self.slot, self.OFFSET_TEMPR) & 0xffff
        return temp / 16.0


##------------------------------------------------------------------------------
## main
##------------------------------------------------------------------------------
if __name__ == "__main__":

    FAMILY_CODE = 0x28

    # Get the IP, user and password for the ELMA crate from either user input,
    # or ei2cdefine.py
    if (ei2cdefine.ENABLED):
        ip   = ei2cdefine.HNAME
        user = ei2cdefine.USER
        pwd  = ei2cdefine.PWD
    else:
        ip   = raw_input("ELMA crate IP or hostname : ")
        user = raw_input("ELMA crate user name      : ")
        pwd  = raw_input("ELMA crate password       : ")
    elma = EI2C(ip, user, pwd)
    elma.open()

    # Ask for slot number
    while 1:
        try:
            slot = raw_input("Slot no.: ")
            slot = int(slot)
            break
        except TypeError as e:
            print("Please input a decimal slot number.")
        except SlotError as e:
            print(e.strerror)
        except KeyboardInterrupt:
            sys.exit();
        except:
            print("Unexpected error: ", sys.exc_info()[0])

    # Print which board is detected in the selected slot
    bid = elma.get_bid(slot)

    # CONV-TTL-BLO gateware changed memory map in v3.0 and golden v0.2
    gwvers = elma.read(slot, 0x04) & 0xff
    baseaddr = 0x200
    if (bid == "TBLO"):
        if ((gwvers >= 0x10) and (gwvers <= 0x22)):
            baseaddr = 0x080

    # Create onewire and thermometer objects
    onewire = COpenCoresOneWire(elma, slot, baseaddr, 99, 19)
    ds18b20 = CDS18B20(elma, slot)

    # Reading of unique ID
    unique_id = ds18b20.read_serial_number()
    if(unique_id == -1):
        msg = "ERROR: TempID IC20: Unable to read 1-wire thermometer"
        print(msg)
    else:
        print("Unique ID: %.12X" % (unique_id))

    # Reading of temperature
    temp = ds18b20.read_temp(unique_id)
    print("Current temperature: %3.3f" % temp)

    # Cheking if received values are reasonable
    if temp < 10.0 or temp > 50.0:
        msg = "ERROR: TempID IC20: Temperature: %d out of range[10 .. 50oC]" % (temp)
        print(msg)

    if((unique_id & 0xFF) != FAMILY_CODE):
        family_code = unique_id & 0xFF
        msg = "ERROR: TempID IC20: Invalid family code: 0x%.8X" % (family_code)
        print(msg)

    elma.close()

