LCOV - code coverage report
Current view: top level - AP_HAL_SITL - HAL_SITL_Class.cpp (source / functions) Hit Total Coverage
Test: lcov.info Lines: 107 107 100.0 %
Date: 2026-09-09 11:02:08 Functions: 13 13 100.0 %

          Line data    Source code
       1             : #include <AP_HAL/AP_HAL.h>
       2             : 
       3             : #if CONFIG_HAL_BOARD == HAL_BOARD_SITL
       4             : 
       5             : #include <assert.h>
       6             : #include <errno.h>
       7             : #include <signal.h>
       8             : #include <stdio.h>
       9             : #include <sys/types.h>
      10             : #include <sys/stat.h>
      11             : #include <fcntl.h>
      12             : 
      13             : #include "AP_HAL_SITL.h"
      14             : #include "AP_HAL_SITL_Namespace.h"
      15             : #include "HAL_SITL_Class.h"
      16             : #include "Scheduler.h"
      17             : #include "AnalogIn.h"
      18             : #include "UARTDriver.h"
      19             : #include "I2CDevice.h"
      20             : #include "Storage.h"
      21             : #include "RCInput.h"
      22             : #include "RCOutput.h"
      23             : #include "GPIO.h"
      24             : #include "SITL_State.h"
      25             : #include "Util.h"
      26             : #include "DSP.h"
      27             : #include "CANSocketIface.h"
      28             : #include "SPIDevice.h"
      29             : 
      30             : #include <AP_BoardConfig/AP_BoardConfig.h>
      31             : #include <AP_HAL_Empty/AP_HAL_Empty.h>
      32             : #include <AP_HAL_Empty/AP_HAL_Empty_Private.h>
      33             : #include <AP_InternalError/AP_InternalError.h>
      34             : #include <AP_Logger/AP_Logger.h>
      35             : #include <AP_RCProtocol/AP_RCProtocol_config.h>
      36             : #include <AP_HAL/SIMState.h>
      37             : #include <AP_HAL/utility/Socket_native.h>
      38             : 
      39             : using namespace HALSITL;
      40             : 
      41             : HAL_SITL& hal_sitl = (HAL_SITL&)AP_HAL::get_HAL_mutable();
      42             : 
      43             : static Storage sitlStorage;
      44             : static SITL_State sitlState;
      45             : static Scheduler sitlScheduler(&sitlState);
      46             : #if AP_RCPROTOCOL_ENABLED
      47             : static RCInput sitlRCInput;
      48             : #else
      49             : static Empty::RCInput  sitlRCInput;
      50             : #endif
      51             : static RCOutput sitlRCOutput(&sitlState);
      52             : static GPIO sitlGPIO(&sitlState);
      53             : static AnalogIn sitlAnalogIn(&sitlState);
      54             : 
      55             : #if AP_SIM_ENABLED
      56             : static AP_HAL::SIMState xsimstate;
      57             : #endif
      58             : 
      59             : #if HAL_WITH_DSP
      60             : static DSP dspDriver;
      61             : #endif
      62             : 
      63             : 
      64             : // use the Empty HAL for hardware we don't emulate
      65             : static Empty::OpticalFlow emptyOpticalFlow;
      66             : static Empty::Flash emptyFlash;
      67             : 
      68             : static UARTDriver sitlSerial0Driver(0, &sitlState);
      69             : static UARTDriver sitlSerial1Driver(1, &sitlState);
      70             : static UARTDriver sitlSerial2Driver(2, &sitlState);
      71             : static UARTDriver sitlSerial3Driver(3, &sitlState);
      72             : static UARTDriver sitlSerial4Driver(4, &sitlState);
      73             : static UARTDriver sitlSerial5Driver(5, &sitlState);
      74             : static UARTDriver sitlSerial6Driver(6, &sitlState);
      75             : static UARTDriver sitlSerial7Driver(7, &sitlState);
      76             : static UARTDriver sitlSerial8Driver(8, &sitlState);
      77             : static UARTDriver sitlSerial9Driver(9, &sitlState);
      78             : 
      79             : static I2CDeviceManager i2c_mgr_instance;
      80             : 
      81             : #if defined(HAL_BUILD_AP_PERIPH)
      82             : static Empty::SPIDeviceManager spi_mgr_instance;
      83             : #else
      84             : static SPIDeviceManager spi_mgr_instance;
      85             : #endif
      86             : static Util utilInstance(&sitlState);
      87             : 
      88             : #if HAL_NUM_CAN_IFACES
      89             : static HALSITL::CANIface* canDrivers[HAL_NUM_CAN_IFACES];
      90             : #endif
      91             : 
      92             : static Empty::WSPIDeviceManager wspi_mgr_instance;
      93             : 
      94        2145 : HAL_SITL::HAL_SITL() :
      95             :     AP_HAL::HAL(
      96             :         &sitlSerial0Driver,
      97             :         &sitlSerial1Driver,
      98             :         &sitlSerial2Driver,
      99             :         &sitlSerial3Driver,
     100             :         &sitlSerial4Driver,
     101             :         &sitlSerial5Driver,
     102             :         &sitlSerial6Driver,
     103             :         &sitlSerial7Driver,
     104             :         &sitlSerial8Driver,
     105             :         &sitlSerial9Driver,
     106             :         &i2c_mgr_instance,
     107             :         &spi_mgr_instance,  /* spi */
     108             :         &wspi_mgr_instance,
     109             :         &sitlAnalogIn,      /* analogin */
     110             :         &sitlStorage, /* storage */
     111             :         &sitlSerial0Driver, /* console */
     112             :         &sitlGPIO,          /* gpio */
     113             :         &sitlRCInput,       /* rcinput */
     114             :         &sitlRCOutput,      /* rcoutput */
     115             :         &sitlScheduler,     /* scheduler */
     116             :         &utilInstance,      /* util */
     117             :         &emptyOpticalFlow,  /* onboard optical flow */
     118             :         &emptyFlash,        /* flash driver */
     119             : #if AP_SIM_ENABLED
     120             : &xsimstate,
     121             : #endif
     122             : #if HAL_WITH_DSP
     123             :         &dspDriver,         /* dsp driver */
     124             : #endif
     125             : #if HAL_NUM_CAN_IFACES
     126             :         (AP_HAL::CANIface**)canDrivers
     127             : #else
     128             :         nullptr
     129             : #endif
     130             :         ),           /* CAN */
     131        2145 :     _sitl_state(&sitlState)
     132        2145 : {}
     133             : 
     134             : static char *new_argv[100];
     135             : 
     136             : /*
     137             :   save watchdog data
     138             :  */
     139         424 : static bool watchdog_save(const uint32_t *data, uint32_t nwords)
     140             : {
     141         424 :     int fd = ::open("persistent.dat.tmp", O_WRONLY|O_CREAT|O_TRUNC, 0644);
     142         424 :     bool ret = false;
     143         424 :     if (fd != -1) {
     144         424 :         if (::write(fd, data, nwords*4) == (ssize_t)(nwords*4)) {
     145         424 :             ret = true;
     146             :         }
     147         424 :         ::close(fd);
     148             :     }
     149         424 :     if (ret) {
     150         424 :         ret = ::rename("persistent.dat.tmp", "persistent.dat") == 0;
     151             :     }
     152         424 :     return ret;
     153             : }
     154             : 
     155             : /*
     156             :   load watchdog data
     157             :  */
     158           1 : static bool watchdog_load(uint32_t *data, uint32_t nwords)
     159             : {
     160           1 :     int fd = ::open("persistent.dat", O_RDONLY, 0644);
     161           1 :     bool ret = false;
     162           1 :     if (fd != -1) {
     163           1 :         ret = (::read(fd, data, nwords*4) == (ssize_t)(nwords*4));
     164           1 :         ::close(fd);
     165             :     }
     166           1 :     return ret;
     167             : }
     168             : 
     169             : /*
     170             :   implement watchdoh reset via SIGALRM
     171             :  */
     172           1 : static void sig_alrm(int signum)
     173             : {
     174             :     static char env[] = "SITL_WATCHDOG_RESET=1";
     175           1 :     putenv(env);
     176           1 :     printf("GOT SIGALRM\n");
     177           1 :     SocketAPM_native::cleanup_unix_paths();
     178           1 :     execv(new_argv[0], new_argv);
     179           1 : }
     180             : 
     181         454 : void HAL_SITL::exit_signal_handler(int signum)
     182             : {
     183         454 :     HALSITL::Scheduler::_should_exit = true;
     184         454 : }
     185             : 
     186        2086 : void HAL_SITL::setup_signal_handlers() const
     187             : {
     188        2086 :     struct sigaction sa = { };
     189             : 
     190        2086 :     sa.sa_flags = SA_NOCLDSTOP;
     191        2086 :     sa.sa_handler = HAL_SITL::exit_signal_handler;
     192        2086 :     sigaction(SIGTERM, &sa, NULL);
     193             : #if defined(HAL_COVERAGE_BUILD) && HAL_COVERAGE_BUILD == 1
     194        2086 :     sigaction(SIGINT, &sa, NULL);
     195        2086 :     sigaction(SIGHUP, &sa, NULL);
     196        2086 :     sigaction(SIGQUIT, &sa, NULL);
     197             : #endif
     198             : 
     199        2086 : }
     200             : 
     201             : /*
     202             :   fill 8k of stack with NaN. This allows us to find uses of
     203             :   uninitialised memory without valgrind
     204             :  */
     205     4171669 : static void fill_stack_nan(void)
     206             : {
     207             :     float stk[2048];
     208     4171669 :     fill_nanf(stk, ARRAY_SIZE(stk));
     209     4171669 : }
     210             : 
     211           6 : uint8_t HAL_SITL::get_instance() const
     212             : {
     213           6 :     return _sitl_state->get_instance();
     214             : }
     215             : 
     216             : #if defined(HAL_BUILD_AP_PERIPH)
     217             : bool HAL_SITL::run_in_maintenance_mode() const
     218             : {
     219             :     return _sitl_state->run_in_maintenance_mode();
     220             : }
     221             : #endif
     222             : 
     223   187275482 : uint32_t HAL_SITL::get_uart_output_full_queue_count() const
     224             : {
     225   187275482 :     return _sitl_state->_serial_0_outqueue_full_count;
     226             : }
     227             : 
     228        2094 : void HAL_SITL::run(int argc, char * const argv[], Callbacks* callbacks) const
     229             : {
     230        2094 :     assert(callbacks);
     231             : 
     232        2094 :     utilInstance.init(argc, argv);
     233        2094 :     _sitl_state->init(argc, argv);
     234             : 
     235        2094 :     scheduler->init();
     236        2094 :     serial(0)->begin(115200);
     237             : 
     238        2094 :     rcin->init();
     239        2094 :     rcout->init();
     240             : 
     241             :     // spi->init();
     242        2094 :     analogin->init();
     243             : 
     244        2094 :     if (getenv("SITL_WATCHDOG_RESET")) {
     245           1 :         INTERNAL_ERROR(AP_InternalError::error_t::watchdog_reset);
     246           1 :         if (watchdog_load((uint32_t *)&utilInstance.persistent_data, (sizeof(utilInstance.persistent_data)+3)/4)) {
     247           1 :             serial(0)->printf("Loaded watchdog data");
     248           1 :             utilInstance.last_persistent_data = utilInstance.persistent_data;
     249             :         }
     250             :     }
     251             : 
     252             :     // form a new argv, removing problem parameters. This is used for reboot
     253        2094 :     uint8_t new_argv_offset = 0;
     254       19586 :     for (uint8_t i=0; i<ARRAY_SIZE(new_argv) && i<argc; i++) {
     255       17492 :         if (!strcmp(argv[i], "-w")) {
     256             :             // don't wipe params on reboot
     257         294 :             continue;
     258             :         }
     259       17198 :         new_argv[new_argv_offset++] = argv[i];
     260             :     }
     261             :     
     262        2094 :     fill_stack_nan();
     263             : 
     264        2094 :     callbacks->setup();
     265        2086 :     scheduler->set_system_initialized();
     266             : 
     267             : #if HAL_LOGGING_ENABLED
     268        2086 :     if (getenv("SITL_WATCHDOG_RESET")) {
     269           1 :         const AP_HAL::Util::PersistentData &pd = util->persistent_data;
     270           2 :         AP::logger().WriteCritical("WDOG", "TimeUS,Task,IErr,IErrCnt,IErrLn,MavMsg,MavCmd,SemLine", "QbIHHHHH",
     271             :                                    AP_HAL::micros64(),
     272           1 :                                    pd.scheduler_task,
     273           1 :                                    pd.internal_errors,
     274           1 :                                    pd.internal_error_count,
     275           1 :                                    pd.internal_error_last_line,
     276           1 :                                    pd.last_mavlink_msgid,
     277           1 :                                    pd.last_mavlink_cmd,
     278           1 :                                    pd.semaphore_line);
     279             :     }
     280             : #endif
     281             : 
     282        2086 :     bool using_watchdog = AP_BoardConfig::watchdog_enabled();
     283        2086 :     if (using_watchdog) {
     284           3 :         signal(SIGALRM, sig_alrm);
     285           3 :         alarm(2);
     286             :     }
     287        2086 :     setup_signal_handlers();
     288             : 
     289        2086 :     uint32_t last_watchdog_save = AP_HAL::millis();
     290        2086 :     uint8_t fill_count = 0;
     291             : 
     292             :     while (true) {
     293    41686708 :         if (HALSITL::Scheduler::_should_exit) {
     294         454 :             ::fprintf(stderr, "Exitting\n");
     295         454 :             exit(0);
     296             :         }
     297    41686254 :         if (fill_count++ % 10 == 0) {
     298             :             // only fill every 10 loops. This still gives us a lot of
     299             :             // protection, but saves a lot of CPU
     300     4169575 :             fill_count = 1u;
     301     4169575 :             fill_stack_nan();
     302             :         }
     303    41686254 :         callbacks->loop();
     304    41684622 :         HALSITL::Scheduler::_run_io_procs();
     305             : 
     306    41684622 :         uint32_t now = AP_HAL::millis();
     307    41684622 :         if (now - last_watchdog_save >= 100 && using_watchdog) {
     308             :             // save persistent data every 100ms
     309         424 :             last_watchdog_save = now;
     310         424 :             watchdog_save((uint32_t *)&utilInstance.persistent_data, (sizeof(utilInstance.persistent_data)+3)/4);
     311             :         }
     312             : 
     313    41684622 :         if (using_watchdog) {
     314             :             // note that this only works for a speedup of 1
     315        2137 :             alarm(2);
     316             :         }
     317    41684622 :     }
     318             : 
     319             :     actually_reboot();
     320             : }
     321             : 
     322        1639 : void HAL_SITL::actually_reboot()
     323             : {
     324        1639 :     SocketAPM_native::cleanup_unix_paths();
     325        1639 :     execv(new_argv[0], new_argv);
     326        1639 :     AP_HAL::panic("PANIC: REBOOT FAILED: %s", strerror(errno));
     327             : }
     328             : 
     329             : static HAL_SITL hal_sitl_inst;
     330             : 
     331        2137 : const AP_HAL::HAL& AP_HAL::get_HAL() {
     332        2137 :     return hal_sitl_inst;
     333             : }
     334             : 
     335        4239 : AP_HAL::HAL& AP_HAL::get_HAL_mutable() {
     336        4239 :     return hal_sitl_inst;
     337             : }
     338             : 
     339             : #endif  // CONFIG_HAL_BOARD == HAL_BOARD_SITL

Generated by: LCOV version 1.14