diff --git a/Core/Inc/PSE_unit.h b/Core/Inc/PSE_unit.h index 5e192b2..0d3d13e 100644 --- a/Core/Inc/PSE_unit.h +++ b/Core/Inc/PSE_unit.h @@ -43,5 +43,6 @@ typedef struct{ } pse_unit; void load_units(pse_unit* units, pse_syringe* syringes, pse_stepper_conf* stepper_confs, uint8_t unit_num); +void save_units(pse_unit* units, uint8_t unit_num); #endif diff --git a/Core/Inc/PSE_unit_edit_screen.h b/Core/Inc/PSE_unit_edit_screen.h index 93cc602..14027d7 100644 --- a/Core/Inc/PSE_unit_edit_screen.h +++ b/Core/Inc/PSE_unit_edit_screen.h @@ -10,6 +10,6 @@ #include "PSE_unit.h" -void PSE_unit_edit_screen_Gen(lv_obj_t* parent, pse_unit* unit); +void PSE_unit_edit_screen_Gen(lv_obj_t* parent, pse_unit* units, pse_unit* unit, uint8_t units_num); #endif /* INC_PSE_EDIT_SCREEN_H_ */ diff --git a/Core/Inc/pse_stepper_planer.h b/Core/Inc/pse_stepper_planer.h index ff022c9..1cf181a 100644 --- a/Core/Inc/pse_stepper_planer.h +++ b/Core/Inc/pse_stepper_planer.h @@ -12,7 +12,7 @@ #define PSE_STEPPER_INTERRUPT_RATE 20000 // 64Mhz (Presc 64, count 50) : 20kHz #define PSE_STEPPER_SCREW_PITCH 1000 // M6 : 1000µm / rotation -#define PSE_STEPPER_STEPS_PER_ROTATION 200 // NEMA17 without microstepping 200 steps/rotation +#define PSE_STEPPER_STEPS_PER_ROTATION 6400 // NEMA17 200 steps/rotation with 32x microstepping void pse_sp_start_axis(pse_stepper_conf* conf); void pse_sp_stop_axis(pse_stepper_conf* conf); diff --git a/Core/Src/PSE_unit.c b/Core/Src/PSE_unit.c index e0ff0c5..8fd4c54 100644 --- a/Core/Src/PSE_unit.c +++ b/Core/Src/PSE_unit.c @@ -7,21 +7,81 @@ #include "PSE_unit.h" -// TODO: load from SD-card -void load_units(pse_unit* units, pse_syringe* syringes, pse_stepper_conf* stepper_confs, 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], - }; - syringes[i] = (pse_syringe){ - .name = "Test", - .diameter = 26700, - }; - } +#include "fatfs.h" +#include "lvgl.h" + +static void generate_default_units(pse_unit* units, pse_syringe* syringes, pse_stepper_conf* stepper_confs, 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], + }; + 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, uint8_t unit_num){ + // Open save file + FIL saveFile; + if(f_open(&saveFile, "PSE_save.txt", FA_READ) != FR_OK){ + lv_obj_t * mbox1 = lv_msgbox_create(NULL, "Error", "Could not load configuration to SD card", NULL, true); + lv_obj_center(mbox1); + generate_default_units(units, syringes, stepper_confs, 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]; + + res += f_read(&saveFile, units[i].syringe, sizeof(pse_syringe), &bytesRead); + res += f_read(&saveFile, units[i].stepper_conf, sizeof(pse_stepper_conf), &bytesRead); + + if(res != FR_OK){ + generate_default_units(units, syringes, stepper_confs, unit_num); + return; + } + } + + f_close(&saveFile); +} + +void save_units(pse_unit* units, uint8_t unit_num){ + // Open save file + FIL saveFile; + if(f_open(&saveFile, "PSE_save.txt", FA_WRITE | FA_OPEN_ALWAYS) != FR_OK){ + lv_obj_t * mbox1 = lv_msgbox_create(NULL, "Error", "Could not save configuration to SD card", NULL, true); + 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_conf, sizeof(pse_stepper_conf), &bytesRead); + + if(res != FR_OK){ + return; + } + } + + f_close(&saveFile); } diff --git a/Core/Src/PSE_unit_edit_screen.c b/Core/Src/PSE_unit_edit_screen.c index b5131ce..4d87a27 100644 --- a/Core/Src/PSE_unit_edit_screen.c +++ b/Core/Src/PSE_unit_edit_screen.c @@ -19,13 +19,16 @@ static lv_obj_t* parent_screen; static lv_obj_t* this_screen; +static pse_unit* c_pse_units; static pse_unit* c_pse_unit; +static uint8_t c_pse_units_num; static void back_button_handler(lv_event_t * e){ lv_event_code_t code = lv_event_get_code(e); if(code == LV_EVENT_CLICKED) { - // Save + save_units(c_pse_units, c_pse_units_num); + // update stepper pwm generation pse_stepper_planer_compute_sps(c_pse_unit); @@ -191,13 +194,15 @@ static lv_obj_t* controls_widget(lv_obj_t* parent, pse_unit* unit){ return cont; } -void PSE_unit_edit_screen_Gen(lv_obj_t* parent, pse_unit* unit){ +void PSE_unit_edit_screen_Gen(lv_obj_t* parent, pse_unit* units, pse_unit* c_unit, uint8_t units_num){ parent_screen = parent; // Create a new screen lv_obj_t* scr = lv_obj_create(NULL); this_screen = scr; - c_pse_unit = unit; + c_pse_units = units; + c_pse_unit = c_unit; + c_pse_units_num = units_num; // create the top menu on the top 20% lv_obj_t* top_menu = lv_obj_create(scr); @@ -226,16 +231,16 @@ void PSE_unit_edit_screen_Gen(lv_obj_t* parent, pse_unit* unit){ lv_obj_set_grid_dsc_array(units_grid, widg_col_dsc, widg_row_dsc); // Flow widget - lv_obj_t* flow = flow_widget(units_grid, unit); + lv_obj_t* flow = flow_widget(units_grid, c_unit); lv_obj_set_grid_cell(flow, LV_GRID_ALIGN_CENTER, 0, 1, LV_GRID_ALIGN_CENTER, 0, 1); // Set volume widget - lv_obj_t* vol = volume_widget(units_grid, unit); + lv_obj_t* vol = volume_widget(units_grid, c_unit); lv_obj_set_grid_cell(vol, LV_GRID_ALIGN_CENTER, 1, 1, LV_GRID_ALIGN_CENTER, 0, 1); // Syringe widget - lv_obj_t* syringe = syringe_widget(units_grid, unit); + lv_obj_t* syringe = syringe_widget(units_grid, c_unit); lv_obj_set_grid_cell(syringe, LV_GRID_ALIGN_CENTER, 2, 1, LV_GRID_ALIGN_CENTER, 0, 1); // controls widget - lv_obj_t* controls = controls_widget(units_grid, unit); + lv_obj_t* controls = controls_widget(units_grid, c_unit); lv_obj_set_grid_cell(controls, LV_GRID_ALIGN_CENTER, 3, 1, LV_GRID_ALIGN_CENTER, 0, 1); // fade in the new screen diff --git a/Core/Src/home_screen.c b/Core/Src/home_screen.c index 712c710..23dd921 100644 --- a/Core/Src/home_screen.c +++ b/Core/Src/home_screen.c @@ -66,7 +66,7 @@ static void unit_widget_clicked_handler(lv_event_t* e){ if(code == LV_EVENT_CLICKED) { pse_unit* unit = lv_event_get_user_data(e); - PSE_unit_edit_screen_Gen(screen, unit); + PSE_unit_edit_screen_Gen(screen, units, unit, units_num); } } diff --git a/Core/Src/main.c b/Core/Src/main.c index 61c8a56..778149c 100644 --- a/Core/Src/main.c +++ b/Core/Src/main.c @@ -231,7 +231,7 @@ int main(void) disp_drv.flush_cb = &my_flush_cb; lv_disp_drv_register(&disp_drv); - lv_disp_t * disp = lv_disp_drv_register(&disp_drv); + lv_disp_drv_register(&disp_drv); // load the default theme lv_theme_t * th = lv_theme_default_init(lv_disp_get_default(), lv_color_hex(0x2BAEE1), lv_color_hex(0x001361), true, LV_FONT_DEFAULT); @@ -261,23 +261,19 @@ int main(void) // initialize the Touchscreen Driver ADS7843_Init(&Touch_Def); - load_units(pse_units, pse_syringes, pse_stepper_confs, PSE_UNITS_NUM); - pse_sp_set_timer(&htim4); - Home_Screen_Gen(pse_units, PSE_UNITS_NUM); - - // SD tests - char mynewdiskPath[4]; + // mount the SD card + char SD_disk_path[4]; FATFS FatFs; - uint8_t wtext[] = "Hello world"; - uint32_t wbytes; - FIL MyFile; + f_mount(&FatFs, SD_disk_path, 0); - HAL_Delay(1000); + // Load saved units + load_units(pse_units, pse_syringes, pse_stepper_confs, PSE_UNITS_NUM); - f_mount(&FatFs, mynewdiskPath, 0); - f_open(&MyFile, "STM32.TXT", FA_CREATE_ALWAYS | FA_WRITE); - f_write(&MyFile, wtext, sizeof(wtext), (void *)&wbytes); - f_close(&MyFile); + // Set timer used for step interrupts + pse_sp_set_timer(&htim4); + + // Load the home screen + Home_Screen_Gen(pse_units, PSE_UNITS_NUM); /* USER CODE END 2 */ /* Infinite loop */