Tools: Replay: make it work again

Tools: Replay: ignore setting of LOG_DISARMED

Otherwise log files that come in with LOG_DISARMED false don't get any
significant output

Tools: Replay: apply user parameters after any PARM message

Tools: Replay: emit timestamp when EKF is force-started

Tools: Replay: use stderr for what it's good for

Tools: Replay: force log disarmed
This commit is contained in:
Peter Barker 2018-04-22 20:19:11 +10:00 committed by Peter Barker
parent af66d72510
commit 5452730fc9
7 changed files with 229 additions and 97 deletions

View File

@ -88,11 +88,6 @@ bool DataFlashFileReader::update(char type[5])
return handle_log_format_msg(f); return handle_log_format_msg(f);
} }
if (!done_format_msgs) {
done_format_msgs = true;
end_format_msgs();
}
const struct log_Format &f = formats[hdr[2]]; const struct log_Format &f = formats[hdr[2]];
if (f.length == 0) { if (f.length == 0) {
// can't just throw these away as the format specifies the // can't just throw these away as the format specifies the

View File

@ -22,8 +22,6 @@ public:
protected: protected:
int fd = -1; int fd = -1;
bool done_format_msgs = false;
virtual void end_format_msgs(void) {}
struct log_Format formats[LOGREADER_MAX_FORMATS] {}; struct log_Format formats[LOGREADER_MAX_FORMATS] {};

View File

@ -383,7 +383,8 @@ bool LR_MsgHandler_PARM::set_parameter(const char *name, const float value)
{ {
const char *ignore_parms[] = { "GPS_TYPE", "AHRS_EKF_TYPE", "EK2_ENABLE", "EK3_ENABLE" const char *ignore_parms[] = { "GPS_TYPE", "AHRS_EKF_TYPE", "EK2_ENABLE", "EK3_ENABLE"
"COMPASS_ORIENT", "COMPASS_ORIENT2", "COMPASS_ORIENT", "COMPASS_ORIENT2",
"COMPASS_ORIENT3", "LOG_FILE_BUFSIZE"}; "COMPASS_ORIENT3", "LOG_FILE_BUFSIZE",
"LOG_DISARMED"};
for (uint8_t i=0; i < ARRAY_SIZE(ignore_parms); i++) { for (uint8_t i=0; i < ARRAY_SIZE(ignore_parms); i++) {
if (strncmp(name, ignore_parms[i], AP_MAX_NAME_SIZE) == 0) { if (strncmp(name, ignore_parms[i], AP_MAX_NAME_SIZE) == 0) {
::printf("Ignoring set of %s to %f\n", name, value); ::printf("Ignoring set of %s to %f\n", name, value);

View File

@ -18,7 +18,7 @@
#include "MsgHandler.h" #include "MsgHandler.h"
#include "Replay.h" #include "Replay.h"
#define DEBUG 0 #define DEBUG 1
#if DEBUG #if DEBUG
# define debug(fmt, args...) printf(fmt "\n", ##args) # define debug(fmt, args...) printf(fmt "\n", ##args)
#else #else
@ -29,12 +29,19 @@
extern const AP_HAL::HAL& hal; extern const AP_HAL::HAL& hal;
const struct LogStructure log_structure[] = { const struct LogStructure running_codes_log_structure[] = {
LOG_COMMON_STRUCTURES, LOG_COMMON_STRUCTURES,
}; };
LogReader::LogReader(AP_AHRS &_ahrs, AP_InertialSensor &_ins, Compass &_compass, AP_GPS &_gps, LogReader::LogReader(AP_AHRS &_ahrs,
AP_Airspeed &_airspeed, DataFlash_Class &_dataflash, const char **&_nottypes): AP_InertialSensor &_ins,
Compass &_compass,
AP_GPS &_gps,
AP_Airspeed &_airspeed,
DataFlash_Class &_dataflash,
struct LogStructure *log_structure,
uint8_t log_structure_count,
const char **&_nottypes):
DataFlashFileReader(), DataFlashFileReader(),
vehicle(VehicleType::VEHICLE_UNKNOWN), vehicle(VehicleType::VEHICLE_UNKNOWN),
ahrs(_ahrs), ahrs(_ahrs),
@ -47,8 +54,15 @@ LogReader::LogReader(AP_AHRS &_ahrs, AP_InertialSensor &_ins, Compass &_compass,
gyro_mask(7), gyro_mask(7),
last_timestamp_usec(0), last_timestamp_usec(0),
installed_vehicle_specific_parsers(false), installed_vehicle_specific_parsers(false),
_log_structure(log_structure),
nottypes(_nottypes) nottypes(_nottypes)
{ {
if (log_structure_count != 0) {
::fprintf(stderr, "Do NOT put anything in the log_structure before passing it in here");
abort(); // so there.
}
initialise_fmt_map();
} }
struct log_Format deferred_formats[LOGREADER_MAX_FORMATS]; struct log_Format deferred_formats[LOGREADER_MAX_FORMATS];
@ -83,17 +97,53 @@ void LogReader::maybe_install_vehicle_specific_parsers() {
} }
/* /*
messages which we will be generating, so should be discarded messages which we will be generating, so should be discarded.
Additionally, FMT messages for messages NOT in this list will be
passed straight through to the output file, whereas FMT messages for
messages IN this list must come from LOG_BASE_STRUCTURES in
LogStructure.h
Note that there is an existing with FMTU messages, as these are
emitted both from the common structures at log startup and also when
Log_Write(...) is called for the first time for a particular format
name. Since we include it in generated_names FMTU messages will not
be passed through from the source logs - but since the Replay code
does call Log_Write(...) you will end up with a small selection of
FMTU messages from that.
*/ */
static const char *generated_names[] = { "EKF1", "EKF2", "EKF3", "EKF4", "EKF5", static const char *generated_names[] = {
"NKF1", "NKF2", "NKF3", "NKF4", "NKF5", "FMT",
"NKF6", "NKF7", "NKF8", "NKF9", "NKF10", "FMTU",
"AHR2", "POS", "CHEK", "NKF1", "NKF2", "NKF3", "NKF4", "NKF5", "NKF6", "NKF7", "NKF8", "NKF9", "NKF0",
"IMT", "IMT2", "NKQ1", "NKQ2",
"MAG", "MAG2", "XKF1", "XKF2", "XKF3", "XKF4", "XKF5", "XKF6", "XKF7", "XKF8", "XKF9", "XKF0",
"BARO", "BAR2", "XKQ1", "XKQ2", "XKFD", "XKV1", "XKV2",
"GPS","GPA", "AHR2",
"NKA", "NKV", NULL }; "ORGN",
"POS",
"CHEK",
"IMT", "IMT2", "IMT3",
"MAG", "MAG2",
"BARO", "BAR2",
"GPS","GPA",
NULL,
};
// these names we emit from the code as normal, but are emitted using
// Log_Write. Thus they are not present in LOG_COMMON_STRUCTURES. A
// format will be written for this by the code itself the first time
// the message is emitted to the log. However, we must not write the
// messages from the old log to the new log, so we need to keep a map
// of IDs to prune out...
static const char *log_write_names[] = {
"NKA",
"NKV",
"NKT1",
"NKT2",
nullptr
};
/* /*
see if a type is in a list of types see if a type is in a list of types
@ -111,30 +161,78 @@ bool LogReader::in_list(const char *type, const char *list[])
return false; return false;
} }
void LogReader::initialise_fmt_map()
{
for (const char **name = generated_names;
*name !=nullptr;
name++) {
bool found = false;
for (uint8_t n=0; n<ARRAY_SIZE(running_codes_log_structure); n++) {
if (streq(*name, running_codes_log_structure[n].name)) {
const uint8_t t = running_codes_log_structure[n].msg_type;
mapped_msgid[t] = t;
found = true;
break;
}
}
if (!found) {
if (streq(*name, "CHEK")) {
// HACK: CHEK is emitted using Log_Write, so doesn't
// have a fixed address to pre-populate the fmt-map
// with....
continue;
}
::fprintf(stderr, "Failed to find apparently-generated-name (%s) in COMMON_LOG_STRUCTURES\n", *name);
abort();
}
}
}
/* /*
map from an incoming format type to an outgoing format type map from an incoming format type to an outgoing format type
*/ */
uint8_t LogReader::map_fmt_type(const char *name, uint8_t intype) uint8_t LogReader::map_fmt_type(const char *name, uint8_t intype)
{ {
if (intype == 128) {
// everybody's favourite FMT message...
return 128;
}
if (mapped_msgid[intype] != 0) { if (mapped_msgid[intype] != 0) {
// already mapped // already mapped
return mapped_msgid[intype]; return mapped_msgid[intype];
} }
// see if it is in our structure list for (uint8_t n=next_msgid; n<255; n++) {
for (uint8_t i=0; i<ARRAY_SIZE(log_structure); i++) { ::fprintf(stderr, "next_msgid=%u\n", next_msgid);
if (strcmp(name, log_structure[i].name) == 0) { bool already_mapped = false;
mapped_msgid[intype] = log_structure[i].msg_type; for (uint16_t i=0; i<sizeof(mapped_msgid); i++) {
return mapped_msgid[intype]; if (mapped_msgid[i] == n) {
// already mapped - must be one of our generated names
already_mapped = true;
break;
}
} }
if (already_mapped) {
continue;
}
if (DataFlash_Class::instance()->msg_type_in_use(n)) {
continue;
}
mapped_msgid[intype] = n;
next_msgid = n+1;
break;
} }
// it is a new one, allocate an ID if (mapped_msgid[intype] == 0) {
mapped_msgid[intype] = next_msgid++; ::fprintf(stderr, "mapping failed\n");
abort();
}
return mapped_msgid[intype]; return mapped_msgid[intype];
} }
bool LogReader::save_message_type(const char *name) bool LogReader::save_message_type(const char *name)
{ {
bool save_message = !in_list(name, generated_names); bool save_message = !in_list(name, generated_names);
save_message = save_message && !in_list(name, log_write_names);
if (save_chek_messages && strcmp(name, "CHEK") == 0) { if (save_chek_messages && strcmp(name, "CHEK") == 0) {
save_message = true; save_message = true;
} }
@ -148,21 +246,53 @@ bool LogReader::handle_log_format_msg(const struct log_Format &f)
memcpy(name, f.name, 4); memcpy(name, f.name, 4);
debug("Defining log format for type (%d) (%s)\n", f.type, name); debug("Defining log format for type (%d) (%s)\n", f.type, name);
if (save_message_type(name)) { struct LogStructure s = _log_structure[_log_structure_count++];
/* dataflash.set_num_types(_log_structure_count);
any messages which we won't be generating internally in
replay should get the original FMT header if (in_list(name, log_write_names)) {
We need to remap the type in the FMT header to avoid debug("%s is a Log_Write-written message\n", name);
conflicts with our current table } else {
*/ if (in_list(name, generated_names)) {
struct log_Format f_mapped = f; debug("Log format for type (%d) (%s) taken from running code\n",
f_mapped.type = map_fmt_type(name, f.type); f.type, name);
dataflash.WriteBlock(&f_mapped, sizeof(f_mapped)); bool found = false;
for (uint8_t n=0; n<ARRAY_SIZE(running_codes_log_structure); n++) {
if (streq(name, running_codes_log_structure[n].name)) {
found = true;
memcpy(&s, &running_codes_log_structure[n], sizeof(LogStructure));
break;
}
}
if (!found) {
::fprintf(stderr, "Expected to be able to emit an FMT for (%s), but no FMT message found in running code\n", name);
abort();
}
} else {
debug("Log format for type (%d) (%s) taken from log\n", f.type, name);
// generate a LogStructure entry for this FMT
s.msg_type = map_fmt_type(name, f.type);
s.msg_len = f.length;
s.name = f.name;
s.format = f.format;
s.labels = f.labels;
} }
if (msgparser[f.type] != NULL) { // emit the FMT to DataFlash:
return true; struct log_Format pkt {};
} pkt.head1 = HEAD_BYTE1;
pkt.head2 = HEAD_BYTE2;
pkt.msgid = LOG_FORMAT_MSG;
pkt.type = s.msg_type;
pkt.length = s.msg_len;
strncpy(pkt.name, s.name, sizeof(pkt.name));
strncpy(pkt.format, s.format, sizeof(pkt.format));
strncpy(pkt.labels, s.labels, sizeof(pkt.labels));
dataflash.WriteCriticalBlock(&pkt, sizeof(pkt));
}
if (msgparser[f.type] != NULL) {
return true;
}
// map from format name to a parser subclass: // map from format name to a parser subclass:
if (streq(name, "PARM")) { if (streq(name, "PARM")) {
@ -281,6 +411,9 @@ bool LogReader::handle_msg(const struct log_Format &f, uint8_t *msg) {
memcpy(name, f.name, 4); memcpy(name, f.name, 4);
if (save_message_type(name)) { if (save_message_type(name)) {
// write this message through to output log, changing the ID
// present in the input log to that used for the same message
// name in the output log
if (mapped_msgid[msg[2]] == 0) { if (mapped_msgid[msg[2]] == 0) {
printf("Unknown msgid %u\n", (unsigned)msg[2]); printf("Unknown msgid %u\n", (unsigned)msg[2]);
exit(1); exit(1);
@ -350,28 +483,3 @@ bool LogReader::set_parameter(const char *name, float value)
} }
return true; return true;
} }
/*
called when the last FMT message has been processed
*/
void LogReader::end_format_msgs(void)
{
// write out any formats we will be producing
for (uint8_t i=0; generated_names[i]; i++) {
for (uint8_t n=0; n<ARRAY_SIZE(log_structure); n++) {
if (strcmp(generated_names[i], log_structure[n].name) == 0) {
const struct LogStructure *s = &log_structure[n];
struct log_Format pkt {};
pkt.head1 = HEAD_BYTE1;
pkt.head2 = HEAD_BYTE2;
pkt.msgid = LOG_FORMAT_MSG;
pkt.type = s->msg_type;
pkt.length = s->msg_len;
strncpy(pkt.name, s->name, sizeof(pkt.name));
strncpy(pkt.format, s->format, sizeof(pkt.format));
strncpy(pkt.labels, s->labels, sizeof(pkt.labels));
dataflash.WriteCriticalBlock(&pkt, sizeof(pkt));
}
}
}
}

View File

@ -6,7 +6,15 @@
class LogReader : public DataFlashFileReader class LogReader : public DataFlashFileReader
{ {
public: public:
LogReader(AP_AHRS &_ahrs, AP_InertialSensor &_ins, Compass &_compass, AP_GPS &_gps, AP_Airspeed &_airspeed, DataFlash_Class &_dataflash, const char **&nottypes); LogReader(AP_AHRS &_ahrs,
AP_InertialSensor &_ins,
Compass &_compass,
AP_GPS &_gps,
AP_Airspeed &_airspeed,
DataFlash_Class &_dataflash,
struct LogStructure *log_structure,
uint8_t log_structure_count,
const char **&nottypes);
bool wait_type(const char *type); bool wait_type(const char *type);
const Vector3f &get_attitude(void) const { return attitude; } const Vector3f &get_attitude(void) const { return attitude; }
@ -32,7 +40,6 @@ public:
static bool in_list(const char *type, const char *list[]); static bool in_list(const char *type, const char *list[]);
protected: protected:
virtual void end_format_msgs(void) override;
private: private:
AP_AHRS &ahrs; AP_AHRS &ahrs;
@ -41,6 +48,8 @@ private:
AP_GPS &gps; AP_GPS &gps;
AP_Airspeed &airspeed; AP_Airspeed &airspeed;
DataFlash_Class &dataflash; DataFlash_Class &dataflash;
struct LogStructure *_log_structure;
uint8_t _log_structure_count;
uint8_t accel_mask; uint8_t accel_mask;
uint8_t gyro_mask; uint8_t gyro_mask;
@ -72,6 +81,7 @@ private:
void maybe_install_vehicle_specific_parsers(); void maybe_install_vehicle_specific_parsers();
void initialise_fmt_map();
uint8_t map_fmt_type(const char *name, uint8_t intype); uint8_t map_fmt_type(const char *name, uint8_t intype);
bool save_message_type(const char *name); bool save_message_type(const char *name);

View File

@ -100,22 +100,16 @@ void ReplayVehicle::load_parameters(void)
AP_Param::set_default_by_name("LOG_FILE_BUFSIZE", 60); AP_Param::set_default_by_name("LOG_FILE_BUFSIZE", 60);
} }
static const struct LogStructure min_log_structure[] = {
{ LOG_FORMAT_MSG, sizeof(log_Format),
"FMT", "BBnNZ", "Type,Length,Name,Format,Columns", "-b---", "-----" },
{ LOG_PARAMETER_MSG, sizeof(log_Parameter),
"PARM", "QNf", "TimeUS,Name,Value", "s--", "F--" },
{ LOG_MESSAGE_MSG, sizeof(log_Message),
"MSG", "QZ", "TimeUS,Message", "s-", "F-" },
};
void ReplayVehicle::setup(void) void ReplayVehicle::setup(void)
{ {
load_parameters(); load_parameters();
// we pass a minimal log structure, as we will be outputting the // we pass an empty log structure, filling the structure in with
// log structures we need manually, to prevent FMT duplicates // either the format present in the log (if we do not emit the
dataflash.Init(min_log_structure, ARRAY_SIZE(min_log_structure)); // message as a product of Replay), or the format understood in
// the current code (if we do emit the message in the normal
// places in the EKF, for example)
dataflash.Init(log_structure, 0);
ahrs.set_compass(&compass); ahrs.set_compass(&compass);
ahrs.set_fly_forward(true); ahrs.set_fly_forward(true);
@ -539,6 +533,7 @@ void Replay::setup()
_vehicle.setup(); _vehicle.setup();
inhibit_gyro_cal(); inhibit_gyro_cal();
force_log_disarmed();
if (log_info.update_rate == 400) { if (log_info.update_rate == 400) {
// assume copter for 400Hz // assume copter for 400Hz
@ -563,6 +558,12 @@ void Replay::inhibit_gyro_cal() {
abort(); abort();
} }
} }
void Replay::force_log_disarmed() {
if (!logreader.set_parameter("LOG_DISARMED", 1)) {
::fprintf(stderr, "Failed to set LOG_DISARMED parameter\n");
abort();
}
}
/* /*
setup user -p parameters setup user -p parameters
@ -625,15 +626,10 @@ void Replay::write_ekf_logs(void)
void Replay::read_sensors(const char *type) void Replay::read_sensors(const char *type)
{ {
if (!done_parameters && !streq(type,"FMT") && !streq(type,"PARM")) { if (streq(type, "PARM")) {
done_parameters = true;
set_user_parameters(); set_user_parameters();
} }
if (done_parameters && streq(type, "PARM")) {
set_user_parameters();
}
if (!done_home_init) { if (!done_home_init) {
if (streq(type, "GPS") && if (streq(type, "GPS") &&
(_vehicle.gps.status() >= AP_GPS::GPS_OK_FIX_3D) && done_baro_init) { (_vehicle.gps.status() >= AP_GPS::GPS_OK_FIX_3D) && done_baro_init) {
@ -667,13 +663,21 @@ void Replay::read_sensors(const char *type)
} }
} }
static bool ekf_force_started = false;
if (!ekf_force_started) {
if (log_info.have_imt2 ||
log_info.have_imt) {
_vehicle.ahrs.force_ekf_start();
::fprintf(stderr, "EKF force-started at %u\n", AP_HAL::micros());
ekf_force_started = true;
}
}
bool run_ahrs = false; bool run_ahrs = false;
if (log_info.have_imt2) { if (log_info.have_imt2) {
run_ahrs = streq(type, "IMT2"); run_ahrs = streq(type, "IMT2");
_vehicle.ahrs.force_ekf_start();
} else if (log_info.have_imt) { } else if (log_info.have_imt) {
run_ahrs = streq(type, "IMT"); run_ahrs = streq(type, "IMT");
_vehicle.ahrs.force_ekf_start();
} else if (log_info.have_imu2) { } else if (log_info.have_imu2) {
run_ahrs = streq(type, "IMU2"); run_ahrs = streq(type, "IMU2");
} else { } else {
@ -740,7 +744,7 @@ void Replay::log_check_generate(void)
velocity.x, velocity.x,
velocity.y, velocity.y,
velocity.z velocity.z
}; );
} }
@ -828,11 +832,15 @@ void Replay::loop()
} }
last_timestamp = AP_HAL::micros64(); last_timestamp = AP_HAL::micros64();
read_sensors(type); if (streq(type, "FMT")) {
if (!seen_non_fmt) {
if (!streq(type,"ATT")) { return;
return; }
} else {
seen_non_fmt = true;
} }
read_sensors(type);
} }

View File

@ -68,6 +68,8 @@ public:
AP_Vehicle::FixedWing aparm; AP_Vehicle::FixedWing aparm;
AP_Airspeed airspeed; AP_Airspeed airspeed;
AP_Int32 unused; // logging is magic for Replay; this is unused AP_Int32 unused; // logging is magic for Replay; this is unused
struct LogStructure log_structure[256] = {
};
DataFlash_Class dataflash{unused}; DataFlash_Class dataflash{unused};
private: private:
@ -118,14 +120,21 @@ private:
SITL::SITL sitl; SITL::SITL sitl;
#endif #endif
LogReader logreader{_vehicle.ahrs, _vehicle.ins, _vehicle.compass, _vehicle.gps, _vehicle.airspeed, _vehicle.dataflash, nottypes}; LogReader logreader{_vehicle.ahrs,
_vehicle.ins,
_vehicle.compass,
_vehicle.gps,
_vehicle.airspeed,
_vehicle.dataflash,
_vehicle.log_structure,
0,
nottypes};
FILE *ekf1f; FILE *ekf1f;
FILE *ekf2f; FILE *ekf2f;
FILE *ekf3f; FILE *ekf3f;
FILE *ekf4f; FILE *ekf4f;
bool done_parameters;
bool done_baro_init; bool done_baro_init;
bool done_home_init; bool done_home_init;
int32_t arm_time_ms = -1; int32_t arm_time_ms = -1;
@ -161,6 +170,7 @@ private:
void set_ins_update_rate(uint16_t update_rate); void set_ins_update_rate(uint16_t update_rate);
void inhibit_gyro_cal(); void inhibit_gyro_cal();
void force_log_disarmed();
void usage(void); void usage(void);
void set_user_parameters(void); void set_user_parameters(void);
@ -178,6 +188,8 @@ private:
void flush_and_exit(); void flush_and_exit();
FILE *xfopen(const char *f, const char *mode); FILE *xfopen(const char *f, const char *mode);
bool seen_non_fmt;
}; };
/* /*