WS: Show received signal age (#2087)
* Feat: Show received signal age: by @LY2NEO with some fixes from me * WS: Signal age display GUI fixes and improvements * WeatherStation: refactor variable names * WS: GUI fixes and improvements: add icons by @Karator and apply UI changes * Weather Station: proper event flow for view redraw. Co-authored-by: あく <alleteam@gmail.com>
This commit is contained in:
		
							parent
							
								
									9d728a1c65
								
							
						
					
					
						commit
						01e24f6837
					
				
							
								
								
									
										
											BIN
										
									
								
								applications/plugins/weather_station/images/Humid_8x13.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								applications/plugins/weather_station/images/Humid_8x13.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 3.5 KiB | 
							
								
								
									
										
											BIN
										
									
								
								applications/plugins/weather_station/images/Timer_11x11.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								applications/plugins/weather_station/images/Timer_11x11.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 3.5 KiB | 
| @ -99,6 +99,17 @@ bool ws_block_generic_serialize( | ||||
|             break; | ||||
|         } | ||||
| 
 | ||||
|         //DATE AGE set
 | ||||
|         FuriHalRtcDateTime curr_dt; | ||||
|         furi_hal_rtc_get_datetime(&curr_dt); | ||||
|         uint32_t curr_ts = furi_hal_rtc_datetime_to_timestamp(&curr_dt); | ||||
| 
 | ||||
|         temp_data = curr_ts; | ||||
|         if(!flipper_format_write_uint32(flipper_format, "Ts", &temp_data, 1)) { | ||||
|             FURI_LOG_E(TAG, "Unable to add timestamp"); | ||||
|             break; | ||||
|         } | ||||
| 
 | ||||
|         temp_data = instance->channel; | ||||
|         if(!flipper_format_write_uint32(flipper_format, "Ch", &temp_data, 1)) { | ||||
|             FURI_LOG_E(TAG, "Unable to add Channel"); | ||||
| @ -168,6 +179,12 @@ bool ws_block_generic_deserialize(WSBlockGeneric* instance, FlipperFormat* flipp | ||||
|         } | ||||
|         instance->humidity = (uint8_t)temp_data; | ||||
| 
 | ||||
|         if(!flipper_format_read_uint32(flipper_format, "Ts", (uint32_t*)&temp_data, 1)) { | ||||
|             FURI_LOG_E(TAG, "Missing timestamp"); | ||||
|             break; | ||||
|         } | ||||
|         instance->timestamp = (uint32_t)temp_data; | ||||
| 
 | ||||
|         if(!flipper_format_read_uint32(flipper_format, "Ch", (uint32_t*)&temp_data, 1)) { | ||||
|             FURI_LOG_E(TAG, "Missing Channel"); | ||||
|             break; | ||||
|  | ||||
| @ -29,6 +29,7 @@ struct WSBlockGeneric { | ||||
|     uint8_t data_count_bit; | ||||
|     uint8_t battery_low; | ||||
|     uint8_t humidity; | ||||
|     uint32_t timestamp; | ||||
|     uint8_t channel; | ||||
|     uint8_t btn; | ||||
|     float temp; | ||||
|  | ||||
| @ -8,7 +8,7 @@ | ||||
| #include <m-array.h> | ||||
| 
 | ||||
| #define FRAME_HEIGHT 12 | ||||
| #define MAX_LEN_PX 100 | ||||
| #define MAX_LEN_PX 112 | ||||
| #define MENU_ITEMS 4u | ||||
| #define UNLOCK_CNT 3 | ||||
| 
 | ||||
| @ -189,7 +189,7 @@ void ws_view_receiver_draw(Canvas* canvas, WSReceiverModel* model) { | ||||
|             canvas_set_color(canvas, ColorBlack); | ||||
|         } | ||||
|         canvas_draw_icon(canvas, 4, 2 + i * FRAME_HEIGHT, ReceiverItemIcons[item_menu->type]); | ||||
|         canvas_draw_str(canvas, 15, 9 + i * FRAME_HEIGHT, furi_string_get_cstr(str_buff)); | ||||
|         canvas_draw_str(canvas, 14, 9 + i * FRAME_HEIGHT, furi_string_get_cstr(str_buff)); | ||||
|         furi_string_reset(str_buff); | ||||
|     } | ||||
|     if(scrollbar) { | ||||
|  | ||||
| @ -9,9 +9,11 @@ | ||||
| 
 | ||||
| struct WSReceiverInfo { | ||||
|     View* view; | ||||
|     FuriTimer* timer; | ||||
| }; | ||||
| 
 | ||||
| typedef struct { | ||||
|     uint32_t curr_ts; | ||||
|     FuriString* protocol_name; | ||||
|     WSBlockGeneric* generic; | ||||
| } WSReceiverInfoModel; | ||||
| @ -28,6 +30,10 @@ void ws_view_receiver_info_update(WSReceiverInfo* ws_receiver_info, FlipperForma | ||||
|             flipper_format_read_string(fff, "Protocol", model->protocol_name); | ||||
| 
 | ||||
|             ws_block_generic_deserialize(model->generic, fff); | ||||
| 
 | ||||
|             FuriHalRtcDateTime curr_dt; | ||||
|             furi_hal_rtc_get_datetime(&curr_dt); | ||||
|             model->curr_ts = furi_hal_rtc_datetime_to_timestamp(&curr_dt); | ||||
|         }, | ||||
|         true); | ||||
| } | ||||
| @ -44,46 +50,76 @@ void ws_view_receiver_info_draw(Canvas* canvas, WSReceiverInfoModel* model) { | ||||
|         "%s %db", | ||||
|         furi_string_get_cstr(model->protocol_name), | ||||
|         model->generic->data_count_bit); | ||||
|     canvas_draw_str(canvas, 5, 8, buffer); | ||||
|     canvas_draw_str(canvas, 0, 8, buffer); | ||||
| 
 | ||||
|     if(model->generic->channel != WS_NO_CHANNEL) { | ||||
|         snprintf(buffer, sizeof(buffer), "Ch: %01d", model->generic->channel); | ||||
|         canvas_draw_str(canvas, 105, 8, buffer); | ||||
|         canvas_draw_str(canvas, 106, 8, buffer); | ||||
|     } | ||||
| 
 | ||||
|     if(model->generic->id != WS_NO_ID) { | ||||
|         snprintf(buffer, sizeof(buffer), "Sn: 0x%02lX", model->generic->id); | ||||
|         canvas_draw_str(canvas, 5, 20, buffer); | ||||
|         canvas_draw_str(canvas, 0, 20, buffer); | ||||
|     } | ||||
| 
 | ||||
|     if(model->generic->btn != WS_NO_BTN) { | ||||
|         snprintf(buffer, sizeof(buffer), "Btn: %01d", model->generic->btn); | ||||
|         canvas_draw_str(canvas, 62, 20, buffer); | ||||
|         canvas_draw_str(canvas, 57, 20, buffer); | ||||
|     } | ||||
| 
 | ||||
|     if(model->generic->battery_low != WS_NO_BATT) { | ||||
|         snprintf( | ||||
|             buffer, sizeof(buffer), "Batt: %s", (!model->generic->battery_low ? "ok" : "low")); | ||||
|         canvas_draw_str(canvas, 90, 20, buffer); | ||||
|         canvas_draw_str_aligned(canvas, 126, 17, AlignRight, AlignCenter, buffer); | ||||
|     } | ||||
| 
 | ||||
|     snprintf(buffer, sizeof(buffer), "Data: 0x%llX", model->generic->data); | ||||
|     canvas_draw_str(canvas, 5, 32, buffer); | ||||
|     canvas_draw_str(canvas, 0, 32, buffer); | ||||
| 
 | ||||
|     elements_bold_rounded_frame(canvas, 2, 37, 123, 25); | ||||
|     elements_bold_rounded_frame(canvas, 0, 38, 127, 25); | ||||
|     canvas_set_font(canvas, FontPrimary); | ||||
| 
 | ||||
|     if(model->generic->temp != WS_NO_TEMPERATURE) { | ||||
|         canvas_draw_icon(canvas, 18, 42, &I_Therm_7x16); | ||||
|         canvas_draw_icon(canvas, 6, 43, &I_Therm_7x16); | ||||
|         snprintf(buffer, sizeof(buffer), "%3.1f C", (double)model->generic->temp); | ||||
|         canvas_draw_str_aligned(canvas, 63, 46, AlignRight, AlignTop, buffer); | ||||
|         canvas_draw_circle(canvas, 55, 45, 1); | ||||
|         canvas_draw_str_aligned(canvas, 47, 47, AlignRight, AlignTop, buffer); | ||||
|         canvas_draw_circle(canvas, 38, 46, 1); | ||||
|     } | ||||
| 
 | ||||
|     if(model->generic->humidity != WS_NO_HUMIDITY) { | ||||
|         canvas_draw_icon(canvas, 75, 42, &I_Humid_10x15); | ||||
|         canvas_draw_icon(canvas, 53, 44, &I_Humid_8x13); | ||||
|         snprintf(buffer, sizeof(buffer), "%d%%", model->generic->humidity); | ||||
|         canvas_draw_str(canvas, 91, 54, buffer); | ||||
|         canvas_draw_str(canvas, 64, 55, buffer); | ||||
|     } | ||||
| 
 | ||||
|     if((int)model->generic->timestamp > 0 && model->curr_ts) { | ||||
|         int ts_diff = (int)model->curr_ts - (int)model->generic->timestamp; | ||||
| 
 | ||||
|         canvas_draw_icon(canvas, 91, 46, &I_Timer_11x11); | ||||
| 
 | ||||
|         if(ts_diff > 60) { | ||||
|             int tmp_sec = ts_diff; | ||||
|             int cnt_min = 1; | ||||
|             for(int i = 1; tmp_sec > 60; i++) { | ||||
|                 tmp_sec = tmp_sec - 60; | ||||
|                 cnt_min = i; | ||||
|             } | ||||
| 
 | ||||
|             if(model->curr_ts % 2 == 0) { | ||||
|                 canvas_draw_str_aligned(canvas, 105, 51, AlignLeft, AlignCenter, "Old"); | ||||
|             } else { | ||||
|                 if(cnt_min >= 59) { | ||||
|                     canvas_draw_str_aligned(canvas, 105, 51, AlignLeft, AlignCenter, "Old"); | ||||
|                 } else { | ||||
|                     snprintf(buffer, sizeof(buffer), "%dm", cnt_min); | ||||
|                     canvas_draw_str_aligned(canvas, 114, 51, AlignCenter, AlignCenter, buffer); | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|         } else { | ||||
|             snprintf(buffer, sizeof(buffer), "%d", ts_diff); | ||||
|             canvas_draw_str_aligned(canvas, 112, 51, AlignCenter, AlignCenter, buffer); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| @ -98,14 +134,19 @@ bool ws_view_receiver_info_input(InputEvent* event, void* context) { | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
| void ws_view_receiver_info_enter(void* context) { | ||||
|     furi_assert(context); | ||||
| } | ||||
| 
 | ||||
| void ws_view_receiver_info_exit(void* context) { | ||||
| static void ws_view_receiver_info_enter(void* context) { | ||||
|     furi_assert(context); | ||||
|     WSReceiverInfo* ws_receiver_info = context; | ||||
| 
 | ||||
|     furi_timer_start(ws_receiver_info->timer, 1000); | ||||
| } | ||||
| 
 | ||||
| static void ws_view_receiver_info_exit(void* context) { | ||||
|     furi_assert(context); | ||||
|     WSReceiverInfo* ws_receiver_info = context; | ||||
| 
 | ||||
|     furi_timer_stop(ws_receiver_info->timer); | ||||
| 
 | ||||
|     with_view_model( | ||||
|         ws_receiver_info->view, | ||||
|         WSReceiverInfoModel * model, | ||||
| @ -113,6 +154,20 @@ void ws_view_receiver_info_exit(void* context) { | ||||
|         false); | ||||
| } | ||||
| 
 | ||||
| static void ws_view_receiver_info_timer(void* context) { | ||||
|     WSReceiverInfo* ws_receiver_info = context; | ||||
|     // Force redraw
 | ||||
|     with_view_model( | ||||
|         ws_receiver_info->view, | ||||
|         WSReceiverInfoModel * model, | ||||
|         { | ||||
|             FuriHalRtcDateTime curr_dt; | ||||
|             furi_hal_rtc_get_datetime(&curr_dt); | ||||
|             model->curr_ts = furi_hal_rtc_datetime_to_timestamp(&curr_dt); | ||||
|         }, | ||||
|         true); | ||||
| } | ||||
| 
 | ||||
| WSReceiverInfo* ws_view_receiver_info_alloc() { | ||||
|     WSReceiverInfo* ws_receiver_info = malloc(sizeof(WSReceiverInfo)); | ||||
| 
 | ||||
| @ -135,12 +190,17 @@ WSReceiverInfo* ws_view_receiver_info_alloc() { | ||||
|         }, | ||||
|         true); | ||||
| 
 | ||||
|     ws_receiver_info->timer = | ||||
|         furi_timer_alloc(ws_view_receiver_info_timer, FuriTimerTypePeriodic, ws_receiver_info); | ||||
| 
 | ||||
|     return ws_receiver_info; | ||||
| } | ||||
| 
 | ||||
| void ws_view_receiver_info_free(WSReceiverInfo* ws_receiver_info) { | ||||
|     furi_assert(ws_receiver_info); | ||||
| 
 | ||||
|     furi_timer_free(ws_receiver_info->timer); | ||||
| 
 | ||||
|     with_view_model( | ||||
|         ws_receiver_info->view, | ||||
|         WSReceiverInfoModel * model, | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 MX
						MX