#!/usr/bin/env python
#-*- coding: utf-8 -*-
#----------------------------------------------------------------------
import pigpio
import time
import math

import globals

#----------------------------------------------------------------------
I2C_BMP280 = 0x76
#----------------------------------------------------------------------
# BMP280
#----------------------------------------------------------------------
idReg 		=	0xD0 	# chip id
resetReg 	=	0xE0	# reset register
statusReg	=	0xF3	# status register
overModeReg	=	0xF4	# The “ctrl_meas” register sets the data acquisition options
configReg	=	0xF5	# The “config” register sets the rate, filter and interface options
#----------------------------------------------------------------------
# three regs for raw pressure data: _msb, _lsb, _xlsb
rawBar_msb	=	0xF7	
rawBar_lsb	=	0xF8
rawBar_xlsb	=	0xF9
#----------------------------------------------------------------------
# three regs for raw temperature data: _msb, _lsb, _xlsb
rawTemp_msb	=	0xFA	
rawTemp_lsb	=	0xFB
rawTemp_xlsb=	0xFC
#----------------------------------------------------------------------
# standard configs suggested:
# name				P over		T over		Timing
# ultraLowPower		1x	(1)		1x	(1)		6.4
# lowPower			2x	(2)		1x	(1)		8.7
# stdRes			4x	(3)		1x	(1)		13.3
# highRes			8x	(4)		1x	(1)		22.5
# ultraHighRes		16x	(5)		2x	(2)		43.2

ulSet	=	(1,1,6.4)
lSet	=	(2,1,8.7)
sSet	=	(3,1,13.3)
hSet	=	(4,1,22.5)
uhSet	=	(5,2,43.2)
presets	=	(ulSet,lSet,sSet,hSet,uhSet)
#----------------------------------------------------------------------
# calibration registers
dig_T1 = 0x88
dig_T2 = 0x8A
dig_T3 = 0x8C
dig_P1 = 0x8E
dig_P2 = 0x90
dig_P3 = 0x92
dig_P4 = 0x94
dig_P5 = 0x96
dig_P6 = 0x98
dig_P7 = 0x9A
dig_P8 = 0x9C
dig_P9 = 0x9E
#----------------------------------------------------------------------
def BMP280_init():
	global handle_i2c_BMP280
	global BMP280_open_flag

	try:
		#---------------------------------------------------------------------
		if globals.DEBUG:
			print(" ")
			print("BMP280_init :")
			
		#---------------------------------------------------------------------
		handle_i2c_BMP280 = globals.RPi.i2c_open(globals.I2C_BUS_1, I2C_BMP280)
		if (handle_i2c_BMP280 < 0):
			if globals.DEBUG:
				print("  ouverture handle i2c : échec !")
			return False
		else:
			if globals.DEBUG:
				print("  handle i2c ouvert !")
			BMP280_open_flag = True

		time.sleep(0.010)
		
		#---------------------------------------------------------------------
		if globals.DEBUG:
			print("  reset... (1s)")
		if not BMP280_reset():
			return False

		time.sleep(0.020)
		
		#---------------------------------------------------------------------
		if globals.DEBUG:
			print("  BMP280_verifySensorId...")
		if not BMP280_verifySensorId():
			return False

		time.sleep(0.020)
		
		#---------------------------------------------------------------------
		(measuring,im_update,Flag_1) = BMP280_getSensorStatus()
		if Flag_1:
			print("  Status: Measuring {} - im_update {}".format(measuring,im_update))			
		else:
			return False
		
		(iirFilterCfg,standbyCfg,Flag_1) = BMP280_getConfig()
		if Flag_1:
			print("  Config: IIR Filter {:03b} - Standby {:03b}".format(iirFilterCfg,standbyCfg))	
		else:
			return False
		
		(presOverCfg,tempOverCfg,powerModeCfg,Flag_1) = BMP280_getOverMode()
		if Flag_1:
			print("  Config: Pressure Oversampling {:03b}".format(presOverCfg) )
			print("  Config: Temperature Oversampling {:03b}".format(tempOverCfg))
			print("  Config: Power Mode {:02b}".format(powerModeCfg))	
		else:
			return False
		
		(pressure,temperature,Flag_1) = BMP280_getReading(4)
		if Flag_1:
			print("  Mesures : P = {:.2f}hPa ; T = {:.2f}°C".format(pressure,temperature))
		else:
			return False

		return True
		
		#---------------------------------------------------------------------
			
	except:
		if globals.DEBUG:
			print("  exception !")

		time.sleep(0.020)
		
		#---------------------------------------------------------------------

		return False
		
#----------------------------------------------------------------------
def BMP280_close():
	try:
		globals.RPi.i2c_close(handle_i2c_BMP280)

		time.sleep(0.010)					
		return True
		
	except:
		if globals.DEBUG:
			print("BMP280_close : exception !")

		time.sleep(0.010)					
		return False
		
#----------------------------------------------------------------------
def BMP280_getRawValues():
	try:
		(count, data) = globals.RPi.i2c_read_i2c_block_data(handle_i2c_BMP280, rawBar_msb, 6)

		if (count == 6) :
			return (data[0],data[1],data[2],data[3],data[4],data[5],True)
		else:
			return (0,0,0,0,0,0,False)
	
	except:
		if globals.DEBUG:
			print("  BMP280_getRawValues : exception !")
		return (0,0,0,0,0,0,False)
		
#----------------------------------------------------------------------
def BMP280_verifySensorId():
	try:
		BMP280_Id = globals.RPi.i2c_read_byte_data(handle_i2c_BMP280, idReg)
		if BMP280_Id == 0x58:
			return True
		else:
			if globals.DEBUG:
				print("  BMP280_verifySensorId : Id not 0x58 !")
			return False
	except:
		if globals.DEBUG:
			print("  BMP280_verifySensorId : exception !")
		return False
		
#----------------------------------------------------------------------
def BMP280_setBit(byte,bit,index):
	mask = 1 << index
	byte &= ~mask
	if bit:
		byte |= mask
	return byte
	
#----------------------------------------------------------------------
def BMP280_readUnsigned(reg):
	try:
		value = globals.RPi.i2c_read_word_data(handle_i2c_BMP280, reg)
		return (value, True)
		
	except:
		if globals.DEBUG:
			print("  BMP280_readUnsigned : exception !")
		return (0, False)
		
#----------------------------------------------------------------------
def BMP280_readSigned(reg):
	try:
		value = globals.RPi.i2c_read_word_data(handle_i2c_BMP280, reg)
		if value > 32767:
			value -= 65536		
		return (value, True)
		
	except:
		if globals.DEBUG:
			print("  BMP280_readSigned : exception !")
		return (0, False)
		
#----------------------------------------------------------------------
def BMP280_getSensorStatus():
	try:
		BMP280_status    = globals.RPi.i2c_read_byte_data(handle_i2c_BMP280, statusReg)
		BMP280_measuring = (BMP280_status)>>3&1
		BMP280_im_update = (BMP280_status)&1
		return (BMP280_measuring, BMP280_im_update, True)
		
	except:
		if globals.DEBUG:
			print("  BMP280_getSensorStatus : exception !")
		return (0,0,False)
		
#----------------------------------------------------------------------
def BMP280_getOverMode():
	try:
		regValue     = globals.RPi.i2c_read_byte_data(handle_i2c_BMP280, overModeReg)
		presOverCfg  = (regValue >> 2) & 0b111
		tempOverCfg  = (regValue >> 5) & 0b111
		powerModeCfg = (regValue) & 0b11
		return (presOverCfg,tempOverCfg,powerModeCfg, True)
		
	except:
		if globals.DEBUG:
			print("  BMP280_getOverMode : exception !")
		return (0,0,0,False)
		
#----------------------------------------------------------------------
def BMP280_reset():
	try:
		globals.RPi.i2c_write_byte_data(handle_i2c_BMP280, resetReg, 0xB6)
		time.sleep(1.000)					
		return True
	
	except:
		if globals.DEBUG:
			print("  BMP280_reset : exception !")
		return False
		
#----------------------------------------------------------------------
def BMP280_setPresOver(value):
	try:
		# Oversampling for pressure. This accepts 5 level, equivalent to 1x - 2x - 4x - 8x - 16x oversampling
		if value not in range(1,6):
			if globals.DEBUG:
				print("  Oversampling value unsupported (accepted 1-5) !" + str(value)  )
			return False
		else:
			# get actual value
			regValue = globals.RPi.i2c_read_byte_data(handle_i2c_BMP280, overModeReg)
			
			# bitwising 3 bit value. for pressure we have bits 4,3 and 2
			regValue = BMP280_setBit(regValue,(value>>2)&1,4)
			regValue = BMP280_setBit(regValue,(value>>1)&1,3)
			regValue = BMP280_setBit(regValue,(value>>0)&1,2)
			
			# writing back value to register
			globals.RPi.i2c_write_byte_data(handle_i2c_BMP280, overModeReg, regValue)
			return True
		
	except: 
		if globals.DEBUG:
			print("  BMP280_setPresOver : exception !")
		return False
		
#----------------------------------------------------------------------
def BMP280_setTempOver(value):
	try:
		# Oversampling for pressure. This accepts 5 level, equivalent to 1x - 2x - 4x - 8x - 16x oversampling
		if value not in range(1,6):
			if globals.DEBUG:
				print( "  Oversampling value unsupported (accepted 1-5) !" + str(value) )
			return False
		else:
			# get actual value
			regValue = globals.RPi.i2c_read_byte_data(handle_i2c_BMP280, overModeReg)
			
			# bitwising 3 bit value. for pressure we have bits 4,3 and 2
			regValue = BMP280_setBit(regValue,(value>>2)&1,7)
			regValue = BMP280_setBit(regValue,(value>>1)&1,6)
			regValue = BMP280_setBit(regValue,(value>>0)&1,5)
			
			# writing back value to register
			globals.RPi.i2c_write_byte_data(handle_i2c_BMP280, overModeReg, regValue)
			return True
		
	except: 
		if globals.DEBUG:
			print("  BMP280_setTempOver : exception !")
		return False
		
#----------------------------------------------------------------------
def BMP280_setStandby(value):
	try:
		if value not in range(0,8):
			if globals.DEBUG:
				print("  Standby value unsupported (accepted 0-7) !" + str(value)  )
			return False
		else:
			# get actual value
			regValue = globals.RPi.i2c_read_byte_data(handle_i2c_BMP280, configReg)
			
			# bitwising 3 bit value. for standby we have bits 7,6 and 5
			regValue = BMP280_setBit(regValue,(value>>2)&1,7)
			regValue = BMP280_setBit(regValue,(value>>1)&1,6)
			regValue = BMP280_setBit(regValue,(value>>0)&1,5)
			# writing back value to register
			
			globals.RPi.i2c_write_byte_data(handle_i2c_BMP280, configReg, regValue)

			return True
		
	except: 
		if globals.DEBUG:
			print("  BMP280_setStandby : exception !")
		return False
		
#----------------------------------------------------------------------
def BMP280_getReading(preset):
	try:
		if preset not in range(0,5):
			if globals.DEBUG:
				print("  Preset unknown unsupported (accepted 0,1,2,3,4) !" + str(preset)  )
			return (0,0,False)
		else:
			# writing oversample Pressure settings to device
			if not BMP280_setPresOver(presets[preset][0]):
				if globals.DEBUG:
					print("  BMP280_getReading : anomalie dans BMP280_setPresOver !")
				return (0,0,False)
			
			# writing oversample Temperature settings to device
			if not BMP280_setTempOver(presets[preset][1]):
				if globals.DEBUG:
					print("  BMP280_getReading : anomalie dans MP280_setTempOver !")
				return (0,0,False)
			
			# toggle a reading by writing the "forced" power mode
			if not BMP280_setPowerMode(1):
				if globals.DEBUG:
					print("  BMP280_getReading : anomalie dans BMP280_setPowerMode !")
				return (0,0,False)
			
			# waiting for the reading to complete.
			time.sleep(presets[preset][2]/1000)
			
			# now i can read the raw values from device
			(msbPress,lsbPress,xlsbPress,msbTemp,lsbTemp,xlsbTemp,Flag_1) = BMP280_getRawValues()
			if Flag_1:
				# joining values
				pValue = (msbPress << 12) + (lsbPress << 4) + (xlsbPress >> 4)
				tValue =  (msbTemp << 12) +  (lsbTemp << 4) +  (xlsbTemp >> 4)
				
				# compensation
				(pValue,tValue,Flag_2) = BMP280_compensateValues(pValue,tValue)
				
				if Flag_2:
					# formatting
					pValue = pValue / 256.0 / 100.0
					tValue = tValue / 100.0
					return (pValue,tValue,True)
				
				else:
					if globals.DEBUG:
						print("  BMP280_getReading : anomalie dans BMP280_compensateValues !")
					return (0,0,False)
				
			else:
				if globals.DEBUG:
					print("  BMP280_getReading : anomalie dans BMP280_getRawValues !")
				return (0,0,False)
			
	except:
		if globals.DEBUG:
			print("  BMP280_getReading : exception !")
		return (0,0,False)
		
#----------------------------------------------------------------------
def BMP280_compensateValues(rawPressure, rawTemp):

	try:

		# compensation en température
		(dig_T1_value, Flag_1) = BMP280_readUnsigned(dig_T1)
		(dig_T2_value, Flag_2) = BMP280_readSigned(dig_T2)
		(dig_T3_value, Flag_3) = BMP280_readSigned(dig_T3)

		if ( Flag_1 and Flag_2 and Flag_3 ) :
			t1 = ( ( ( rawTemp >> 3 ) - ( dig_T1_value << 1 ) ) * dig_T2_value ) >> 11
			t2 = ( ( ( rawTemp >> 4 ) - dig_T1_value ) * ( ( rawTemp >> 4 ) - dig_T1_value ) >> 12 ) * dig_T3_value >> 14
			tRaw = t1 + t2
			tValue = ( tRaw * 5 + 128 ) >> 8

		else:
			return ( 0, 0, False )

		# compensation en pression
		(dig_P1_value, Flag_1)  = BMP280_readUnsigned(dig_P1)
		(dig_P2_value, Flag_2)  = BMP280_readSigned(dig_P2)
		(dig_P3_value, Flag_3)  = BMP280_readSigned(dig_P3)
		(dig_P4_value, Flag_4)  = BMP280_readSigned(dig_P4)
		(dig_P5_value, Flag_5)  = BMP280_readSigned(dig_P5)
		(dig_P6_value, Flag_6)  = BMP280_readSigned(dig_P6)
		(dig_P7_value, Flag_7)  = BMP280_readSigned(dig_P7)
		(dig_P8_value, Flag_8)  = BMP280_readSigned(dig_P8)
		(dig_P9_value, Flag_9)  = BMP280_readSigned(dig_P9)
				
		if ( Flag_1 and Flag_2 and Flag_3 and Flag_4 and Flag_5 and Flag_6 and Flag_7 and Flag_8 and Flag_9 ) :
			
			p1 = tRaw - 128000
			p2 = p1 * p1 * dig_P6_value
			p2 = p2 + ( ( p1*dig_P5_value ) << 17 )
			p2 = p2 + ( ( dig_P4_value) << 35 )
			p1 = ( ( p1 * p1 * dig_P3_value ) >> 8 ) + ( ( p1 * dig_P2_value ) << 12 )
			p1 = ( ( ( (1) << 47 ) + p1 ) ) * ( dig_P1_value ) >> 33
			
			if ( p1 == 0 ) : 
				pValue = 0
			else :
				pValue = 1048576 - rawPressure
				pValue = ( ( ( pValue << 31 ) - p2 ) * 3125 ) / p1
				pValue = math.floor( pValue )
			
			p1 = ( ( dig_P9_value ) * ( pValue >> 13 ) * ( pValue >> 13 ) ) >> 25
			p2 = ( ( dig_P8_value ) * pValue ) >> 19
			pValue = ( ( pValue + p1 + p2 ) >> 8 ) + ( ( dig_P7_value ) << 4 )
			
		else:
			return ( 0, 0, False )
			
		return ( pValue, tValue, True )
	
	except:
		if globals.DEBUG:
			print("  BMP280_compensateValues : exception !")
		return (0,0,False)
		
#----------------------------------------------------------------------
def BMP280_getConfig():
	try:
		# returns contents of the config reg
		regValue = globals.RPi.i2c_read_byte_data(handle_i2c_BMP280, configReg)
		iirFilterCfg = (regValue >> 2) & 0b111
		standbyCfg   = (regValue >> 5) & 0b111
		return (iirFilterCfg,standbyCfg, True)
		
	except:
		if globals.DEBUG:
			print("  BMP280_getConfig : exception !")
		return (0,0,False)
		
#----------------------------------------------------------------------
def BMP280_setIirFilter(value):
	try:

		if value not in range(0,8):
			if globals.DEBUG:
				print("  IirFilter value unsupported (accepted 0-7) !" + str(value)  )
			return False
		else:
			# get actual value
			regValue = globals.RPi.i2c_read_byte_data(handle_i2c_BMP280, configReg)
			
			# bitwising 3 bit value. for filter we have bits 4,3 and 2
			regValue = BMP280_setBit(regValue,(value>>2)&1,4)
			regValue = BMP280_setBit(regValue,(value>>1)&1,3)
			regValue = BMP280_setBit(regValue,(value>>0)&1,2)
			
			# writing back value to register
			globals.RPi.i2c_write_byte_data(handle_i2c_BMP280, configReg, regValue)

			return True
		
	except: 
		if globals.DEBUG:
			print("  BMP280_setIirFilter : exception !")
		return False
		
#----------------------------------------------------------------------
def BMP280_setPowerMode(value):
	try:
		# Power modes : 0=standby, 1=Forced (one shot), 2=Normal (cyclic)
		if value not in range(0,3):
			if globals.DEBUG:
				print("  Power mode unsupported (accepted 0,1,2) !" + str(value)  )
			return False
		else:
			# value 2 (normal) should be 3 for register
			if value == 2: 
				value = 3
				
			# get actual value
			regValue = globals.RPi.i2c_read_byte_data(handle_i2c_BMP280, overModeReg)
			
			# bitwising 2 bit value. for power mode we have bits 1 and 0
			regValue = BMP280_setBit(regValue,(value>>1)&1,1)
			regValue = BMP280_setBit(regValue,(value>>0)&1,0)
			
			# writing back value to register
			globals.RPi.i2c_write_byte_data(handle_i2c_BMP280, overModeReg, regValue)
			
			return True
		
	except: 
		if globals.DEBUG:
			print("  BMP280_setPowerMode : exception !")
		return False
		
#----------------------------------------------------------------------
def BMP280_read():
	try:
		chaine_BMP280 = [ "99.9", "9999.9" ]

		preset = 4
		
		# toggle a reading by writing the "forced" power mode
		if BMP280_setPowerMode(1):
			
			# waiting for the reading to complete.
			time.sleep(presets[preset][2]/1000)
			
			# now i can read the raw values from device
			(msbPress,lsbPress,xlsbPress,msbTemp,lsbTemp,xlsbTemp,Flag_1) = BMP280_getRawValues()
			if Flag_1:
			
				# joining values
				pValue = (msbPress << 12) + (lsbPress << 4) + (xlsbPress >> 4)
				tValue =  (msbTemp << 12) + ( lsbTemp << 4) +  (xlsbTemp >> 4)
				
				# compensation
				(pValue,tValue,Flag_2) = BMP280_compensateValues(pValue,tValue)
				
				if Flag_2:
					# formatting
					BMP280_P = pValue / 256.0 / 100.0
					BMP280_T = tValue / 100.0

					chaine_BMP280_T  = "%.2f" % BMP280_T
					chaine_BMP280_P  = "%.1f" % BMP280_P
					chaine_BMP280    = [chaine_BMP280_T, chaine_BMP280_P]
					
				else:
					globals.Flag_mesures_OK += 10
					if globals.DEBUG:
						print("BMP280_read : anomalie dans BMP280_compensateValues !")
			
			else:
				globals.Flag_mesures_OK += 20
				if globals.DEBUG:
					print("BMP280_read : anomalie dans BMP280_getRawValues !")
			
		else:
			globals.Flag_mesures_OK += 30
			if globals.DEBUG:
				print("BMP280_read : anomalie dans BMP280_setPowerMode !")
		
	except:
		globals.Flag_mesures_OK += 40
		if globals.DEBUG:
			print("BMP280_read : exception !")

	finally:
		return chaine_BMP280
		
#----------------------------------------------------------------------
