@@ -58,6 +58,19 @@ MEMFAULT_STATIC_ASSERT(sizeof(sMfltRebootInfo) == MEMFAULT_REBOOT_TRACKING_REGIO
5858
5959static sMfltRebootInfo * s_mflt_reboot_info ;
6060
61+ //! Struct to retrieve reboot reason data from. Matches the fields of sMfltRebootReason
62+ //! as documented in reboot_tracking.h
63+ typedef struct {
64+ eMemfaultRebootReason reboot_reg_reason ;
65+ eMemfaultRebootReason prior_stored_reason ;
66+ bool is_valid ;
67+ } sMfltRebootReasonData ;
68+
69+ // Private struct to store reboot reason after reboot tracking is initialized
70+ static sMfltRebootReasonData s_reboot_reason_data = {
71+ .is_valid = false,
72+ };
73+
6174static bool prv_check_or_init_struct (void ) {
6275 if (s_mflt_reboot_info == NULL ) {
6376 return false;
@@ -93,11 +106,50 @@ static bool prv_read_reset_info(sMfltResetReasonInfo *info) {
93106 return true;
94107}
95108
109+ //! Records reboot reasons from reboot register and prior saved reboot
110+ //!
111+ //! Stores both the new reboot reason derived from a platform's reboot register and
112+ //! any previously saved reboot reason. If there is no previously stored reboot reason,
113+ //! the reboot register reason is used.
114+ //!
115+ //! @param reboot_reg_reason New reboot reason from this boot
116+ //! @param prior_stored_reason Prior reboot reason stored in s_mflt_reboot_info
117+ static void prv_record_reboot_reason (eMemfaultRebootReason reboot_reg_reason ,
118+ eMemfaultRebootReason prior_stored_reason ) {
119+ s_reboot_reason_data .reboot_reg_reason = reboot_reg_reason ;
120+
121+ if (prior_stored_reason != (eMemfaultRebootReason )MEMFAULT_REBOOT_REASON_NOT_SET ) {
122+ s_reboot_reason_data .prior_stored_reason = prior_stored_reason ;
123+ } else {
124+ s_reboot_reason_data .prior_stored_reason = reboot_reg_reason ;
125+ }
126+
127+ s_reboot_reason_data .is_valid = true;
128+ }
129+
130+ static bool prv_get_unexpected_reboot_occurred (void ) {
131+ // Check prior_stored_reason, reboot is unexpected if prior reason is set and in error range or
132+ // unknown
133+ if (s_reboot_reason_data .prior_stored_reason !=
134+ (eMemfaultRebootReason )MEMFAULT_REBOOT_REASON_NOT_SET ) {
135+ if (s_reboot_reason_data .prior_stored_reason == kMfltRebootReason_Unknown ||
136+ s_reboot_reason_data .prior_stored_reason >= kMfltRebootReason_UnknownError ) {
137+ return true;
138+ }
139+ }
140+
141+ // Check reboot_reg_reason second, reboot is unexpected if in error range or unknown
142+ return (s_reboot_reason_data .reboot_reg_reason == kMfltRebootReason_Unknown ||
143+ s_reboot_reason_data .reboot_reg_reason >= kMfltRebootReason_UnknownError );
144+ }
145+
96146static void prv_record_reboot_event (eMemfaultRebootReason reboot_reason ,
97147 const sMfltRebootTrackingRegInfo * reg ) {
98- if (reboot_reason >= kMfltRebootReason_UnknownError ) {
99- s_mflt_reboot_info -> crash_count ++ ;
100- }
148+ // Store both the new reason reported by hardware and the current recorded reason
149+ // The combination of these will be used to determine if the bootup was expected
150+ // by the metrics subsystem
151+ // s_mflt_reboot_info can be cleared by any call to memfault_reboot_tracking_collect_reset_info
152+ prv_record_reboot_reason (reboot_reason , s_mflt_reboot_info -> last_reboot_reason );
101153
102154 if (s_mflt_reboot_info -> last_reboot_reason != MEMFAULT_REBOOT_REASON_NOT_SET ) {
103155 // we are already tracking a reboot. We don't overwrite this because generally the first reboot
@@ -132,6 +184,10 @@ void memfault_reboot_tracking_boot(
132184 }
133185
134186 prv_record_reboot_event (reset_reason , NULL );
187+
188+ if (prv_get_unexpected_reboot_occurred ()) {
189+ s_mflt_reboot_info -> crash_count ++ ;
190+ }
135191}
136192
137193void memfault_reboot_tracking_mark_reset_imminent (eMemfaultRebootReason reboot_reason ,
@@ -190,3 +246,31 @@ void memfault_reboot_tracking_mark_coredump_saved(void) {
190246
191247 s_mflt_reboot_info -> coredump_saved = 1 ;
192248}
249+
250+ int memfault_reboot_tracking_get_reboot_reason (sMfltRebootReason * reboot_reason ) {
251+ if (reboot_reason == NULL || !s_reboot_reason_data .is_valid ) {
252+ return -1 ;
253+ }
254+
255+ * reboot_reason = (sMfltRebootReason ){
256+ .reboot_reg_reason = s_reboot_reason_data .reboot_reg_reason ,
257+ .prior_stored_reason = s_reboot_reason_data .prior_stored_reason ,
258+ };
259+
260+ return 0 ;
261+ }
262+
263+ int memfault_reboot_tracking_get_unexpected_reboot_occurred (bool * unexpected_reboot_occurred ) {
264+ if (unexpected_reboot_occurred == NULL || !s_reboot_reason_data .is_valid ) {
265+ return -1 ;
266+ }
267+
268+ * unexpected_reboot_occurred = prv_get_unexpected_reboot_occurred ();
269+ return 0 ;
270+ }
271+
272+ void memfault_reboot_tracking_clear_reboot_reason (void ) {
273+ s_reboot_reason_data = (sMfltRebootReasonData ){
274+ .is_valid = false,
275+ };
276+ }
0 commit comments