static lv_obj_t *chart_ppg[2]; static void create_chart(void) { if(chart[0] == NULL) { //chart[0] & chart[1] are global variable obj_chart = lv_obj_create(obj_spo2_window); lv_obj_set_style_bg_opa(obj_chart, LV_PART_MAIN, LV_OPA_TRANSP); lv_obj_set_style_border_opa(obj_chart, LV_PART_MAIN, LV_OPA_TRANSP); lv_obj_set_style_border_width(obj_chart, 0, LV_PART_MAIN); lv_obj_align(obj_chart, LV_ALIGN_BOTTOM_MID, 0, 0); lv_obj_set_style_pad_all(obj_chart, 0, LV_PART_MAIN); lv_obj_set_style_pad_column(obj_chart, -5, LV_PART_MAIN); lv_obj_set_style_pad_row(obj_chart, 0, LV_PART_MAIN); lv_obj_clear_flag(obj_chart, LV_OBJ_FLAG_SCROLLABLE); chart[0] = lv_chart_create(obj_chart); lv_obj_add_style(chart[0], &style_obj_chart, LV_PART_MAIN); lv_chart_set_update_mode(chart[0], LV_CHART_UPDATE_MODE_CIRCULAR); lv_obj_align(chart[0], LV_ALIGN_TOP_MID, 0, 0); lv_chart_set_div_line_count(chart[0], 0, 0); lv_chart_set_point_count(chart[0], 342); lv_obj_set_style_bg_opa(chart[0], LV_OPA_TRANSP, LV_PART_MAIN); lv_obj_set_style_border_opa(chart[0], LV_OPA_TRANSP, LV_PART_MAIN); lv_obj_set_style_pad_all(chart[0], LV_PART_MAIN, 0); lv_obj_set_style_bg_opa(chart[0], LV_OPA_100, LV_PART_ITEMS); lv_obj_set_style_line_width(chart[0], 2, LV_PART_INDICATOR); lv_obj_set_style_size(chart[0], 0, LV_PART_INDICATOR); /*radius of points*/ series_chart[0] = lv_chart_add_series(chart[0], lv_palette_main(LV_PALETTE_CYAN), LV_CHART_AXIS_PRIMARY_Y); lv_chart_set_range(chart[0], LV_CHART_AXIS_PRIMARY_Y, 0, 255); lv_chart_set_all_value(chart[0], series_chart[0], 0); chart[1] = lv_chart_create(obj_chart); lv_obj_add_style(chart[1], &style_obj_chart, LV_PART_MAIN); lv_chart_set_update_mode(chart[1], LV_CHART_UPDATE_MODE_CIRCULAR); lv_obj_align(chart[1], LV_ALIGN_TOP_MID, 0, 0); lv_chart_set_div_line_count(chart[1], 0, 0); lv_chart_set_point_count(chart[1], 342); series_chart[1] = lv_chart_add_series(chart[1], lv_palette_main(LV_PALETTE_CYAN), LV_CHART_AXIS_SECONDARY_Y); lv_chart_set_range(chart[1], LV_CHART_AXIS_SECONDARY_Y, 0, 255); lv_chart_set_all_value(chart[1], series_chart[1], 0); lv_obj_set_style_bg_opa(chart[1], LV_OPA_TRANSP, LV_PART_MAIN | LV_STATE_DEFAULT); lv_obj_set_style_pad_all(chart[1], LV_PART_MAIN, 0); lv_obj_set_style_bg_opa(chart[1], LV_OPA_100, LV_PART_ITEMS); lv_obj_set_style_line_width(chart[1], 2, LV_PART_INDICATOR); lv_obj_set_style_size(chart[1], 0, LV_PART_INDICATOR);/*radius of points*/ lv_obj_set_style_border_opa(chart[1], LV_OPA_TRANSP, LV_PART_MAIN); lv_obj_set_flex_flow(obj_chart, LV_FLEX_FLOW_COLUMN); lv_obj_set_flex_align(obj_chart, LV_FLEX_ALIGN_START, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER); lv_obj_add_flag(chart[0], LV_OBJ_FLAG_EVENT_BUBBLE); lv_obj_add_flag(chart[1], LV_OBJ_FLAG_EVENT_BUBBLE); lv_obj_add_flag(obj_chart, LV_OBJ_FLAG_EVENT_BUBBLE); bool fill = is_chart_filled(); // this is my function you can coment this part if(fill == true) { lv_obj_add_event_cb(chart[0], chart_draw_cb, LV_EVENT_DRAW_PART_BEGIN, NULL); lv_obj_add_event_cb(chart[1], chart_draw_cb, LV_EVENT_DRAW_PART_BEGIN, NULL); } else if(fill == false) { lv_obj_remove_event_cb(chart[0], chart_draw_cb); lv_obj_remove_event_cb(chart[1], chart_draw_cb); } lv_chart_refresh(chart[0]); lv_chart_refresh(chart[1]); } refresh_chart_graph(); } static void chart_draw_cb(lv_event_t *e) { lv_obj_t *obj = lv_event_get_target(e); /*Add the faded area before the lines are drawn*/ lv_obj_draw_part_dsc_t *dsc = lv_event_get_draw_part_dsc(e); if(dsc->part == LV_PART_ITEMS) { if(!dsc->p1 || !dsc->p2) return; /*Draw a rectangle that will be affected by the mask*/ lv_draw_rect_dsc_t draw_rect_dsc; lv_draw_rect_dsc_init(&draw_rect_dsc); draw_rect_dsc.bg_opa = LV_OPA_100; draw_rect_dsc.bg_color = dsc->line_dsc->color; lv_area_t a; a.x1 = dsc->p1->x; a.x2 = dsc->p2->x - 1; a.y1 = LV_MIN(dsc->p1->y, dsc->p2->y); a.y2 = obj->coords.y2; lv_draw_rect(dsc->draw_ctx, &draw_rect_dsc, &a); } } /** in the project sometimes, we want to hide the de active chart this function recognizes the active chart and also this function set the chart to the new value */ static void refresh_chart_data(void) { uint8_t new_chart_data = 0; static uint16_t chart_x = 0; static bool toggle_menu_window_state = false; /*We should dequeue the queue_chart until it gets empty, even if we shouldn't display its data.*/ while(xQueueReceive(queue_chart, &new_chart_data, 0U)) { if(NULL == obj_menu_window) { //when obj_menu_window is created the de active chart is hidden if(true == toggle_menu_window_state) { //this part is for recognizing if there was switching between the //state with two charts to the state with one chart(another chart is hidden) or vice versa /* make series[1]->y_points[0] = series[0]->y_points[341], to not have visual discontinuity. */ lv_chart_set_value_by_id(chart[1], series_chart[1], 0, series_chart[0]->y_points[342 - 1]); chart_x = chart_x % 342; toggle_menu_window_state = false; } if(chart_x < 342) { //set chat[0] to new value lv_chart_set_value_by_id(chart[0], series_chart[0], chart_x, new_chart_data); } else if(chart_x == 342) { /* repeat the last data of chart[0] in first data of chart[1] to not have visual discontinuity. */ lv_chart_set_value_by_id(chart[1], series_chart[1], chart_x % 342, series_chart[0]->y_points[342 - 1]); chart_x++; lv_chart_set_value_by_id(chart[1], series_chart[1], chart_x % 342, new_chart_data); } else if(chart_x > 342) {//set chat[1] to new value lv_chart_set_value_by_id(chart[1], series_chart[1], chart_x % 342, new_chart_data); } } else if(NULL != obj_menu_window) { if(false == toggle_menu_window_state) { //this part is for recognizing if there was switching between the //state with two charts to the state with one chart(another chart is hidden) or vice versa toggle_menu_window_state = true; if(chart_x >= 342) { lv_obj_t *obj = chart[0]; lv_chart_series_t *ser = series_chart[0]; chart[0] = chart[1]; series_chart[0] = series_chart[1]; chart[1] = obj; series_chart[1] = ser; lv_obj_swap(chart[1], chart[0]); } lv_obj_add_flag(chart[1], LV_OBJ_FLAG_HIDDEN); lv_chart_set_all_value(chart[1], series_chart[1], 0); } lv_chart_set_value_by_id(chart[0], series_chart[0], chart_x % 342, new_chart_data); } chart_x++; if(chart_x >= 2 * 342) { chart_x = 0; } } } static void refresh_chart_size(void) { if(chart[0] == NULL) { create_chart(); } if(HOR_ORIENTATION == display_rotation) { if(NULL == obj_menu_window) { lv_obj_clear_flag(chart[1], LV_OBJ_FLAG_HIDDEN); lv_obj_set_size(chart[0], 348, 110); lv_obj_set_size(chart[1], 348, 110); lv_obj_set_size(obj_chart, 2 * 348 - 4, 115); lv_obj_set_flex_flow(obj_chart, LV_FLEX_FLOW_ROW); } else if(NULL != obj_menu_window) { lv_obj_set_size(chart[0], 348, 110); lv_obj_set_size(chart[1], 348, 110); lv_obj_set_size(obj_chart, 348, 115); } } else if(VER_ORIENTATION == display_rotation) { if(NULL == obj_menu_window) { lv_obj_clear_flag(chart[1], LV_OBJ_FLAG_HIDDEN); lv_obj_set_size(chart[0], 348, 215); lv_obj_set_size(chart[1], 348, 215); lv_obj_set_size(obj_chart, 348, 438); lv_obj_set_flex_flow(obj_chart, LV_FLEX_FLOW_COLUMN); } else if(NULL != obj_menu_window) { lv_obj_set_size(chart[0], 348, 135); lv_obj_set_size(chart[1], 348, 135); lv_obj_set_size(obj_chart, 348, 150); } } }