/**
 * @file HTPA_32x32d.c
 * @brief Library for HTPA 32x32d infrared array sensor
 * @author Tim-Erik Düntzsch t.duentzsch@fasttube.de
 * 
 * @date 25.03.2023 - first implementation (untested)
 * 
 * @todo finish HTPA_ReadBlock function
 * @todo add calibration function
 * @todo add temperature conversion function
 * 
 * @test communication and readout
 * 
 * @version 0.1
 */

#include <stdbool.h>
#include "main.h"
#include "HTPA_32x32d.h"

// I2C address
#define HTPA_SENSOR_ADDRESS		0x1A
#define HTPA_EEPROM_ADDRESS		0x50

// Sensor configuration registers (write only)
#define HTPA_SENSOR_CONFIG		0x01	// Configuration register
#define HTPA_SENSOR_TRIM_1		0x03	// Amplification and ADC resolution
#define HTPA_SENSOR_TRIM_2		0x04	// Bias current of Top ADC
#define HTPA_SENSOR_TRIM_3		0x05	// Bias current of Bot ADC
#define HTPA_SENSOR_TRIM_4		0x06	// Clock frequency
#define HTPA_SENSOR_TRIM_5		0x07	// Common mode voltage preamplifier top
#define HTPA_SENSOR_TRIM_6		0x08	// Common mode voltage preamplifier bot
#define HTPA_SENSOR_TRIM_7		0x09	// Interal pull-ups SDA, SCL
// Sensor read only registers
#define HTPA_SENSOR_STATUS		0x02	// Status register
#define HTPA_SENSOR_READTOP		0x0A	// Read top half
#define HTPA_SENSOR_READBOT		0x0B	// Read bot half
// I2C transmit delay
#define I2C_MAX_DELAY			0xFFFFFFFF

I2C_HandleTypeDef i2c_handle;
HAL_StatusTypeDef i2c_return;	// error handling maybe?

uint16_t blockData[128];

/**
 * @brief Initialization of HTPA Sensor
 * 
 * Sets the wakeup bit in the status register and writes the desired sensor
 * configuration to the respective registers.
 * Afterwards the sensor is in idle and ready for conversion.
 * 
 * @param *hi2c: Pointer to I2C Handle
*/
void HTPA_Init(I2C_HandleTypeDef *hi2c){
	i2c_handle = *hi2c;
	// Berechnung für clk / sample aus I2C parametern?
	HTPA_WriteRegister(HTPA_SENSOR_CONFIG, 0x01);	// wakeup
	HTPA_WriteRegister(HTPA_SENSOR_TRIM_1, 0x0C);
	HTPA_WriteRegister(HTPA_SENSOR_TRIM_2, 0x0C);
	HTPA_WriteRegister(HTPA_SENSOR_TRIM_3, 0x0C);
	HTPA_WriteRegister(HTPA_SENSOR_TRIM_4, 0x14);
	HTPA_WriteRegister(HTPA_SENSOR_TRIM_5, 0x0C);
	HTPA_WriteRegister(HTPA_SENSOR_TRIM_6, 0x0C);
	HTPA_WriteRegister(HTPA_SENSOR_TRIM_7, 0x88);
	HTPA_WriteRegister(HTPA_SENSOR_CONFIG, 0x09);	// start sensor
}

/**
 * @brief Read data of one block in one array half
 * 
 * Block selection gets written to the config register and conversion is started.
 * After selected block of upper and lower half are converted, the selected half
 * is read and the data stored in the passed array.
 * 
 * @param array_half: 	select top or bottom half of array
 * @param block:		select block of array half (0-3)
 * @param *pData[128]:	pointer to 128 word array for read data
*/
void HTPA_ReadBlock(uint8_t array_half, uint8_t block, uint16_t *pData[128]){
	uint8_t config = 0;
	config = (block << 4);	// bit 5,4 block
	config |= 0x09;					// bit 3 start | bit 1 wakeup
	HTPA_WriteRegister(HTPA_SENSOR_CONFIG, config);
	// tbc
}

/**
 * @brief Write to selected sensor register
 * 
 * description
 * 
 * @param register_address: 	address of register
 * @param byte:					byte to be written to register
*/
void HTPA_WriteRegister(uint8_t register_address, uint8_t byte){
	uint8_t i2c_data = register_address;
	uint8_t i2c_address = (HTPA_SENSOR_ADDRESS << 1);
	i2c_address &= 0xFE;	// set read/write bit to write (0)
	HAL_I2C_Master_Transmit(&i2c_handle, i2c_address, &i2c_data, 1, I2C_MAX_DELAY);
	i2c_data = byte;
	HAL_I2C_Master_Transmit(&i2c_handle, i2c_address, &i2c_data, 1, I2C_MAX_DELAY);
}

/**
 * @brief Get status of sensor
 * 
 * Reads the sensors status register and stores the information in
 * the HTPA_Statsu structure.
 * 
 * @return HTPA_Status:		status register struct
*/
HTPA_Status HTPA_GetStatus(void){
	HAL_StatusTypeDef i2c_status;
	HTPA_Status status_return;
	uint8_t i2c_data = HTPA_SENSOR_STATUS;
	uint8_t i2c_address = (HTPA_SENSOR_ADDRESS << 1);
	uint8_t i2c_readData = 0;
	i2c_address &= 0xFE;	// set read/write bit 0 to write (0)
	HAL_I2C_Master_Transmit(&i2c_handle, i2c_address, &i2c_data, 1, I2C_MAX_DELAY);
	i2c_address |= 0x01;	// set read/write bit 0 to read (1)
	i2c_status = HAL_I2C_Master_Receive(&i2c_handle, i2c_address, &i2c_readData, 1, I2C_MAX_DELAY);
	status_return.block = (i2c_readData >> 4) && 0xFC;
	status_return.vdd_meas = (i2c_readData >> 2) && 0xFE;
	status_return.blind = (i2c_readData >> 1) && 0xFE;
	status_return.eoc = i2c_readData && 0xFE;
	return status_return;
}
