#include "LOLIN_HP303B.h"



const int32_t LOLIN_HP303B::scaling_facts[HP303B__NUM_OF_SCAL_FACTS]
	= {524288, 1572864, 3670016, 7864320, 253952, 516096, 1040384, 2088960};



//////// 		Constructor, Destructor, begin, end			////////


/**
 * Standard Constructor
 */
LOLIN_HP303B::LOLIN_HP303B(void)
{
	//assume that initialization has failed before it has been done
	m_initFail = 1U;
}

/**
 * Standard Destructor
 */
LOLIN_HP303B::~LOLIN_HP303B(void)
{
	end();
}



/**
 * Standard I2C begin function
 *
 * &bus: 			I2CBus which connects MC to HP303B
 * slaveAddress: 	Address of the HP303B (0x77 or 0x76)
 */
void LOLIN_HP303B::begin(TwoWire &bus, uint8_t slaveAddress)
{
	//this flag will show if the initialization was successful
	m_initFail = 0U;

	//Set I2C bus connection
	m_SpiI2c = 1U;
	m_i2cbus = &bus;
	m_slaveAddress = slaveAddress;

	// Init bus
	m_i2cbus->begin();

	delay(50);		//startup time of HP303B

	init();
}

void LOLIN_HP303B::begin(uint8_t slaveAddress)
{
	begin(Wire,slaveAddress);
}

/**
 * SPI begin function for HP303B with 4-wire SPI
 */
void LOLIN_HP303B::begin(SPIClass &bus, int32_t chipSelect)
{
	begin(bus, chipSelect, 0U);
}

/**
 * Standard SPI begin function
 *
 * &bus: 			SPI bus which connects MC to HP303B
 * chipSelect: 		Number of the CS line for the HP303B
 * threeWire: 		1 if HP303B is connected with 3-wire SPI
 * 					0 if HP303B is connected with 4-wire SPI (standard)
 */
void LOLIN_HP303B::begin(SPIClass &bus, int32_t chipSelect, uint8_t threeWire)
{
	//this flag will show if the initialization was successful
	m_initFail = 0U;

	//Set SPI bus connection
	m_SpiI2c = 0U;
	m_spibus = &bus;
	m_chipSelect = chipSelect;

	// Init bus
	m_spibus->begin();
	m_spibus->setDataMode(SPI_MODE3);

	pinMode(m_chipSelect, OUTPUT);
	digitalWrite(m_chipSelect, HIGH);

	delay(50);		//startup time of HP303B

	//switch to 3-wire mode if necessary
	//do not use writeByteBitfield or check option to set SPI mode!
	//Reading is not possible until SPI-mode is valid
	if(threeWire)
	{
		m_threeWire = 1U;
		if(writeByte(HP303B__REG_ADR_SPI3W, HP303B__REG_CONTENT_SPI3W))
		{
			m_initFail = 1U;
			return;
		}
	}

	init();
}

/**
 * End function for HP303B
 * Sets the sensor to idle mode
 */
void LOLIN_HP303B::end(void)
{
	standby();
}


////////		Declaration of other public functions starts here			////////


/**
 * returns the Product ID of the connected HP303B sensor
 */
uint8_t LOLIN_HP303B::getProductId(void)
{
	return m_productID;
}

/**
 * returns the Revision ID of the connected HP303B sensor
 */
uint8_t LOLIN_HP303B::getRevisionId(void)
{
	return m_revisionID;
}

/**
 * Sets the HP303B to standby mode
 *
 * returns:		0 on success
 * 				-2 if object initialization failed
 * 				-1 on other fail
 */
int16_t LOLIN_HP303B::standby(void)
{
	//abort if initialization failed
	if(m_initFail)
	{
		return HP303B__FAIL_INIT_FAILED;
	}
	//set device to idling mode
	int16_t ret = setOpMode(IDLE);
	if(ret != HP303B__SUCCEEDED)
	{
		return ret;
	}
	//flush the FIFO
	ret = writeByteBitfield(1U, HP303B__REG_INFO_FIFO_FL);
	if(ret < 0)
	{
		return ret;
	}
	//disable the FIFO
	ret = writeByteBitfield(0U, HP303B__REG_INFO_FIFO_EN);
	return ret;
}


/**
 * performs one temperature measurement and writes result to the given address
 *
 * &result:		reference to a 32-Bit signed Integer value where the result will be written
 * 				It will not be written if result==NULL
 * returns: 	0 on success
 * 				-4 if the HP303B is could not finish its measurement in time
 * 				-3 if the HP303B is already busy
 * 				-2 if the object initialization failed
 * 				-1 on other fail
 */
int16_t LOLIN_HP303B::measureTempOnce(int32_t &result)
{
	return measureTempOnce(result, m_tempOsr);
}

/**
 * performs one temperature measurement and writes result to the given address
 * the desired precision can be set with oversamplingRate
 *
 * &result:				reference to a 32-Bit signed Integer where the result will be written
 * 						It will not be written if result==NULL
 * oversamplingRate: 	a value from 0 to 7 that decides about the precision
 * 						of the measurement
 * 						If this value equals n, the HP303B will perform
 * 						2^n measurements and combine the results
 * returns: 			0 on success
 * 						-4 if the HP303B is could not finish its measurement in time
 * 						-3 if the HP303B is already busy
 * 						-2 if the object initialization failed
 * 						-1 on other fail
 */
int16_t LOLIN_HP303B::measureTempOnce(int32_t &result, uint8_t oversamplingRate)
{
	//Start measurement
	int16_t ret = startMeasureTempOnce(oversamplingRate);
	if(ret!=HP303B__SUCCEEDED)
	{
		return ret;
	}

	//wait until measurement is finished
	delay(calcBusyTime(0U, m_tempOsr)/HP303B__BUSYTIME_SCALING);
	delay(HP303B__BUSYTIME_FAILSAFE);

	ret = getSingleResult(result);
	if(ret!=HP303B__SUCCEEDED)
	{
		standby();
	}
	return ret;
}

/**
 * starts a single temperature measurement
 *
 * returns: 	0 on success
 * 				-3 if the HP303B is already busy
 * 				-2 if the object initialization failed
 * 				-1 on other fail
 */
int16_t LOLIN_HP303B::startMeasureTempOnce(void)
{
	return startMeasureTempOnce(m_tempOsr);
}

/**
 * starts a single temperature measurement
 * The desired precision can be set with oversamplingRate
 *
 * oversamplingRate: 	a value from 0 to 7 that decides about the precision
 * 						of the measurement
 * 						If this value equals n, the HP303B will perform
 * 						2^n measurements and combine the results
 * returns: 			0 on success
 * 						-3 if the HP303B is already busy
 * 						-2 if the object initialization failed
 * 						-1 on other fail
 */
int16_t LOLIN_HP303B::startMeasureTempOnce(uint8_t oversamplingRate)
{
	//abort if initialization failed
	if(m_initFail)
	{
		return HP303B__FAIL_INIT_FAILED;
	}
	//abort if device is not in idling mode
	if(m_opMode!=IDLE)
	{
		return HP303B__FAIL_TOOBUSY;
	}

	if(oversamplingRate!=m_tempOsr)
	{
		//configuration of oversampling rate
		if(configTemp(0U, oversamplingRate) != HP303B__SUCCEEDED)
		{
			return HP303B__FAIL_UNKNOWN;
		}
	}

	//set device to temperature measuring mode
	return setOpMode(0U, 1U, 0U);
}

/**
 * performs one pressure measurement and writes result to the given address
 *
 * &result:		reference to a 32-Bit signed Integer value where the result will be written
 * 				It will not be written if result==NULL
 * returns: 	0 on success
 * 				-4 if the HP303B is could not finish its measurement in time
 * 				-3 if the HP303B is already busy
 * 				-2 if the object initialization failed
 * 				-1 on other fail
 */
int16_t LOLIN_HP303B::measurePressureOnce(int32_t &result)
{
	return measurePressureOnce(result, m_prsOsr);
}

/**
 * performs one pressure measurement and writes result to the given address
 * the desired precision can be set with oversamplingRate
 *
 * &result:				reference to a 32-Bit signed Integer where the result will be written
 * 						It will not be written if result==NULL
 * oversamplingRate: 	a value from 0 to 7 that decides about the precision
 * 						of the measurement
 * 						If this value equals n, the HP303B will perform
 * 						2^n measurements and combine the results
 * returns: 			0 on success
 * 						-4 if the HP303B is could not finish its measurement in time
 * 						-3 if the HP303B is already busy
 * 						-2 if the object initialization failed
 * 						-1 on other fail
 */
int16_t LOLIN_HP303B::measurePressureOnce(int32_t &result, uint8_t oversamplingRate)
{
	//start the measurement
	int16_t ret = startMeasurePressureOnce(oversamplingRate);
	if(ret != HP303B__SUCCEEDED)
	{
		return ret;
	}

	//wait until measurement is finished
	delay(calcBusyTime(0U, m_prsOsr)/HP303B__BUSYTIME_SCALING);
	delay(HP303B__BUSYTIME_FAILSAFE);

	ret = getSingleResult(result);
	if(ret!=HP303B__SUCCEEDED)
	{
		standby();
	}
	return ret;
}

/**
 * starts a single pressure measurement
 *
 * returns: 	0 on success
 * 				-3 if the HP303B is already busy
 * 				-2 if the object initialization failed
 * 				-1 on other fail
 */
int16_t LOLIN_HP303B::startMeasurePressureOnce(void)
{
	return startMeasurePressureOnce(m_prsOsr);
}

/**
 * starts a single pressure measurement
 * The desired precision can be set with oversamplingRate
 *
 * oversamplingRate: 	a value from 0 to 7 that decides about the precision
 * 						of the measurement
 * 						If this value equals n, the HP303B will perform
 * 						2^n measurements and combine the results
 * returns: 			0 on success
 * 						-3 if the HP303B is already busy
 * 						-2 if the object initialization failed
 * 						-1 on other fail
 */
int16_t LOLIN_HP303B::startMeasurePressureOnce(uint8_t oversamplingRate)
{
	//abort if initialization failed
	if(m_initFail)
	{
		return HP303B__FAIL_INIT_FAILED;
	}
	//abort if device is not in idling mode
	if(m_opMode != IDLE)
	{
		return HP303B__FAIL_TOOBUSY;
	}
	//configuration of oversampling rate, lowest measure rate to avoid conflicts
	if(oversamplingRate != m_prsOsr)
	{
		if(configPressure(0U, oversamplingRate))
		{
			return HP303B__FAIL_UNKNOWN;
		}
	}
	//set device to pressure measuring mode
	return setOpMode(0U, 0U, 1U);
}

/**
 * gets the result a single temperature or pressure measurement in °C or Pa
 *
 * &result:		reference to a 32-Bit signed Integer value where the result will be written
 * returns: 	0 on success
 * 				-4 if the HP303B is still busy
 * 				-3 if the HP303B is not in command mode
 * 				-2 if the object initialization failed
 * 				-1 on other fail
 */
int16_t LOLIN_HP303B::getSingleResult(int32_t &result)
{
	//abort if initialization failed
	if(m_initFail)
	{
		return HP303B__FAIL_INIT_FAILED;
	}

	//read finished bit for current opMode
	int16_t rdy;
	switch(m_opMode)
	{
	case CMD_TEMP: 	//temperature
		rdy = readByteBitfield(HP303B__REG_INFO_TEMP_RDY);
		break;
	case CMD_PRS: 	//pressure
		rdy = readByteBitfield(HP303B__REG_INFO_PRS_RDY);
		break;
	default: 	//HP303B not in command mode
		return HP303B__FAIL_TOOBUSY;
	}

	//read new measurement result
	switch(rdy)
	{
	case HP303B__FAIL_UNKNOWN: 	//could not read ready flag
		return HP303B__FAIL_UNKNOWN;
	case 0: 						//ready flag not set, measurement still in progress
		return HP303B__FAIL_UNFINISHED;
	case 1: 						//measurement ready, expected case
		LOLIN_HP303B::Mode oldMode = m_opMode;
		m_opMode = IDLE;				//opcode was automatically reseted by HP303B
		switch(oldMode)
		{
		case CMD_TEMP: 	//temperature
			return getTemp(&result);		//get and calculate the temperature value
		case CMD_PRS: 	//pressure
			return getPressure(&result);	//get and calculate the pressure value
		default:
			return HP303B__FAIL_UNKNOWN;	//should already be filtered above
		}
	}
	return HP303B__FAIL_UNKNOWN;
}

/**
 * starts a continuous temperature measurement
 * The desired precision can be set with oversamplingRate
 * The desired number of measurements per second can be set with measureRate
 *
 * measureRate: 		a value from 0 to 7 that decides about
 * 						the number of measurements per second
 * 						If this value equals n, the HP303B will perform
 * 						2^n measurements per second
 * oversamplingRate: 	a value from 0 to 7 that decides about
 * 						the precision of the measurements
 * 						If this value equals m, the HP303B will perform
 * 						2^m internal measurements and combine the results
 * 						to one more exact measurement
 * returns: 			0 on success
 * 						-4 if measureRate or oversamplingRate is too high
 * 						-3 if the HP303B is already busy
 * 						-2 if the object initialization failed
 * 						-1 on other fail
 * 	NOTE: 				If measure rate is n and oversampling rate is m,
 * 						the HP303B performs 2^(n+m) internal measurements per second.
 * 						The HP303B cannot operate with high precision and high speed
 * 						at the same time.
 * 						Consult the datasheet for more information.
 */
int16_t LOLIN_HP303B::startMeasureTempCont(uint8_t measureRate, uint8_t oversamplingRate)
{
	//abort if initialization failed
	if(m_initFail)
	{
		return HP303B__FAIL_INIT_FAILED;
	}
	//abort if device is not in idling mode
	if(m_opMode != IDLE)
	{
		return HP303B__FAIL_TOOBUSY;
	}
	//abort if speed and precision are too high
	if(calcBusyTime(measureRate, oversamplingRate) >= HP303B__MAX_BUSYTIME)
	{
		return HP303B__FAIL_UNFINISHED;
	}
	//update precision and measuring rate
	if(configTemp(measureRate, oversamplingRate))
	{
		return HP303B__FAIL_UNKNOWN;
	}
	//enable result FIFO
	if(writeByteBitfield(1U, HP303B__REG_INFO_FIFO_EN))
	{
		return HP303B__FAIL_UNKNOWN;
	}
	//Start measuring in background mode
	if(setOpMode(1U, 1U, 0U))
	{
		return HP303B__FAIL_UNKNOWN;
	}
	return HP303B__SUCCEEDED;
}


/**
 * starts a continuous temperature measurement
 * The desired precision can be set with oversamplingRate
 * The desired number of measurements per second can be set with measureRate
 *
 * measureRate: 		a value from 0 to 7 that decides about
 * 						the number of measurements per second
 * 						If this value equals n, the HP303B will perform
 * 						2^n measurements per second
 * oversamplingRate: 	a value from 0 to 7 that decides about the precision
 * 						of the measurements
 * 						If this value equals m, the HP303B will perform
 * 						2^m internal measurements
 * 						and combine the results to one more exact measurement
 * returns: 			0 on success
 * 						-4 if measureRate or oversamplingRate is too high
 * 						-3 if the HP303B is already busy
 * 						-2 if the object initialization failed
 * 						-1 on other fail
 * 	NOTE: 				If measure rate is n and oversampling rate is m,
 * 						the HP303B performs 2^(n+m) internal measurements per second.
 * 						The HP303B cannot operate with high precision and high speed
 * 						at the same time.
 * 						Consult the datasheet for more information.
 */
int16_t LOLIN_HP303B::startMeasurePressureCont(uint8_t measureRate, uint8_t oversamplingRate)
{
	//abort if initialization failed
	if(m_initFail)
	{
		return HP303B__FAIL_INIT_FAILED;
	}
	//abort if device is not in idling mode
	if(m_opMode != IDLE)
	{
		return HP303B__FAIL_TOOBUSY;
	}
	//abort if speed and precision are too high
	if(calcBusyTime(measureRate, oversamplingRate) >= HP303B__MAX_BUSYTIME)
	{
		return HP303B__FAIL_UNFINISHED;
	}
	//update precision and measuring rate
	if(configPressure(measureRate, oversamplingRate))
		return HP303B__FAIL_UNKNOWN;
	//enable result FIFO
	if(writeByteBitfield(1U, HP303B__REG_INFO_FIFO_EN))
	{
		return HP303B__FAIL_UNKNOWN;
	}
	//Start measuring in background mode
	if(setOpMode(1U, 0U, 1U))
	{
		return HP303B__FAIL_UNKNOWN;
	}
	return HP303B__SUCCEEDED;
}

/**
 * starts a continuous temperature and pressure measurement
 * The desired precision can be set with tempOsr and prsOsr
 * The desired number of measurements per second can be set with tempMr and prsMr
 *
 * tempMr				measure rate for temperature
 * tempOsr				oversampling rate for temperature
 * prsMr				measure rate for pressure
 * prsOsr				oversampling rate for pressure
 * returns: 			0 on success
 * 						-4 if precision or speed is too high
 * 						-3 if the HP303B is already busy
 * 						-2 if the object initialization failed
 * 						-1 on other fail
 * 	NOTE: 				High precision and speed for both temperature and pressure
 * 						can not be reached at the same time.
 * 						Estimated time for temperature and pressure measurement
 * 						is the sum of both values.
 * 						This sum must not be more than 1 second.
 * 						Consult the datasheet for more information.
 */
int16_t LOLIN_HP303B::startMeasureBothCont(uint8_t tempMr,
										 uint8_t tempOsr,
										 uint8_t prsMr,
										 uint8_t prsOsr)
{
	//abort if initialization failed
	if(m_initFail)
	{
		return HP303B__FAIL_INIT_FAILED;
	}
	//abort if device is not in idling mode
	if(m_opMode!=IDLE)
	{
		return HP303B__FAIL_TOOBUSY;
	}
	//abort if speed and precision are too high
	if(calcBusyTime(tempMr, tempOsr) + calcBusyTime(prsMr, prsOsr)>=HP303B__MAX_BUSYTIME)
	{
		return HP303B__FAIL_UNFINISHED;
	}
	//update precision and measuring rate
	if(configTemp(tempMr, tempOsr))
	{
		return HP303B__FAIL_UNKNOWN;
	}
	//update precision and measuring rate
	if(configPressure(prsMr, prsOsr))
		return HP303B__FAIL_UNKNOWN;
	//enable result FIFO
	if(writeByteBitfield(1U, HP303B__REG_INFO_FIFO_EN))
	{
		return HP303B__FAIL_UNKNOWN;
	}
	//Start measuring in background mode
	if(setOpMode(1U, 1U, 1U))
	{
		return HP303B__FAIL_UNKNOWN;
	}
	return HP303B__SUCCEEDED;
}

/**
 * Gets the results from continuous measurements and writes them to given arrays
 *
 * *tempBuffer: 	The start address of the buffer where the temperature results
 * 					are written
 * 					If this is NULL, no temperature results will be written out
 * &tempCount:		This has to be a reference to a number which contains
 * 					the size of the buffer for temperature results.
 * 					When the function ends, it will contain
 * 					the number of bytes written to the buffer
 * *prsBuffer: 		The start address of the buffer where the pressure results
 * 					are written
 * 					If this is NULL, no pressure results will be written out
 * &prsCount:		This has to be a reference to a number which contains
 * 					the size of the buffer for pressure results.
 * 					When the function ends, it will contain
 * 					the number of bytes written to the buffer
 * returns:			0 on success
 * 					-3 if HP303B is not in background mode
 * 					-2 if the object initialization failed
 * 					-1 on other fail
 */
int16_t LOLIN_HP303B::getContResults(int32_t *tempBuffer,
								   uint8_t &tempCount,
								   int32_t *prsBuffer,
								   uint8_t &prsCount)
{
	if(m_initFail)
	{
		return HP303B__FAIL_INIT_FAILED;
	}
	//abort if device is not in background mode
	if(!(m_opMode & INVAL_OP_CONT_NONE))
	{
		return HP303B__FAIL_TOOBUSY;
	}

	//prepare parameters for buffer length and count
	uint8_t tempLen = tempCount;
	uint8_t prsLen = prsCount;
	tempCount = 0U;
	prsCount = 0U;

	//while FIFO is not empty
	while(readByteBitfield(HP303B__REG_INFO_FIFO_EMPTY) == 0)
	{
		int32_t result;
		//read next result from FIFO
		int16_t type = getFIFOvalue(&result);
		switch(type)
		{
		case 0: //temperature
			//calculate compensated pressure value
			result = calcTemp(result);
			//if buffer exists and is not full
			//write result to buffer and increase temperature result counter
			if(tempBuffer != NULL)
			{
				if(tempCount<tempLen)
				{
					tempBuffer[tempCount++] = result;
				}
			}
			break;
		case 1: //pressure
			//calculate compensated pressure value
			result = calcPressure(result);
			//if buffer exists and is not full
			//write result to buffer and increase pressure result counter
			if(prsBuffer != NULL)
			{
				if(prsCount<prsLen)
				{
					prsBuffer[prsCount++] = result;
				}
			}
			break;
		case -1: //read failed
			break;	//continue while loop
					//if connection failed permanently,
					//while condition will become false
					//if read failed only once, loop will try again
		}
	}
	return HP303B__SUCCEEDED;
}

/**
 * Sets the active state of the Interrupt pin
 *
 * polarity: 	If this is 0, the interrupt pin of the HP303B will be low-active
 * 				If this is 1, the interrupt pin of the HP303B will be high-active
 * returns:		0 on success,
 * 				-1 on fail
 */
int16_t LOLIN_HP303B::setInterruptPolarity(uint8_t polarity)
{
	//Interrupts are not supported with 4 Wire SPI
	if(!m_SpiI2c & !m_threeWire)
	{
		return HP303B__FAIL_UNKNOWN;
	}
	return writeByteBitfield(polarity, HP303B__REG_INFO_INT_HL);
}

/**
 * Sets the sources that are able to cause interrupts
 *
 * fifoFull: 	if this is 1, an interrupt will be generated
 * 				when the FIFO is full
 * 				if this is 0, the FIFO will not generate any interrupts
 * tempReady: 	if this is 1, an interrupt will be generated
 * 				when a temperature measurement is finished
 * 				if this is 0, no interrupt will be generated
 * 				after finishing a temperature measurement
 * prsReady: 	if this is 1, an interrupt will be generated
 * 				when a pressure measurement is finished
 * 				if this is 0, no interrupt will be generated
 * 				after finishing a pressure measurement
 * returns: 	0 on success, -1 on fail
 */
int16_t LOLIN_HP303B::setInterruptSources(uint8_t fifoFull, uint8_t tempReady, uint8_t prsReady)
{
	//Interrupts are not supported with 4 Wire SPI
	if(!m_SpiI2c & !m_threeWire)
	{
		return HP303B__FAIL_UNKNOWN;
	}
	//mask parameters
	fifoFull &= HP303B__REG_MASK_INT_EN_FIFO >> HP303B__REG_SHIFT_INT_EN_FIFO;
	tempReady &= HP303B__REG_MASK_INT_EN_TEMP >> HP303B__REG_SHIFT_INT_EN_TEMP;
	prsReady &= HP303B__REG_MASK_INT_EN_PRS >> HP303B__REG_SHIFT_INT_EN_PRS;
	//read old value from register
	int16_t regData = readByte(HP303B__REG_ADR_INT_EN_FIFO);
	if(regData <0)
	{
		return HP303B__FAIL_UNKNOWN;
	}
	uint8_t toWrite = (uint8_t)regData;
	//update FIFO enable bit
	toWrite &= ~HP303B__REG_MASK_INT_EN_FIFO;	//clear bit
	toWrite |= fifoFull << HP303B__REG_SHIFT_INT_EN_FIFO;	//set new bit
	//update TempReady enable bit
	toWrite &= ~HP303B__REG_MASK_INT_EN_TEMP;
	toWrite |= tempReady << HP303B__REG_SHIFT_INT_EN_TEMP;
	//update PrsReady enable bit
	toWrite &= ~HP303B__REG_MASK_INT_EN_PRS;
	toWrite |= prsReady << HP303B__REG_SHIFT_INT_EN_PRS;
	//write updated value to register
	return writeByte(HP303B__REG_ADR_INT_EN_FIFO, toWrite);
}

/**
 * Gets the interrupt status flag of the FIFO
 *
 * Returns: 	1 if the FIFO is full and caused an interrupt
 * 				0 if the FIFO is not full or FIFO interrupt is disabled
 * 				-1 on fail
 */
int16_t LOLIN_HP303B::getIntStatusFifoFull(void)
{
	return readByteBitfield(HP303B__REG_INFO_INT_FLAG_FIFO);
}

/**
 * Gets the interrupt status flag that indicates a finished temperature measurement
 *
 * Returns: 	1 if a finished temperature measurement caused an interrupt
 * 				0 if there is no finished temperature measurement
 * 					or interrupts are disabled
 * 				-1 on fail
 */
int16_t LOLIN_HP303B::getIntStatusTempReady(void)
{
	return readByteBitfield(HP303B__REG_INFO_INT_FLAG_TEMP);
}

/**
 * Gets the interrupt status flag that indicates a finished pressure measurement
 *
 * Returns: 	1 if a finished pressure measurement caused an interrupt
 * 				0 if there is no finished pressure measurement
 * 					or interrupts are disabled
 * 				-1 on fail
 */
int16_t LOLIN_HP303B::getIntStatusPrsReady(void)
{
	return readByteBitfield(HP303B__REG_INFO_INT_FLAG_PRS);
}

/**
 * Function to fix a hardware problem on some devices
 * You have this problem if you measure a temperature which is too high (e.g. 60°C when temperature is around 20°C)
 * Call correctTemp() directly after begin() to fix this issue
 */
int16_t LOLIN_HP303B::correctTemp(void)
{
	if(m_initFail)
	{
		return HP303B__FAIL_INIT_FAILED;
	}
	writeByte(0x0E, 0xA5);
	writeByte(0x0F, 0x96);
	writeByte(0x62, 0x02);
	writeByte(0x0E, 0x00);
	writeByte(0x0F, 0x00);
	
	//perform a first temperature measurement (again)
	//the most recent temperature will be saved internally
	//and used for compensation when calculating pressure
	int32_t trash;
	measureTempOnce(trash);
	
	return HP303B__SUCCEEDED;
}



//////// 	Declaration of private functions starts here	////////


/**
 * Initializes the sensor.
 * This function has to be called from begin()
 * and requires a valid bus initialization.
 */
void LOLIN_HP303B::init(void)
{
	int16_t prodId = readByteBitfield(HP303B__REG_INFO_PROD_ID);
	if(prodId != HP303B__PROD_ID)
	{
		//Connected device is not a HP303B
		m_initFail = 1U;
		return;
	}
	m_productID = prodId;

	int16_t revId = readByteBitfield(HP303B__REG_INFO_REV_ID);
	if(revId < 0)
	{
		m_initFail = 1U;
		return;
	}
	m_revisionID = revId;

	//find out which temperature sensor is calibrated with coefficients...
	int16_t sensor = readByteBitfield(HP303B__REG_INFO_TEMP_SENSORREC);
	if(sensor < 0)
	{
		m_initFail = 1U;
		return;
	}

	//...and use this sensor for temperature measurement
	m_tempSensor = sensor;
	if(writeByteBitfield((uint8_t)sensor, HP303B__REG_INFO_TEMP_SENSOR) < 0)
	{
		m_initFail = 1U;
		return;
	}

	//read coefficients
	if(readcoeffs() < 0)
	{
		m_initFail = 1U;
		return;
	}

	//set to standby for further configuration
	standby();

	//set measurement precision and rate to standard values;
	configTemp(HP303B__TEMP_STD_MR, HP303B__TEMP_STD_OSR);
	configPressure(HP303B__PRS_STD_MR, HP303B__PRS_STD_OSR);

	//perform a first temperature measurement
	//the most recent temperature will be saved internally
	//and used for compensation when calculating pressure
	int32_t trash;
	measureTempOnce(trash);

	//make sure the HP303B is in standby after initialization
	standby();	

	// Fix IC with a fuse bit problem, which lead to a wrong temperature 
	// Should not affect ICs without this problem
	correctTemp();
}


/**
 * reads the compensation coefficients from the HP303B
 * this is called once from init(), which is called from begin()
 *
 * returns: 	0 on success, -1 on fail
 */
int16_t LOLIN_HP303B::readcoeffs(void)
{
	uint8_t buffer[HP303B__REG_LEN_COEF];
	//read COEF registers to buffer
	int16_t ret = readBlock(HP303B__REG_ADR_COEF,
							HP303B__REG_LEN_COEF,
							buffer);
	//abort if less than REG_LEN_COEF bytes were read
	if(ret < HP303B__REG_LEN_COEF)
	{
		return HP303B__FAIL_UNKNOWN;
	}

	//compose coefficients from buffer content
	m_c0Half =    ((uint32_t)buffer[0] << 4)
				| (((uint32_t)buffer[1] >> 4) & 0x0F);
	//this construction recognizes non-32-bit negative numbers
	//and converts them to 32-bit negative numbers with 2's complement
	if(m_c0Half & ((uint32_t)1 << 11))
	{
		m_c0Half -= (uint32_t)1 << 12;
	}
	//c0 is only used as c0*0.5, so c0_half is calculated immediately
	m_c0Half = m_c0Half / 2U;

	//now do the same thing for all other coefficients
	m_c1 = (((uint32_t)buffer[1] & 0x0F) << 8) | (uint32_t)buffer[2];
	if(m_c1 & ((uint32_t)1 << 11))
	{
		m_c1 -= (uint32_t)1 << 12;
	}

	m_c00 =   ((uint32_t)buffer[3] << 12)
			| ((uint32_t)buffer[4] << 4)
			| (((uint32_t)buffer[5] >> 4) & 0x0F);
	if(m_c00 & ((uint32_t)1 << 19))
	{
		m_c00 -= (uint32_t)1 << 20;
	}

	m_c10 =   (((uint32_t)buffer[5] & 0x0F) << 16)
			| ((uint32_t)buffer[6] << 8)
			| (uint32_t)buffer[7];
	if(m_c10 & ((uint32_t)1<<19))
	{
		m_c10 -= (uint32_t)1 << 20;
	}

	m_c01 =   ((uint32_t)buffer[8] << 8)
			| (uint32_t)buffer[9];
	if(m_c01 & ((uint32_t)1 << 15))
	{
		m_c01 -= (uint32_t)1 << 16;
	}

	m_c11 =   ((uint32_t)buffer[10] << 8)
			| (uint32_t)buffer[11];
	if(m_c11 & ((uint32_t)1 << 15))
	{
		m_c11 -= (uint32_t)1 << 16;
	}

	m_c20 =   ((uint32_t)buffer[12] << 8)
			| (uint32_t)buffer[13];
	if(m_c20 & ((uint32_t)1 << 15))
	{
		m_c20 -= (uint32_t)1 << 16;
	}

	m_c21 =   ((uint32_t)buffer[14] << 8)
			| (uint32_t)buffer[15];
	if(m_c21 & ((uint32_t)1 << 15))
	{
		m_c21 -= (uint32_t)1 << 16;
	}

	m_c30 =   ((uint32_t)buffer[16] << 8)
			| (uint32_t)buffer[17];
	if(m_c30 & ((uint32_t)1 << 15))
	{
		m_c30 -= (uint32_t)1 << 16;
	}

	return HP303B__SUCCEEDED;
}

/**
 * Sets the Operation Mode of the HP303B
 *
 * background:		determines the general behavior of the HP303B
 *  				0 enables command mode (only measure on commands)
 * 					1 enables background mode (continuous work in background)
 * temperature: 	set 1 to measure temperature
 * pressure: 		set 1 to measure pressure
 * return:			0 on success, -1 on fail
 *
 * NOTE!
 * You cannot set background to 1 without setting temperature and pressure
 * You cannot set both temperature and pressure when background mode is disabled
 */
int16_t LOLIN_HP303B::setOpMode(uint8_t background, uint8_t temperature, uint8_t pressure)
{
	uint8_t opMode =  (background & HP303B__LSB) << 2U
					| (temperature & HP303B__LSB) << 1U
					| (pressure & HP303B__LSB);
	return setOpMode(opMode);
}


/**
 * Sets the Operation Mode of the HP303B
 *
 * opMode: 			the new OpMode that has to be set
 * return: 			0 on success, -1 on fail
 *
 * NOTE!
 * You cannot set background to 1 without setting temperature and pressure
 * You cannot set both temperature and pressure when background mode is disabled
 */
int16_t LOLIN_HP303B::setOpMode(uint8_t opMode)
{
	//Filter irrelevant bits
	opMode &= HP303B__REG_MASK_OPMODE >> HP303B__REG_SHIFT_OPMODE;
	//Filter invalid OpModes
	if(opMode == INVAL_OP_CMD_BOTH || opMode == INVAL_OP_CONT_NONE)
	{
		return HP303B__FAIL_UNKNOWN;
	}
	//Set OpMode
	if(writeByte(HP303B__REG_ADR_OPMODE, opMode))
	{
		return HP303B__FAIL_UNKNOWN;
	}
	m_opMode = (LOLIN_HP303B::Mode)opMode;
	return HP303B__SUCCEEDED;
}

/**
 * Configures temperature measurement
 *
 * tempMr: 	the new measure rate for temperature
 * 				This can be a value from 0U to 7U.
 * 				Actual measure rate will be 2^tempMr,
 * 				so this will be a value from 1 to 128.
 * tempOsr: 	the new oversampling rate for temperature
 * 				This can be a value from 0U to 7U.
 * 				Actual measure rate will be 2^tempOsr,
 * 				so this will be a value from 1 to 128.
 * returns: 	0 normally or -1 on fail
 */
int16_t LOLIN_HP303B::configTemp(uint8_t tempMr, uint8_t tempOsr)
{
	//mask parameters
	tempMr &= HP303B__REG_MASK_TEMP_MR >> HP303B__REG_SHIFT_TEMP_MR;
	tempOsr &= HP303B__REG_MASK_TEMP_OSR >> HP303B__REG_SHIFT_TEMP_OSR;

	//set config register according to parameters
	uint8_t toWrite = tempMr << HP303B__REG_SHIFT_TEMP_MR;
	toWrite |= tempOsr << HP303B__REG_SHIFT_TEMP_OSR;
	//using recommended temperature sensor
	toWrite |=    HP303B__REG_MASK_TEMP_SENSOR
				& (m_tempSensor << HP303B__REG_SHIFT_TEMP_SENSOR);
	int16_t ret = writeByte(HP303B__REG_ADR_TEMP_MR, toWrite);
	//abort immediately on fail
	if(ret != HP303B__SUCCEEDED)
	{
		return HP303B__FAIL_UNKNOWN;
	}

	//set TEMP SHIFT ENABLE if oversampling rate higher than eight(2^3)
	if(tempOsr > HP303B__OSR_SE)
	{
		ret=writeByteBitfield(1U, HP303B__REG_INFO_TEMP_SE);
	}
	else
	{
		ret=writeByteBitfield(0U, HP303B__REG_INFO_TEMP_SE);
	}

	if(ret == HP303B__SUCCEEDED)
	{	//save new settings
		m_tempMr = tempMr;
		m_tempOsr = tempOsr;
	}
	else
	{
		//try to rollback on fail avoiding endless recursion
		//this is to make sure that shift enable and oversampling rate
		//are always consistent
		if(tempMr != m_tempMr || tempOsr != m_tempOsr)
		{
			configTemp(m_tempMr, m_tempOsr);
		}
	}
	return ret;
}

/**
 * Configures pressure measurement
 *
 * prsMr: 		the new measure rate for pressure
 * 				This can be a value from 0U to 7U.
 * 				Actual measure rate will be 2^prs_mr,
 * 				so this will be a value from 1 to 128.
 * prsOs: 	the new oversampling rate for temperature
 * 				This can be a value from 0U to 7U.
 * 				Actual measure rate will be 2^prsOsr,
 * 				so this will be a value from 1 to 128.
 * returns: 	0 normally or -1 on fail
 */
int16_t LOLIN_HP303B::configPressure(uint8_t prsMr, uint8_t prsOsr)
{
	//mask parameters
	prsMr &= HP303B__REG_MASK_PRS_MR >> HP303B__REG_SHIFT_PRS_MR;
	prsOsr &= HP303B__REG_MASK_PRS_OSR >> HP303B__REG_SHIFT_PRS_OSR;

	//set config register according to parameters
	uint8_t toWrite = prsMr << HP303B__REG_SHIFT_PRS_MR;
	toWrite |= prsOsr << HP303B__REG_SHIFT_PRS_OSR;
	int16_t ret = writeByte(HP303B__REG_ADR_PRS_MR, toWrite);
	//abort immediately on fail
	if(ret != HP303B__SUCCEEDED)
	{
		return HP303B__FAIL_UNKNOWN;
	}

	//set PM SHIFT ENABLE if oversampling rate higher than eight(2^3)
	if(prsOsr > HP303B__OSR_SE)
	{
		ret = writeByteBitfield(1U, HP303B__REG_INFO_PRS_SE);
	}
	else
	{
		ret = writeByteBitfield(0U, HP303B__REG_INFO_PRS_SE);
	}

	if(ret == HP303B__SUCCEEDED)
	{	//save new settings
		m_prsMr = prsMr;
		m_prsOsr = prsOsr;
	}
	else
	{	//try to rollback on fail avoiding endless recursion
		//this is to make sure that shift enable and oversampling rate
		//are always consistent
		if(prsMr != m_prsMr || prsOsr != m_prsOsr)
		{
			configPressure(m_prsMr, m_prsOsr);
		}
	}
	return ret;
}

/**
 * calculates the time that the HP303B needs for 2^mr measurements
 * with an oversampling rate of 2^osr
 *
 * mr: 		Measure rate for temperature or pressure
 * osr: 	Oversampling rate for temperature or pressure
 * returns: time that the HP303B needs for this measurement
 * 			a value of 10000 equals 1 second
 * 	NOTE! 	The measurement time for temperature and pressure
 * 			in sum must not be more than 1 second!
 * 			Timing behavior of pressure and temperature sensors
 * 			can be considered as equal.
 */
uint16_t LOLIN_HP303B::calcBusyTime(uint16_t mr, uint16_t osr)
{
	//mask parameters first
	mr &= HP303B__REG_MASK_TEMP_MR >> HP303B__REG_SHIFT_TEMP_MR;
	osr &= HP303B__REG_MASK_TEMP_OSR >> HP303B__REG_SHIFT_TEMP_OSR;
	//formula from datasheet (optimized)
	return ((uint32_t)20U << mr) + ((uint32_t)16U << (osr + mr));
}

/**
 * Gets the next temperature measurement result in degrees of Celsius
 *
 * result: 	address where the result will be written
 * returns:	0 on success
 * 			-1 on fail;
 */
int16_t LOLIN_HP303B::getTemp(int32_t *result)
{
	uint8_t buffer[3] = {0};
	//read raw pressure data to buffer

	int16_t i = readBlock(HP303B__REG_ADR_TEMP,
							HP303B__REG_LEN_TEMP,
							buffer);
	if(i != HP303B__REG_LEN_TEMP)
	{
		//something went wrong
		return HP303B__FAIL_UNKNOWN;
	}

	//compose raw temperature value from buffer
	int32_t temp =    (uint32_t)buffer[0] << 16
					| (uint32_t)buffer[1] << 8
					| (uint32_t)buffer[2];
	//recognize non-32-bit negative numbers
	//and convert them to 32-bit negative numbers using 2's complement
	if(temp & ((uint32_t)1 << 23))
	{
		temp -= (uint32_t)1 << 24;
	}

	//return temperature
	*result = calcTemp(temp);
	return HP303B__SUCCEEDED;
}

/**
 * Gets the next pressure measurement result in Pa
 *
 * result: 	address where the result will be written
 * returns: 0 on success
 * 			-1 on fail;
 */
int16_t LOLIN_HP303B::getPressure(int32_t *result)
{
	uint8_t buffer[3] = {0};
	//read raw pressure data to buffer
	int16_t i = readBlock(HP303B__REG_ADR_PRS,
							HP303B__REG_LEN_PRS,
							buffer);
	if(i != HP303B__REG_LEN_PRS)
	{
		//something went wrong
		//negative pressure is not allowed
		return HP303B__FAIL_UNKNOWN;
	}

	//compose raw pressure value from buffer
	int32_t prs =   (uint32_t)buffer[0] << 16
					| (uint32_t)buffer[1] << 8
					| (uint32_t)buffer[2];
	//recognize non-32-bit negative numbers
	//and convert them to 32-bit negative numbers using 2's complement
	if(prs & ((uint32_t)1 << 23))
	{
		prs -= (uint32_t)1 << 24;
	}

	*result = calcPressure(prs);
	return HP303B__SUCCEEDED;
}

/**
 * reads the next raw value from the HP303B FIFO
 *
 * value: 	address where the value will be written
 * returns:	-1 on fail
 * 			0 if result is a temperature raw value
 * 			1 if result is a pressure raw value
 */
int16_t LOLIN_HP303B::getFIFOvalue(int32_t* value)
{
	//abort on invalid argument
	if(value == NULL)
	{
		return HP303B__FAIL_UNKNOWN;
	}

	uint8_t buffer[HP303B__REG_LEN_PRS] = {0};
	//always read from pressure raw value register
	int16_t i = readBlock(HP303B__REG_ADR_PRS,
							HP303B__REG_LEN_PRS,
							buffer);
	if(i != HP303B__REG_LEN_PRS)
	{
		//something went wrong
		//return error code
		return HP303B__FAIL_UNKNOWN;
	}
	//compose raw pressure value from buffer
	*value =  (uint32_t)buffer[0] << 16
			| (uint32_t)buffer[1] << 8
			| (uint32_t)buffer[2];
	//recognize non-32-bit negative numbers
	//and convert them to 32-bit negative numbers using 2's complement
	if(*value & ((uint32_t)1 << 23))
	{
		*value -= (uint32_t)1 << 24;
	}

	//least significant bit shows measurement type
	return buffer[2] & HP303B__LSB;
}

/**
 * Calculates a scaled and compensated pressure value from raw data
 * raw: 	raw temperature value read from HP303B
 * returns: temperature value in °C
 */
int32_t LOLIN_HP303B::calcTemp(int32_t raw)
{
	double temp = raw;
	
	//scale temperature according to scaling table and oversampling
	temp /= scaling_facts[m_tempOsr];

	//update last measured temperature
	//it will be used for pressure compensation
	m_lastTempScal = temp;

	//Calculate compensated temperature
	temp = m_c0Half + m_c1 * temp;

	//return temperature
	return (int32_t)temp;
}

/**
 * Calculates a scaled and compensated pressure value from raw data
 * raw: 	raw pressure value read from HP303B
 * returns: pressure value in Pa
 */
int32_t LOLIN_HP303B::calcPressure(int32_t raw)
{
	double prs = raw;

	//scale pressure according to scaling table and oversampling
	prs /= scaling_facts[m_prsOsr];

	//Calculate compensated pressure
	prs =   m_c00
			+ prs * (m_c10 + prs * (m_c20 + prs * m_c30))
			+ m_lastTempScal * (m_c01 + prs * (m_c11 + prs * m_c21));

	//return pressure
	return (int32_t)prs;
}

/**
 * reads a byte from HP303B
 *
 * regAdress: 	Address that has to be read
 * returns: 	register content or -1 on fail
 */
int16_t LOLIN_HP303B::readByte(uint8_t regAddress)
{
	//delegate to specialized function if HP303B is connected via SPI
	if(m_SpiI2c==0)
	{
		return readByteSPI(regAddress);
	}
	
	m_i2cbus->beginTransmission(m_slaveAddress);
	m_i2cbus->write(regAddress);
    m_i2cbus->endTransmission(0);
	//request 1 byte from slave
	if(m_i2cbus->requestFrom(m_slaveAddress, 1U, 1U) > 0)
	{
		return m_i2cbus->read();	//return this byte on success
	}
	else
	{
		return HP303B__FAIL_UNKNOWN;	//if 0 bytes were read successfully
	}
}

/**
 * reads a byte from HP303B via SPI
 * this function is automatically called by readByte
 * if HP303B is connected via SPI
 *
 * regAdress: 	Address that has to be read
 * returns: 	register content or -1 on fail
 */
int16_t LOLIN_HP303B::readByteSPI(uint8_t regAddress)
{
	//this function is only made for communication via SPI
	if(m_SpiI2c != 0)
	{
		return HP303B__FAIL_UNKNOWN;
	}
	//mask regAddress
	regAddress &= ~HP303B__SPI_RW_MASK;
	//reserve and initialize bus
	m_spibus->beginTransaction(SPISettings(HP303B__SPI_MAX_FREQ,
											MSBFIRST,
											SPI_MODE3));
	//enable ChipSelect for HP303B
	digitalWrite(m_chipSelect, LOW);
	//send address with read command to HP303B
	m_spibus->transfer(regAddress | HP303B__SPI_READ_CMD);
	//receive register content from HP303B
	uint8_t ret = m_spibus->transfer(0xFF);	//send a dummy byte while receiving
	//disable ChipSelect for HP303B
	digitalWrite(m_chipSelect, HIGH);
	//close current SPI transaction
	m_spibus->endTransaction();
	//return received data
	return ret;
}

/**
 * reads a block from HP303B
 *
 * regAdress: 	Address that has to be read
 * length: 		Length of data block
 * buffer: 	Buffer where data will be stored
 * returns: 	number of bytes that have been read successfully
 * 				NOTE! This is not always equal to length
 * 					  due to rx-Buffer overflow etc.
 */
int16_t LOLIN_HP303B::readBlock(uint8_t regAddress, uint8_t length, uint8_t *buffer)
{
	//delegate to specialized function if HP303B is connected via SPI
	if(m_SpiI2c == 0)
	{
		return readBlockSPI(regAddress, length, buffer);
	}
	//do not read if there is no buffer
	if(buffer == NULL)
	{
		return 0;	//0 bytes read successfully
	}
	
	m_i2cbus->beginTransmission(m_slaveAddress);
	m_i2cbus->write(regAddress);
    m_i2cbus->endTransmission(0);
	//request length bytes from slave
	int16_t ret = m_i2cbus->requestFrom(m_slaveAddress, length, 1U);
	//read all received bytes to buffer
	for(int16_t count = 0; count < ret; count++)
	{
		buffer[count] = m_i2cbus->read();
	}
	return ret;
}

/**
 * reads a block from HP303B via SPI
 *
 * regAdress: 	Address that has to be read
 * length: 		Length of data block
 * readbuffer: 	Buffer where data will be stored
 * returns: 	number of bytes that have been read successfully
 * 				NOTE! This is not always equal to length
 * 					  due to rx-Buffer overflow etc.
 */
int16_t LOLIN_HP303B::readBlockSPI(uint8_t regAddress, uint8_t length, uint8_t *buffer)
{
	//this function is only made for communication via SPI
	if(m_SpiI2c != 0)
	{
		return HP303B__FAIL_UNKNOWN;
	}
	//do not read if there is no buffer
	if(buffer == NULL)
	{
		return 0;		//0 bytes were read successfully
	}
	//mask regAddress
	regAddress &= ~HP303B__SPI_RW_MASK;
	//reserve and initialize bus
	m_spibus->beginTransaction(SPISettings(HP303B__SPI_MAX_FREQ,
											MSBFIRST,
											SPI_MODE3));
	//enable ChipSelect for HP303B
	digitalWrite(m_chipSelect, LOW);
	//send address with read command to HP303B
	m_spibus->transfer(regAddress | HP303B__SPI_READ_CMD);

	//receive register contents from HP303B
	for(uint8_t count = 0; count < length; count++)
	{
		buffer[count] = m_spibus->transfer(0xFF);//send a dummy byte while receiving
	}

	//disable ChipSelect for HP303B
	digitalWrite(m_chipSelect, HIGH);
	//close current SPI transaction
	m_spibus->endTransaction();
	//return received data
	return length;
}

/**
 * writes a given byte to a given register of HP303B without checking
 *
 * regAdress: 	Address of the register that has to be updated
 * data:		Byte that will be written to the register
 * return:		0 if byte was written successfully
 * 				or -1 on fail
 */
int16_t LOLIN_HP303B::writeByte(uint8_t regAddress, uint8_t data)
{
	return writeByte(regAddress, data, 0U);
}

/**
 * writes a given byte to a given register of HP303B
 *
 * regAdress: 	Address of the register that has to be updated
 * data:		Byte that will be written to the register
 * check: 		If this is true, register content will be read after writing
 * 				to check if update was successful
 * return:		0 if byte was written successfully
 * 				or -1 on fail
 */
int16_t LOLIN_HP303B::writeByte(uint8_t regAddress, uint8_t data, uint8_t check)
{
	//delegate to specialized function if HP303B is connected via SPI
	if(m_SpiI2c==0)
	{
		return writeByteSpi(regAddress, data, check);
	}
	m_i2cbus->beginTransmission(m_slaveAddress);
	m_i2cbus->write(regAddress);			//Write Register number to buffer
	m_i2cbus->write(data);					//Write data to buffer
	if(m_i2cbus->endTransmission() != 0) 	//Send buffer content to slave
	{
		return HP303B__FAIL_UNKNOWN;
	}
	else
	{
		if(check == 0) return 0;			//no checking
		if(readByte(regAddress) == data)	//check if desired by calling function
		{
			return HP303B__SUCCEEDED;
		}
		else
		{
			return HP303B__FAIL_UNKNOWN;
		}
	}
}

/**
 * writes a given byte to a given register of HP303B via SPI
 *
 * regAdress: 	Address of the register that has to be updated
 * data:		Byte that will be written to the register
 * check: 		If this is true, register content will be read after writing
 * 				to check if update was successful
 * return:		0 if byte was written successfully
 * 				or -1 on fail
 */
int16_t LOLIN_HP303B::writeByteSpi(uint8_t regAddress, uint8_t data, uint8_t check)
{
	//this function is only made for communication via SPI
	if(m_SpiI2c != 0)
	{
		return HP303B__FAIL_UNKNOWN;
	}
	//mask regAddress
	regAddress &= ~HP303B__SPI_RW_MASK;
	//reserve and initialize bus
	m_spibus->beginTransaction(SPISettings(HP303B__SPI_MAX_FREQ,
											MSBFIRST,
											SPI_MODE3));
	//enable ChipSelect for HP303B
	digitalWrite(m_chipSelect, LOW);
	//send address with read command to HP303B
	m_spibus->transfer(regAddress | HP303B__SPI_WRITE_CMD);

	//write register content from HP303B
	m_spibus->transfer(data);

	//disable ChipSelect for HP303B
	digitalWrite(m_chipSelect, HIGH);
	//close current SPI transaction
	m_spibus->endTransaction();

	//check if necessary
	if(check == 0)
	{
		//no checking necessary
		return HP303B__SUCCEEDED;
	}
	//checking necessary
	if(readByte(regAddress) == data)
	{
		//check passed
		return HP303B__SUCCEEDED;
	}
	else
	{
		//check failed
		return HP303B__FAIL_UNKNOWN;
	}
}

/**
 * updates some given bits of a given register of HP303B without checking
 *
 * regAdress: 	Address of the register that has to be updated
 * data:		BitValues that will be written to the register
 * shift:		Amount of bits the data byte is shifted (left) before being masked
 * mask: 		Masks the bits of the register that have to be updated
 * 				Bits with value 1 are updated
 * 				Bits with value 0 are not changed
 * return:		0 if byte was written successfully
 * 				or -1 on fail
 */
int16_t LOLIN_HP303B::writeByteBitfield(uint8_t data,
										uint8_t regAddress,
										uint8_t mask,
										uint8_t shift)
{
	return writeByteBitfield(data, regAddress, mask, shift, 0U);
}

/**
 * updates some given bits of a given register of HP303B
 *
 * regAdress: 	Address of the register that has to be updated
 * data:		BitValues that will be written to the register
 * shift:		Amount of bits the data byte is shifted (left) before being masked
 * mask: 		Masks the bits of the register that have to be updated
 * 				Bits with value 1 are updated
 * 				Bits with value 0 are not changed
 * check: 		enables/disables check after writing
 * 				0 disables check
 * 				if check fails, -1 will be returned
 * return:		0 if byte was written successfully
 * 				or -1 on fail
 */
int16_t LOLIN_HP303B::writeByteBitfield(uint8_t data,
										uint8_t regAddress,
										uint8_t mask,
										uint8_t shift,
										uint8_t check)
{
	int16_t old = readByte(regAddress);
	if(old < 0)
	{
		//fail while reading
		return old;
	}
	return writeByte(regAddress, ((uint8_t)old & ~mask)|((data << shift) & mask), check);
}

/**
 * reads some given bits of a given register of HP303B
 *
 * regAdress: 	Address of the register that has to be updated
 * mask: 		Masks the bits of the register that have to be updated
 * 				Bits masked with value 1 are read
 * 				Bits masked with value 0 are set 0
 * shift:		Amount of bits the data byte is shifted (right) after being masked
 * return:		read and processed bits
 * 				or -1 on fail
 */
int16_t LOLIN_HP303B::readByteBitfield(uint8_t regAddress, uint8_t mask, uint8_t shift)
{
	int16_t ret = readByte(regAddress);
	if(ret<0)
	{
		return ret;
	}
	return (((uint8_t)ret) & mask) >> shift;
}
