#!/usr/bin/python
#coding: utf8

# Copyright CERN, 2011 - 2013 (INCAA Computers BV)
# Author: Samuel Iglesias Gonsalvez <siglesia@cern.ch>
# Author: Julian Lewis (Julian.Lewis@cern.ch)
# Author: INCAA Computers BV (info@incaacomputers.com)
# Licence: GPL v2 or later.
# Website: http://www.ohwr.org
# Website: http://www.incaacomputers.com
# Version: 2.0 (Last modifications: 13/06/2013)
#
# FPGA firmware: spec_pts_tempid.bin
#
# Description
#  Testing of the "Thermometer & Unique ID, DS18B20" chip on the SPEC board (IC19).

import sys
import rr
import time
import os

from onewire import COpenCoresOneWire

from ctypes import *
from ptsexcept import *

"""
test09: reads serial number of the temperature sensor.
"""

##-------------------------------------------------------------------------------------------------
##                                          DS18B20 class                                        --
##-------------------------------------------------------------------------------------------------

class CDS18B20:

    ROM_SEARCH = 0xF0
    ROM_READ   = 0x33
    ROM_MATCH  = 0x55
    ROM_SKIP   = 0xCC
    ROM_ALARM_SEARCH = 0xEC

    CONVERT_TEMP      = 0x44
    WRITE_SCRATCHPAD  = 0x4E
    READ_SCRATCHPAD   = 0xBE
    COPY_SCRATCHPAD   = 0x48
    RECALL_EEPROM     = 0xB8
    READ_POWER_SUPPLY = 0xB4

    def __init__(self, onewire, port):
        self.onewire = onewire
        self.port = port

    def read_serial_number(self):
        if(1 != self.onewire.reset(self.port)):
            msg = "ERROR: TempID IC13: Not responding"
            raise PtsError(msg)

        else:
            err = self.onewire.write_byte(self.port, self.ROM_READ)
            if err != 0:
                msg = "ERROR: TempID IC13: Write failed"
                raise PtsError(msg)

            family_code = self.onewire.read_byte(self.port)
            serial_number = 0
            for i in range(6):
                serial_number |= self.onewire.read_byte(self.port) << (i*8)
            crc = self.onewire.read_byte(self.port)

        return ((crc<<56) | (serial_number<<8) | family_code)

    def access(self, serial_number):
        if(1 != self.onewire.reset(self.port)):
            msg = "ERROR: TempID IC19: Not responding"
            raise PtsError(msg)

        else:
            err = self.onewire.write_byte(self.port, self.ROM_MATCH)
            block = []
            for i in range(8):
                block.append(serial_number & 0xFF)
                serial_number >>= 8
            self.onewire.write_block(self.port, block)
            return 0

    def read_temp(self, serial_number):
        err = self.access(serial_number)
        err = self.onewire.write_byte(self.port, self.CONVERT_TEMP)
        time.sleep(0.8)
        err = self.access(serial_number)
        err = self.onewire.write_byte(self.port, self.READ_SCRATCHPAD)
        data = self.onewire.read_block(self.port, 9)
        temp = (data[1] << 8) | (data[0])
        if(temp & 0x1000):
            temp = -0x10000 + temp
        temp = temp/16.0
        return temp

##-------------------------------------------------------------------------------------------------
##                                             main                                              --
##-------------------------------------------------------------------------------------------------

def main (default_directory='.'):
    # Configure the FPGA using the program fpga_loader
    path_fpga_loader = '../firmwares/fpga_loader';
    path_firmware = '../firmwares/spec_pts_tempid.bin';
    firmware_loader = os.path.join(default_directory, path_fpga_loader)
    bitstream = os.path.join(default_directory, path_firmware)
    print "Loading firmware: %s" % (firmware_loader + ' ' + bitstream)
    os.system( firmware_loader + ' ' + bitstream)
    #time.sleep(2);

    # Load board library and open the corresponding device
    print "Loading hardware access library and opening devices\n"
    spec = rr.Gennum();

    print "Test09 Start"
    init_test_time = time.time()
    ret_error = None

    TEMPID_1WIRE_WB_ADDR = 0x40000
    FAMILY_CODE          = 0x28

    onewire = COpenCoresOneWire(spec, TEMPID_1WIRE_WB_ADDR, 249, 49)
    ds18b20 = CDS18B20(onewire, 0)

    # Reading of unique ID

    unique_id = ds18b20.read_serial_number()
    if(unique_id == -1):
        msg = "ERROR: TempID IC13: Unable to read 1-wire thermometer"
        print(msg)
        ret_error = msg
    else:
        print("Unique ID: %.12X\n" % (unique_id))

    # Reading of temperature

    temp = ds18b20.read_temp(unique_id)
    print("Current temperature: %3.3f\n" % temp)

    # Cheking if received values are reasonable 

    if temp < 10.0 or temp > 50.0:
        msg = "ERROR: TempID IC13: Temperature: %d out of range[10 .. 50oC]" % (temp)
        print(msg)
        ret_error - msg

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

    end_test_time = time.time()
    print "End of Test09"
    print "RESULT: [{}]".format("FAIL" if ret_error else "OK")
    print 'Test09 elapsed time: {:.2f} seconds'.format(end_test_time-init_test_time)
    if ret_error:
        raise PtsError(ret_error)

    
    
if __name__ == '__main__' :
    main();
