PX4 Firmware
PX4 Autopilot Software http://px4.io
Replay.hpp
Go to the documentation of this file.
1 /****************************************************************************
2  *
3  * Copyright (c) 2016-2019 PX4 Development Team. All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * 1. Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  * notice, this list of conditions and the following disclaimer in
13  * the documentation and/or other materials provided with the
14  * distribution.
15  * 3. Neither the name PX4 nor the names of its contributors may be
16  * used to endorse or promote products derived from this software
17  * without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
22  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
23  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
24  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
25  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
26  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
27  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
29  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30  * POSSIBILITY OF SUCH DAMAGE.
31  *
32  ****************************************************************************/
33 
34 #pragma once
35 
36 #include <fstream>
37 #include <map>
38 #include <vector>
39 #include <set>
40 #include <string>
41 
42 #include "definitions.hpp"
43 
44 #include <px4_platform_common/module.h>
45 #include <uORB/uORBTopics.h>
47 
48 namespace px4
49 {
50 
51 /**
52  * @class Replay
53  * Parses an ULog file and replays it in 'real-time'. The timestamp of each replayed message is offset
54  * to match the starting time of replay. It keeps a stream for each subscription to find the next message
55  * to replay. This is necessary because data messages from different subscriptions don't need to be in
56  * monotonic increasing order.
57  */
58 class Replay : public ModuleBase<Replay>
59 {
60 public:
61  Replay() = default;
62 
63  virtual ~Replay();
64 
65  /** @see ModuleBase */
66  static int task_spawn(int argc, char *argv[]);
67 
68  /** @see ModuleBase */
69  static Replay *instantiate(int argc, char *argv[]);
70 
71  /** @see ModuleBase */
72  static int custom_command(int argc, char *argv[]);
73 
74  /** @see ModuleBase */
75  static int print_usage(const char *reason = nullptr);
76 
77  /** @see ModuleBase::run() */
78  void run() override;
79 
80  /**
81  * Apply the parameters from the log
82  * @param quiet do not print an error if true and no log file given via ENV
83  * @return 0 on success
84  */
85  static int applyParams(bool quiet);
86 
87  /**
88  * Tell the replay module that we want to use replay mode.
89  * After that, only 'replay start' must be executed (typically the last step after startup).
90  * @param file_name file name of the used log replay file. Will be copied.
91  */
92  static void setupReplayFile(const char *file_name);
93 
94  static bool isSetup() { return _replay_file; }
95 
96 protected:
97 
98  /**
99  * @class Compatibility base class to convert topics to an updated format
100  */
102  {
103  public:
104  virtual ~CompatBase() = default;
105 
106  /**
107  * apply compatibility to a topic
108  * @param data input topic (can be modified in place)
109  * @return new topic data
110  */
111  virtual void *apply(void *data) = 0;
112  };
113 
115  {
116  public:
117  CompatSensorCombinedDtType(int gyro_integral_dt_offset_log, int gyro_integral_dt_offset_intern,
118  int accelerometer_integral_dt_offset_log, int accelerometer_integral_dt_offset_intern);
119 
120  void *apply(void *data) override;
121  private:
126  };
127 
128  struct Subscription {
129 
130  const orb_metadata *orb_meta = nullptr; ///< if nullptr, this subscription is invalid
131  orb_advert_t orb_advert = nullptr;
132  uint8_t multi_id;
133  int timestamp_offset; ///< marks the field of the timestamp
134 
135  bool ignored = false; ///< if true, it will not be considered for publication in the main loop
136 
137  std::streampos next_read_pos;
138  uint64_t next_timestamp; ///< timestamp of the file
139 
140  CompatBase *compat = nullptr;
141 
142  // statistics
143  int error_counter = 0;
144  int publication_counter = 0;
145  };
146 
147  /**
148  * Find the offset & field size in bytes for a given field name
149  * @param format format string, as specified by ULog
150  * @param field_name search for this field
151  * @param offset returned offset
152  * @param field_size returned field size
153  * @return true if found, false otherwise
154  */
155  static bool findFieldOffset(const std::string &format, const std::string &field_name, int &offset, int &field_size);
156 
157  /**
158  * publish an orb topic
159  * @param sub
160  * @param data
161  * @return true if published, false otherwise
162  */
163  bool publishTopic(Subscription &sub, void *data);
164 
165  /**
166  * called when entering the main replay loop
167  */
168  virtual void onEnterMainLoop() {}
169 
170  /**
171  * called when exiting the main replay loop
172  */
173  virtual void onExitMainLoop() {}
174 
175  /**
176  * called when a new subscription is added
177  */
178  virtual void onSubscriptionAdded(Subscription &sub, uint16_t msg_id) {}
179 
180  /**
181  * handle delay until topic can be published.
182  * @param next_file_timestamp timestamp of next message to publish
183  * @param timestamp_offset offset between file start time and replay start time
184  * @return timestamp that the message to publish should have
185  */
186  virtual uint64_t handleTopicDelay(uint64_t next_file_time, uint64_t timestamp_offset);
187 
188  /**
189  * handle the publication of a topic update
190  * @return true if published, false otherwise
191  */
192  virtual bool handleTopicUpdate(Subscription &sub, void *data, std::ifstream &replay_file);
193 
194  /**
195  * read a topic from the file (offset given by the subscription) into _read_buffer
196  */
197  void readTopicDataToBuffer(const Subscription &sub, std::ifstream &replay_file);
198 
199  /**
200  * Find next data message for this subscription, starting with the stored file offset.
201  * Skip the first message, and if found, read the timestamp and store the new file offset.
202  * This also takes care of new subscriptions and parameter updates. When reaching EOF,
203  * the subscription is set to invalid.
204  * File seek position is arbitrary after this call.
205  * @return false on file error
206  */
207  bool nextDataMessage(std::ifstream &file, Subscription &subscription, int msg_id);
208 
209  std::vector<Subscription *> _subscriptions;
210  std::vector<uint8_t> _read_buffer;
211 
212 private:
213  std::set<std::string> _overridden_params;
214  std::map<std::string, std::string> _file_formats; ///< all formats we read from the file
215 
218  std::streampos _data_section_start; ///< first ADD_LOGGED_MSG message
219 
220  /** keep track of file position to avoid adding a subscription multiple times. */
221  std::streampos _subscription_file_pos = 0;
222 
223  int64_t _read_until_file_position = 1ULL << 60; ///< read limit if log contains appended data
224 
225  bool readFileHeader(std::ifstream &file);
226 
227  /**
228  * Read definitions section: check formats, apply parameters and store
229  * the start of the data section.
230  * @return true on success
231  */
232  bool readFileDefinitions(std::ifstream &file);
233 
234  ///file parsing methods. They return false, when further parsing should be aborted.
235  bool readFormat(std::ifstream &file, uint16_t msg_size);
236  bool readAndAddSubscription(std::ifstream &file, uint16_t msg_size);
237  bool readFlagBits(std::ifstream &file, uint16_t msg_size);
238 
239  /**
240  * Read the file header and definitions sections. Apply the parameters from this section
241  * and apply user-defined overridden parameters.
242  * @return true on success
243  */
244  bool readDefinitionsAndApplyParams(std::ifstream &file);
245 
246  /**
247  * Read and handle additional messages starting at current file position, while position < end_position.
248  * This handles dropout and parameter update messages.
249  * We need to handle these separately, because they have no timestamp. We look at the file position instead.
250  * @return false on file error
251  */
252  bool readAndHandleAdditionalMessages(std::ifstream &file, std::streampos end_position);
253  bool readDropout(std::ifstream &file, uint16_t msg_size);
254  bool readAndApplyParameter(std::ifstream &file, uint16_t msg_size);
255 
256  static const orb_metadata *findTopic(const std::string &name);
257 
258  /** get the array size from a type. eg. float[3] -> return float */
259  static std::string extractArraySize(const std::string &type_name_full, int &array_size);
260 
261  /** get the size of a type that is not an array */
262  static size_t sizeOfType(const std::string &type_name);
263 
264  /** get the size of a type that can be an array */
265  static size_t sizeOfFullType(const std::string &type_name_full);
266 
267  void setUserParams(const char *filename);
268 
269  static char *_replay_file;
270 };
271 
272 } //namespace px4
virtual void * apply(void *data)=0
apply compatibility to a topic
void readTopicDataToBuffer(const Subscription &sub, std::ifstream &replay_file)
read a topic from the file (offset given by the subscription) into _read_buffer
Definition: Replay.cpp:862
static int applyParams(bool quiet)
Apply the parameters from the log.
Definition: Replay.cpp:986
static Replay * instantiate(int argc, char *argv[])
Definition: Replay.cpp:1017
bool nextDataMessage(std::ifstream &file, Subscription &subscription, int msg_id)
Find next data message for this subscription, starting with the stored file offset.
Definition: Replay.cpp:557
std::streampos _subscription_file_pos
keep track of file position to avoid adding a subscription multiple times.
Definition: Replay.hpp:221
bool readAndHandleAdditionalMessages(std::ifstream &file, std::streampos end_position)
Read and handle additional messages starting at current file position, while position < end_position...
Definition: Replay.cpp:472
std::vector< uint8_t > _read_buffer
Definition: Replay.hpp:210
std::map< std::string, std::string > _file_formats
all formats we read from the file
Definition: Replay.hpp:214
Parses an ULog file and replays it in &#39;real-time&#39;.
Definition: Replay.hpp:58
bool readAndApplyParameter(std::ifstream &file, uint16_t msg_size)
Definition: Replay.cpp:505
virtual void onExitMainLoop()
called when exiting the main replay loop
Definition: Replay.hpp:173
static char * _replay_file
Definition: Replay.hpp:269
bool readFlagBits(std::ifstream &file, uint16_t msg_size)
Definition: Replay.cpp:251
bool readAndAddSubscription(std::ifstream &file, uint16_t msg_size)
Definition: Replay.cpp:324
virtual uint64_t handleTopicDelay(uint64_t next_file_time, uint64_t timestamp_offset)
handle delay until topic can be published.
Definition: Replay.cpp:878
std::vector< Subscription * > _subscriptions
Definition: Replay.hpp:209
int timestamp_offset
marks the field of the timestamp
Definition: Replay.hpp:133
static int print_usage(const char *reason=nullptr)
Definition: Replay.cpp:1036
uint64_t _file_start_time
Definition: Replay.hpp:216
Replay()=default
int64_t _read_until_file_position
read limit if log contains appended data
Definition: Replay.hpp:223
virtual ~CompatBase()=default
static int custom_command(int argc, char *argv[])
Definition: Replay.cpp:944
static std::string extractArraySize(const std::string &type_name_full, int &array_size)
get the array size from a type.
Definition: Replay.cpp:656
uint8_t * data
Definition: dataman.cpp:149
std::streampos next_read_pos
Definition: Replay.hpp:137
virtual void onEnterMainLoop()
called when entering the main replay loop
Definition: Replay.hpp:168
static bool findFieldOffset(const std::string &format, const std::string &field_name, int &offset, int &field_size)
Find the offset & field size in bytes for a given field name.
Definition: Replay.cpp:441
virtual void onSubscriptionAdded(Subscription &sub, uint16_t msg_id)
called when a new subscription is added
Definition: Replay.hpp:178
__BEGIN_DECLS typedef void * orb_advert_t
ORB topic advertiser handle.
Definition: uORB.h:134
bool readDropout(std::ifstream &file, uint16_t msg_size)
Definition: Replay.cpp:547
bool readFileDefinitions(std::ifstream &file)
Read definitions section: check formats, apply parameters and store the start of the data section...
Definition: Replay.cpp:194
uint64_t _replay_start_time
Definition: Replay.hpp:217
void run() override
Definition: Replay.cpp:745
const char * name
Definition: tests_main.c:58
Object metadata.
Definition: uORB.h:50
virtual ~Replay()
Definition: Replay.cpp:87
static int task_spawn(int argc, char *argv[])
Definition: Replay.cpp:958
bool publishTopic(Subscription &sub, void *data)
publish an orb topic
Definition: Replay.cpp:894
std::streampos _data_section_start
first ADD_LOGGED_MSG message
Definition: Replay.hpp:218
struct @83::@85::@87 file
std::set< std::string > _overridden_params
Definition: Replay.hpp:213
uint64_t next_timestamp
timestamp of the file
Definition: Replay.hpp:138
static bool isSetup()
Definition: Replay.hpp:94
static const orb_metadata * findTopic(const std::string &name)
Definition: Replay.cpp:642
static size_t sizeOfFullType(const std::string &type_name_full)
get the size of a type that can be an array
Definition: Replay.cpp:706
Definition: bst.cpp:62
static size_t sizeOfType(const std::string &type_name)
get the size of a type that is not an array
Definition: Replay.cpp:671
bool readFileHeader(std::ifstream &file)
Definition: Replay.cpp:170
bool readDefinitionsAndApplyParams(std::ifstream &file)
Read the file header and definitions sections.
Definition: Replay.cpp:714
static void setupReplayFile(const char *file_name)
Tell the replay module that we want to use replay mode.
Definition: Replay.cpp:118
void setUserParams(const char *filename)
Definition: Replay.cpp:128
bool readFormat(std::ifstream &file, uint16_t msg_size)
file parsing methods. They return false, when further parsing should be aborted.
Definition: Replay.cpp:298
virtual bool handleTopicUpdate(Subscription &sub, void *data, std::ifstream &replay_file)
handle the publication of a topic update
Definition: Replay.cpp:872