1414#include "drivers/accel.h"
1515#include "drivers/ambient_light.h"
1616#include "drivers/audio.h"
17+ #include "drivers/battery.h"
1718#include "drivers/led_controller.h"
1819#include "drivers/mag.h"
1920#include "drivers/vibe.h"
2829#define STATUS_STRING_LEN 128
2930#define TEST_DURATION_SEC 10
3031
32+ // Battery temperature range (in millicelsius)
33+ #define TEMP_MIN_MC 15000 // 15.0C
34+ #define TEMP_MAX_MC 35000 // 35.0C
35+
3136#if CAPABILITY_HAS_SPEAKER
3237static const int16_t sine_wave_4k [] = {
3338 0 , 32767 , 0 , -32768 , 0 , 32767 , 0 , -32768 ,
@@ -61,6 +66,7 @@ typedef enum {
6166#endif
6267 TestState_ALS ,
6368 TestState_Vibe ,
69+ TestState_Battery ,
6470 NumTestStates
6571} TestState ;
6672
@@ -84,6 +90,7 @@ typedef struct {
8490
8591 bool running ;
8692 bool menu_active ;
93+ bool test_failed ;
8794#if CAPABILITY_HAS_SPEAKER
8895 bool audio_playing ;
8996#endif
@@ -223,6 +230,27 @@ static void prv_test_vibe(AppData *data) {
223230 vibes_long_pulse ();
224231}
225232
233+ static void prv_test_battery (AppData * data ) {
234+ BatteryConstants battery_const ;
235+ battery_get_constants (& battery_const );
236+ const BatteryChargeState charge_state = battery_get_charge_state ();
237+
238+ char time_str [16 ];
239+ prv_format_time (time_str , sizeof (time_str ), data -> total_elapsed_sec );
240+
241+ int8_t temp_c = (int8_t )(battery_const .t_mc / 1000 );
242+ uint8_t temp_c_frac = ((battery_const .t_mc > 0 ? battery_const .t_mc : - battery_const .t_mc ) % 1000 ) / 10 ;
243+ int32_t current_ma = battery_const .i_ua / 1000 ;
244+
245+ sniprintf (data -> status_string , sizeof (data -> status_string ),
246+ "BATTERY TEST\nCycle: %" PRIu32 "\nTime: %s\n\n%" PRId32 "mV %" PRId32 "mA\n%" PRId8 ".%02" PRIu8 "C (%" PRIu8 "%%)\nUSB:%s Charging:%s" ,
247+ data -> cycle_count , time_str , battery_const .v_mv , current_ma ,
248+ temp_c , temp_c_frac , charge_state .charge_percent ,
249+ charge_state .is_plugged ? "Y" : "N" ,
250+ charge_state .is_charging ? "Y" : "N" );
251+ text_layer_set_text (& data -> status , data -> status_string );
252+ }
253+
226254static void prv_advance_test (AppData * data ) {
227255 data -> test_elapsed_sec = 0 ;
228256
@@ -295,12 +323,26 @@ static void prv_advance_test(AppData *data) {
295323
296324static void prv_update_display (AppData * data ) {
297325 if (!data -> running ) {
298- // Display the finished message
299- char time_str [16 ];
300- prv_format_time (time_str , sizeof (time_str ), data -> total_elapsed_sec );
301- sniprintf (data -> status_string , sizeof (data -> status_string ),
302- "FINISHED\n\nTotal Time: %s\nCycles: %" PRIu32 ,
303- time_str , data -> cycle_count );
326+ if (data -> test_failed ) {
327+ // Display failure message with battery % and temperature
328+ BatteryConstants battery_const ;
329+ battery_get_constants (& battery_const );
330+ const BatteryChargeState charge_state = battery_get_charge_state ();
331+
332+ int8_t temp_c = (int8_t )(battery_const .t_mc / 1000 );
333+ uint8_t temp_c_frac = ((battery_const .t_mc > 0 ? battery_const .t_mc : - battery_const .t_mc ) % 1000 ) / 10 ;
334+
335+ sniprintf (data -> status_string , sizeof (data -> status_string ),
336+ "TEST FAIL\n\nBattery: %" PRIu8 "%% %" PRId8 ".%02" PRIu8 "C\nCheck conditions" ,
337+ charge_state .charge_percent , temp_c , temp_c_frac );
338+ } else {
339+ // Display the finished message
340+ char time_str [16 ];
341+ prv_format_time (time_str , sizeof (time_str ), data -> total_elapsed_sec );
342+ sniprintf (data -> status_string , sizeof (data -> status_string ),
343+ "FINISHED\n\nTotal Time: %s\nCycles: %" PRIu32 ,
344+ time_str , data -> cycle_count );
345+ }
304346 text_layer_set_text (& data -> status , data -> status_string );
305347 return ;
306348 }
@@ -345,6 +387,9 @@ static void prv_update_display(AppData *data) {
345387 case TestState_Vibe :
346388 prv_test_vibe (data );
347389 break ;
390+ case TestState_Battery :
391+ prv_test_battery (data );
392+ break ;
348393 default :
349394 break ;
350395 }
@@ -353,6 +398,41 @@ static void prv_update_display(AppData *data) {
353398static void prv_handle_second_tick (struct tm * tick_time , TimeUnits units_changed ) {
354399 AppData * data = app_state_get_user_data ();
355400
401+ // Continuous battery charge management (always active)
402+ BatteryChargeState charge_state = battery_get_charge_state ();
403+ BatteryConstants battery_const ;
404+ battery_get_constants (& battery_const );
405+
406+ // Disable charging if temperature is out of range
407+ if (battery_const .t_mc < TEMP_MIN_MC || battery_const .t_mc > TEMP_MAX_MC ) {
408+ battery_set_charge_enable (false);
409+ } else if (charge_state .charge_percent < 70 ) {
410+ battery_set_charge_enable (true);
411+ } else if (charge_state .charge_percent > 75 ) {
412+ battery_set_charge_enable (false);
413+ }
414+
415+ // Check battery temperature during test
416+ if (data -> running ) {
417+ if (battery_const .t_mc < TEMP_MIN_MC || battery_const .t_mc > TEMP_MAX_MC ) {
418+ data -> test_failed = true;
419+ data -> running = false;
420+ tick_timer_service_unsubscribe ();
421+ prv_update_display (data );
422+ return ;
423+ }
424+
425+ // Check if battery drops below 70% while not charging
426+ charge_state = battery_get_charge_state ();
427+ if (charge_state .charge_percent < 70 && !charge_state .is_charging ) {
428+ data -> test_failed = true;
429+ data -> running = false;
430+ tick_timer_service_unsubscribe ();
431+ prv_update_display (data );
432+ return ;
433+ }
434+ }
435+
356436 if (!data -> running ) {
357437 return ;
358438 }
@@ -513,6 +593,9 @@ static void prv_start_tests(TestDuration duration) {
513593 data -> saved_backlight_color = led_controller_rgb_get_color ();
514594#endif
515595
596+ // Initialize battery charge management
597+ battery_set_charge_enable (true);
598+
516599 switch (duration ) {
517600 case Duration_2Hours :
518601 data -> max_duration_sec = 2 * 3600 ;
@@ -549,6 +632,7 @@ static void prv_handle_init(void) {
549632 * data = (AppData ) {
550633 .running = false,
551634 .menu_active = true,
635+ .test_failed = false,
552636#if CAPABILITY_HAS_SPEAKER
553637 .audio_playing = false,
554638#endif
@@ -604,6 +688,9 @@ static void prv_handle_deinit(void) {
604688 if (data -> running ) {
605689 tick_timer_service_unsubscribe ();
606690 }
691+
692+ // Disable charging when app is closing
693+ battery_set_charge_enable (false);
607694}
608695
609696static void s_main (void ) {
0 commit comments