/* * 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 #include 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, .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; if(asprintf(&filename, "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); free(filename); 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); free(filename); return; } free(filename); // 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->nL_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)1000 * c_pse_unit->set_volume / c_pse_unit->nL_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; if(asprintf(&filename, "PSEsave%d", 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); free(filename); 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); free(filename); 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); free(filename); } void pse_unit_compute_volume_delivered(pse_unit* unit){ unit->volume = (int64_t)1 * (unit->stepper_status->steps_counter - unit->start_pos) * unit->nL_per_step / 1000; } void pse_unit_compute_volume_per_step(pse_unit* unit){ uint64_t numerator = (uint64_t)1 * (unit->syringe->diameter * unit->syringe->diameter) * PSE_STEPPER_SCREW_PITCH; uint64_t denominator = (uint64_t)1273238 * PSE_STEPPER_STEPS_PER_ROTATION; unit->nL_per_step = numerator / denominator; }