/*
 * PSE_unit.c
 *
 *  Created on: Aug 9, 2023
 *      Author: leo
 */

#include "pse_stepper_planer.h"
#define _GNU_SOURCE

#include "PSE_unit.h"

#include "fatfs.h"
#include "lvgl.h"

#include <stdio.h>
#include <stdlib.h>

static void generate_default_units(pse_unit* units, pse_syringe* syringes, pse_stepper_conf* stepper_confs,pse_stepper_status* stepper_status, pse_home_display* home_displays, uint8_t unit_num){
	for(int i = 0; i < unit_num; i++){
		units[i] = (pse_unit){
	      .enabled = i%2,
	      .port = i,
	      .flow = 1500*(i+1),
	      .volume = 0,
	      .set_volume = 0,
	      .syringe = &syringes[i],
			  .stepper_conf = &stepper_confs[i],
				.stepper_status = &stepper_status[i],
			  .home_display = &home_displays[i],
	    };
	    syringes[i] = (pse_syringe){
	    	.name = "Test",
	    	.diameter = 26700,
	    };
	  }
}


// Load units from file
// Units configuration are saved as binary, in the order [pse_unit, pse_syringe, pse_stepper_conf] with each unit back to back
// In case of any error fallback to a default configuration
void load_units(pse_unit* units, pse_syringe* syringes, pse_stepper_conf* stepper_confs, pse_stepper_status* stepper_status, pse_home_display* home_displays, uint8_t unit_num, uint16_t ws_ind){
	// Open save file
	FIL saveFile;

	char filename[16];
	if(snprintf(filename, 16, "PSEsave%d", ws_ind) == -1){
		lv_obj_t * mbox1 = lv_msgbox_create(NULL, "Error", "Could not load configuration from SD card (filename gen error)", NULL, true);
		lv_obj_center(mbox1);
		return;
	}

	if(f_open(&saveFile, filename, FA_READ) != FR_OK){
		lv_obj_t * mbox1 = lv_msgbox_create(NULL, "Error", "Could not load configuration from SD card", NULL, true);
		lv_obj_center(mbox1);
		generate_default_units(units, syringes, stepper_confs, stepper_status, home_displays, unit_num);
		return;
	}

	// read configuration sequentially
	for(int i = 0; i < unit_num; i++){
		FRESULT res;
		UINT bytesRead;
		res = f_read(&saveFile, &units[i], sizeof(units[i]), &bytesRead);
		units[i].syringe = &syringes[i];
		units[i].stepper_conf = &stepper_confs[i];
		units[i].home_display = &home_displays[i];
		units[i].stepper_status = &stepper_status[i];

		res += f_read(&saveFile, units[i].syringe, sizeof(pse_syringe), &bytesRead);
		res += f_read(&saveFile, units[i].stepper_status, sizeof(pse_stepper_status), &bytesRead);

		if(res != FR_OK){
			generate_default_units(units, syringes, stepper_confs, stepper_status, home_displays, unit_num);
			return;
		}
	}

	f_close(&saveFile);

  // compute prescalers/period for each units
  for(int i = 0; i < unit_num; i++){
    pse_unit* c_pse_unit = &units[i];
		// update stepper pwm generation
		pse_stepper_planer_compute_sps(c_pse_unit);

		// compute volume delivered per steps
		pse_unit_compute_volume_per_step(c_pse_unit);

		// set limit if volume defined
		if(c_pse_unit->set_volume != 0){
			if(c_pse_unit->pL_per_step == 0) break; // TODO: alert popup / better resolution
			if(c_pse_unit->flow == 0) break;
			c_pse_unit->stepper_status->stop_at_limit = 1;
			c_pse_unit->stepper_status->stop_steps = (uint64_t)1000000 * c_pse_unit->set_volume / c_pse_unit->pL_per_step;
		}
		else
			c_pse_unit->stepper_status->stop_at_limit = 0;
  }
  
}

void load_units_short(pse_unit* units, uint8_t unit_num, uint16_t ws_ind){
	load_units(units, units->syringe, units->stepper_conf, units->stepper_status , units->home_display, unit_num, ws_ind);
}

void save_units(pse_unit* units, uint8_t unit_num, uint16_t ws_ind){
	// Open save file
	FIL saveFile;

	char filename[16];
	if(snprintf(filename, 16, "PSEsave%u", ws_ind) == -1){
		lv_obj_t * mbox1 = lv_msgbox_create(NULL, "Error", "Could not save configuration to SD card (filename gen error)", NULL, true);
		lv_obj_center(mbox1);
		return;
	}

	FRESULT res;
	if((res = f_open(&saveFile, filename, FA_WRITE | FA_OPEN_ALWAYS)) != FR_OK){
		lv_obj_t * mbox1 = lv_msgbox_create(NULL, "Error", "aaa", NULL, true);
		lv_obj_t* text = lv_msgbox_get_text(mbox1);
		lv_label_set_text_fmt(text, "Could not save configuration to SD card (file open failed %d <%s>)", res, filename);
		lv_obj_center(mbox1);
		return;
	}

	for(int i = 0; i < unit_num; i++){
		FRESULT res;
		UINT bytesRead;
		res = f_write(&saveFile, &units[i], sizeof(units[i]), &bytesRead);
		res += f_write(&saveFile, units[i].syringe, sizeof(pse_syringe), &bytesRead);
		res += f_write(&saveFile, units[i].stepper_status, sizeof(pse_stepper_status), &bytesRead);

		if(res != FR_OK){
			return;
		}
	}

	f_close(&saveFile);
}

void pse_unit_compute_volume_delivered(pse_unit* unit){
	unit->volume = (int64_t)1 * (unit->stepper_status->steps_counter - unit->start_pos) * unit->pL_per_step / 1000000;
}

void pse_unit_compute_volume_per_step(pse_unit* unit){
	uint64_t numerator = (uint64_t)1000 * (unit->syringe->diameter * unit->syringe->diameter) * PSE_STEPPER_SCREW_PITCH;
	uint64_t denominator = (uint64_t)1273238 * PSE_STEPPER_STEPS_PER_ROTATION;
	unit->pL_per_step = numerator / denominator;
}
