/main/battery.c
#include <stdbool.h>
#include "freertos/FreeRTOS.h"
#include "freertos/semphr.h"
#include "esp_adc_cal.h"
#include "esp_log.h"

#include "battery.h"
#include "gfx.h"
#include "io.h"

#define BATT_ADC_COUNTS 64

battery_info_t batt_info;
SemaphoreHandle_t battery_access_mutex;

void battery_task(void* pvParameters) {
	const char TAG[] = "battery_task";
	esp_adc_cal_characteristics_t chars;
	esp_adc_cal_value_t cal = esp_adc_cal_characterize(ADC_UNIT_2, ADC_ATTEN_DB_11, ADC_WIDTH_BIT_12, 2450, &chars);

	switch (cal) {
	case ESP_ADC_CAL_VAL_EFUSE_VREF:
		ESP_LOGI(TAG, "ADC calibrated with eFuse Vref");
		break;
	case ESP_ADC_CAL_VAL_EFUSE_TP:
		ESP_LOGI(TAG, "ADC calibrated with two point value");
		break;
	case ESP_ADC_CAL_VAL_DEFAULT_VREF:
		ESP_LOGI(TAG, "ADC calibrated with default Vref");
		break;
	default:
		ESP_LOGI(TAG, "ADC calibrated with unknown method %d", cal);
	}

	while (1) {
		io_batt_enable(true);

		int total = 0;
		int counts = 0;
		for (int i = 0; i < BATT_ADC_COUNTS; i++) {
			int v;
			esp_err_t ret = adc2_get_raw(ADC2_CHANNEL_5, ADC_WIDTH_BIT_12, &v);
			if (ret != ESP_OK) {
				continue;
			}
			total += v;
			counts++;
		}
		int raw_value = total / counts;
		int adc_mV = esp_adc_cal_raw_to_voltage(raw_value, &chars);
		int batt_mV = (adc_mV * 1657) / 1000 + 294;
		int percentage = ((batt_mV - 3000) * 100) / 1150;
		bool charging = io_charging();

		xSemaphoreTake(battery_access_mutex, portMAX_DELAY);
		batt_info.mV = batt_mV;
		batt_info.percentage = percentage;
		batt_info.charging = charging;
		xSemaphoreGive(battery_access_mutex);

		gfx_data_t* gd = gfx_acquire_data(SCENE_NO_CHANGE);
		gd->battery.mV = batt_mV;
		gd->battery.percentage = percentage;
		gd->battery.charging = charging;
		gfx_release_data();

		ESP_LOGI(TAG, "%dmV [raw %d adc %dmV] %d%% %s", batt_mV, raw_value, adc_mV, percentage, charging ? "charging" : "not charging");

		io_batt_enable(false);

		vTaskDelay(10000 / portTICK_PERIOD_MS);
	}
}

int battery_init() {
	battery_access_mutex = xSemaphoreCreateMutex();
	//xSemaphoreGive(battery_access_mutex);
	xTaskCreate(battery_task, "batt", 4096, NULL, 1, NULL);

	return 1;
}

battery_info_t battery_get_state() {
	xSemaphoreTake(battery_access_mutex, portMAX_DELAY);
	battery_info_t batt_info_copy = batt_info;
	xSemaphoreGive(battery_access_mutex);
	return batt_info_copy;
}