# Christian Fiot June 2021
# LED driver PCA9955B   16bits
# Sample catcher controller VA
#
# Installation Pump platform circuit
# Set J2-J3 to match connection connector to the controller ...
# Pump0 =
#
# Usage:
# from M24C02 import M24C02
# EEP7 = M24C02(0x057, traceDebug=True)
# EEP7.begin()  # return True if chip is found
# EEP7.readHeader()
# EEP7.writeHeader( recSmp7[10])
# EEP7.readStartConditions()
# EEP7.writeStartConditions( recSmp7[21])
# EEP7.readStopConditions()
# EEP7.writeStopConditions( recSmp7[7])
# EEP7.resetSampler()
#
#
# Sample header (org 0, len 13)
# 0 = File format - 1 - Version 1
# 1 = ID (high byte) / 16bit
# 2 = ID (low byte)
# 3 = sampling storage type - 1= bag, 2= desorption tube
# 4 = desorption tube type - 1= Tenax, 2= Carcopack, 3= Carbosieve ...
# 5 = sensor target - 1= VOC, 2= PID, 3= CH4, 4= CO2, 5= H2S
# 6 = detection trigger (high byte) - ppm / 16bit
# 7 = detection trigger (low byte)
# 8 = sampling duration sec (high byte) - up to 18hour / 16bit
# 9 = sampling duration sec (low byte)
# 10 = usage / cycles  counter H / 16bit
# 11 = usage / cycles counter L
# 12 = Status - 0= empty, 1= in use,  2= filled
#
#
# Sample Start conditions (Org 20, len 21)
# 0 = Fipy ID (high byte) / 16bit
# 1 = Fipy ID (low byte)
# 2 = Latitude HH ( Latitude * 10^6) /  from 89.999999 to -89.999999  * 10^6  /  32bit
# 3 = Latitude HL
# 4 = Latitude LH
# 5 = Latitude lL
# 6 = Longitude HH ( Longitude * 10^6) /  from 89.999999 to -89.999999  * 10^6  /  32bit
# 7 = Longitude HL
# 8 = Longitude LH
# 9 = Longitude LL
# 10 = year fron 0 to 99 (2000 to 2099)
# 11 = month
# 12 = day
# 13 = hour
# 14 = minute
# 15 = second
# 16 = temperature in degree C
# 17 = relative humidity in %
# 18 = pressure in Pa
# 19 = gas reading (high byte) in ppm / 16bit
# 20 = gas reading (low byte)
#
# Sample End conditions (org 50, len 7)
# 0 = sampling duration sec (high byte) / 16bit
# 1 = sampling duration sec (low byte)
# 2 = temperature in degree C
# 3 = relative humidity in %
# 4 = pressure in Pa
# 5 = gas reading (high byte) in ppm / 16bit
# 6 = gas reading (low byte)


import time # utime
import ustruct
from trap import *
from machine import I2C # 2.2.18




# valid adr $50 to $57
class M24C02():

    def __init__(self, iicadr=0x057, i2c=None, sda='P22', scl='P21', traceDebug=False, sdAccess=False):
        self.trace = traceDebug
        self.adr = iicadr
        self.sdAccess = sdAccess

        self.data = bytearray(1)
        self.fileHeader = [0] * 13

        # I2C bus declaration is extenal
        # PCA is connected on I2C bus #1   SDA-P22   SCL-P21
        if i2c is not None: # 2.2.18
            self.i2c1 = i2c
        else:
            # from machine import I2C
            self.i2c1 = I2C(0, mode=I2C.MASTER, pins=(sda, scl))


    def write(self, adreg, data, paused=5): # tw
        self.data[0] = data
        self.i2c1.writeto_mem(self.adr, adreg, self.data)
        time.sleep_ms(paused)

    def read(self, adreg):
        self.i2c1.readfrom_mem_into(self.adr, adreg, self.data)
        return self.data[0]

    def begin(self):
        try:
            # self.read(0)
            # print('Begin I2C1 scan ...')
            # print(self.i2c1.scan())
            self.readHeader()
            print('Detected PumpPlatform #' + str(self.adr & 0x07) + ' - M24C02 Adr: ' + str(self.adr))
            return True

        except Exception as e:
            scratch =  'PumpPlatform - M24C02 Adr:' + str(self.adr) + ' not found - '
            file_errLog(0, scratch + str(e), self.sdAccess)
            if self.trace:
                # 2.2.18 print('Begin I2C1 scan ...')
                # 2.2.18 print(self.i2c1.scan())
                pass
            return False

    # Sample header (org 0, len 13)
    # 0 = File format - 1 - Version 1
    # 1 = ID (high byte) / 16bit
    # 2 = ID (low byte)
    # 3 = sampling storage type - 1= bag, 2= desorption tube
    # 4 = desorption tube type - 1= Tenax, 2= Carcopack, 3= Carbosieve ...
    # 5 = sensor target - 1= VOC, 2= PID, 3= CH4, 4= CO2, 5= H2S
    # 6 = detection trigger (high byte) - ppm / 16bit
    # 7 = detection trigger (low byte)
    # 8 = sampling duration sec (high byte) - up to 18hour / 16bit
    # 9 = sampling duration sec (low byte)
    # 10 = usage / cycles  counter H / 16bit
    # 11 = usage / cycles counter L
    # 12 = Status - 0= empty, 1= in use,  2= filled
    def readHeader(self):
        EEPacket = []
        for x in range(13):
            self.read(x)
            EEPacket.append(self.data[0])
        if self.trace:
            print('Sample header')
            print('File format: ' + str(EEPacket[0]))
            print('ID: ' + str((EEPacket[1] * 256) +  EEPacket[2]) )
            print('Gas storage type: ' + str(EEPacket[3]))
            print('Desorption tube type: ' + str(EEPacket[4]))
            print('Sensor target type: ' + str(EEPacket[5]))
            print('Detection trigger: ' + str( ( EEPacket[6] * 256) +  EEPacket[7]) + ' ppm')
            print('Sampling duration: ' + str( ( EEPacket[8] * 256) +  EEPacket[9]) + ' Sec')
            print('Cycle count: ' + str( ( EEPacket[10] * 256) +  EEPacket[11]))
            print('Status: ' + str(EEPacket[12]))
        self.fileHeader = EEPacket
        return EEPacket

    # used once when a container is created
    # EEPacket = [Format, idH, idL, storage, tube, target, triggerH, triggerL, smpH, smpL]
    # EEPacket = [1, 0, 1, 2, 1, 1, 0, 10, 7, 8]
    # EEP7.writeHeader(EEPacket)
    def writeHeader(self, EEPacket):
        n = 0
        for x in EEPacket:
            self.write(n, x)
            if self.trace:
                print('Sample (' + str(n) + '): ' + str(x) )
            n += 1
        self.write(10, 0) # clear cycle count
        self.write(11, 0)
        self.write(12, 0) # update status, 0= empty
        self.readHeader() # update self.fileHeader

    # inc cycle count - the number of time the tube is used
    def incCycle(self):
        # cycles = self.read(10, 0) * 256 # inc cycle count in header
        # cycles = cycles + self.read(11, 0)
        cycles = (self.fileHeader[10] << 8) + self.fileHeader[11]
        cycles = cycles + 1
        if self.trace:
            print('Cycle count: ' + str( cycles))
        self.write(10, cycles >> 8)
        self.write(11, cycles & 0x0FF)
        self.readHeader() # update self.fileHeader

    def updateStatus(self, n):
        self.write(12, n) # update status
        self.readHeader() # update self.fileHeader

    # clear Start and End condition data
    def resetSampler(self):
        EEPacket = [0] * 21 # [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
        self.writeStartConditions (EEPacket)
        EEPacket = [0, 0, 0, 0, 0, 0, 0]
        self.writeStopConditions (EEPacket)
        self.updateStatus(0)   # self.write(12, 0)  # update status, 0= empty container


    # Sample Start conditions (Org 20, len 21)
    # 0 = Fipy ID (high byte) / 16bit
    # 1 = Fipy ID (low byte)
    # 2 = Latitude HH ( Latitude * 10^6) /  from 89.999999 to -89.999999  * 10^6  /  32bit
    # 3 = Latitude HL
    # 4 = Latitude LH
    # 5 = Latitude lL
    # 6 = Longitude HH ( Longitude * 10^6) /  from 89.999999 to -89.999999  * 10^6  /  32bit
    # 7 = Longitude HL
    # 8 = Longitude LH
    # 9 = Longitude LL
    # 10 = year fron 0 to 99 (2000 to 2099)
    # 11 = month
    # 12 = day
    # 13 = hour
    # 14 = minute
    # 15 = second
    # 16 = temperature in degree C
    # 17 = relative humidity in %
    # 18 = pressure in Pa
    # 19 = gas reading (high byte) in ppm / 16bit
    # 20 = gas reading (low byte)
    def readStartConditions(self):
        EEPacket = []
        for x in range(21):
            self.read(x+20)
            EEPacket.append(self.data[0])
        if self.trace:
            print('Sample Start Conditions')
            print('Fipy ID: ' + str( ( EEPacket[0] * 256) +  EEPacket[1]))
            print('Latitude: ' + str( (( EEPacket[2] * 16,777,216) +  ( EEPacket[3] * 65536) + ( EEPacket[4] * 256) + EEPacket[5]) / 1000000 ))
            print('Longitude: ' + str( (( EEPacket[6] * 16,777,216) +  ( EEPacket[7] * 65536) + ( EEPacket[8] * 256) + EEPacket[9]) / 1000000 ))
            print('Year: ' + str(EEPacket[10] + 2000))
            print('Month: ' + str(EEPacket[11]) )
            print('Day: ' + str(EEPacket[12]) )
            print('Hour: ' + str(EEPacket[13]) )
            print('Minute: ' + str(EEPacket[14]) )
            print('Second: ' + str(EEPacket[15]) )
            print('Temperature: ' + str(EEPacket[16]) + ' C')
            print('Humidity: ' + str(EEPacket[17]) + ' RH')
            print('Pression: ' + str(EEPacket[18]) + ' Pa')
            print('Sensor reading: ' + str( ( EEPacket[19] * 256) +  EEPacket[20]) + ' ppm')
        return EEPacket

    # EEPacket = [year-2000, month, day, hour, min, sec, temp, RH, ATM, sensorH, sensorL]
    def writeStartConditions(self, EEPacket):
        self.resetSampler()
        n = 20
        for x in EEPacket:
            self.write(n, x)
            if self.trace:
                print('Sample (' + str(n) + '): ' + str(x) )
            n += 1
        self.updateStatus(1)  # self.write(12, 1) # update status, 1= in use


    # Sample End conditions (org 50, len 7)
    # 0 = sampling duration sec (high byte) / 16bit
    # 1 = sampling duration sec (low byte)
    # 2 = temperature in degree C
    # 3 = relative humidity in %
    # 4 = pressure in Pa
    # 5 = gas reading (high byte) in ppm / 16bit
    # 6 = gas reading (low byte)
    def readStopConditions(self):
        EEPacket = []
        for x in range(7):
            self.read(x+50)
            EEPacket.append(self.data[0])
        if self.trace:
            print('Sampling duration: ' + str( ( EEPacket[0] * 256) +  EEPacket[1]) + ' Sec')
            print('Temperature: ' + str(EEPacket[2]) + ' C')
            print('Humidity: ' + str(EEPacket[3]) + ' RH')
            print('Pression: ' + str(EEPacket[4]) + ' Pa')
            print('Sensor reading: ' + str( ( EEPacket[5] * 256) +  EEPacket[6]) + ' ppm')
        return EEPacket


    # EEPacket = [smpH, smpL, temp, RH, ATM, sensorH, sensorL]
    def writeStopConditions(self, EEPacket):
        n = 50
        for x in EEPacket:
            self.write(n, x)
            if self.trace:
                print('Sample (' + str(n) + '): ' + str(x) )
            n += 1
        self.incCycle()
        self.updateStatus(2)  # self.write(12, 2) # update status, 2= filled
