/*
 * TMP144.c
 *
 *  Created on: 23 Mar 2022
 *      Author: Jasper
 */

#include "TMP144.h"

#include "string.h"

static const uint8_t TMP144_SEQ_RESET[] = {0x55, 0xB4};
static const uint8_t TMP144_SEQ_ADDR[] = {0x55, 0x8C, 0x90};
static const uint8_t TMP144_SEQ_READ_TEMPS[] = {0x55, 0xF1};

volatile uint16_t temperatures[N_CELLS];

static volatile TMP144Bus bus_busbar;
static volatile TMP144Bus bus_other;

#define CHECK_STATUS(s) {HAL_StatusTypeDef _s = s; if (_s != HAL_OK) return _s;}

HAL_StatusTypeDef tmp144_init(UART_HandleTypeDef* busbar_side, UART_HandleTypeDef* other_side) {
	bus_busbar.handle = busbar_side;
	bus_other.handle = other_side;

	bus_busbar.state = TMP144_IDLE;
	bus_other.state = TMP144_IDLE;

	// TODO: Configure this in EEPROM
	bus_busbar.n_sensors = 11;
	bus_busbar.sensor_mappings[0] = 8;
	bus_busbar.sensor_mappings[1] = 8;
	bus_busbar.sensor_mappings[2] = 8;
	bus_busbar.sensor_mappings[3] = 6;
	bus_busbar.sensor_mappings[4] = 6;
	bus_busbar.sensor_mappings[5] = 4;
	bus_busbar.sensor_mappings[6] = 4;
	bus_busbar.sensor_mappings[7] = 4;
	bus_busbar.sensor_mappings[8] = 2;
	bus_busbar.sensor_mappings[9] = 2;
	bus_busbar.sensor_mappings[10] = 2;
	bus_other.n_sensors = 13;
	bus_other.sensor_mappings[0] = 1;
	bus_other.sensor_mappings[1] = 1;
	bus_other.sensor_mappings[2] = 1;
	bus_other.sensor_mappings[3] = 3;
	bus_other.sensor_mappings[4] = 3;
	bus_other.sensor_mappings[5] = 5;
	bus_other.sensor_mappings[6] = 5;
	bus_other.sensor_mappings[7] = 5;
	bus_other.sensor_mappings[8] = 5;
	bus_other.sensor_mappings[9] = 7;
	bus_other.sensor_mappings[10] = 7;
	bus_other.sensor_mappings[11] = 9;
	bus_other.sensor_mappings[12] = 9;

	CHECK_STATUS(tmp144_init_reset(&bus_busbar));
	CHECK_STATUS(tmp144_init_reset(&bus_other));

	return HAL_OK;
}

HAL_StatusTypeDef tmp144_init_reset(TMP144Bus* bus) {
	if (bus->state != TMP144_IDLE) {
		return HAL_ERROR;
	}

	bus->state = TMP144_RESETTING;
	CHECK_STATUS(HAL_UART_Receive_IT(bus->handle, bus->rxbuf, 2));
	// Keep sending Global Software Reset until it echoes back (as per 7.5.2)
	int tries = 0;
	do {
		if (tries > 10) {
			return HAL_TIMEOUT;
		}
		CHECK_STATUS(HAL_UART_Transmit(bus->handle, TMP144_SEQ_RESET, sizeof(TMP144_SEQ_RESET), 100));
		HAL_Delay(100);
		tries++;
	} while (bus->state == TMP144_RESETTING);

	bus->state = TMP144_INITIALIZING;
	CHECK_STATUS(HAL_UART_Receive_IT(bus->handle, bus->rxbuf, 3));
	CHECK_STATUS(HAL_UART_Transmit(bus->handle, TMP144_SEQ_ADDR, sizeof(TMP144_SEQ_ADDR), 100));

	return HAL_OK;
}


HAL_StatusTypeDef tmp144_init_post_reset(TMP144Bus* bus) {
	if (bus->state != TMP144_RESETTING || memcmp(bus->rxbuf, TMP144_SEQ_RESET, sizeof(TMP144_SEQ_RESET)) != 0) {
		return HAL_ERROR;
	}

	bus->state = TMP144_IDLE;

	return HAL_OK;
}

HAL_StatusTypeDef tmp144_init_post_addr(TMP144Bus* bus) {
	size_t idx_response = sizeof(TMP144_SEQ_ADDR) - 1;
	if (bus->state != TMP144_INITIALIZING || memcmp(bus->rxbuf, TMP144_SEQ_ADDR, idx_response) != 0) {
		return HAL_ERROR;
	}

	uint8_t n_sensors = bus->rxbuf[idx_response] - TMP144_SEQ_ADDR[idx_response];
	if (n_sensors != bus->n_sensors) {
		return HAL_ERROR;
	}
	bus->state = TMP144_IDLE;

	return HAL_OK;
}

HAL_StatusTypeDef tmp144_read_temps() {
	CHECK_STATUS(tmp144_send_read_temps(&bus_busbar));
	CHECK_STATUS(tmp144_send_read_temps(&bus_other));

	return HAL_OK;
}

HAL_StatusTypeDef tmp144_send_read_temps(TMP144Bus* bus) {
	if (bus->state != TMP144_IDLE) {
		return HAL_ERROR;
	}

	bus->state = TMP144_READING_TEMP;
//	HAL_UART_Receive_IT(bus->handle, bus->rxbuf, sizeof(TMP144_SEQ_READ_TEMPS) + 2 * bus->n_sensors);
	CHECK_STATUS(HAL_UART_Receive_IT(bus->handle, bus->rxbuf, sizeof(TMP144_SEQ_READ_TEMPS) + 2 * bus->n_sensors));
	CHECK_STATUS(HAL_UART_Transmit(bus->handle, TMP144_SEQ_READ_TEMPS, sizeof(TMP144_SEQ_READ_TEMPS), 100));

	return HAL_OK;
}

HAL_StatusTypeDef tmp144_recv_temps(TMP144Bus* bus) {
	if (bus->state != TMP144_READING_TEMP) {
		return HAL_ERROR;
	}

	bus->state = TMP144_IDLE;
	size_t headerlen = sizeof(TMP144_SEQ_READ_TEMPS);
	if (memcmp(bus->rxbuf, TMP144_SEQ_READ_TEMPS, headerlen) != 0) {
		return HAL_ERROR;
	}

	// Find max temperature for each cell
	uint8_t current_cell = bus->sensor_mappings[0];
	uint16_t max_temp = 0;
	for (size_t i = 0; i < bus->n_sensors; i++) {
		uint8_t cell = bus->sensor_mappings[i];
		if (cell != current_cell) {
			temperatures[current_cell] = max_temp;
			current_cell = cell;
			max_temp = 0;
		}

		size_t buf_offset = headerlen + 2 * i;
		uint16_t temp = (bus->rxbuf[buf_offset] >> 4) | (bus->rxbuf[buf_offset + 1] << 4);
		if (temp > max_temp) {
			max_temp = temp;
		}
	}
	temperatures[current_cell] = max_temp;

	return HAL_OK;
}

void HAL_UART_RxCpltCallback(UART_HandleTypeDef* handle) {
	TMP144Bus* bus;
	if (handle == bus_busbar.handle) {
		bus = &bus_busbar;
	} else if (handle == bus_other.handle) {
		bus = &bus_other;
	} else {
		// TODO
		Error_Handler();
	}

	switch (bus->state) {
	case TMP144_IDLE:
		// TODO
		Error_Handler();
	case TMP144_RESETTING:
		tmp144_init_post_reset(bus);
		break;
	case TMP144_INITIALIZING:
		tmp144_init_post_addr(bus);
		break;
	case TMP144_READING_TEMP:
		tmp144_recv_temps(bus);
		break;
	default:
		// TODO
		Error_Handler();
	}
}
