James Kuszmaul | 60bb868 | 2023-08-07 07:39:34 -0700 | [diff] [blame] | 1 | #ifndef DOCUMENTATION_AOS_EXAMPLES_CLOCK_OFFSET_READER_H_ |
| 2 | #define DOCUMENTATION_AOS_EXAMPLES_CLOCK_OFFSET_READER_H_ |
| 3 | #include "aos/events/event_loop.h" |
| 4 | #include "aos/network/message_bridge_server_generated.h" |
| 5 | #include "documentation/aos/examples/sensor_data_generated.h" |
| 6 | |
| 7 | namespace examples { |
| 8 | |
| 9 | // This class is a sample that is shown in the markdown documentation. |
| 10 | // If it needs to get updated, the sample should get updated as well. |
| 11 | // TODO(james): Get a convenient way to directly include portions of files in |
| 12 | // markdown so that we don't just manually copy-and-paste the code between |
| 13 | // spots. |
| 14 | class SensorAgeReader { |
| 15 | public: |
| 16 | SensorAgeReader(aos::EventLoop *event_loop) |
| 17 | : event_loop_(event_loop), |
| 18 | clock_offset_fetcher_( |
| 19 | event_loop->MakeFetcher<aos::message_bridge::ServerStatistics>( |
| 20 | "/aos")) { |
| 21 | event_loop_->MakeWatcher( |
| 22 | "/input", [this](const SensorData &msg) { HandleSensorData(msg); }); |
| 23 | } |
| 24 | |
| 25 | void HandleSensorData(const SensorData &msg) { |
| 26 | std::chrono::nanoseconds monotonic_offset{0}; |
| 27 | clock_offset_fetcher_.Fetch(); |
| 28 | if (clock_offset_fetcher_.get() != nullptr) { |
| 29 | for (const auto connection : *clock_offset_fetcher_->connections()) { |
| 30 | if (connection->has_node() && connection->node()->has_name() && |
| 31 | connection->node()->name()->string_view() == "sensor") { |
| 32 | if (connection->has_monotonic_offset()) { |
| 33 | monotonic_offset = |
| 34 | std::chrono::nanoseconds(connection->monotonic_offset()); |
| 35 | } else { |
| 36 | // If we don't have a monotonic offset, that means we aren't |
| 37 | // connected, in which case we should just exit early. |
| 38 | // The ServerStatistics message will always populate statuses for |
| 39 | // every node, so we don't have to worry about missing the "sensor" |
| 40 | // node (although it can be good practice to check that the node you |
| 41 | // are looking for actually exists, to protect against programming |
| 42 | // errors). |
| 43 | LOG(WARNING) << "Message bridge disconnected."; |
| 44 | return; |
| 45 | } |
| 46 | break; |
| 47 | } |
| 48 | } |
| 49 | } else { |
| 50 | LOG(WARNING) << "No message bridge status available."; |
| 51 | return; |
| 52 | } |
| 53 | const aos::monotonic_clock::time_point now = event_loop_->monotonic_now(); |
| 54 | // The monotonic_remote_time will be the time that the message was sent on |
| 55 | // the source node; by offsetting it by the monotonic_offset, we should get |
| 56 | // a reasonable estimate of when it was sent. This does not account for any |
| 57 | // delays between the sensor reading and when it actually got sent. |
| 58 | const aos::monotonic_clock::time_point send_time( |
| 59 | event_loop_->context().monotonic_remote_time - monotonic_offset); |
| 60 | // Many sensors may include some sort of hardware timestamp indicating when |
| 61 | // the measurement was taken, which is likely before the sent time. This can |
| 62 | // be populated as a data field inside of the message, and if it is using |
| 63 | // the same monotonic clock as AOS is then we can do the same offset |
| 64 | // computation, but get a timestamp for when the data was actually captured. |
| 65 | const aos::monotonic_clock::time_point capture_time( |
| 66 | std::chrono::nanoseconds(msg.hardware_capture_time_ns()) - |
| 67 | monotonic_offset); |
| 68 | LOG(INFO) << "The sensor data was sent " |
| 69 | << aos::time::DurationInSeconds(now - send_time) |
| 70 | << " seconds ago."; |
| 71 | LOG(INFO) << "The sensor data was read off of the hardware " |
| 72 | << aos::time::DurationInSeconds(now - capture_time) |
| 73 | << " seconds ago."; |
| 74 | } |
| 75 | |
| 76 | aos::EventLoop *event_loop_; |
| 77 | aos::Fetcher<aos::message_bridge::ServerStatistics> clock_offset_fetcher_; |
| 78 | }; |
| 79 | } // namespace examples |
| 80 | #endif // DOCUMENTATION_AOS_EXAMPLES_CLOCK_OFFSET_READER_H_ |