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; |             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; |         temp_data = instance->channel; | ||||||
|         if(!flipper_format_write_uint32(flipper_format, "Ch", &temp_data, 1)) { |         if(!flipper_format_write_uint32(flipper_format, "Ch", &temp_data, 1)) { | ||||||
|             FURI_LOG_E(TAG, "Unable to add Channel"); |             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; |         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)) { |         if(!flipper_format_read_uint32(flipper_format, "Ch", (uint32_t*)&temp_data, 1)) { | ||||||
|             FURI_LOG_E(TAG, "Missing Channel"); |             FURI_LOG_E(TAG, "Missing Channel"); | ||||||
|             break; |             break; | ||||||
|  | |||||||
| @ -29,6 +29,7 @@ struct WSBlockGeneric { | |||||||
|     uint8_t data_count_bit; |     uint8_t data_count_bit; | ||||||
|     uint8_t battery_low; |     uint8_t battery_low; | ||||||
|     uint8_t humidity; |     uint8_t humidity; | ||||||
|  |     uint32_t timestamp; | ||||||
|     uint8_t channel; |     uint8_t channel; | ||||||
|     uint8_t btn; |     uint8_t btn; | ||||||
|     float temp; |     float temp; | ||||||
|  | |||||||
| @ -8,7 +8,7 @@ | |||||||
| #include <m-array.h> | #include <m-array.h> | ||||||
| 
 | 
 | ||||||
| #define FRAME_HEIGHT 12 | #define FRAME_HEIGHT 12 | ||||||
| #define MAX_LEN_PX 100 | #define MAX_LEN_PX 112 | ||||||
| #define MENU_ITEMS 4u | #define MENU_ITEMS 4u | ||||||
| #define UNLOCK_CNT 3 | #define UNLOCK_CNT 3 | ||||||
| 
 | 
 | ||||||
| @ -189,7 +189,7 @@ void ws_view_receiver_draw(Canvas* canvas, WSReceiverModel* model) { | |||||||
|             canvas_set_color(canvas, ColorBlack); |             canvas_set_color(canvas, ColorBlack); | ||||||
|         } |         } | ||||||
|         canvas_draw_icon(canvas, 4, 2 + i * FRAME_HEIGHT, ReceiverItemIcons[item_menu->type]); |         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); |         furi_string_reset(str_buff); | ||||||
|     } |     } | ||||||
|     if(scrollbar) { |     if(scrollbar) { | ||||||
|  | |||||||
| @ -9,9 +9,11 @@ | |||||||
| 
 | 
 | ||||||
| struct WSReceiverInfo { | struct WSReceiverInfo { | ||||||
|     View* view; |     View* view; | ||||||
|  |     FuriTimer* timer; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| typedef struct { | typedef struct { | ||||||
|  |     uint32_t curr_ts; | ||||||
|     FuriString* protocol_name; |     FuriString* protocol_name; | ||||||
|     WSBlockGeneric* generic; |     WSBlockGeneric* generic; | ||||||
| } WSReceiverInfoModel; | } 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); |             flipper_format_read_string(fff, "Protocol", model->protocol_name); | ||||||
| 
 | 
 | ||||||
|             ws_block_generic_deserialize(model->generic, fff); |             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); |         true); | ||||||
| } | } | ||||||
| @ -44,46 +50,76 @@ void ws_view_receiver_info_draw(Canvas* canvas, WSReceiverInfoModel* model) { | |||||||
|         "%s %db", |         "%s %db", | ||||||
|         furi_string_get_cstr(model->protocol_name), |         furi_string_get_cstr(model->protocol_name), | ||||||
|         model->generic->data_count_bit); |         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) { |     if(model->generic->channel != WS_NO_CHANNEL) { | ||||||
|         snprintf(buffer, sizeof(buffer), "Ch: %01d", model->generic->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) { |     if(model->generic->id != WS_NO_ID) { | ||||||
|         snprintf(buffer, sizeof(buffer), "Sn: 0x%02lX", model->generic->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) { |     if(model->generic->btn != WS_NO_BTN) { | ||||||
|         snprintf(buffer, sizeof(buffer), "Btn: %01d", model->generic->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) { |     if(model->generic->battery_low != WS_NO_BATT) { | ||||||
|         snprintf( |         snprintf( | ||||||
|             buffer, sizeof(buffer), "Batt: %s", (!model->generic->battery_low ? "ok" : "low")); |             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); |     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); |     canvas_set_font(canvas, FontPrimary); | ||||||
| 
 | 
 | ||||||
|     if(model->generic->temp != WS_NO_TEMPERATURE) { |     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); |         snprintf(buffer, sizeof(buffer), "%3.1f C", (double)model->generic->temp); | ||||||
|         canvas_draw_str_aligned(canvas, 63, 46, AlignRight, AlignTop, buffer); |         canvas_draw_str_aligned(canvas, 47, 47, AlignRight, AlignTop, buffer); | ||||||
|         canvas_draw_circle(canvas, 55, 45, 1); |         canvas_draw_circle(canvas, 38, 46, 1); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     if(model->generic->humidity != WS_NO_HUMIDITY) { |     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); |         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; |     return true; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void ws_view_receiver_info_enter(void* context) { | static void ws_view_receiver_info_enter(void* context) { | ||||||
|     furi_assert(context); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void ws_view_receiver_info_exit(void* context) { |  | ||||||
|     furi_assert(context); |     furi_assert(context); | ||||||
|     WSReceiverInfo* ws_receiver_info = 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( |     with_view_model( | ||||||
|         ws_receiver_info->view, |         ws_receiver_info->view, | ||||||
|         WSReceiverInfoModel * model, |         WSReceiverInfoModel * model, | ||||||
| @ -113,6 +154,20 @@ void ws_view_receiver_info_exit(void* context) { | |||||||
|         false); |         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_view_receiver_info_alloc() { | ||||||
|     WSReceiverInfo* ws_receiver_info = malloc(sizeof(WSReceiverInfo)); |     WSReceiverInfo* ws_receiver_info = malloc(sizeof(WSReceiverInfo)); | ||||||
| 
 | 
 | ||||||
| @ -135,12 +190,17 @@ WSReceiverInfo* ws_view_receiver_info_alloc() { | |||||||
|         }, |         }, | ||||||
|         true); |         true); | ||||||
| 
 | 
 | ||||||
|  |     ws_receiver_info->timer = | ||||||
|  |         furi_timer_alloc(ws_view_receiver_info_timer, FuriTimerTypePeriodic, ws_receiver_info); | ||||||
|  | 
 | ||||||
|     return ws_receiver_info; |     return ws_receiver_info; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void ws_view_receiver_info_free(WSReceiverInfo* ws_receiver_info) { | void ws_view_receiver_info_free(WSReceiverInfo* ws_receiver_info) { | ||||||
|     furi_assert(ws_receiver_info); |     furi_assert(ws_receiver_info); | ||||||
| 
 | 
 | ||||||
|  |     furi_timer_free(ws_receiver_info->timer); | ||||||
|  | 
 | ||||||
|     with_view_model( |     with_view_model( | ||||||
|         ws_receiver_info->view, |         ws_receiver_info->view, | ||||||
|         WSReceiverInfoModel * model, |         WSReceiverInfoModel * model, | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 MX
						MX