dRonin  adbada4
dRonin firmware
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
systemmod.c
Go to the documentation of this file.
1 
17 /*
18  * This program is free software; you can redistribute it and/or modify
19  * it under the terms of the GNU General Public License as published by
20  * the Free Software Foundation; either version 3 of the License, or
21  * (at your option) any later version.
22  *
23  * This program is distributed in the hope that it will be useful, but
24  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
25  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
26  * for more details.
27  *
28  * You should have received a copy of the GNU General Public License along
29  * with this program; if not, see <http://www.gnu.org/licenses/>
30  */
31 
32 #include "openpilot.h"
33 #include <eventdispatcher.h>
34 #include <utlist.h>
35 
36 #include "systemmod.h"
37 #include "sanitycheck.h"
38 #include "taskinfo.h"
39 #include "taskmonitor.h"
40 #include "pios_thread.h"
41 #include "pios_mutex.h"
42 #include "pios_queue.h"
43 #include "misc_math.h"
44 #include "morsel.h"
45 
46 #include "annunciatorsettings.h"
47 #include "flightstatus.h"
48 #include "manualcontrolcommand.h"
49 #include "manualcontrolsettings.h"
50 #include "objectpersistence.h"
51 #include "stabilizationsettings.h"
52 #include "stateestimation.h"
53 #include "systemsettings.h"
54 #include "systemstats.h"
55 #include "watchdogstatus.h"
56 
57 #ifdef SYSTEMMOD_RGBLED_SUPPORT
58 #include "rgbledsettings.h"
59 #include "rgbleds.h"
60 #endif
61 
62 #ifdef PIOS_INCLUDE_DAC_ANNUNCIATOR
63 #include "pios_annuncdac.h"
64 
65 extern annuncdac_dev_t pios_dac_annunciator_id;
66 #endif
67 
68 #if defined(PIOS_INCLUDE_DEBUG_CONSOLE) && defined(DEBUG_THIS_FILE)
69 #define DEBUG_MSG(format, ...) PIOS_COM_SendFormattedString(PIOS_COM_DEBUG, format, ## __VA_ARGS__)
70 #else
71 #define DEBUG_MSG(format, ...)
72 #endif
73 
74 #ifndef IDLE_COUNTS_PER_SEC_AT_NO_LOAD
75 #define IDLE_COUNTS_PER_SEC_AT_NO_LOAD 995998 // calibrated by running tests/test_cpuload.c
76 // must be updated if the FreeRTOS or compiler
77 // optimisation options are changed.
78 #endif
79 
80 #if defined(PIOS_SYSTEM_STACK_SIZE)
81 #define STACK_SIZE_BYTES PIOS_SYSTEM_STACK_SIZE
82 #else
83 #define STACK_SIZE_BYTES 1024
84 #endif
85 
86 #define TASK_PRIORITY PIOS_THREAD_PRIO_NORMAL
87 
88 /* When we're blinking morse code, this works out to 10.6 WPM. It's also
89  * nice and relatively prime to most other rates of things, so we don't get
90  * bad beat frequencies. */
91 
92 #ifdef SYSTEMMOD_RGBLED_SUPPORT
93 #define SYSTEM_RAPID_UPDATES
94 
95 #define SYSTEM_UPDATE_PERIOD_MS 29
96 #define SYSTEM_UPDATE_PERIOD_MS4TH (SYSTEM_UPDATE_PERIOD_MS * 4)
97 
98 #else
99 
100 #define SYSTEM_UPDATE_PERIOD_MS 117
101 #define SYSTEM_UPDATE_PERIOD_MS4TH (SYSTEM_UPDATE_PERIOD_MS)
102 
103 #endif
104 
105 // Private types
106 
110 typedef struct {
113  struct pios_queue *queue;
115 
121  uint16_t updatePeriodMs;
124 };
126 
127 // Private types
128 
129 // Private variables
133 
134 static volatile uint32_t idleCounter;
135 static volatile uint32_t idleCounterClear;
136 static struct pios_thread *systemTaskHandle;
138 
139 static volatile bool config_check_needed;
140 static const char * volatile custom_blink_string;
141 
142 // Private functions
143 static void systemPeriodicCb(const UAVObjEvent *ev,
144  void *ctx, void *obj_data, int len);
145 static void objectUpdatedCb(const UAVObjEvent *ev,
146  void *ctx, void *obj, int len);
147 static uint32_t processPeriodicUpdates();
148 static int32_t eventPeriodicCreate(UAVObjEvent *ev,
150  uint16_t periodMs);
151 static int32_t eventPeriodicUpdate(UAVObjEvent *ev,
153  uint16_t periodMs);
154 
155 #ifndef NO_SENSORS
156 static void configurationUpdatedCb(const UAVObjEvent *ev,
157  void *ctx, void *obj, int len);
158 #endif
159 
160 void system_task();
161 
162 static inline void updateStats();
163 static inline void updateSystemAlarms();
164 #if defined(WDG_STATS_DIAGNOSTICS)
165 static inline void updateWDGstats();
166 #endif
167 
172 int32_t SystemModStart(void)
173 {
174  // Create periodic event that will be used to update the telemetry stats
175  UAVObjEvent ev;
176  memset(&ev, 0, sizeof(UAVObjEvent));
178 
179  EventClearStats();
180 
181  return 0;
182 }
183 
188 int32_t SystemModInitialize(void)
189 {
190  // Create mutex
191  mutex = PIOS_Recursive_Mutex_Create();
192  if (mutex == NULL)
193  return -1;
194 
195  if (SystemSettingsInitialize() == -1
196  || SystemStatsInitialize() == -1
197  || FlightStatusInitialize() == -1
198  || ObjectPersistenceInitialize() == -1
199  || AnnunciatorSettingsInitialize() == -1
201  || RGBLEDSettingsInitialize() == -1
202 #endif
203  ) {
204  return -1;
205  }
206 #if defined(DIAG_TASKS)
207  if (TaskInfoInitialize() == -1)
208  return -1;
209 #endif
210 #if defined(WDG_STATS_DIAGNOSTICS)
211  if (WatchdogStatusInitialize() == -1)
212  return -1;
213 #endif
214 
215  objectPersistenceQueue = PIOS_Queue_Create(1, sizeof(UAVObjEvent));
216  if (objectPersistenceQueue == NULL)
217  return -1;
218 
219  return 0;
220 }
221 
224 {
226  /* We failed to malloc during task creation,
227  * system behaviour is undefined. Reset and let
228  * the BootFault code recover for us.
229  */
230  PIOS_SYS_Reset();
231  }
232 
233 #if defined(PIOS_INCLUDE_IAP)
234  /* Record a successful boot */
236 #endif
237 
240 
241  TaskMonitorAdd(TASKINFO_RUNNING_SYSTEM, systemTaskHandle);
242 
243  // Listen for SettingPersistance object updates, connect a callback function
244  ObjectPersistenceConnectQueue(objectPersistenceQueue);
245 
246 #if defined(PIOS_INCLUDE_WDG) && defined(PIOS_WDG_SYSTEM)
248 #endif
249 
250 #ifndef NO_SENSORS
251  // Run this initially to make sure the configuration is checked
253 
254  // Whenever the configuration changes, make sure it is safe to fly
255  if (StabilizationSettingsHandle())
256  StabilizationSettingsConnectCallback(configurationUpdatedCb);
257  if (SystemSettingsHandle())
258  SystemSettingsConnectCallback(configurationUpdatedCb);
259  if (ManualControlSettingsHandle())
260  ManualControlSettingsConnectCallback(configurationUpdatedCb);
261  if (FlightStatusHandle())
262  FlightStatusConnectCallback(configurationUpdatedCb);
263 #endif
264 
265  // Main system loop
266  while (1) {
267 #if defined(PIOS_INCLUDE_WDG) && defined(PIOS_WDG_SYSTEM)
269 #endif
270 
271  int32_t delayTime = processPeriodicUpdates();
272 
273  UAVObjEvent ev;
274 
275  if (PIOS_Queue_Receive(objectPersistenceQueue, &ev, delayTime) == true) {
276  // If object persistence is updated call the callback
277  objectUpdatedCb(&ev, NULL, NULL, 0);
278  }
279  }
280 }
281 
282 #if defined(PIOS_INCLUDE_ANNUNC)
283 
284 #define BLINK_STRING_RADIO "r "
285 
289 static inline uint8_t indicate_error(const char **sequence)
290 {
291 #ifdef PIPXTREME
292  *sequence="t"; /* Dashes */
293  return SYSTEMALARMS_ALARM_WARNING;
294 #else
295 
296  SystemAlarmsData alarms;
297  SystemAlarmsGet(&alarms);
298 
299  *sequence = NULL;
300 
301  uint8_t worst_sev = 0;
302 
303  bool generic = false;
304 
305  for (uint32_t i = 0; i < SYSTEMALARMS_ALARM_NUMELEM; i++) {
306  // If this is less severe than the current alarm, continue.
307  if (alarms.Alarm[i] < worst_sev) {
308  continue;
309  }
310 
311  // If there's a tie and the previous answer is not the
312  // 'generic' alarm, continue.
313  if ((!generic) && (alarms.Alarm[i] == worst_sev)) {
314  continue;
315  }
316 
317  uint8_t thresh = SYSTEMALARMS_ALARM_WARNING;
318 
319  if (i == SYSTEMALARMS_ALARM_TELEMETRY) {
320  // Suppress most alarms from telemetry.
321  // The user can identify if present from GCS.
322  thresh = SYSTEMALARMS_ALARM_CRITICAL;
323  }
324 
325  if (i == SYSTEMALARMS_ALARM_EVENTSYSTEM) {
326  // Skip event system alarms-- nuisance
327  continue;
328  }
329 
330  if (alarms.Alarm[i] < thresh) {
331  continue;
332  }
333 
334  // OK, we have a candidate alarm.
335 
336  worst_sev = alarms.Alarm[i];
337  generic = false;
338 
339  switch (i) {
340  case SYSTEMALARMS_ALARM_BATTERY:
341  // -... b for battery
342  *sequence = "b ";
343  break;
344  case SYSTEMALARMS_ALARM_SYSTEMCONFIGURATION:
345  // -.-. c for configuration
346  *sequence = "c ";
347  break;
348  case SYSTEMALARMS_ALARM_GPS:
349  // --. g for GPS
350  *sequence = "g ";
351  break;
352  case SYSTEMALARMS_ALARM_MANUALCONTROL:
353  // .-. r for radio
354  *sequence = BLINK_STRING_RADIO;
355  break;
356  default:
357  // .- a for alarm
358  *sequence = "a ";
359 
360  generic = true;
361  break;
362  }
363  }
364 
365  return worst_sev;
366 #endif /* PIPXTREME */
367 }
368 #endif
369 
370 DONT_BUILD_IF(ANNUNCIATORSETTINGS_ANNUNCIATEAFTERARMING_NUMELEM !=
371  ANNUNCIATORSETTINGS_ANNUNCIATEANYTIME_NUMELEM,
372  AnnuncSettingsMismatch1);
373 DONT_BUILD_IF(ANNUNCIATORSETTINGS_ANNUNCIATEAFTERARMING_MAXOPTVAL !=
374  ANNUNCIATORSETTINGS_ANNUNCIATEANYTIME_MAXOPTVAL,
375  AnnuncSettingsMismatch2);
376 
377 #if defined(PIOS_INCLUDE_ANNUNC)
378 static inline bool should_annunc(AnnunciatorSettingsData *annunciatorSettings,
379  bool been_armed, bool is_manual_control, uint8_t blink_prio,
380  uint8_t cfg_field) {
381  PIOS_Assert(cfg_field <
382  ANNUNCIATORSETTINGS_ANNUNCIATEAFTERARMING_NUMELEM);
383 
384  if (been_armed) {
385  if (blink_prio >= annunciatorSettings->AnnunciateAfterArming[cfg_field]) {
386  return true;
387  } else if (is_manual_control && annunciatorSettings->AnnunciateAfterArming[cfg_field] == ANNUNCIATORSETTINGS_ANNUNCIATEAFTERARMING_MANUALCONTROLONLY) {
388  return true;
389  }
390  }
391 
392  if (blink_prio >= annunciatorSettings->AnnunciateAnytime[cfg_field]) {
393  return true;
394  } else if (is_manual_control && annunciatorSettings->AnnunciateAnytime[cfg_field] == ANNUNCIATORSETTINGS_ANNUNCIATEANYTIME_MANUALCONTROLONLY) {
395  return true;
396  }
397 
398  return false;
399 }
400 
401 static inline void consider_annunc(AnnunciatorSettingsData *annunciatorSettings,
402  bool is_active, bool been_armed, bool is_manual_control,
403  uint8_t blink_prio, uint32_t annunc_id,
404  uint8_t cfg_field) {
405  if (
406  is_active &&
407  should_annunc(annunciatorSettings, been_armed,
408  is_manual_control, blink_prio, cfg_field)
409  ) {
410  PIOS_ANNUNC_On(annunc_id);
411  } else {
412  PIOS_ANNUNC_Off(annunc_id);
413  }
414 }
415 #endif
416 
417 void system_annunc_custom_string(const char *string)
418 {
419  custom_blink_string = string;
420 }
421 
422 static void systemPeriodicCb(const UAVObjEvent *ev,
423  void *ctx, void *obj_data, int len)
424 {
425  (void) ev; (void) ctx; (void) obj_data; (void) len;
426 
427  static unsigned int counter=0;
428 
429  counter++;
430 
431 #ifndef NO_SENSORS
432  if (config_check_needed) {
434  config_check_needed = false;
435  }
436 #endif
437 
438 #ifdef SYSTEM_RAPID_UPDATES
439  bool fourth = (counter & 3) == 0;
440 #else
441  bool fourth = true; // All of this stuff, do each time
442 #endif
443 
444  if (fourth) {
445  // Update the system statistics
446  updateStats();
447 
448 #ifndef PIPXTREME
449  // Update the system alarms
451 #endif /* PIPXTREME */
452 
453 #if defined(WDG_STATS_DIAGNOSTICS)
454  updateWDGstats();
455 #endif
456 
457 #if defined(DIAG_TASKS)
458  // Update the task status object
460 #endif
461  }
462 
463 #if defined(PIOS_INCLUDE_ANNUNC)
464  // Figure out what we should be doing.
465 
466  static const char *blink_string = NULL;
467  static uint32_t blink_state = 0;
468  static uint8_t blink_prio = 0;
469  static bool ever_armed = false;
470  static uint8_t armed_status = FLIGHTSTATUS_ARMED_DISARMED;
471  static bool is_manual_control = false;
472  static int morse;
473 
474 #ifdef SYSTEMMOD_RGBLED_SUPPORT
475  static bool led_override = false;
476 #endif
477 
478  // Evaluate all our possible annunciator sources.
479  // The most important: indicate_error / alarms
480 
481  if (fourth) {
482  const char *candidate_blink;
483  uint8_t candidate_prio;
484 
485  if (custom_blink_string) {
486  candidate_prio = ANNUNCIATORSETTINGS_ANNUNCIATEANYTIME_HAIRONFIRE;
487 
488  candidate_blink = custom_blink_string;
489  } else {
490  candidate_prio = indicate_error(&candidate_blink);
491  }
492 
493  if (candidate_prio > blink_prio) {
494  // Preempt!
495  blink_state = 0;
496  blink_string = candidate_blink;
497  blink_prio = candidate_prio;
498 
499  if (blink_prio == ANNUNCIATORSETTINGS_ANNUNCIATEANYTIME_HAIRONFIRE) {
500  custom_blink_string = NULL;
501  }
502 
503  if (blink_string &&
504  !strcmp(blink_string, BLINK_STRING_RADIO)) {
505  /* XXX do this in a more robust way */
506  is_manual_control = true;
507  } else {
508  is_manual_control = false;
509  }
510  }
511 
512  FlightStatusArmedGet(&armed_status);
513 
514  if (armed_status == FLIGHTSTATUS_ARMED_ARMED) {
515  ever_armed = true;
516  } else {
517  if ((counter & 15) == 0) {
518  /* Every 16 cycles through here, kick off
519  * a config check next cycle when disarmed.
520  * Works around #1776 where tasks race
521  * through startup... but it also just
522  * seems prudent to check this stuff
523  * every half second or so while disarmed.
524  * (for lost events, etc.)
525  */
526  config_check_needed = true;
527  }
528  }
529 
530  if ((blink_prio == 0) && (blink_state == 0)) {
531  // Nothing else to do-- show armed status
532  if (armed_status == FLIGHTSTATUS_ARMED_ARMED) {
533  blink_string = "I"; // .. pairs of blinks.
534  } else {
535  blink_string = "T"; // - single long blinks
536  }
537 
538  blink_prio = SHAREDDEFS_ALARMLEVELS_OK;
539  }
540 
541  morse = morse_send(&blink_string, &blink_state);
542 
543  AnnunciatorSettingsData annunciatorSettings;
544  AnnunciatorSettingsGet(&annunciatorSettings);
545 
546 #ifdef PIOS_LED_HEARTBEAT
547  consider_annunc(&annunciatorSettings, morse > 0, ever_armed,
548  is_manual_control,
549  blink_prio, PIOS_LED_HEARTBEAT,
550  ANNUNCIATORSETTINGS_ANNUNCIATEANYTIME_LED_HEARTBEAT);
551 #endif
552 
553 #ifdef PIOS_LED_ALARM
554  consider_annunc(&annunciatorSettings, morse > 0, ever_armed,
555  is_manual_control,
556  blink_prio, PIOS_LED_ALARM,
557  ANNUNCIATORSETTINGS_ANNUNCIATEANYTIME_LED_ALARM);
558 #endif
559 
560  uint8_t buzzer_prio = blink_prio;
561 
562 #ifndef PIPXTREME
563  if (annunciatorSettings.ManualBuzzer !=
564  ANNUNCIATORSETTINGS_MANUALBUZZER_DISABLED) {
565  float acc[MANUALCONTROLCOMMAND_ACCESSORY_NUMELEM];
566  ManualControlCommandAccessoryGet(acc);
567  /* DONT_BUILD_IF to protect this at end of file */
568  if (acc[annunciatorSettings.ManualBuzzer - 1] > 0.0f)
569  buzzer_prio = ANNUNCIATORSETTINGS_ANNUNCIATEANYTIME_HAIRONFIRE;
570  }
571 #endif
572 
573  (void) buzzer_prio;
574 
575 #ifdef PIOS_ANNUNCIATOR_BUZZER
576  consider_annunc(&annunciatorSettings, morse > 0, ever_armed,
577  is_manual_control,
578  buzzer_prio, PIOS_ANNUNCIATOR_BUZZER,
579  ANNUNCIATORSETTINGS_ANNUNCIATEANYTIME_BUZZER);
580 #endif
581 
582 #ifdef PIOS_INCLUDE_DAC_ANNUNCIATOR
583  if (pios_dac_annunciator_id) {
584  if (should_annunc(&annunciatorSettings, ever_armed,
585  is_manual_control, buzzer_prio,
586  ANNUNCIATORSETTINGS_ANNUNCIATEANYTIME_DAC)) {
587  PIOS_ANNUNCDAC_SetValue(pios_dac_annunciator_id,
588  true, morse > 0);
589  } else {
590  PIOS_ANNUNCDAC_SetValue(pios_dac_annunciator_id,
591  false, false);
592  }
593  }
594 #endif
595 
596 #ifdef PIOS_INCLUDE_ACTUATOR_ANNUNCIATOR
597  if (should_annunc(&annunciatorSettings, ever_armed,
598  is_manual_control, buzzer_prio,
599  ANNUNCIATORSETTINGS_ANNUNCIATEANYTIME_ACTUATORS)) {
601  1, 0xffff);
602  }
603 #endif
604 
605 #ifdef SYSTEMMOD_RGBLED_SUPPORT
606  led_override = should_annunc(&annunciatorSettings,
607  ever_armed, is_manual_control, blink_prio,
608  ANNUNCIATORSETTINGS_ANNUNCIATEANYTIME_RGB_LEDS);
609 #endif
610 
611  if (morse < 0) {
612  // This means we were told "completed"
613  blink_string = NULL;
614  blink_prio = 0;
615 
616  is_manual_control = false;
617  }
618  }
619 
620 #ifdef SYSTEMMOD_RGBLED_SUPPORT
621  systemmod_process_rgb_leds(led_override, morse > 0, blink_prio,
622  FLIGHTSTATUS_ARMED_DISARMED != armed_status,
623  (FLIGHTSTATUS_ARMED_ARMING == armed_status) &&
624  ((counter & 3) < 2));
625 #endif /* SYSTEMMOD_RGBLED_SUPPORT */
626 
627 #endif /* PIOS_INCLUDE_ANNUNC */
628 }
629 
630 
634 static void objectUpdatedCb(const UAVObjEvent *ev,
635  void *ctx, void *obj_data, int len)
636 {
637  (void) ctx; (void) obj_data; (void) len;
638 
639  ObjectPersistenceData objper;
640  UAVObjHandle obj;
641 
642  // If the object updated was the ObjectPersistence execute requested action
643  if (ev->obj == ObjectPersistenceHandle()) {
644  // Get object data
645  ObjectPersistenceGet(&objper);
646 
647  int retval = 1;
648 
649  // When this is called because of this method don't do anything
650  if (objper.Operation == OBJECTPERSISTENCE_OPERATION_ERROR ||
651  objper.Operation == OBJECTPERSISTENCE_OPERATION_COMPLETED) {
652  return;
653  }
654 
655  if (objper.Operation == OBJECTPERSISTENCE_OPERATION_LOAD) {
656  // Get selected object
657  obj = UAVObjGetByID(objper.ObjectID);
658  if (obj == 0) {
659  return;
660  }
661  // Load selected instance
662  retval = UAVObjLoad(obj, objper.InstanceID);
663  } else if (objper.Operation == OBJECTPERSISTENCE_OPERATION_SAVE) {
664  // Get selected object
665  obj = UAVObjGetByID(objper.ObjectID);
666  if (obj == 0) {
667  return;
668  }
669 
670  // Save selected instance
671  retval = UAVObjSave(obj, objper.InstanceID);
672  } else if (objper.Operation == OBJECTPERSISTENCE_OPERATION_DELETE) {
673  // Delete selected instance
674  retval = UAVObjDeleteById(objper.ObjectID, objper.InstanceID);
675  } else if (objper.Operation == OBJECTPERSISTENCE_OPERATION_FULLERASE) {
676  retval = -1;
677 #if defined(PIOS_INCLUDE_LOGFS_SETTINGS)
678  extern uintptr_t pios_uavo_settings_fs_id;
679  retval = PIOS_FLASHFS_Format(pios_uavo_settings_fs_id);
680 #endif
681  }
682 
683  // Yield when saving, so if there's a ton of updates we don't
684  // prevent other threads from updatin'.
685  PIOS_Thread_Sleep(25);
686 
687  switch(retval) {
688  case 0:
689  objper.Operation = OBJECTPERSISTENCE_OPERATION_COMPLETED;
690  ObjectPersistenceSet(&objper);
691  break;
692  case -1:
693  objper.Operation = OBJECTPERSISTENCE_OPERATION_ERROR;
694  ObjectPersistenceSet(&objper);
695  break;
696  default:
697  break;
698  }
699  }
700 }
701 
702 #ifndef NO_SENSORS
703 
707 static void configurationUpdatedCb(const UAVObjEvent *ev,
708  void *ctx, void *obj, int len)
709 {
710  (void) ev; (void) ctx; (void) obj; (void) len;
711  config_check_needed = true;
712 }
713 #endif
714 
718 #if defined(WDG_STATS_DIAGNOSTICS)
719 static WatchdogStatusData watchdogStatus;
720 static void updateWDGstats()
721 {
722  // Only update if something has changed
723  if (watchdogStatus.ActiveFlags != PIOS_WDG_GetActiveFlags() ||
724  watchdogStatus.BootupFlags != PIOS_WDG_GetBootupFlags()) {
725  watchdogStatus.BootupFlags = PIOS_WDG_GetBootupFlags();
726  watchdogStatus.ActiveFlags = PIOS_WDG_GetActiveFlags();
727  WatchdogStatusSet(&watchdogStatus);
728  }
729 }
730 #endif
731 
735 static void updateStats()
736 {
737  static uint32_t lastTickCount = 0;
738  SystemStatsData stats;
739 
740  // Get stats and update
741  SystemStatsGet(&stats);
742  stats.FlightTime = PIOS_Thread_Systime();
743  stats.HeapRemaining = PIOS_heap_get_free_size();
744  stats.FastHeapRemaining = PIOS_fastheap_get_free_size();
745 
746  // Get Irq stack status
747  stats.IRQStackRemaining = (uint16_t)PIOS_SYS_IrqStackUnused();
748  stats.OSStackRemaining = (uint16_t)PIOS_SYS_OsStackUnused();
749 
750  // When idleCounterClear was not reset by the idle-task, it means the idle-task did not run
751  if (idleCounterClear) {
752  idleCounter = 0;
753  }
754 
755  uint32_t now = PIOS_Thread_Systime();
756  if (now > lastTickCount) {
757  float dT = (now - lastTickCount) / 1000.0f;
758 
759  // In the case of a slightly miscalibrated max idle count, make sure CPULoad does
760  // not go negative and set an alarm inappropriately.
761  float idleFraction = ((float)idleCounter / dT) / (float)IDLE_COUNTS_PER_SEC_AT_NO_LOAD;
762  if (idleFraction > 1)
763  stats.CPULoad = 0;
764  else
765  stats.CPULoad = 100 - roundf(100.0f * idleFraction);
766  } //else: TickCount has wrapped, do not calc now
767 
768  lastTickCount = now;
769  idleCounterClear = 1;
770 
771  SystemStatsSet(&stats);
772 }
773 
777 static void updateSystemAlarms()
778 {
779 #ifndef PIPXTREME
780  SystemStatsData stats;
781  UAVObjStats objStats;
782  EventStats evStats;
783  SystemStatsGet(&stats);
784 
785  // Check heap, IRQ stack and malloc failures
787  || (stats.HeapRemaining < HEAP_LIMIT_CRITICAL)
788 #if !defined(ARCH_POSIX) && !defined(ARCH_WIN32) && defined(CHECK_IRQ_STACK)
789  || (stats.IRQStackRemaining < IRQSTACK_LIMIT_CRITICAL)
790 #endif
791  ) {
792  AlarmsSet(SYSTEMALARMS_ALARM_OUTOFMEMORY, SYSTEMALARMS_ALARM_CRITICAL);
793  } else if (
794  (stats.HeapRemaining < HEAP_LIMIT_WARNING)
795 #if !defined(ARCH_POSIX) && !defined(ARCH_WIN32) && defined(CHECK_IRQ_STACK)
796  || (stats.IRQStackRemaining < IRQSTACK_LIMIT_WARNING)
797 #endif
798  ) {
799  AlarmsSet(SYSTEMALARMS_ALARM_OUTOFMEMORY, SYSTEMALARMS_ALARM_WARNING);
800  } else {
801  AlarmsClear(SYSTEMALARMS_ALARM_OUTOFMEMORY);
802  }
803 
804  // Check CPU load
805 #ifdef FLIGHT_POSIX
806  // XXX do something meaningful here in the future.
807  // Right now CPU monitoring on posix is worthless.
808  AlarmsClear(SYSTEMALARMS_ALARM_CPUOVERLOAD);
809 #else
810  if (stats.CPULoad > CPULOAD_LIMIT_CRITICAL) {
811  AlarmsSet(SYSTEMALARMS_ALARM_CPUOVERLOAD, SYSTEMALARMS_ALARM_CRITICAL);
812  } else if (stats.CPULoad > CPULOAD_LIMIT_WARNING) {
813  AlarmsSet(SYSTEMALARMS_ALARM_CPUOVERLOAD, SYSTEMALARMS_ALARM_WARNING);
814  } else {
815  AlarmsClear(SYSTEMALARMS_ALARM_CPUOVERLOAD);
816  }
817 #endif
818 
819  // Check for event errors
820  UAVObjGetStats(&objStats);
821  EventGetStats(&evStats);
823  EventClearStats();
824  if (objStats.eventCallbackErrors > 0 || objStats.eventQueueErrors > 0 || evStats.eventErrors > 0) {
825  AlarmsSet(SYSTEMALARMS_ALARM_EVENTSYSTEM, SYSTEMALARMS_ALARM_WARNING);
826  } else {
827  AlarmsClear(SYSTEMALARMS_ALARM_EVENTSYSTEM);
828  }
829 
830  if (objStats.lastCallbackErrorID || objStats.lastQueueErrorID || evStats.lastErrorID) {
831  SystemStatsData sysStats;
832  SystemStatsGet(&sysStats);
833  sysStats.EventSystemWarningID = evStats.lastErrorID;
834  sysStats.ObjectManagerCallbackID = objStats.lastCallbackErrorID;
835  sysStats.ObjectManagerQueueID = objStats.lastQueueErrorID;
836  SystemStatsSet(&sysStats);
837  }
838 #endif
839 }
840 
845 {
846  // Called when the scheduler has no tasks to run
847  if (idleCounterClear == 0) {
848  ++idleCounter;
849  } else {
850  idleCounter = 0;
851  idleCounterClear = 0;
852  }
853 }
854 
859 void EventGetStats(EventStats* statsOut)
860 {
862  memcpy(statsOut, &stats, sizeof(EventStats));
864 }
865 
870 {
872  memset(&stats, 0, sizeof(EventStats));
874 }
875 
883 /* XXX TODO: would be nice to get context record logic in these */
885 {
886  return eventPeriodicCreate(ev, cb, 0, periodMs);
887 }
888 
897 {
898  return eventPeriodicUpdate(ev, cb, 0, periodMs);
899 }
900 
908 int32_t EventPeriodicQueueCreate(UAVObjEvent* ev, struct pios_queue *queue, uint16_t periodMs)
909 {
910  return eventPeriodicCreate(ev, 0, queue, periodMs);
911 }
912 
920 int32_t EventPeriodicQueueUpdate(UAVObjEvent* ev, struct pios_queue *queue, uint16_t periodMs)
921 {
922  return eventPeriodicUpdate(ev, 0, queue, periodMs);
923 }
924 
933 static int32_t eventPeriodicCreate(UAVObjEvent* ev, UAVObjEventCallback cb, struct pios_queue *queue, uint16_t periodMs)
934 {
935  PeriodicObjectList* objEntry;
936  // Get lock
938  // Check that the object is not already connected
939  LL_FOREACH(objList, objEntry)
940  {
941  if (objEntry->evInfo.cb == cb &&
942  objEntry->evInfo.queue == queue &&
943  objEntry->evInfo.ev.obj == ev->obj &&
944  objEntry->evInfo.ev.instId == ev->instId &&
945  objEntry->evInfo.ev.event == ev->event)
946  {
947  // Already registered, do nothing
949  return -1;
950  }
951  }
952  // Create handle
954  if (objEntry == NULL) return -1;
955  objEntry->evInfo.ev.obj = ev->obj;
956  objEntry->evInfo.ev.instId = ev->instId;
957  objEntry->evInfo.ev.event = ev->event;
958  objEntry->evInfo.ev.throttle = NULL;
959  objEntry->evInfo.cb = cb;
960  objEntry->evInfo.queue = queue;
961  objEntry->updatePeriodMs = periodMs;
962  objEntry->timeToNextUpdateMs = randomize_int(periodMs); // avoid bunching of updates
963  // Add to list
964  LL_APPEND(objList, objEntry);
965  // Release lock
967  return 0;
968 }
969 
978 static int32_t eventPeriodicUpdate(UAVObjEvent* ev, UAVObjEventCallback cb, struct pios_queue *queue, uint16_t periodMs)
979 {
980  PeriodicObjectList* objEntry;
981  // Get lock
983  // Find object
984  LL_FOREACH(objList, objEntry)
985  {
986  if (objEntry->evInfo.cb == cb &&
987  objEntry->evInfo.queue == queue &&
988  objEntry->evInfo.ev.obj == ev->obj &&
989  objEntry->evInfo.ev.instId == ev->instId &&
990  objEntry->evInfo.ev.event == ev->event)
991  {
992  // Object found, update period
993  objEntry->updatePeriodMs = periodMs;
994  objEntry->timeToNextUpdateMs = randomize_int(periodMs); // avoid bunching of updates
995  // Release lock
997  return 0;
998  }
999  }
1000  // If this point is reached the object was not found
1002  return -1;
1003 }
1004 
1005 /* It can take this long before a "first callback" on a registration,
1006  * so it's advantageous for it to not be too long. (e.g. we don't have a
1007  * mechanism to wakeup on list change */
1008 #define MAX_UPDATE_PERIOD_MS 350
1009 
1014 static uint32_t processPeriodicUpdates()
1015 {
1016  PeriodicObjectList* objEntry;
1017  int32_t timeNow;
1018  int32_t offset;
1019 
1020  // Get lock
1022 
1023  // Iterate through each object and update its timer, if zero then transmit object.
1024  // Also calculate smallest delay to next update.
1025  uint32_t now = PIOS_Thread_Systime();
1026  uint32_t timeToNextUpdate = PIOS_Thread_Systime() + MAX_UPDATE_PERIOD_MS;
1027  LL_FOREACH(objList, objEntry)
1028  {
1029  // If object is configured for periodic updates
1030  if (objEntry->updatePeriodMs > 0)
1031  {
1032  // Check if time for the next update
1033  timeNow = PIOS_Thread_Systime();
1034  if (objEntry->timeToNextUpdateMs <= timeNow)
1035  {
1036  // Reset timer
1037  offset = ( timeNow - objEntry->timeToNextUpdateMs ) % objEntry->updatePeriodMs;
1038  objEntry->timeToNextUpdateMs = timeNow + objEntry->updatePeriodMs - offset;
1039  // Invoke callback, if one
1040  if ( objEntry->evInfo.cb != 0)
1041  {
1042  objEntry->evInfo.cb(&objEntry->evInfo.ev, NULL, NULL, 0); // the function is expected to copy the event information
1043  }
1044  // Push event to queue, if one
1045  if ( objEntry->evInfo.queue != 0)
1046  {
1047  if (PIOS_Queue_Send(objEntry->evInfo.queue, &objEntry->evInfo.ev, 0) != true ) // do not block if queue is full
1048  {
1049  if (objEntry->evInfo.ev.obj != NULL)
1050  stats.lastErrorID = UAVObjGetID(objEntry->evInfo.ev.obj);
1051  ++stats.eventErrors;
1052  }
1053  }
1054  }
1055  // Update minimum delay
1056  if (objEntry->timeToNextUpdateMs < timeToNextUpdate)
1057  {
1058  timeToNextUpdate = objEntry->timeToNextUpdateMs;
1059  }
1060  }
1061  }
1062 
1063  // Done
1065  return timeToNextUpdate - now;
1066 }
1067 
1068 DONT_BUILD_IF(ANNUNCIATORSETTINGS_MANUALBUZZER_MAXOPTVAL >
1069  MANUALCONTROLCOMMAND_ACCESSORY_NUMELEM, TooManyManualBuzzers);
1070 
#define LL_FOREACH(head, el)
Definition: utlist.h:263
#define SYSTEMMOD_RGBLED_SUPPORT
Definition: pios_config.h:65
void UAVObjClearStats()
uint32_t PIOS_Thread_Systime(void)
Definition: pios_thread.c:212
static volatile uint32_t idleCounter
Definition: systemmod.c:134
uint32_t lastCallbackErrorID
UAVObjHandle UAVObjGetByID(uint32_t id)
struct pios_queue * PIOS_Queue_Create(size_t queue_length, size_t item_size)
Definition: pios_queue.c:47
static int32_t eventPeriodicCreate(UAVObjEvent *ev, UAVObjEventCallback cb, struct pios_queue *queue, uint16_t periodMs)
Definition: systemmod.c:933
uint32_t lastErrorID
int32_t EventPeriodicQueueCreate(UAVObjEvent *ev, struct pios_queue *queue, uint16_t periodMs)
Definition: systemmod.c:908
UAVObjEventCallback cb
Definition: systemmod.c:112
size_t PIOS_fastheap_get_free_size(void)
Definition: pios_heap.c:221
#define HEAP_LIMIT_WARNING
bool PIOS_WDG_RegisterFlag(uint16_t flag_requested)
Register a module against the watchdog.
Definition: pios_wdg.c:86
#define IRQSTACK_LIMIT_CRITICAL
void vApplicationIdleHook(void)
Definition: systemmod.c:844
System module.
bool PIOS_WDG_UpdateFlag(uint16_t flag)
Function called by modules to indicate they are still running.
Definition: pios_wdg.c:102
bool PIOS_Queue_Send(struct pios_queue *queuep, const void *itemp, uint32_t timeout_ms)
Definition: pios_queue.c:141
uint32_t eventErrors
int32_t UAVObjSave(UAVObjHandle obj_handle, uint16_t instId)
int32_t AlarmsSet(SystemAlarmsAlarmElem alarm, SystemAlarmsAlarmOptions severity)
Definition: alarms.c:97
uintptr_t pios_uavo_settings_fs_id
Definition: pios_board.c:50
static volatile uint32_t idleCounterClear
Definition: systemmod.c:135
static void systemPeriodicCb(const UAVObjEvent *ev, void *ctx, void *obj_data, int len)
Definition: systemmod.c:422
bool PIOS_Queue_Receive(struct pios_queue *queuep, void *itemp, uint32_t timeout_ms)
Definition: pios_queue.c:213
void TaskMonitorUpdateAll(void)
Definition: taskmonitor.c:116
#define HEAP_LIMIT_CRITICAL
uint32_t eventQueueErrors
void PIOS_ANNUNC_Off(uint32_t annunc_id)
#define IDLE_COUNTS_PER_SEC_AT_NO_LOAD
Definition: systemmod.c:75
void * PIOS_malloc_no_dma(size_t size)
Definition: pios_heap.c:166
void EventGetStats(EventStats *statsOut)
Definition: systemmod.c:859
Task monitoring library.
UAVObjHandle obj
uint32_t lastQueueErrorID
static PeriodicObjectList * objList
Definition: systemmod.c:130
void UAVObjGetStats(UAVObjStats *statsOut)
Utilities to validate a flight configuration.
uint16_t PIOS_WDG_GetBootupFlags()
Returns the flags that were set at bootup.
Definition: pios_wdg.c:125
int32_t EventPeriodicCallbackCreate(UAVObjEvent *ev, UAVObjEventCallback cb, uint16_t periodMs)
Definition: systemmod.c:884
#define PIOS_LED_ALARM
Definition: pios_board.h:86
uint16_t PIOS_WDG_GetActiveFlags()
Returns the currently active flags.
Definition: pios_wdg.c:137
void EventClearStats()
Definition: systemmod.c:869
void PIOS_Thread_ChangePriority(enum pios_thread_prio_e prio)
Definition: pios_thread.c:78
#define MAX_UPDATE_PERIOD_MS
Definition: systemmod.c:1008
struct pios_recursive_mutex * PIOS_Recursive_Mutex_Create(void)
Definition: pios_mutex.c:115
#define MODULE_HIPRI_INITCALL(ifn, sfn)
Definition: pios_initcall.h:66
void PIOS_ANNUNCDAC_SetValue(annuncdac_dev_t dev, bool active, bool value)
Set whether we should be beeping.
static void updateSystemAlarms()
Definition: systemmod.c:777
uint32_t UAVObjGetID(UAVObjHandle obj)
void system_task()
Definition: systemmod.c:223
#define SYSTEM_UPDATE_PERIOD_MS
Definition: systemmod.c:100
int actuator_send_dshot_command(uint8_t cmd_id, uint8_t num_to_send, uint16_t channel_mask)
Definition: actuator.c:170
#define CPULOAD_LIMIT_WARNING
bool PIOS_Recursive_Mutex_Lock(struct pios_recursive_mutex *mtx, uint32_t timeout_ms)
Definition: pios_mutex.c:139
#define LL_APPEND(head, add)
Definition: utlist.h:234
uint32_t randomize_int(uint32_t interval)
Definition: misc_math.c:340
int32_t SystemModStart(void)
Definition: systemmod.c:172
Event dispatcher, distributes object events as callbacks. Alternative to using tasks and queues...
#define CPULOAD_LIMIT_CRITICAL
#define IRQSTACK_LIMIT_WARNING
void PIOS_ANNUNC_On(uint32_t annunc_id)
int32_t configuration_check()
Definition: sanitycheck.c:84
struct pios_queue * queue
Definition: systemmod.c:113
int32_t TaskMonitorAdd(TaskInfoRunningElem task, struct pios_thread *threadp)
Definition: taskmonitor.c:67
uint8_t i
Definition: msp_messages.h:97
int32_t PIOS_SYS_Reset(void)
int32_t EventPeriodicQueueUpdate(UAVObjEvent *ev, struct pios_queue *queue, uint16_t periodMs)
Definition: systemmod.c:920
void systemmod_process_rgb_leds(bool led_override, bool led_override_active, uint8_t blink_prio, bool is_armed, bool force_dim)
int32_t EventPeriodicCallbackUpdate(UAVObjEvent *ev, UAVObjEventCallback cb, uint16_t periodMs)
Definition: systemmod.c:896
size_t PIOS_SYS_OsStackUnused(void)
#define DSHOT_CMD_BEACON3
Definition: pios_modules.h:66
#define PIOS_WDG_SYSTEM
Definition: pios_board.h:82
DONT_BUILD_IF(ANNUNCIATORSETTINGS_ANNUNCIATEAFTERARMING_NUMELEM!=ANNUNCIATORSETTINGS_ANNUNCIATEANYTIME_NUMELEM, AnnuncSettingsMismatch1)
static struct pios_thread * systemTaskHandle
Definition: systemmod.c:136
static const char *volatile custom_blink_string
Definition: systemmod.c:140
#define TASK_PRIORITY
Definition: systemmod.c:86
int32_t UAVObjDeleteById(uint32_t obj_id, uint16_t inst_id)
void(* UAVObjEventCallback)(const UAVObjEvent *ev, void *cb_ctx, void *uavo_data, int uavo_len)
void PIOS_Thread_Sleep(uint32_t time_ms)
Definition: pios_thread.c:229
int32_t SystemModInitialize(void)
Definition: systemmod.c:188
uint32_t offset
Definition: uavtalk_priv.h:51
struct PeriodicObjectListStruct * next
Definition: systemmod.c:123
int morse_send(const char **c, uint32_t *state)
Definition: morsel.c:212
static EventStats stats
Definition: systemmod.c:132
static void objectUpdatedCb(const UAVObjEvent *ev, void *ctx, void *obj, int len)
Definition: systemmod.c:634
tuple f
Definition: px_mkfw.py:81
static void updateStats()
Definition: systemmod.c:735
uint32_t eventCallbackErrors
static uint32_t processPeriodicUpdates()
Definition: systemmod.c:1014
UAVObjEventType event
bool PIOS_heap_malloc_failed_p(void)
Definition: pios_heap.c:47
Includes PiOS and core architecture components.
int32_t AlarmsClear(SystemAlarmsAlarmElem alarm)
Definition: alarms.c:171
size_t PIOS_SYS_IrqStackUnused(void)
UAVObjEvent ev
Definition: systemmod.c:111
int32_t UAVObjLoad(UAVObjHandle obj_handle, uint16_t instId)
void PIOS_IAP_WriteBootCount(uint16_t)
Definition: pios_iap.c:98
static struct pios_queue * queue
Definition: actuator.c:82
void system_annunc_custom_string(const char *string)
Definition: systemmod.c:417
static void configurationUpdatedCb(const UAVObjEvent *ev, void *ctx, void *obj, int len)
Definition: systemmod.c:707
EventCallbackInfo evInfo
Definition: systemmod.c:120
int32_t PIOS_FLASHFS_Format(uintptr_t fs_id)
Erases all filesystem arenas and activate the first arena.
static struct pios_queue * objectPersistenceQueue
Definition: systemmod.c:137
if(BaroAltitudeHandle()!=NULL)
struct annuncdac_dev_s * annuncdac_dev_t
struct ObjectEventEntryThrottled * throttle
#define PIOS_Assert(test)
Definition: pios_debug.h:52
bool PIOS_Recursive_Mutex_Unlock(struct pios_recursive_mutex *mtx)
Definition: pios_mutex.c:144
static int32_t eventPeriodicUpdate(UAVObjEvent *ev, UAVObjEventCallback cb, struct pios_queue *queue, uint16_t periodMs)
Definition: systemmod.c:978
#define PIOS_ANNUNCIATOR_BUZZER
Definition: pios_board.h:87
size_t PIOS_heap_get_free_size(void)
Definition: pios_heap.c:74
struct pios_thread * PIOS_Thread_WrapCurrentThread(const char *namep)
Creates a handle for the current thread.
Definition: pios_thread.c:51
static struct pios_recursive_mutex * mutex
Definition: systemmod.c:131
#define PIOS_MUTEX_TIMEOUT_MAX
Definition: pios_mutex.h:30
static volatile bool config_check_needed
Definition: systemmod.c:139
#define PIOS_LED_HEARTBEAT
Definition: pios_board.h:85