#!/usr/bin/env python
#-*- coding: utf-8 -*-
#----------------------------------------------------------------------
# bibliothèques "système"
#----------------------------------------------------------------------
import time
import smbus2
import struct

#----------------------------------------------------------------------
# bibliothèques "locales"
#----------------------------------------------------------------------
import globals
import CRC8

#----------------------------------------------------------------------
# variables et constantes
#----------------------------------------------------------------------
I2C_SPS30 = 0x69

#--------------------------------------------------------------------------------------------------
def SPS30_open() :

	global SPS30_open_flag

	try :
		if ( globals.BUS_7_OK_flag ) :
		
			if globals.DEBUG_SPS30:
				print("SPS30_open : starting...")
				print(" ")
			globals.bus_7.read_byte(I2C_SPS30)
			SPS30_open_flag = True
			return True
		else :
			SPS30_open_flag = False
			return False
	except:
		SPS30_open_flag = False
		return False

#-----------------------------------------------------------------------------
def SPS30_init():

	try:
		#---------------------------------------------------------------------
		if SPS30_open_flag :
		
			#---------------------------------------------------------------------
			if globals.DEBUG_SPS30:
				print("SPS30_init : starting...")

			#---------------------------------------------------------------------
			if not SPS30_reset():
				if globals.DEBUG_SPS30 :
					print("  SPS30_init : SPS30_reset -> échec !")
				return False

			#---------------------------------------------------------------------
			version_array = SPS30_get_version()
			
			if ( not version_array[0] ) :
				if globals.DEBUG_SPS30 :
					print("  SPS30_init : SPS30_get_version -> échec !")
				return False
				
			Version_string = version_array[1]
			
			if ( Version_string == "None" ) :
				if globals.DEBUG_SPS30 :
					print("  SPS30_init : version : anomalie de valeur !")
				return False
			else:
				if globals.DEBUG_SPS30 :
					print( "  SPS30_init : version = " + Version_string )

			#---------------------------------------------------------------------
			lecture_SPS30         = SPS30_get_cleaning_intervalle()
			Cleaning_interval     = lecture_SPS30[1]
			Cleaning_interval_str = lecture_SPS30[2]
			
			if ( not lecture_SPS30[0] ) :
				return False
			
			if ( ( Cleaning_interval < 0 ) or ( Cleaning_interval > 999999 ) ) :
				if globals.DEBUG_SPS30 :
					print("  SPS30_init : intervalle de nettoyage : anomalie de valeur !")
				return False
			else:
				if globals.DEBUG_SPS30 :
					print( "  SPS30_init : intervalle de nettoyage = " + Cleaning_interval_str + " s")

			#---------------------------------------------------------------------
			'''
			if not SPS30_startMeasurement():
				if globals.DEBUG_SPS30 :
					print( "  SPS30_init : SPS30_startMeasurement -> échec !!! " )
				return False
			else :
				if globals.DEBUG_SPS30 :
					print( "  SPS30_init : SPS30_startMeasurement -> succès... " )
			'''	
			#---------------------------------------------------------------------
			if not SPS30_stopMeasurement() :
				if globals.DEBUG_SPS30 :
					print( "  SPS30_init : SPS30_stopMeasurement -> échec !!! " )
				return False
			else :
				if globals.DEBUG_SPS30 :
					print( "  SPS30_init : SPS30_stopMeasurement -> succès... " )
				
			#---------------------------------------------------------------------
			return True

			#---------------------------------------------------------------------
		
		else :
			#---------------------------------------------------------------------
			if globals.DEBUG_SPS30:
				print("  SPS30_init : SPS30_open_flag = False !")
				print(" ")
			return False
		
	except Exception as except_str:
		print("  SPS30_init : exception -> ", except_str )
		print(" ")
		return False
		
#----------------------------------------------------------------------
def SPS30_startMeasurement():
	try:
		raw_message = [0x00, 0x10, 0x03, 0x00, 0xac]
		write_txn = smbus2.i2c_msg.write(I2C_SPS30, raw_message)
		globals.bus_7.i2c_rdwr(write_txn)
		time.sleep(0.020)
		return True
	
	except:
		if globals.DEBUG_SPS30 :
			print("  SPS30_startMeasurement : exception !")
		return False
		
#----------------------------------------------------------------------
def SPS30_stopMeasurement():
	try:
		raw_message = [0x01, 0x04]
		write_txn = smbus2.i2c_msg.write(I2C_SPS30, raw_message)
		globals.bus_7.i2c_rdwr(write_txn)
		time.sleep(0.020)
		return True
	
	except:
		if globals.DEBUG_SPS30 :
			print("  SPS30_stopMeasurement : exception !")
		return False
		
#----------------------------------------------------------------------
def SPS30_reset():
	try:
		raw_message = [0xd3, 0x04]
		write_txn = smbus2.i2c_msg.write(I2C_SPS30, raw_message)
		globals.bus_7.i2c_rdwr(write_txn)
		time.sleep(0.100)
		return True
	
	except:
		if globals.DEBUG_SPS30 :
			print("  SPS30_reset : exception !")
		return False
		
#----------------------------------------------------------------------
def SPS30_StartFanCleaning():
	try:
		raw_message = [0x56, 0x07]
		write_txn = smbus2.i2c_msg.write(I2C_SPS30, raw_message)
		globals.bus_7.i2c_rdwr(write_txn)
		time.sleep(0.005)
		return True
	
	except:
		if globals.DEBUG_SPS30 :
			print("  SPS30_StartFanCleaning : exception !")
		return False
		
#--------------------------------------------------------------------------------------------------
# read CLEAN_INTERVALLE
#--------------------------------------------------------------------------------------------------
def SPS30_get_cleaning_intervalle():
	try:
		retour = [False, 999999, "999999"]
		data_crc8 = [0,0]
		Flag_crc8 = True
		
		raw_message = [0x80, 0x04]
		write_txn = smbus2.i2c_msg.write(I2C_SPS30, raw_message)
		globals.bus_7.i2c_rdwr(write_txn)

		time.sleep(0.005)
		
		read_txn = smbus2.i2c_msg.read(I2C_SPS30, 6)
		globals.bus_7.i2c_rdwr(read_txn)
		data = list(read_txn)

		if ( len(data) == 6 ):
			
			for i in range(2):
				data_crc8[i] = CRC8.crc8_scd30(data[3*i],data[3*i+1])
				Flag_crc8    = Flag_crc8 and ( data[3*i+2]  == data_crc8[i] )
				
			if Flag_crc8:
				cleaning_interval     = data[4] + (data[3] << 8) + (data[1] << 16) + (data[0] << 24)
				cleaning_interval_str = str(cleaning_interval)
				retour = [True, cleaning_interval, cleaning_interval_str]
			else:
				if globals.DEBUG_SPS30 :
					print("  SPS30_get_cleaning_intervalle : erreur CRC !")
				
		else:
			if globals.DEBUG_SPS30 :
				print("  SPS30_get_cleaning_intervalle : erreur Nb bytes !")

	except: 
		retour = [False, 999999, "999999"]
		if globals.DEBUG_SPS30 :
			print("  SPS30_get_cleaning_intervalle : exception !")
	
	finally:
		return retour
		
#--------------------------------------------------------------------------------------------------
# set CLEAN_INTERVALLE
#--------------------------------------------------------------------------------------------------
def SPS30_set_cleaning_intervalle(CLEANING_INTERVALLE_string):
	try:
		return_STATUS = False
		console_string = "  SPS30_set_cleaning_intervalle -> ?"
		
		CLEANING_INTERVALLE_int_value = int(CLEANING_INTERVALLE_string)
		LLSB = 0xFF &  CLEANING_INTERVALLE_int_value
		LMSB = 0xFF & (CLEANING_INTERVALLE_int_value >>  8)
		MLSB = 0xFF & (CLEANING_INTERVALLE_int_value >> 16)
		MMSB = 0xFF & (CLEANING_INTERVALLE_int_value >> 24)

		L_CRC = CRC8.crc8_scd30(LMSB,LLSB)
		M_CRC = CRC8.crc8_scd30(MMSB,MLSB)

		raw_message = [0x80, 0x04, MMSB, MLSB, M_CRC, LMSB, LLSB, L_CRC]
		write_txn = smbus2.i2c_msg.write(I2C_SPS30, raw_message)
		globals.bus_7.i2c_rdwr(write_txn)

		time.sleep(0.020)
		
		console_string = "  SCD41_set_sensor_altitude -> OK : " + str(MMSB) + "_" +  str(MLSB) + "_" +  str(M_CRC) + " ; " + str(MMSB) + "_" +  str(MLSB) + "_" +  str(L_CRC)
		return_STATUS = True

	except: 
		return_STATUS = False
		if globals.DEBUG_SPS30 :
			print("  SPS30_set_cleaning_intervalle : exception !")
	
	finally:
		return return_STATUS
		
#----------------------------------------------------------------------
def SPS30_readDataReady():
	try:
		raw_message = [0x02, 0x02]
		write_txn = smbus2.i2c_msg.write(I2C_SPS30, raw_message)
		globals.bus_7.i2c_rdwr(write_txn)

		time.sleep(0.010)
		
		read_txn = smbus2.i2c_msg.read(I2C_SPS30, 3)
		globals.bus_7.i2c_rdwr(read_txn)
		data = list(read_txn)

		if ( len(data) == 3 ):
			data_crc8 = CRC8.crc8_scd30(data[0],data[1])

			if (data[2] == data_crc8) and (data[0] == 0x00) and (data[1] == 0x01) :
				return True
			else:
				if globals.DEBUG_SPS30 :
					print("  SPS30_readDataReady : erreur CRC ou data not ready ! : " + str(data[0]) + " " + str(data[1]) + " " + str(data[2]) + " " + str(data_crc8) )
				return False
				
		else:
			if globals.DEBUG_SPS30 :
				print("  SPS30_readDataReady : erreur 3 bytes !")
			return False
			
	except:
		if globals.DEBUG_SPS30 :
			print("  SPS30_readDataReady : exception !")
		return False
		
#----------------------------------------------------------------------
def SPS30_calcFloat(SixBytesArray):
	struct_float = struct.pack('>BBBB', SixBytesArray[0], SixBytesArray[1], SixBytesArray[3], SixBytesArray[4])
	float_values = struct.unpack('>f', struct_float)
	first = float_values[0]
	return first
	
#----------------------------------------------------------
def SPS30_read():
	try:
		#--------------------------------------------------------------
		chaine_SPS30 = ["999.99", "999.99", "999.99", "999.99"]
		
		#--------------------------------------------------------------
		if SPS30_readDataReady():
		
			raw_message = [0x03, 0x00]
			write_txn = smbus2.i2c_msg.write(I2C_SPS30, raw_message)
			globals.bus_7.i2c_rdwr(write_txn)

			time.sleep(0.010)
			
			read_txn = smbus2.i2c_msg.read(I2C_SPS30, 60)
			globals.bus_7.i2c_rdwr(read_txn)
			data = list(read_txn)

			if ( len(data) == 60 ):
			
				# calcul et test des CRC
				data_crc8 = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
				Flag_crc8 = True
				for i in range(20):
					data_crc8[i] = CRC8.crc8_scd30(data[3*i],data[3*i+1])
					
					Flag_crc8 = Flag_crc8 and ( data[3*i+2]  == data_crc8[i] )
					
				if Flag_crc8:
					chaine_SPS30 = [ 
						"{0:.3f}".format( SPS30_calcFloat(data[0:5]) ) , 
						"{0:.3f}".format( SPS30_calcFloat(data[6:11]) ) , 
						"{0:.3f}".format( SPS30_calcFloat(data[12:17]) ) , 
						"{0:.3f}".format( SPS30_calcFloat(data[18:23]) ) 
					 ]
					 
				else:
					globals.Flag_mesures_OK = ( globals.Flag_mesures_OK & 0xFFFFFF0FFFFF ) | 0x000000100000
					if globals.DEBUG_SPS30 :
						print("  SPS30_read : erreur CRC !")
			else:
				globals.Flag_mesures_OK = ( globals.Flag_mesures_OK & 0xFFFFFF0FFFFF ) | 0x000000200000
				if globals.DEBUG_SPS30 :
					print("  SPS30_read : erreur nb bytes !")
		else:
			globals.Flag_mesures_OK = ( globals.Flag_mesures_OK & 0xFFFFFF0FFFFF ) | 0x000000300000
			if globals.DEBUG_SPS30 :
				print("  SPS30_read : data not ready !")
			
	except:
		globals.Flag_mesures_OK = ( globals.Flag_mesures_OK & 0xFFFFFF0FFFFF ) | 0x000000400000
		if globals.DEBUG_SPS30 :
			print("  SPS30_read : exception !")
		
	finally:
		return chaine_SPS30
		
#--------------------------------------------------------------------------------------------------
# read VERSION
#--------------------------------------------------------------------------------------------------
def SPS30_get_version():
	try:
		retour = [False, "None"]
		data_crc8 = [0,0]
		Flag_crc8 = True
		
		raw_message = [0xd1, 0x00]
		write_txn = smbus2.i2c_msg.write(I2C_SPS30, raw_message)
		globals.bus_7.i2c_rdwr(write_txn)

		time.sleep(0.010)
		
		read_txn = smbus2.i2c_msg.read(I2C_SPS30, 3)
		globals.bus_7.i2c_rdwr(read_txn)
		data = list(read_txn)

		if ( len(data) == 3 ):
			
			for i in range(1):
				data_crc8[i] = CRC8.crc8_scd30(data[3*i],data[3*i+1])
				Flag_crc8    = Flag_crc8 and ( data[3*i+2]  == data_crc8[i] )
				
			if Flag_crc8:
				version     = (data[0] << 8) + data[1]
				version_str = '0x%.4X' % version
				retour = [True, version_str]
			else:
				if globals.DEBUG_SPS30 :
					print("  SPS30_get_version : erreur CRC !")
				
		else:
			if globals.DEBUG_SPS30 :
				print("  SPS30_get_version : erreur Nb bytes !")

	except: 

		if globals.DEBUG_SPS30 :
			print("  SPS30_get_version : exception !")
	
	finally:
		return retour
		
#--------------------------------------------------------------------------------------------------
