2019-01-18 00:23:42 -04:00
# include "AP_Logger.h"
2015-06-25 10:53:20 -03:00
2019-01-18 00:23:42 -04:00
# include "AP_Logger_Backend.h"
2015-08-06 09:18:28 -03:00
2019-01-18 00:23:42 -04:00
# include "AP_Logger_File.h"
2019-01-18 18:45:36 -04:00
# include "AP_Logger_SITL.h"
# include "AP_Logger_DataFlash.h"
2019-01-18 00:23:42 -04:00
# include "AP_Logger_MAVLink.h"
2018-08-07 07:22:21 -03:00
# include <AP_InternalError/AP_InternalError.h>
2017-06-12 10:05:02 -03:00
# include <GCS_MAVLink/GCS.h>
2020-06-06 07:59:50 -03:00
# include <AP_BoardConfig/AP_BoardConfig.h>
2017-03-29 22:08:24 -03:00
2019-02-10 14:05:22 -04:00
AP_Logger * AP_Logger : : _singleton ;
2016-05-03 03:33:15 -03:00
2016-08-02 02:08:07 -03:00
extern const AP_HAL : : HAL & hal ;
2019-01-20 00:03:20 -04:00
# ifndef HAL_LOGGING_FILE_BUFSIZE
2020-11-07 23:55:57 -04:00
# if HAL_MEM_CLASS >= HAL_MEM_CLASS_1000
# define HAL_LOGGING_FILE_BUFSIZE 200
# elif HAL_MEM_CLASS >= HAL_MEM_CLASS_500
# define HAL_LOGGING_FILE_BUFSIZE 80
# elif HAL_MEM_CLASS >= HAL_MEM_CLASS_300
2019-09-22 19:52:01 -03:00
# define HAL_LOGGING_FILE_BUFSIZE 50
# else
2019-01-20 00:03:20 -04:00
# define HAL_LOGGING_FILE_BUFSIZE 16
2019-09-22 19:52:01 -03:00
# endif
# endif
2018-06-09 18:43:50 -03:00
2020-12-22 13:25:44 -04:00
# ifndef HAL_LOGGING_STACK_SIZE
2021-04-14 17:24:37 -03:00
# define HAL_LOGGING_STACK_SIZE 1324
2020-12-22 13:25:44 -04:00
# endif
2019-01-20 00:03:20 -04:00
# ifndef HAL_LOGGING_MAV_BUFSIZE
# define HAL_LOGGING_MAV_BUFSIZE 8
2018-06-09 18:43:50 -03:00
# endif
2019-08-03 04:00:17 -03:00
# ifndef HAL_LOGGING_FILE_TIMEOUT
# define HAL_LOGGING_FILE_TIMEOUT 5
# endif
2019-06-10 18:55:30 -03:00
// by default log for 15 seconds after disarming
# ifndef HAL_LOGGER_ARM_PERSIST
# define HAL_LOGGER_ARM_PERSIST 15
# endif
2019-01-20 00:03:20 -04:00
# ifndef HAL_LOGGING_BACKENDS_DEFAULT
2021-01-06 22:04:09 -04:00
# if HAL_LOGGING_DATAFLASH_ENABLED
2019-02-28 21:23:55 -04:00
# define HAL_LOGGING_BACKENDS_DEFAULT Backend_Type::BLOCK
2021-01-06 22:04:09 -04:00
# elif HAL_LOGGING_FILESYSTEM_ENABLED
2019-02-28 21:23:55 -04:00
# define HAL_LOGGING_BACKENDS_DEFAULT Backend_Type::FILESYSTEM
2021-01-06 22:04:09 -04:00
# elif HAL_LOGGING_MAVLINK_ENABLED
# define HAL_LOGGING_BACKENDS_DEFAULT Backend_Type::MAVLINK
# else
# define HAL_LOGGING_BACKENDS_DEFAULT 0
2019-01-20 00:03:20 -04:00
# endif
# endif
2019-01-18 00:23:42 -04:00
const AP_Param : : GroupInfo AP_Logger : : var_info [ ] = {
2015-12-07 18:35:18 -04:00
// @Param: _BACKEND_TYPE
2019-01-18 00:23:42 -04:00
// @DisplayName: AP_Logger Backend Storage type
2019-01-21 12:55:00 -04:00
// @Description: Bitmap of what Logger backend types to enable. Block-based logging is available on SITL and boards with dataflash chips. Multiple backends can be selected.
2019-01-18 18:45:36 -04:00
// @Bitmask: 0:File,1:MAVLink,2:Block
2015-11-09 18:14:22 -04:00
// @User: Standard
2019-02-28 21:23:55 -04:00
AP_GROUPINFO ( " _BACKEND_TYPE " , 0 , AP_Logger , _params . backend_types , uint8_t ( HAL_LOGGING_BACKENDS_DEFAULT ) ) ,
2015-12-03 07:01:53 -04:00
// @Param: _FILE_BUFSIZE
2020-05-05 14:00:54 -03:00
// @DisplayName: Maximum AP_Logger File and Block Backend buffer size (in kilobytes)
// @Description: The File and Block backends use a buffer to store data before writing to the block device. Raising this value may reduce "gaps" in your SD card logging. This buffer size may be reduced depending on available memory. PixHawk requires at least 4 kilobytes. Maximum value available here is 64 kilobytes.
2015-12-03 07:01:53 -04:00
// @User: Standard
2019-01-20 00:03:20 -04:00
AP_GROUPINFO ( " _FILE_BUFSIZE " , 1 , AP_Logger , _params . file_bufsize , HAL_LOGGING_FILE_BUFSIZE ) ,
2015-12-03 07:01:53 -04:00
2016-05-08 23:00:55 -03:00
// @Param: _DISARMED
// @DisplayName: Enable logging while disarmed
// @Description: If LOG_DISARMED is set to 1 then logging will be enabled while disarmed. This can make for very large logfiles but can help a lot when tracking down startup issues
2016-05-12 14:54:51 -03:00
// @Values: 0:Disabled,1:Enabled
2016-05-08 23:00:55 -03:00
// @User: Standard
2019-01-18 00:23:42 -04:00
AP_GROUPINFO ( " _DISARMED " , 2 , AP_Logger , _params . log_disarmed , 0 ) ,
2016-05-08 23:00:55 -03:00
// @Param: _REPLAY
// @DisplayName: Enable logging of information needed for Replay
// @Description: If LOG_REPLAY is set to 1 then the EKF2 state estimator will log detailed information needed for diagnosing problems with the Kalman filter. It is suggested that you also raise LOG_FILE_BUFSIZE to give more buffer space for logging and use a high quality microSD card to ensure no sensor data is lost
2016-05-12 14:54:51 -03:00
// @Values: 0:Disabled,1:Enabled
2016-05-08 23:00:55 -03:00
// @User: Standard
2019-01-18 00:23:42 -04:00
AP_GROUPINFO ( " _REPLAY " , 3 , AP_Logger , _params . log_replay , 0 ) ,
2016-07-28 02:58:20 -03:00
// @Param: _FILE_DSRMROT
// @DisplayName: Stop logging to current file on disarm
2020-05-05 14:00:54 -03:00
// @Description: When set, the current log file is closed when the vehicle is disarmed. If LOG_DISARMED is set then a fresh log will be opened. Applies to the File and Block logging backends.
2016-07-28 02:58:20 -03:00
// @Values: 0:Disabled,1:Enabled
// @User: Standard
2019-01-18 00:23:42 -04:00
AP_GROUPINFO ( " _FILE_DSRMROT " , 4 , AP_Logger , _params . file_disarm_rot , 0 ) ,
2016-07-28 02:58:20 -03:00
2021-05-19 23:34:13 -03:00
# if HAL_LOGGING_MAVLINK_ENABLED
2018-04-23 01:35:29 -03:00
// @Param: _MAV_BUFSIZE
2019-01-18 00:23:42 -04:00
// @DisplayName: Maximum AP_Logger MAVLink Backend buffer size
// @Description: Maximum amount of memory to allocate to AP_Logger-over-mavlink
2018-04-23 01:35:29 -03:00
// @User: Advanced
// @Units: kB
2019-01-20 00:03:20 -04:00
AP_GROUPINFO ( " _MAV_BUFSIZE " , 5 , AP_Logger , _params . mav_bufsize , HAL_LOGGING_MAV_BUFSIZE ) ,
2021-05-19 23:34:13 -03:00
# endif
2018-04-23 01:35:29 -03:00
2019-08-03 04:00:17 -03:00
// @Param: _FILE_TIMEOUT
// @DisplayName: Timeout before giving up on file writes
// @Description: This controls the amount of time before failing writes to a log file cause the file to be closed and logging stopped.
// @User: Standard
// @Units: s
AP_GROUPINFO ( " _FILE_TIMEOUT " , 6 , AP_Logger , _params . file_timeout , HAL_LOGGING_FILE_TIMEOUT ) ,
2020-06-01 17:07:07 -03:00
// @Param: _FILE_MB_FREE
// @DisplayName: Old logs on the SD card will be deleted to maintain this amount of free space
// @Description: Set this such that the free space is larger than your largest typical flight log
// @Units: MB
// @Range: 10 1000
// @User: Standard
AP_GROUPINFO ( " _FILE_MB_FREE " , 7 , AP_Logger , _params . min_MB_free , 500 ) ,
2015-11-09 18:14:22 -04:00
AP_GROUPEND
} ;
2017-11-14 20:02:56 -04:00
# define streq(x, y) (!strcmp(x, y))
2019-01-18 00:23:42 -04:00
AP_Logger : : AP_Logger ( const AP_Int32 & log_bitmask )
2018-06-12 00:34:00 -03:00
: _log_bitmask ( log_bitmask )
2017-08-23 17:40:59 -03:00
{
AP_Param : : setup_object_defaults ( this , var_info ) ;
2019-02-10 14:05:22 -04:00
if ( _singleton ! = nullptr ) {
2019-01-18 00:23:42 -04:00
AP_HAL : : panic ( " AP_Logger must be singleton " ) ;
2017-08-23 17:40:59 -03:00
}
2019-02-10 14:05:22 -04:00
_singleton = this ;
2017-08-23 17:40:59 -03:00
}
2019-01-18 00:23:42 -04:00
void AP_Logger : : Init ( const struct LogStructure * structures , uint8_t num_types )
2017-03-29 22:08:24 -03:00
{
2020-11-07 23:55:57 -04:00
// convert from 8 bit to 16 bit LOG_FILE_BUFSIZE
_params . file_bufsize . convert_parameter_width ( AP_PARAM_INT8 ) ;
2019-04-19 22:26:05 -03:00
if ( hal . util - > was_watchdog_armed ( ) ) {
2021-05-19 23:34:13 -03:00
GCS_SEND_TEXT ( MAV_SEVERITY_INFO , " Forcing logging for watchdog reset " ) ;
2019-04-19 22:26:05 -03:00
_params . log_disarmed . set ( 1 ) ;
}
2015-12-07 20:21:18 -04:00
# if CONFIG_HAL_BOARD == HAL_BOARD_SITL
validate_structures ( structures , num_types ) ;
dump_structures ( structures , num_types ) ;
# endif
2019-02-11 04:38:01 -04:00
if ( _next_backend = = LOGGER_MAX_BACKENDS ) {
2017-03-29 22:08:24 -03:00
AP_HAL : : panic ( " Too many backends " ) ;
return ;
}
_num_types = num_types ;
_structures = structures ;
2021-01-06 22:04:09 -04:00
# if HAL_LOGGING_FILESYSTEM_ENABLED
2019-02-28 21:23:55 -04:00
if ( _params . backend_types & uint8_t ( Backend_Type : : FILESYSTEM ) ) {
2019-01-18 00:23:42 -04:00
LoggerMessageWriter_DFLogStart * message_writer =
new LoggerMessageWriter_DFLogStart ( ) ;
2017-03-29 22:08:24 -03:00
if ( message_writer ! = nullptr ) {
2019-01-18 00:23:42 -04:00
backends [ _next_backend ] = new AP_Logger_File ( * this ,
2017-03-29 22:08:24 -03:00
message_writer ,
HAL_BOARD_LOG_DIRECTORY ) ;
}
if ( backends [ _next_backend ] = = nullptr ) {
2019-01-18 00:23:42 -04:00
hal . console - > printf ( " Unable to open AP_Logger_File " ) ;
2020-03-11 18:24:13 -03:00
// note that message_writer is leaked here; costs several
// hundred bytes to fix for marginal utility
2017-03-29 22:08:24 -03:00
} else {
_next_backend + + ;
}
}
2021-01-06 22:04:09 -04:00
# endif // HAL_LOGGING_FILESYSTEM_ENABLED
2018-02-02 16:35:19 -04:00
2021-01-06 22:04:09 -04:00
# if HAL_LOGGING_DATAFLASH_ENABLED
2019-12-15 18:08:10 -04:00
if ( _params . backend_types & uint8_t ( Backend_Type : : BLOCK ) ) {
2019-02-11 04:38:01 -04:00
if ( _next_backend = = LOGGER_MAX_BACKENDS ) {
2019-01-18 18:45:36 -04:00
AP_HAL : : panic ( " Too many backends " ) ;
return ;
}
2019-01-18 00:23:42 -04:00
LoggerMessageWriter_DFLogStart * message_writer =
new LoggerMessageWriter_DFLogStart ( ) ;
2018-02-02 16:35:19 -04:00
if ( message_writer ! = nullptr ) {
2019-12-15 18:08:10 -04:00
backends [ _next_backend ] = new AP_Logger_DataFlash ( * this , message_writer ) ;
2018-02-02 16:35:19 -04:00
}
if ( backends [ _next_backend ] = = nullptr ) {
2019-12-15 18:08:10 -04:00
hal . console - > printf ( " Unable to open AP_Logger_DataFlash " ) ;
2020-03-11 18:24:13 -03:00
// note that message_writer is leaked here; costs several
// hundred bytes to fix for marginal utility
2018-02-02 16:35:19 -04:00
} else {
_next_backend + + ;
}
}
2019-01-18 18:45:36 -04:00
# endif
2017-03-29 22:08:24 -03:00
2021-01-06 22:04:09 -04:00
# if HAL_LOGGING_SITL_ENABLED
2019-02-28 21:23:55 -04:00
if ( _params . backend_types & uint8_t ( Backend_Type : : BLOCK ) ) {
2019-02-11 04:38:01 -04:00
if ( _next_backend = = LOGGER_MAX_BACKENDS ) {
2017-03-29 22:08:24 -03:00
AP_HAL : : panic ( " Too many backends " ) ;
return ;
}
2019-01-18 00:23:42 -04:00
LoggerMessageWriter_DFLogStart * message_writer =
new LoggerMessageWriter_DFLogStart ( ) ;
2017-03-29 22:08:24 -03:00
if ( message_writer ! = nullptr ) {
2019-01-18 18:45:36 -04:00
backends [ _next_backend ] = new AP_Logger_SITL ( * this , message_writer ) ;
2017-03-29 22:08:24 -03:00
}
if ( backends [ _next_backend ] = = nullptr ) {
2019-01-18 18:45:36 -04:00
hal . console - > printf ( " Unable to open AP_Logger_SITL " ) ;
2020-03-11 18:24:13 -03:00
// note that message_writer is leaked here; costs several
// hundred bytes to fix for marginal utility
2017-03-29 22:08:24 -03:00
} else {
_next_backend + + ;
}
}
# endif
2019-12-15 18:08:10 -04:00
// the "main" logging type needs to come before mavlink so that index 0 is correct
2021-01-06 22:04:09 -04:00
# if HAL_LOGGING_MAVLINK_ENABLED
2019-12-15 18:08:10 -04:00
if ( _params . backend_types & uint8_t ( Backend_Type : : MAVLINK ) ) {
2019-02-11 04:38:01 -04:00
if ( _next_backend = = LOGGER_MAX_BACKENDS ) {
2019-01-18 18:45:36 -04:00
AP_HAL : : panic ( " Too many backends " ) ;
return ;
}
LoggerMessageWriter_DFLogStart * message_writer =
new LoggerMessageWriter_DFLogStart ( ) ;
if ( message_writer ! = nullptr ) {
2019-12-15 18:08:10 -04:00
backends [ _next_backend ] = new AP_Logger_MAVLink ( * this ,
message_writer ) ;
2019-01-18 18:45:36 -04:00
}
if ( backends [ _next_backend ] = = nullptr ) {
2019-12-15 18:08:10 -04:00
hal . console - > printf ( " Unable to open AP_Logger_MAVLink " ) ;
2020-03-11 18:24:13 -03:00
// note that message_writer is leaked here; costs several
// hundred bytes to fix for marginal utility
2019-01-18 18:45:36 -04:00
} else {
_next_backend + + ;
}
}
# endif
2019-12-15 18:08:10 -04:00
2017-03-29 22:08:24 -03:00
for ( uint8_t i = 0 ; i < _next_backend ; i + + ) {
backends [ i ] - > Init ( ) ;
}
2017-06-12 10:05:02 -03:00
2020-12-22 13:25:44 -04:00
start_io_thread ( ) ;
2017-06-14 22:21:17 -03:00
EnableWrites ( true ) ;
2017-03-29 22:08:24 -03:00
}
2015-12-07 20:21:18 -04:00
# if CONFIG_HAL_BOARD == HAL_BOARD_SITL
# include <stdio.h>
# define DEBUG_LOG_STRUCTURES 0
extern const AP_HAL : : HAL & hal ;
2019-07-04 22:03:10 -03:00
# define Debug(fmt, args ...) do {::fprintf(stderr, "%s:%d: " fmt "\n", __FUNCTION__, __LINE__, ## args); } while(0)
2015-12-07 20:21:18 -04:00
/// return the number of commas present in string
static uint8_t count_commas ( const char * string )
{
uint8_t ret = 0 ;
for ( uint8_t i = 0 ; i < strlen ( string ) ; i + + ) {
if ( string [ i ] = = ' , ' ) {
ret + + ;
}
}
return ret ;
}
2015-12-07 20:21:18 -04:00
/// return a unit name given its ID
2019-01-18 00:23:42 -04:00
const char * AP_Logger : : unit_name ( const uint8_t unit_id )
2015-12-07 20:21:18 -04:00
{
2020-01-02 20:11:01 -04:00
for ( uint8_t i = 0 ; i < unit_id ; i + + ) {
2015-12-07 20:21:18 -04:00
if ( _units [ i ] . ID = = unit_id ) {
return _units [ i ] . unit ;
}
}
return NULL ;
}
/// return a multiplier value given its ID
2019-01-18 00:23:42 -04:00
double AP_Logger : : multiplier_name ( const uint8_t multiplier_id )
2015-12-07 20:21:18 -04:00
{
2020-01-02 20:11:01 -04:00
for ( uint8_t i = 0 ; i < multiplier_id ; i + + ) {
2015-12-07 20:21:18 -04:00
if ( _multipliers [ i ] . ID = = multiplier_id ) {
return _multipliers [ i ] . multiplier ;
}
}
// Should we abort here?
return 1.0f ;
}
2015-12-07 20:21:18 -04:00
/// pretty-print field information from a log structure
2019-01-18 00:23:42 -04:00
void AP_Logger : : dump_structure_field ( const struct LogStructure * logstructure , const char * label , const uint8_t fieldnum )
2015-12-07 20:21:18 -04:00
{
2015-12-07 20:21:18 -04:00
: : fprintf ( stderr , " %s (%s)*(%f) \n " , label , unit_name ( logstructure - > units [ fieldnum ] ) , multiplier_name ( logstructure - > multipliers [ fieldnum ] ) ) ;
2015-12-07 20:21:18 -04:00
}
/// pretty-print log structures
/// @note structures MUST be well-formed
2019-01-18 00:23:42 -04:00
void AP_Logger : : dump_structures ( const struct LogStructure * logstructures , const uint8_t num_types )
2015-12-07 20:21:18 -04:00
{
# if DEBUG_LOG_STRUCTURES
for ( uint16_t i = 0 ; i < num_types ; i + + ) {
2017-06-14 07:22:18 -03:00
const struct LogStructure * logstructure = & logstructures [ i ] ;
: : fprintf ( stderr , " %s \n " , logstructure - > name ) ;
2015-12-07 20:21:18 -04:00
char label [ 32 ] = { } ;
uint8_t labeloffset = 0 ;
int8_t fieldnum = 0 ;
2017-06-14 07:22:18 -03:00
for ( uint8_t j = 0 ; j < strlen ( logstructure - > labels ) ; j + + ) {
char labelchar = logstructure - > labels [ j ] ;
2015-12-07 20:21:18 -04:00
if ( labelchar = = ' \0 ' ) {
break ;
}
if ( labelchar = = ' , ' ) {
2017-06-14 07:22:18 -03:00
dump_structure_field ( logstructure , label , fieldnum ) ;
2015-12-07 20:21:18 -04:00
fieldnum + + ;
labeloffset = 0 ;
memset ( label , ' \0 ' , 32 ) ;
} else {
label [ labeloffset + + ] = labelchar ;
}
}
2017-06-14 07:22:18 -03:00
dump_structure_field ( logstructure , label , fieldnum ) ;
2015-12-07 20:21:18 -04:00
: : fprintf ( stderr , " \n " ) ; // just add a CR to the output
}
# endif
}
2020-04-07 02:16:51 -03:00
bool AP_Logger : : labels_string_is_good ( const char * labels ) const
{
2020-06-06 07:59:50 -03:00
bool passed = true ;
if ( strlen ( labels ) > = LS_LABELS_SIZE ) {
Debug ( " Labels string too long (%u > %u) " , unsigned ( strlen ( labels ) ) , unsigned ( LS_LABELS_SIZE ) ) ;
passed = false ;
}
2020-04-07 02:16:51 -03:00
// This goes through and slices labels up into substrings by
// changing commas to nulls - keeping references to each string in
// label_offsets.
char * label_offsets [ LS_LABELS_SIZE ] ;
uint8_t label_offsets_offset = 0 ;
2020-09-07 05:30:05 -03:00
char labels_copy [ LS_LABELS_SIZE + 1 ] { } ;
strncpy ( labels_copy , labels , LS_LABELS_SIZE ) ;
2020-04-07 02:16:51 -03:00
if ( labels_copy [ 0 ] = = ' , ' ) {
Debug ( " Leading comma in (%s) " , labels ) ;
passed = false ;
}
label_offsets [ label_offsets_offset + + ] = labels_copy ;
2020-09-07 05:30:05 -03:00
const uint8_t len = strnlen ( labels_copy , LS_LABELS_SIZE ) ;
2020-04-07 02:16:51 -03:00
for ( uint8_t i = 0 ; i < len ; i + + ) {
if ( labels_copy [ i ] = = ' , ' ) {
if ( labels_copy [ i + 1 ] = = ' \0 ' ) {
Debug ( " Trailing comma in (%s) " , labels ) ;
passed = false ;
continue ;
}
labels_copy [ i ] = ' \0 ' ;
label_offsets [ label_offsets_offset + + ] = & labels_copy [ i + 1 ] ;
}
}
for ( uint8_t i = 0 ; i < label_offsets_offset - 1 ; i + + ) {
for ( uint8_t j = i + 1 ; j < label_offsets_offset ; j + + ) {
if ( ! strcmp ( label_offsets [ i ] , label_offsets [ j ] ) ) {
Debug ( " Duplicate label (%s) in (%s) " , label_offsets [ i ] , labels ) ;
passed = false ;
}
}
}
return passed ;
}
2019-01-18 00:23:42 -04:00
bool AP_Logger : : validate_structure ( const struct LogStructure * logstructure , const int16_t offset )
2015-12-07 20:21:18 -04:00
{
bool passed = true ;
# if DEBUG_LOG_STRUCTURES
2018-06-15 06:57:28 -03:00
Debug ( " offset=%d ID=%d NAME=%s " , offset , logstructure - > msg_type , logstructure - > name ) ;
2015-12-07 20:21:18 -04:00
# endif
2018-02-22 20:06:45 -04:00
// fields must be null-terminated
# define CHECK_ENTRY(fieldname,fieldname_s,fieldlen) \
do { \
if ( strnlen ( logstructure - > fieldname , fieldlen ) > fieldlen - 1 ) { \
2020-11-05 19:27:02 -04:00
Debug ( " Message %s. " fieldname_s " not NULL-terminated or too long " , logstructure - > name ) ; \
2018-02-22 20:06:45 -04:00
passed = false ; \
} \
} while ( false )
CHECK_ENTRY ( name , " name " , LS_NAME_SIZE ) ;
CHECK_ENTRY ( format , " format " , LS_FORMAT_SIZE ) ;
CHECK_ENTRY ( labels , " labels " , LS_LABELS_SIZE ) ;
CHECK_ENTRY ( units , " units " , LS_UNITS_SIZE ) ;
CHECK_ENTRY ( multipliers , " multipliers " , LS_MULTIPLIERS_SIZE ) ;
# undef CHECK_ENTRY
2015-12-07 20:21:18 -04:00
2017-11-08 00:55:06 -04:00
// ensure each message ID is only used once
if ( seen_ids [ logstructure - > msg_type ] ) {
2018-06-15 06:57:28 -03:00
Debug ( " ID %d used twice (LogStructure offset=%d) " , logstructure - > msg_type , offset ) ;
2017-11-08 00:55:06 -04:00
passed = false ;
}
seen_ids [ logstructure - > msg_type ] = true ;
// ensure we have enough labels to cover columns
uint8_t fieldcount = strlen ( logstructure - > format ) ;
uint8_t labelcount = count_commas ( logstructure - > labels ) + 1 ;
if ( fieldcount ! = labelcount ) {
2020-11-05 19:27:02 -04:00
Debug ( " %s fieldcount=%u does not match labelcount=%u " ,
logstructure - > name , fieldcount , labelcount ) ;
2017-11-08 00:55:06 -04:00
passed = false ;
}
2015-12-07 20:21:18 -04:00
2020-04-07 02:16:51 -03:00
if ( ! labels_string_is_good ( logstructure - > labels ) ) {
passed = false ;
}
2017-11-08 00:55:06 -04:00
// check that the structure is of an appropriate length to take fields
2019-01-18 00:24:08 -04:00
const int16_t msg_len = Write_calc_msg_len ( logstructure - > format ) ;
2017-11-08 00:55:06 -04:00
if ( msg_len ! = logstructure - > msg_len ) {
2018-06-15 06:57:28 -03:00
Debug ( " Calculated message length for (%s) based on format field (%s) does not match structure size (%d != %u) " , logstructure - > name , logstructure - > format , msg_len , logstructure - > msg_len ) ;
2017-11-08 00:55:06 -04:00
passed = false ;
}
2015-12-07 20:21:18 -04:00
2017-11-08 00:55:06 -04:00
// ensure we have units for each field:
if ( strlen ( logstructure - > units ) ! = fieldcount ) {
2020-11-05 19:27:02 -04:00
Debug ( " %s fieldcount=%u does not match unitcount=%u " ,
logstructure - > name , ( unsigned ) fieldcount , ( unsigned ) strlen ( logstructure - > units ) ) ;
2017-11-08 00:55:06 -04:00
passed = false ;
}
2015-12-07 20:21:18 -04:00
2017-11-08 00:55:06 -04:00
// ensure we have multipliers for each field
if ( strlen ( logstructure - > multipliers ) ! = fieldcount ) {
2020-11-05 19:27:02 -04:00
Debug ( " %s fieldcount=%u does not match multipliercount=%u " ,
logstructure - > name , ( unsigned ) fieldcount , ( unsigned ) strlen ( logstructure - > multipliers ) ) ;
2017-11-08 00:55:06 -04:00
passed = false ;
}
2015-12-07 20:21:18 -04:00
2017-11-08 00:55:06 -04:00
// ensure the FMTU messages reference valid units
for ( uint8_t j = 0 ; j < strlen ( logstructure - > units ) ; j + + ) {
char logunit = logstructure - > units [ j ] ;
uint8_t k ;
for ( k = 0 ; k < _num_units ; k + + ) {
if ( logunit = = _units [ k ] . ID ) {
// found this one
break ;
2015-12-07 20:21:18 -04:00
}
}
2017-11-08 00:55:06 -04:00
if ( k = = _num_units ) {
2018-06-15 06:57:28 -03:00
Debug ( " invalid unit=%c " , logunit ) ;
2017-11-08 00:55:06 -04:00
passed = false ;
}
}
2015-12-07 20:21:18 -04:00
2018-01-24 19:20:12 -04:00
// ensure the FMTU messages reference valid multipliers
2017-11-08 00:55:06 -04:00
for ( uint8_t j = 0 ; j < strlen ( logstructure - > multipliers ) ; j + + ) {
char logmultiplier = logstructure - > multipliers [ j ] ;
uint8_t k ;
for ( k = 0 ; k < _num_multipliers ; k + + ) {
if ( logmultiplier = = _multipliers [ k ] . ID ) {
// found this one
break ;
}
}
if ( k = = _num_multipliers ) {
2018-06-15 06:57:28 -03:00
Debug ( " invalid multiplier=%c " , logmultiplier ) ;
2017-11-08 00:55:06 -04:00
passed = false ;
2015-12-07 20:21:18 -04:00
}
2015-12-07 20:21:18 -04:00
}
2018-06-15 06:57:28 -03:00
// ensure any float has a multiplier of zero
2019-06-03 01:09:41 -03:00
if ( false & & passed ) {
2018-06-15 06:57:28 -03:00
for ( uint8_t j = 0 ; j < strlen ( logstructure - > multipliers ) ; j + + ) {
const char fmt = logstructure - > format [ j ] ;
if ( fmt ! = ' f ' ) {
continue ;
}
const char logmultiplier = logstructure - > multipliers [ j ] ;
if ( logmultiplier = = ' 0 ' | |
logmultiplier = = ' ? ' | |
logmultiplier = = ' - ' ) {
continue ;
}
Debug ( " %s[%u] float with non-zero multiplier=%c " ,
logstructure - > name ,
j ,
logmultiplier ) ;
passed = false ;
}
}
2017-11-08 00:55:06 -04:00
return passed ;
}
2019-01-18 00:23:42 -04:00
void AP_Logger : : validate_structures ( const struct LogStructure * logstructures , const uint8_t num_types )
2017-11-08 00:55:06 -04:00
{
Debug ( " Validating structures " ) ;
bool passed = true ;
2019-06-03 01:09:51 -03:00
for ( uint16_t i = 0 ; i < num_types ; i + + ) {
const struct LogStructure * logstructure = & logstructures [ i ] ;
passed = validate_structure ( logstructure , i ) & & passed ;
}
2018-10-14 01:45:07 -03:00
// ensure units are unique:
for ( uint16_t i = 0 ; i < ARRAY_SIZE ( log_Units ) ; i + + ) {
const struct UnitStructure & a = log_Units [ i ] ;
for ( uint16_t j = i + 1 ; j < ARRAY_SIZE ( log_Units ) ; j + + ) {
const struct UnitStructure & b = log_Units [ j ] ;
if ( a . ID = = b . ID ) {
Debug ( " duplicate unit id=%c (%s/%s) " , a . ID , a . unit , b . unit ) ;
passed = false ;
}
if ( streq ( a . unit , b . unit ) ) {
Debug ( " duplicate unit=%s (%c/%c) " , a . unit , a . ID , b . ID ) ;
passed = false ;
}
}
2017-11-08 00:55:06 -04:00
}
2018-10-14 01:45:07 -03:00
// ensure multipliers are unique:
for ( uint16_t i = 0 ; i < ARRAY_SIZE ( log_Multipliers ) ; i + + ) {
const struct MultiplierStructure & a = log_Multipliers [ i ] ;
for ( uint16_t j = i + 1 ; j < ARRAY_SIZE ( log_Multipliers ) ; j + + ) {
const struct MultiplierStructure & b = log_Multipliers [ j ] ;
if ( a . ID = = b . ID ) {
Debug ( " duplicate multiplier id=%c (%f/%f) " ,
a . ID , a . multiplier , b . multiplier ) ;
passed = false ;
}
if ( is_equal ( a . multiplier , b . multiplier ) ) {
if ( a . ID = = ' ? ' & & b . ID = = ' 0 ' ) {
// special case
continue ;
}
Debug ( " duplicate multiplier=%f (%c/%c) " ,
a . multiplier , a . ID , b . ID ) ;
passed = false ;
}
}
}
2015-12-07 20:21:18 -04:00
if ( ! passed ) {
2020-06-06 07:59:50 -03:00
AP_BoardConfig : : config_error ( " See console: Log structures invalid " ) ;
2015-12-07 20:21:18 -04:00
}
}
# endif // CONFIG_HAL_BOARD == HAL_BOARD_SITL
2019-01-18 00:23:42 -04:00
const struct LogStructure * AP_Logger : : structure ( uint16_t num ) const
2015-11-09 18:14:22 -04:00
{
return & _structures [ num ] ;
}
2019-01-18 00:23:42 -04:00
bool AP_Logger : : logging_present ( ) const
2016-07-07 04:12:27 -03:00
{
return _next_backend ! = 0 ;
}
2019-01-18 00:23:42 -04:00
bool AP_Logger : : logging_enabled ( ) const
2016-07-07 04:12:27 -03:00
{
if ( _next_backend = = 0 ) {
return false ;
}
2017-06-09 02:38:07 -03:00
for ( uint8_t i = 0 ; i < _next_backend ; i + + ) {
if ( backends [ i ] - > logging_enabled ( ) ) {
return true ;
}
}
return false ;
2016-07-07 04:12:27 -03:00
}
2019-01-18 00:23:42 -04:00
bool AP_Logger : : logging_failed ( ) const
2016-07-07 04:12:27 -03:00
{
if ( _next_backend < 1 ) {
// we should not have been called!
return true ;
}
2017-06-09 02:38:07 -03:00
for ( uint8_t i = 0 ; i < _next_backend ; i + + ) {
if ( backends [ i ] - > logging_failed ( ) ) {
return true ;
}
}
return false ;
2016-07-07 04:12:27 -03:00
}
2015-11-09 18:14:22 -04:00
2019-01-18 00:24:08 -04:00
void AP_Logger : : Write_MessageF ( const char * fmt , . . . )
2016-08-02 02:08:07 -03:00
{
2018-09-05 23:16:49 -03:00
char msg [ 65 ] { } ; // sizeof(log_Message.msg) + null-termination
2016-08-02 02:08:07 -03:00
va_list ap ;
va_start ( ap , fmt ) ;
hal . util - > vsnprintf ( msg , sizeof ( msg ) , fmt , ap ) ;
va_end ( ap ) ;
2019-01-18 00:24:08 -04:00
Write_Message ( msg ) ;
2016-08-02 02:08:07 -03:00
}
2019-01-18 00:23:42 -04:00
void AP_Logger : : backend_starting_new_log ( const AP_Logger_Backend * backend )
2017-04-28 04:37:13 -03:00
{
2020-12-31 17:03:06 -04:00
_log_start_count + + ;
2017-04-28 04:37:13 -03:00
for ( uint8_t i = 0 ; i < _next_backend ; i + + ) {
if ( backends [ i ] = = backend ) { // pointer comparison!
// reset sent masks
for ( struct log_write_fmt * f = log_write_fmts ; f ; f = f - > next ) {
f - > sent_mask & = ~ ( 1 < < i ) ;
}
break ;
}
}
}
2019-01-18 00:23:42 -04:00
bool AP_Logger : : should_log ( const uint32_t mask ) const
2017-06-14 09:45:54 -03:00
{
2019-06-10 18:55:30 -03:00
bool armed = vehicle_is_armed ( ) ;
2017-06-27 01:14:27 -03:00
if ( ! ( mask & _log_bitmask ) ) {
return false ;
}
2019-06-10 18:55:30 -03:00
if ( ! armed & & ! log_while_disarmed ( ) ) {
2017-06-14 09:45:54 -03:00
return false ;
}
2017-06-19 22:52:47 -03:00
if ( in_log_download ( ) ) {
return false ;
}
2017-06-14 09:45:54 -03:00
if ( _next_backend = = 0 ) {
return false ;
}
return true ;
}
2021-04-30 22:15:11 -03:00
/*
return true if in log download which should prevent logging
*/
bool AP_Logger : : in_log_download ( ) const
{
if ( uint8_t ( _params . backend_types ) & uint8_t ( Backend_Type : : BLOCK ) ) {
// when we have a BLOCK backend then listing completely prevents logging
return transfer_activity ! = TransferActivity : : IDLE ;
}
// for other backends listing does not interfere with logging
return transfer_activity = = TransferActivity : : SENDING ;
}
2019-01-18 00:23:42 -04:00
const struct UnitStructure * AP_Logger : : unit ( uint16_t num ) const
2015-12-07 20:51:46 -04:00
{
return & _units [ num ] ;
}
2019-01-18 00:23:42 -04:00
const struct MultiplierStructure * AP_Logger : : multiplier ( uint16_t num ) const
2015-12-07 20:51:46 -04:00
{
return & log_Multipliers [ num ] ;
}
2017-06-14 09:45:54 -03:00
2015-11-09 18:14:22 -04:00
# define FOR_EACH_BACKEND(methodcall) \
do { \
for ( uint8_t i = 0 ; i < _next_backend ; i + + ) { \
backends [ i ] - > methodcall ; \
} \
} while ( 0 )
2019-01-18 00:23:42 -04:00
void AP_Logger : : PrepForArming ( )
2017-07-06 22:28:42 -03:00
{
FOR_EACH_BACKEND ( PrepForArming ( ) ) ;
}
2019-01-18 00:24:08 -04:00
void AP_Logger : : setVehicle_Startup_Writer ( vehicle_startup_message_Writer writer )
2015-08-06 09:18:28 -03:00
{
_vehicle_messages = writer ;
}
2019-01-18 00:23:42 -04:00
void AP_Logger : : set_vehicle_armed ( const bool armed_state )
2016-07-28 00:06:03 -03:00
{
if ( armed_state = = _armed ) {
// no change in status
return ;
}
_armed = armed_state ;
2016-07-28 02:58:20 -03:00
if ( ! _armed ) {
// went from armed to disarmed
FOR_EACH_BACKEND ( vehicle_was_disarmed ( ) ) ;
}
2016-07-28 00:06:03 -03:00
}
2020-11-15 17:47:39 -04:00
# if APM_BUILD_TYPE(APM_BUILD_Replay)
/*
remember formats for replay . This allows WriteV ( ) to work within
replay
*/
void AP_Logger : : save_format_Replay ( const void * pBuffer )
{
if ( ( ( uint8_t * ) pBuffer ) [ 2 ] = = LOG_FORMAT_MSG ) {
struct log_Format * fmt = ( struct log_Format * ) pBuffer ;
struct log_write_fmt * f = new log_write_fmt ;
f - > msg_type = fmt - > type ;
f - > msg_len = fmt - > length ;
f - > name = strndup ( fmt - > name , sizeof ( fmt - > name ) ) ;
f - > fmt = strndup ( fmt - > format , sizeof ( fmt - > format ) ) ;
f - > labels = strndup ( fmt - > labels , sizeof ( fmt - > labels ) ) ;
f - > next = log_write_fmts ;
log_write_fmts = f ;
}
}
# endif
2016-07-28 00:06:03 -03:00
2015-06-25 10:53:20 -03:00
// start functions pass straight through to backend:
2019-01-18 00:23:42 -04:00
void AP_Logger : : WriteBlock ( const void * pBuffer , uint16_t size ) {
2020-11-15 17:47:39 -04:00
# if APM_BUILD_TYPE(APM_BUILD_Replay)
save_format_Replay ( pBuffer ) ;
# endif
2015-11-09 18:14:22 -04:00
FOR_EACH_BACKEND ( WriteBlock ( pBuffer , size ) ) ;
2015-08-06 09:18:28 -03:00
}
2021-02-09 15:05:03 -04:00
// only the first backend write need succeed for us to be successful
bool AP_Logger : : WriteBlock_first_succeed ( const void * pBuffer , uint16_t size )
{
if ( _next_backend = = 0 ) {
return false ;
}
for ( uint8_t i = 1 ; i < _next_backend ; i + + ) {
backends [ i ] - > WriteBlock ( pBuffer , size ) ;
}
return backends [ 0 ] - > WriteBlock ( pBuffer , size ) ;
}
2020-11-05 19:28:26 -04:00
// write a replay block. This differs from other as it returns false if a backend doesn't
// have space for the msg
bool AP_Logger : : WriteReplayBlock ( uint8_t msg_id , const void * pBuffer , uint16_t size ) {
bool ret = true ;
if ( log_replay ( ) ) {
uint8_t buf [ 3 + size ] ;
buf [ 0 ] = HEAD_BYTE1 ;
buf [ 1 ] = HEAD_BYTE2 ;
buf [ 2 ] = msg_id ;
memcpy ( & buf [ 3 ] , pBuffer , size ) ;
for ( uint8_t i = 0 ; i < _next_backend ; i + + ) {
if ( ! backends [ i ] - > WritePrioritisedBlock ( buf , sizeof ( buf ) , true ) ) {
ret = false ;
}
}
}
2021-01-27 20:30:00 -04:00
# if CONFIG_HAL_BOARD == HAL_BOARD_SITL
2021-03-10 23:50:23 -04:00
// things will almost certainly go sour. However, if we are not
// logging while disarmed then the EKF can be started and trying
// to log things even 'though the backends might be saying "no".
if ( ! ret & & log_while_disarmed ( ) ) {
2021-01-27 20:30:00 -04:00
AP_HAL : : panic ( " Failed to log replay block " ) ;
}
# endif
2020-11-05 19:28:26 -04:00
return ret ;
}
2019-01-18 00:23:42 -04:00
void AP_Logger : : WriteCriticalBlock ( const void * pBuffer , uint16_t size ) {
2015-11-09 18:14:22 -04:00
FOR_EACH_BACKEND ( WriteCriticalBlock ( pBuffer , size ) ) ;
2015-08-06 09:18:28 -03:00
}
2019-01-18 00:23:42 -04:00
void AP_Logger : : WritePrioritisedBlock ( const void * pBuffer , uint16_t size , bool is_critical ) {
2015-11-09 18:14:22 -04:00
FOR_EACH_BACKEND ( WritePrioritisedBlock ( pBuffer , size , is_critical ) ) ;
2015-06-25 10:53:20 -03:00
}
// change me to "DoTimeConsumingPreparations"?
2019-01-18 00:23:42 -04:00
void AP_Logger : : EraseAll ( ) {
2015-11-09 18:14:22 -04:00
FOR_EACH_BACKEND ( EraseAll ( ) ) ;
2015-06-25 10:53:20 -03:00
}
// change me to "LoggingAvailable"?
2019-01-18 00:23:42 -04:00
bool AP_Logger : : CardInserted ( void ) {
2015-11-09 18:14:22 -04:00
for ( uint8_t i = 0 ; i < _next_backend ; i + + ) {
if ( backends [ i ] - > CardInserted ( ) ) {
return true ;
}
}
return false ;
2015-06-25 10:53:20 -03:00
}
2015-08-08 03:13:38 -03:00
2019-01-18 00:23:42 -04:00
void AP_Logger : : StopLogging ( )
2016-04-22 10:33:40 -03:00
{
FOR_EACH_BACKEND ( stop_logging ( ) ) ;
}
2019-01-18 00:23:42 -04:00
uint16_t AP_Logger : : find_last_log ( ) const {
2015-11-09 18:14:22 -04:00
if ( _next_backend = = 0 ) {
return 0 ;
}
return backends [ 0 ] - > find_last_log ( ) ;
2015-06-25 10:53:20 -03:00
}
2019-01-18 18:45:36 -04:00
void AP_Logger : : get_log_boundaries ( uint16_t log_num , uint32_t & start_page , uint32_t & end_page ) {
2015-11-09 18:14:22 -04:00
if ( _next_backend = = 0 ) {
return ;
}
backends [ 0 ] - > get_log_boundaries ( log_num , start_page , end_page ) ;
2015-06-25 10:53:20 -03:00
}
2019-01-18 00:23:42 -04:00
void AP_Logger : : get_log_info ( uint16_t log_num , uint32_t & size , uint32_t & time_utc ) {
2015-11-09 18:14:22 -04:00
if ( _next_backend = = 0 ) {
return ;
}
backends [ 0 ] - > get_log_info ( log_num , size , time_utc ) ;
2015-06-25 10:53:20 -03:00
}
2019-01-18 00:23:42 -04:00
int16_t AP_Logger : : get_log_data ( uint16_t log_num , uint16_t page , uint32_t offset , uint16_t len , uint8_t * data ) {
2015-11-09 18:14:22 -04:00
if ( _next_backend = = 0 ) {
return 0 ;
}
return backends [ 0 ] - > get_log_data ( log_num , page , offset , len , data ) ;
2015-06-25 10:53:20 -03:00
}
2019-01-18 00:23:42 -04:00
uint16_t AP_Logger : : get_num_logs ( void ) {
2015-11-09 18:14:22 -04:00
if ( _next_backend = = 0 ) {
return 0 ;
}
return backends [ 0 ] - > get_num_logs ( ) ;
2015-06-25 10:53:20 -03:00
}
2015-11-09 18:14:22 -04:00
/* we're started if any of the backends are started */
2019-01-18 00:23:42 -04:00
bool AP_Logger : : logging_started ( void ) {
2015-11-09 18:14:22 -04:00
for ( uint8_t i = 0 ; i < _next_backend ; i + + ) {
if ( backends [ i ] - > logging_started ( ) ) {
return true ;
}
}
return false ;
2015-06-25 10:53:20 -03:00
}
2019-04-30 07:22:48 -03:00
void AP_Logger : : handle_mavlink_msg ( GCS_MAVLINK & link , const mavlink_message_t & msg )
2017-06-15 00:29:50 -03:00
{
2019-04-30 07:22:48 -03:00
switch ( msg . msgid ) {
2017-06-15 00:29:50 -03:00
case MAVLINK_MSG_ID_REMOTE_LOG_BLOCK_STATUS :
2019-07-31 21:08:23 -03:00
FOR_EACH_BACKEND ( remote_log_block_status_msg ( link , msg ) ) ;
2017-06-18 20:43:15 -03:00
break ;
case MAVLINK_MSG_ID_LOG_REQUEST_LIST :
2018-05-24 18:29:49 -03:00
FALLTHROUGH ;
2017-06-18 20:43:15 -03:00
case MAVLINK_MSG_ID_LOG_REQUEST_DATA :
2018-05-24 18:29:49 -03:00
FALLTHROUGH ;
2017-06-18 20:43:15 -03:00
case MAVLINK_MSG_ID_LOG_ERASE :
2018-05-24 18:29:49 -03:00
FALLTHROUGH ;
2017-06-18 20:43:15 -03:00
case MAVLINK_MSG_ID_LOG_REQUEST_END :
handle_log_message ( link , msg ) ;
2017-06-15 00:29:50 -03:00
break ;
}
2015-11-10 02:34:31 -04:00
}
2019-01-18 00:23:42 -04:00
void AP_Logger : : periodic_tasks ( ) {
2021-05-19 23:34:13 -03:00
# ifndef HAL_BUILD_AP_PERIPH
2018-03-19 00:37:21 -03:00
handle_log_send ( ) ;
2021-05-19 23:34:13 -03:00
# endif
2018-03-19 00:37:21 -03:00
FOR_EACH_BACKEND ( periodic_tasks ( ) ) ;
2015-08-06 09:18:28 -03:00
}
2015-06-18 22:57:01 -03:00
# if CONFIG_HAL_BOARD == HAL_BOARD_SITL || CONFIG_HAL_BOARD == HAL_BOARD_LINUX
2019-01-18 00:23:42 -04:00
// currently only AP_Logger_File support this:
void AP_Logger : : flush ( void ) {
2015-11-09 18:14:22 -04:00
FOR_EACH_BACKEND ( flush ( ) ) ;
2015-06-18 22:57:01 -03:00
}
# endif
2015-06-25 10:53:20 -03:00
2015-11-09 18:14:22 -04:00
2019-01-29 21:43:24 -04:00
void AP_Logger : : Write_EntireMission ( )
2015-11-09 18:14:22 -04:00
{
2019-01-29 21:43:24 -04:00
FOR_EACH_BACKEND ( Write_EntireMission ( ) ) ;
2015-11-09 18:14:22 -04:00
}
2019-01-18 00:24:08 -04:00
void AP_Logger : : Write_Message ( const char * message )
2015-11-09 18:14:22 -04:00
{
2019-01-18 00:24:08 -04:00
FOR_EACH_BACKEND ( Write_Message ( message ) ) ;
2015-11-09 18:14:22 -04:00
}
2019-10-17 00:48:00 -03:00
void AP_Logger : : Write_Mode ( uint8_t mode , const ModeReason reason )
2015-11-09 18:14:22 -04:00
{
2019-01-18 00:24:08 -04:00
FOR_EACH_BACKEND ( Write_Mode ( mode , reason ) ) ;
2015-11-09 18:14:22 -04:00
}
2019-01-18 00:24:08 -04:00
void AP_Logger : : Write_Parameter ( const char * name , float value )
2015-11-09 18:14:22 -04:00
{
2019-01-18 00:24:08 -04:00
FOR_EACH_BACKEND ( Write_Parameter ( name , value ) ) ;
2015-11-09 18:14:22 -04:00
}
2019-01-18 00:24:08 -04:00
void AP_Logger : : Write_Mission_Cmd ( const AP_Mission & mission ,
2015-11-09 18:14:22 -04:00
const AP_Mission : : Mission_Command & cmd )
{
2019-01-18 00:24:08 -04:00
FOR_EACH_BACKEND ( Write_Mission_Cmd ( mission , cmd ) ) ;
2015-11-09 18:14:22 -04:00
}
2018-12-29 00:02:29 -04:00
void AP_Logger : : Write_RallyPoint ( uint8_t total ,
uint8_t sequence ,
const RallyLocation & rally_point )
{
FOR_EACH_BACKEND ( Write_RallyPoint ( total , sequence , rally_point ) ) ;
}
2019-03-28 03:45:53 -03:00
void AP_Logger : : Write_Rally ( )
{
FOR_EACH_BACKEND ( Write_Rally ( ) ) ;
}
2020-01-15 22:17:01 -04:00
// output a FMT message for each backend if not already done so
void AP_Logger : : Safe_Write_Emit_FMT ( log_write_fmt * f )
{
for ( uint8_t i = 0 ; i < _next_backend ; i + + ) {
if ( ! ( f - > sent_mask & ( 1U < < i ) ) ) {
if ( ! backends [ i ] - > Write_Emit_FMT ( f - > msg_type ) ) {
continue ;
}
f - > sent_mask | = ( 1U < < i ) ;
}
}
}
2019-01-18 00:23:42 -04:00
uint32_t AP_Logger : : num_dropped ( ) const
2016-04-21 03:11:21 -03:00
{
if ( _next_backend = = 0 ) {
return 0 ;
}
return backends [ 0 ] - > num_dropped ( ) ;
}
2015-11-09 18:14:22 -04:00
2015-06-25 10:53:20 -03:00
// end functions pass straight through to backend
2015-11-09 18:14:22 -04:00
2019-01-18 00:24:08 -04:00
/* Write support */
void AP_Logger : : Write ( const char * name , const char * labels , const char * fmt , . . . )
2016-04-20 02:07:48 -03:00
{
va_list arg_list ;
2017-11-07 23:32:45 -04:00
va_start ( arg_list , fmt ) ;
2019-01-18 00:24:08 -04:00
WriteV ( name , labels , nullptr , nullptr , fmt , arg_list ) ;
2017-11-07 23:32:45 -04:00
va_end ( arg_list ) ;
}
2019-01-18 00:24:08 -04:00
void AP_Logger : : Write ( const char * name , const char * labels , const char * units , const char * mults , const char * fmt , . . . )
2017-11-07 23:32:45 -04:00
{
va_list arg_list ;
va_start ( arg_list , fmt ) ;
2019-01-18 00:24:08 -04:00
WriteV ( name , labels , units , mults , fmt , arg_list ) ;
2017-11-07 23:32:45 -04:00
va_end ( arg_list ) ;
}
2019-05-15 01:39:32 -03:00
void AP_Logger : : WriteCritical ( const char * name , const char * labels , const char * fmt , . . . )
{
va_list arg_list ;
va_start ( arg_list , fmt ) ;
WriteV ( name , labels , nullptr , nullptr , fmt , arg_list , true ) ;
va_end ( arg_list ) ;
}
void AP_Logger : : WriteCritical ( const char * name , const char * labels , const char * units , const char * mults , const char * fmt , . . . )
{
va_list arg_list ;
va_start ( arg_list , fmt ) ;
WriteV ( name , labels , units , mults , fmt , arg_list , true ) ;
va_end ( arg_list ) ;
}
void AP_Logger : : WriteV ( const char * name , const char * labels , const char * units , const char * mults , const char * fmt , va_list arg_list , bool is_critical )
2017-11-07 23:32:45 -04:00
{
2020-11-05 19:28:26 -04:00
// WriteV is not safe in replay as we can re-use IDs
2020-11-15 17:47:39 -04:00
const bool direct_comp = APM_BUILD_TYPE ( APM_BUILD_Replay ) ;
struct log_write_fmt * f = msg_fmt_for_name ( name , labels , units , mults , fmt , direct_comp ) ;
2016-05-04 06:06:23 -03:00
if ( f = = nullptr ) {
2016-04-20 02:07:48 -03:00
// unable to map name to a messagetype; could be out of
// msgtypes, could be out of slots, ...
2020-11-15 21:45:11 -04:00
# if !APM_BUILD_TYPE(APM_BUILD_Replay)
2020-04-29 21:40:46 -03:00
INTERNAL_ERROR ( AP_InternalError : : error_t : : logger_mapfailure ) ;
2020-11-15 21:45:11 -04:00
# endif
2016-04-20 02:07:48 -03:00
return ;
}
for ( uint8_t i = 0 ; i < _next_backend ; i + + ) {
2016-05-04 06:06:23 -03:00
if ( ! ( f - > sent_mask & ( 1U < < i ) ) ) {
2019-01-18 00:24:08 -04:00
if ( ! backends [ i ] - > Write_Emit_FMT ( f - > msg_type ) ) {
2016-05-04 06:06:23 -03:00
continue ;
}
f - > sent_mask | = ( 1U < < i ) ;
2016-04-20 02:07:48 -03:00
}
2017-11-07 23:32:45 -04:00
va_list arg_copy ;
va_copy ( arg_copy , arg_list ) ;
2019-05-15 01:39:32 -03:00
backends [ i ] - > Write ( f - > msg_type , arg_copy , is_critical ) ;
2017-11-07 23:32:45 -04:00
va_end ( arg_copy ) ;
2016-04-20 02:07:48 -03:00
}
}
2020-11-06 23:54:45 -04:00
/*
when we are doing replay logging we want to delay start of the EKF
until after the headers are out so that on replay all parameter
values are available
*/
2020-11-05 19:28:26 -04:00
bool AP_Logger : : allow_start_ekf ( ) const
{
2020-11-06 23:54:45 -04:00
if ( ! log_replay ( ) | | ! log_while_disarmed ( ) ) {
2020-11-05 19:28:26 -04:00
return true ;
}
for ( uint8_t i = 0 ; i < _next_backend ; i + + ) {
if ( ! backends [ i ] - > allow_start_ekf ( ) ) {
return false ;
}
}
return true ;
}
2016-04-20 02:07:48 -03:00
2017-11-14 20:02:56 -04:00
# if CONFIG_HAL_BOARD == HAL_BOARD_SITL
2020-11-15 21:45:11 -04:00
bool AP_Logger : : assert_same_fmt_for_name ( const AP_Logger : : log_write_fmt * f ,
2017-11-14 20:02:56 -04:00
const char * name ,
const char * labels ,
const char * units ,
const char * mults ,
const char * fmt ) const
{
bool passed = true ;
if ( ! streq ( f - > name , name ) ) {
// why exactly were we called?!
Debug ( " format names differ (%s) != (%s) " , f - > name , name ) ;
passed = false ;
}
if ( ! streq ( f - > labels , labels ) ) {
Debug ( " format labels differ (%s) vs (%s) " , f - > labels , labels ) ;
passed = false ;
}
2020-11-15 21:45:11 -04:00
if ( ! streq ( f - > fmt , fmt ) ) {
Debug ( " format fmt differ (%s) vs (%s) " ,
( f - > fmt ? f - > fmt : " nullptr " ) ,
( fmt ? fmt : " nullptr " ) ) ;
passed = false ;
}
# if !APM_BUILD_TYPE(APM_BUILD_Replay)
2017-11-14 20:02:56 -04:00
if ( ( f - > units ! = nullptr & & units = = nullptr ) | |
( f - > units = = nullptr & & units ! = nullptr ) | |
( units ! = nullptr & & ! streq ( f - > units , units ) ) ) {
Debug ( " format units differ (%s) vs (%s) " ,
( f - > units ? f - > units : " nullptr " ) ,
( units ? units : " nullptr " ) ) ;
passed = false ;
}
if ( ( f - > mults ! = nullptr & & mults = = nullptr ) | |
( f - > mults = = nullptr & & mults ! = nullptr ) | |
( mults ! = nullptr & & ! streq ( f - > mults , mults ) ) ) {
Debug ( " format mults differ (%s) vs (%s) " ,
( f - > mults ? f - > mults : " nullptr " ) ,
( mults ? mults : " nullptr " ) ) ;
passed = false ;
}
if ( ! passed ) {
2020-06-06 07:59:50 -03:00
AP_BoardConfig : : config_error ( " See console: Format definition must be consistent for every call of Write " ) ;
2017-11-14 20:02:56 -04:00
}
2020-11-15 21:45:11 -04:00
# endif
return passed ;
2017-11-14 20:02:56 -04:00
}
# endif
2020-01-15 22:17:01 -04:00
AP_Logger : : log_write_fmt * AP_Logger : : msg_fmt_for_name ( const char * name , const char * labels , const char * units , const char * mults , const char * fmt , const bool direct_comp )
2016-04-20 02:07:48 -03:00
{
2020-01-15 19:16:25 -04:00
WITH_SEMAPHORE ( log_write_fmts_sem ) ;
2016-05-04 06:06:23 -03:00
struct log_write_fmt * f ;
for ( f = log_write_fmts ; f ; f = f - > next ) {
2020-01-15 22:17:01 -04:00
if ( ! direct_comp ) {
if ( f - > name = = name ) { // ptr comparison
// already have an ID for this name:
2020-11-15 21:45:11 -04:00
# if CONFIG_HAL_BOARD == HAL_BOARD_SITL
if ( ! assert_same_fmt_for_name ( f , name , labels , units , mults , fmt ) ) {
return nullptr ;
}
2020-01-15 22:17:01 -04:00
# endif
return f ;
}
} else {
// direct comparison used from scripting where pointer is not maintained
2020-05-10 01:29:02 -03:00
if ( strcmp ( f - > name , name ) = = 0 ) {
2020-01-15 22:17:01 -04:00
// already have an ID for this name:
2020-11-15 21:45:11 -04:00
# if CONFIG_HAL_BOARD == HAL_BOARD_SITL
if ( ! assert_same_fmt_for_name ( f , name , labels , units , mults , fmt ) ) {
return nullptr ;
}
2017-11-14 20:02:56 -04:00
# endif
2020-01-15 22:17:01 -04:00
return f ;
}
2016-04-20 02:07:48 -03:00
}
}
2020-11-15 21:45:11 -04:00
# if APM_BUILD_TYPE(APM_BUILD_Replay)
// don't allow for new msg types during replay. We will be able to
// support these eventually, but for now they cause corruption
return nullptr ;
# endif
2016-05-04 06:06:23 -03:00
f = ( struct log_write_fmt * ) calloc ( 1 , sizeof ( * f ) ) ;
if ( f = = nullptr ) {
// out of memory
return nullptr ;
2016-04-20 02:07:48 -03:00
}
// no message type allocated for this name. Try to allocate one:
int16_t msg_type = find_free_msg_type ( ) ;
if ( msg_type = = - 1 ) {
2016-05-04 06:06:23 -03:00
free ( f ) ;
return nullptr ;
2016-04-20 02:07:48 -03:00
}
2016-05-04 06:06:23 -03:00
f - > msg_type = msg_type ;
f - > name = name ;
f - > fmt = fmt ;
f - > labels = labels ;
2017-11-07 23:32:45 -04:00
f - > units = units ;
f - > mults = mults ;
2016-05-04 06:06:23 -03:00
2019-01-18 00:24:08 -04:00
int16_t tmp = Write_calc_msg_len ( fmt ) ;
2016-04-20 02:07:48 -03:00
if ( tmp = = - 1 ) {
2016-05-04 06:06:23 -03:00
free ( f ) ;
return nullptr ;
2016-04-20 02:07:48 -03:00
}
2016-05-04 06:06:23 -03:00
f - > msg_len = tmp ;
// add to front of list
f - > next = log_write_fmts ;
log_write_fmts = f ;
2017-11-14 20:02:56 -04:00
# if CONFIG_HAL_BOARD == HAL_BOARD_SITL
2018-02-22 20:06:45 -04:00
char ls_name [ LS_NAME_SIZE ] = { } ;
char ls_format [ LS_FORMAT_SIZE ] = { } ;
char ls_labels [ LS_LABELS_SIZE ] = { } ;
char ls_units [ LS_UNITS_SIZE ] = { } ;
char ls_multipliers [ LS_MULTIPLIERS_SIZE ] = { } ;
2017-11-14 20:02:56 -04:00
struct LogStructure ls = {
f - > msg_type ,
f - > msg_len ,
2018-02-22 20:06:45 -04:00
ls_name ,
ls_format ,
ls_labels ,
ls_units ,
ls_multipliers
2017-11-14 20:02:56 -04:00
} ;
2018-02-22 20:06:45 -04:00
memcpy ( ( char * ) ls_name , f - > name , MIN ( sizeof ( ls_name ) , strlen ( f - > name ) ) ) ;
memcpy ( ( char * ) ls_format , f - > fmt , MIN ( sizeof ( ls_format ) , strlen ( f - > fmt ) ) ) ;
memcpy ( ( char * ) ls_labels , f - > labels , MIN ( sizeof ( ls_labels ) , strlen ( f - > labels ) ) ) ;
2017-11-14 20:02:56 -04:00
if ( f - > units ! = nullptr ) {
2018-02-22 20:06:45 -04:00
memcpy ( ( char * ) ls_units , f - > units , MIN ( sizeof ( ls_units ) , strlen ( f - > units ) ) ) ;
2017-11-14 20:02:56 -04:00
} else {
2018-02-22 20:06:45 -04:00
memset ( ( char * ) ls_units , ' ? ' , MIN ( sizeof ( ls_format ) , strlen ( f - > fmt ) ) ) ;
2017-11-14 20:02:56 -04:00
}
if ( f - > mults ! = nullptr ) {
2018-02-22 20:06:45 -04:00
memcpy ( ( char * ) ls_multipliers , f - > mults , MIN ( sizeof ( ls_multipliers ) , strlen ( f - > mults ) ) ) ;
2017-11-14 20:02:56 -04:00
} else {
2018-02-22 20:06:45 -04:00
memset ( ( char * ) ls_multipliers , ' ? ' , MIN ( sizeof ( ls_format ) , strlen ( f - > fmt ) ) ) ;
2017-11-14 20:02:56 -04:00
}
2019-03-25 03:26:24 -03:00
if ( ! validate_structure ( & ls , ( int16_t ) - 1 ) ) {
2020-06-06 07:59:50 -03:00
AP_BoardConfig : : config_error ( " See console: Log structure invalid " ) ;
2019-03-25 03:26:24 -03:00
}
2017-11-14 20:02:56 -04:00
# endif
2016-05-04 06:06:23 -03:00
return f ;
2016-04-20 02:07:48 -03:00
}
2021-02-01 12:26:29 -04:00
const struct LogStructure * AP_Logger : : structure_for_msg_type ( const uint8_t msg_type ) const
2018-08-08 23:12:18 -03:00
{
for ( uint16_t i = 0 ; i < _num_types ; i + + ) {
const struct LogStructure * s = structure ( i ) ;
if ( s - > msg_type = = msg_type ) {
// in use
return s ;
}
}
return nullptr ;
}
2019-01-18 00:23:42 -04:00
const struct AP_Logger : : log_write_fmt * AP_Logger : : log_write_fmt_for_msg_type ( const uint8_t msg_type ) const
2018-08-08 23:12:18 -03:00
{
struct log_write_fmt * f ;
for ( f = log_write_fmts ; f ; f = f - > next ) {
if ( f - > msg_type = = msg_type ) {
return f ;
}
}
return nullptr ;
}
2016-04-20 02:07:48 -03:00
// returns true if the msg_type is already taken
2019-01-18 00:23:42 -04:00
bool AP_Logger : : msg_type_in_use ( const uint8_t msg_type ) const
2016-04-20 02:07:48 -03:00
{
// check static list of messages (e.g. from LOG_BASE_STRUCTURES)
// check the write format types to see if we've used this one
for ( uint16_t i = 0 ; i < _num_types ; i + + ) {
if ( structure ( i ) - > msg_type = = msg_type ) {
// in use
return true ;
}
}
2016-05-04 06:06:23 -03:00
struct log_write_fmt * f ;
for ( f = log_write_fmts ; f ; f = f - > next ) {
if ( f - > msg_type = = msg_type ) {
2016-04-20 02:07:48 -03:00
return true ;
}
}
return false ;
}
// find a free message type
2019-01-18 00:23:42 -04:00
int16_t AP_Logger : : find_free_msg_type ( ) const
2016-04-20 02:07:48 -03:00
{
// avoid using 255 here; perhaps we want to use it to extend things later
for ( uint16_t msg_type = 254 ; msg_type > 0 ; msg_type - - ) { // more likely to be free at end
if ( ! msg_type_in_use ( msg_type ) ) {
return msg_type ;
}
}
return - 1 ;
}
2018-02-22 20:06:45 -04:00
/*
* It is assumed that logstruct ' s char * variables are valid strings of
* maximum lengths for those fields ( given in LogStructure . h e . g . LS_NAME_SIZE )
*/
2019-01-18 00:23:42 -04:00
bool AP_Logger : : fill_log_write_logstructure ( struct LogStructure & logstruct , const uint8_t msg_type ) const
2016-04-20 02:07:48 -03:00
{
// find log structure information corresponding to msg_type:
2016-05-04 06:06:23 -03:00
struct log_write_fmt * f ;
for ( f = log_write_fmts ; f ; f = f - > next ) {
2020-01-02 20:11:01 -04:00
if ( f - > msg_type = = msg_type ) {
2016-04-20 02:07:48 -03:00
break ;
}
}
2016-08-02 18:36:54 -03:00
if ( ! f ) {
return false ;
}
2016-04-20 02:07:48 -03:00
logstruct . msg_type = msg_type ;
2018-02-22 20:06:45 -04:00
strncpy ( ( char * ) logstruct . name , f - > name , LS_NAME_SIZE ) ;
strncpy ( ( char * ) logstruct . format , f - > fmt , LS_FORMAT_SIZE ) ;
strncpy ( ( char * ) logstruct . labels , f - > labels , LS_LABELS_SIZE ) ;
2017-11-07 23:32:45 -04:00
if ( f - > units ! = nullptr ) {
2018-02-22 20:06:45 -04:00
strncpy ( ( char * ) logstruct . units , f - > units , LS_UNITS_SIZE ) ;
2017-11-07 23:32:45 -04:00
} else {
2018-02-22 20:06:45 -04:00
memset ( ( char * ) logstruct . units , ' \0 ' , LS_UNITS_SIZE ) ;
memset ( ( char * ) logstruct . units , ' ? ' , MIN ( LS_UNITS_SIZE , strlen ( logstruct . format ) ) ) ;
2017-11-07 23:32:45 -04:00
}
if ( f - > mults ! = nullptr ) {
2018-02-22 20:06:45 -04:00
strncpy ( ( char * ) logstruct . multipliers , f - > mults , LS_MULTIPLIERS_SIZE ) ;
2017-11-07 23:32:45 -04:00
} else {
2018-02-22 20:06:45 -04:00
memset ( ( char * ) logstruct . multipliers , ' \0 ' , LS_MULTIPLIERS_SIZE ) ;
memset ( ( char * ) logstruct . multipliers , ' ? ' , MIN ( LS_MULTIPLIERS_SIZE , strlen ( logstruct . format ) ) ) ;
2017-11-07 23:32:45 -04:00
// special magic to set units/mults for TimeUS, by far and
// away the most common first field
2018-02-22 20:06:45 -04:00
if ( ! strncmp ( logstruct . labels , " TimeUS, " , MIN ( LS_LABELS_SIZE , strlen ( " TimeUS, " ) ) ) ) {
2017-11-07 23:32:45 -04:00
( ( char * ) ( logstruct . units ) ) [ 0 ] = ' s ' ;
( ( char * ) ( logstruct . multipliers ) ) [ 0 ] = ' F ' ;
}
}
2016-05-04 06:06:23 -03:00
logstruct . msg_len = f - > msg_len ;
2016-04-20 02:07:48 -03:00
return true ;
}
/* calculate the length of output of a format string. Note that this
2016-05-12 13:50:13 -03:00
* returns an int16_t ; if it returns - 1 then an error has occurred .
2016-04-20 02:07:48 -03:00
* This was mechanically converted from init_field_types in
* Tools / Replay / MsgHandler . cpp */
2019-01-18 00:24:08 -04:00
int16_t AP_Logger : : Write_calc_msg_len ( const char * fmt ) const
2016-04-20 02:07:48 -03:00
{
uint8_t len = LOG_PACKET_HEADER_LEN ;
for ( uint8_t i = 0 ; i < strlen ( fmt ) ; i + + ) {
switch ( fmt [ i ] ) {
2017-08-29 09:40:20 -03:00
case ' a ' : len + = sizeof ( int16_t [ 32 ] ) ; break ;
2016-04-20 02:07:48 -03:00
case ' b ' : len + = sizeof ( int8_t ) ; break ;
case ' c ' : len + = sizeof ( int16_t ) ; break ;
case ' d ' : len + = sizeof ( double ) ; break ;
case ' e ' : len + = sizeof ( int32_t ) ; break ;
case ' f ' : len + = sizeof ( float ) ; break ;
case ' h ' : len + = sizeof ( int16_t ) ; break ;
case ' i ' : len + = sizeof ( int32_t ) ; break ;
case ' n ' : len + = sizeof ( char [ 4 ] ) ; break ;
case ' B ' : len + = sizeof ( uint8_t ) ; break ;
case ' C ' : len + = sizeof ( uint16_t ) ; break ;
case ' E ' : len + = sizeof ( uint32_t ) ; break ;
case ' H ' : len + = sizeof ( uint16_t ) ; break ;
case ' I ' : len + = sizeof ( uint32_t ) ; break ;
case ' L ' : len + = sizeof ( int32_t ) ; break ;
case ' M ' : len + = sizeof ( uint8_t ) ; break ;
case ' N ' : len + = sizeof ( char [ 16 ] ) ; break ;
case ' Z ' : len + = sizeof ( char [ 64 ] ) ; break ;
case ' q ' : len + = sizeof ( int64_t ) ; break ;
case ' Q ' : len + = sizeof ( uint64_t ) ; break ;
2018-04-17 04:04:03 -03:00
default :
# if CONFIG_HAL_BOARD == HAL_BOARD_SITL
AP_HAL : : panic ( " Unknown format specifier (%c) " , fmt [ i ] ) ;
# endif
return - 1 ;
2016-04-20 02:07:48 -03:00
}
}
return len ;
}
2020-12-22 13:25:44 -04:00
// thread for processing IO - in general IO involves a long blocking DMA write to an SPI device
// and the thread will sleep while this completes preventing other tasks from running, it therefore
// is necessary to run the IO in it's own thread
void AP_Logger : : io_thread ( void )
{
uint32_t last_run_us = AP_HAL : : micros ( ) ;
while ( true ) {
uint32_t now = AP_HAL : : micros ( ) ;
uint32_t delay = 250U ; // always have some delay
if ( now - last_run_us < 1000 ) {
delay = MAX ( 1000 - ( now - last_run_us ) , delay ) ;
}
hal . scheduler - > delay_microseconds ( delay ) ;
last_run_us = AP_HAL : : micros ( ) ;
FOR_EACH_BACKEND ( io_timer ( ) ) ;
}
}
// start the update thread
void AP_Logger : : start_io_thread ( void )
{
WITH_SEMAPHORE ( _log_send_sem ) ;
if ( _io_thread_started ) {
return ;
}
2021-01-06 16:02:26 -04:00
if ( ! hal . scheduler - > thread_create ( FUNCTOR_BIND_MEMBER ( & AP_Logger : : io_thread , void ) , " log_io " , HAL_LOGGING_STACK_SIZE , AP_HAL : : Scheduler : : PRIORITY_IO , 1 ) ) {
2020-12-22 13:25:44 -04:00
AP_HAL : : panic ( " Failed to start Logger IO thread " ) ;
}
_io_thread_started = true ;
return ;
}
2019-01-18 00:24:08 -04:00
/* End of Write support */
2016-04-20 02:07:48 -03:00
2015-11-09 18:14:22 -04:00
# undef FOR_EACH_BACKEND
2017-09-01 08:05:16 -03:00
2019-02-01 07:29:43 -04:00
// Wrote an event packet
2019-10-25 03:03:57 -03:00
void AP_Logger : : Write_Event ( LogEvent id )
2019-02-01 07:29:43 -04:00
{
2019-07-02 06:31:02 -03:00
const struct log_Event pkt {
2019-02-01 07:29:43 -04:00
LOG_PACKET_HEADER_INIT ( LOG_EVENT_MSG ) ,
time_us : AP_HAL : : micros64 ( ) ,
2019-10-25 03:03:57 -03:00
id : ( uint8_t ) id
2019-02-01 07:29:43 -04:00
} ;
WriteCriticalBlock ( & pkt , sizeof ( pkt ) ) ;
}
2019-03-24 22:04:59 -03:00
// Write an error packet
void AP_Logger : : Write_Error ( LogErrorSubsystem sub_system ,
LogErrorCode error_code )
{
2019-07-02 06:31:02 -03:00
const struct log_Error pkt {
2019-03-24 22:04:59 -03:00
LOG_PACKET_HEADER_INIT ( LOG_ERROR_MSG ) ,
time_us : AP_HAL : : micros64 ( ) ,
sub_system : uint8_t ( sub_system ) ,
error_code : uint8_t ( error_code ) ,
} ;
WriteCriticalBlock ( & pkt , sizeof ( pkt ) ) ;
}
2019-06-10 18:55:30 -03:00
/*
return true if we should log while disarmed
*/
bool AP_Logger : : log_while_disarmed ( void ) const
{
if ( _force_log_disarmed ) {
return true ;
}
if ( _params . log_disarmed ! = 0 ) {
return true ;
}
uint32_t now = AP_HAL : : millis ( ) ;
uint32_t persist_ms = HAL_LOGGER_ARM_PERSIST * 1000U ;
// keep logging for HAL_LOGGER_ARM_PERSIST seconds after disarming
const uint32_t arm_change_ms = hal . util - > get_last_armed_change ( ) ;
if ( ! hal . util - > get_soft_armed ( ) & & arm_change_ms ! = 0 & & now - arm_change_ms < persist_ms ) {
return true ;
}
// keep logging for HAL_LOGGER_ARM_PERSIST seconds after an arming failure
if ( _last_arming_failure_ms & & now - _last_arming_failure_ms < persist_ms ) {
return true ;
}
return false ;
}
2019-02-10 14:05:22 -04:00
namespace AP {
AP_Logger & logger ( )
2019-01-17 21:40:57 -04:00
{
2019-02-10 14:05:22 -04:00
return * AP_Logger : : get_singleton ( ) ;
2019-01-17 21:40:57 -04:00
}
2019-02-10 14:05:22 -04:00
} ;