-
Notifications
You must be signed in to change notification settings - Fork 16.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add option to set system time via GCS #7716
Add option to set system time via GCS #7716
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of handling the MAVLINK_MSG_ID_SYSTEM_TIME
in ArduSub/GCS_Mavlink.cpp how about doing it fully in libraries/GCS_MAVLink/GCS_Common.cpp
That way all vehicles would support it.
c0c5749
to
df6be41
Compare
@amilcarlucas Done. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great, thanks !!!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@peterbarker @WickedShell Do you see any problems with changing the SYSTEM_TIME message time origin?
libraries/GCS_MAVLink/GCS_Common.cpp
Outdated
@@ -1743,6 +1743,25 @@ void GCS_MAVLINK::handle_common_gps_message(mavlink_message_t *msg) | |||
AP::gps().handle_msg(msg); | |||
} | |||
|
|||
void GCS_MAVLINK::handle_system_time_message(mavlink_message_t *msg) | |||
{ | |||
static bool system_time_set = false; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think this is good (besides of us trying to not have statics in methods). I think It should be checked at HAL level, I believe we don't want to ever override the system time once it's set.
df6be41
to
b6bbc48
Compare
@OXINARF done. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good generally.
libraries/AP_HAL/Util.cpp
Outdated
@@ -89,6 +106,11 @@ void AP_HAL::Util::get_system_clock_utc(int32_t &hour, int32_t &min, int32_t &se | |||
hour = hour_ms / (60 * 60 * 1000); | |||
} | |||
|
|||
bool AP_HAL::Util::system_time_set() const |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe system_time_was_set()
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
libraries/GCS_MAVLink/GCS_Common.cpp
Outdated
void GCS_MAVLINK::handle_system_time_message(mavlink_message_t *msg) | ||
{ | ||
// exit immediately if system time already set | ||
if (hal.util->system_time_set()) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems a little odd.
Perhaps the clocks are drifting and the GCS wants to bring the clocks back into sync?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The idea behind this PR is to set time once when connecting to the GCS, exactly like the older implementation with GPS.
hal.util->set_system_clock(packet.time_unix_usec); | ||
|
||
// update signing timestamp | ||
GCS_MAVLINK::update_signing_timestamp(packet.time_unix_usec); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pretty sure stuff will go to hell here if time goes backwards.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If a board have a RTC, or anything that gives the correct time, system_time_set
need to be true, like Linux boards.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But the only other place that sets the system time in ardupilot is when the gps is updated, it has no relation to RTC at all.
And the fact that during initialization mavlink packets are being handled, chances are that if the GCS sends this packet it will set the time before the GPS set it.
What if the GCS wants to set the time again, shouldn't it be allowed?
This particular line here looks very wrong btw. If GCS tries to update the time multiple times, we would fail hal.util->set_system_clock()
but change the signing timestamp.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The GCS can look at sensor status flags and send SYSTEM_TIME if gps flags indicate that gps isn't connected.
Other alternative is to look at SYSTEM_TIME epoch time coming from autopilot and set time only once if epoch time is zero (happens when gps isn't connected).
This patch only allows to set time only once, the variable system_time_was_set
will lock set_system_clock
functionality after the first call. Besides that, it appears that this function only needs to be performed once, microsecond accuracy is not critical for system_time
, right ?
In the ROV scenario, there are nearing thousands of sub users whose all logs are in 1970 because they cannot access 10k+ gps systems, this patch allows they to have a correct log time
This particular line here looks very wrong btw. If GCS tries to update the time multiple times, we would fail hal.util->set_system_clock() but change the signing timestamp.
// exit immediately if system time already set
if (hal.util->system_time_was_set()) {
return;
}
This'll allow to set time only once, so this line will not run again.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What if the GCS wants to set the time again, shouldn't it be allowed?
No, it shouldn't be allowed. @patrickelectric is correct that the GCS will only be allowed to set the time once with this patch, and the signing timestamp will only be set once as a result.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is still wrong. If GCS sends multiple times you hal.util->set_system_clock(packet.time_unix_usec);
will fail but a) you will return all went well and b) you will call GCS_MAVLINK::update_signing_timestamp(packet.time_unix_usec);
that you shouldn't.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@lucasdemarchi can you say where in the code this will happen ? The logic behind this is to set time once.
If GCS sends multiple times you hal.util->set_system_clock(packet.time_unix_usec); will fail but a) you will return all went well and b) you will call GCS_MAVLINK::update_signing_timestamp(packet.time_unix_usec); that you shouldn't.
I'll rewrite this.
"If GCS sends multiple times you hal.util->set_system_clock(packet.time_unix_usec);
will not occurs more than once" and update_signing_timestamp
will not occurs.
That's why it have:
// exit immediately if system time already set
if (hal.util->system_time_was_set()) {
return;
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
a) you will return all went well
It's void, there is no return or ACK. The gcs should not care of the result.
you will call GCS_MAVLINK::update_signing_timestamp(packet.time_unix_usec); that you shouldn't.
No, we are not. It happens one time only. And even if we did do it many times, why shouldn't we? Plane calls this method repeatedly, so obviously it is ok.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This still allows time to go backwards, right? Our system time isn't zero when the first mavlink packet comes in, and if it does say zero we'll go backwards (and mavlink2 signing will suffer)
What are the implications for allowing multiple sets of the system time, but only monotonically increasing? AFAICS there's no excuse for any GCS or GPS to give us a time in the future.
Giving a time in the past I have seen; the Sonix board in the SkyViper 2450GPS throws a time estimate at the GPS which is in the past; it may later update that estimate if it gets a better one (e.g. the SkyRocket app connecting and supplying one). That better estimate should (AFAIK) always be in the future. Note that it supplied the information directly to the GPS unit, not via mavlink system_time or similar, but I think the principle is the same - setting the time forward should be allowed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, that's true. But GPS can do the same thing as the GCS, moving the time backwards. But ardupilot doesn't know if a future time or a passed time is correct, the only way is to trust between the GPS or GCS.
b6bbc48
to
be975cf
Compare
libraries/AP_HAL/Util.cpp
Outdated
gettimeofday(&ts, nullptr); | ||
return ((long long)((ts.tv_sec * 1000000) + ts.tv_usec)); | ||
#elif CONFIG_HAL_BOARD == HAL_BOARD_CHIBIOS | ||
return ST2US(chVTGetSystemTime()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No scaling? This is the same as _ms() above.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ST2MS is for ms, ST2US for us.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
aye
libraries/AP_HAL_Linux/Util.cpp
Outdated
@@ -28,6 +28,8 @@ void Util::init(int argc, char * const *argv) { | |||
saved_argc = argc; | |||
saved_argv = argv; | |||
|
|||
_system_time_was_set = CONFIG_HAL_BOARD_SUBTYPE == HAL_BOARD_SUBTYPE_LINUX_NONE; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Did you mean CONFIG_HAL_BOARD == HAL_BOARD_LINUX?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, this is the definition of set_system_clock in linux.
void Util::set_system_clock(uint64_t time_utc_usec)
{
#if CONFIG_HAL_BOARD_SUBTYPE != HAL_BOARD_SUBTYPE_LINUX_NONE
if (system_time_was_set()) {
return;
}
_system_time_was_set = true;
timespec ts;
ts.tv_sec = time_utc_usec/1000000ULL;
ts.tv_nsec = (time_utc_usec % 1000000ULL) * 1000ULL;
clock_settime(CLOCK_REALTIME, &ts);
#endif
}
set_system_clock
only works if CONFIG_HAL_BOARD_SUBTYPE != HAL_BOARD_SUBTYPE_LINUX_NONE
, therefore _system_time_was_set
should be CONFIG_HAL_BOARD_SUBTYPE == HAL_BOARD_SUBTYPE_LINUX_NONE;
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is this line necessary? We are saying system_time_is_set for linux_none, but that's not actually the case. If we initialize it to false, it won't change or hurt.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
be975cf
to
efd3986
Compare
libraries/AP_HAL_Linux/Util.cpp
Outdated
@@ -28,6 +28,8 @@ void Util::init(int argc, char * const *argv) { | |||
saved_argc = argc; | |||
saved_argv = argv; | |||
|
|||
_system_time_was_set = CONFIG_HAL_BOARD == HAL_BOARD_LINUX; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this redundant? We are in Linux namespace.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Check my last comment.
#7716 (comment)
44fd9f7
to
8a4b55a
Compare
Humn... I was pretty sure to have touched this code before. Item (1) from #5548 ... What do you think? |
Linux and PX4 could share the same code, but that is a nonfunctional change unrelated to this PR. Correct? |
@lucasdemarchi, true, that's exactly what are you talking about, I believe that more PR will appear in the future to expand functionality and compatibility between boards. Besides that, I believe that the last updates turn this PR more likely to be accepted. |
Anything else necessary to merge this ? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
https://github.com/ArduPilot/ardupilot/blob/master/ArduSub/commands.cpp#L151
We should remove this flag and use the new hal.util function to check. Same in Copter and Rover.
@jaxxzer Sub, Copter and Rover updated to use HAL. |
libraries/AP_HAL_Linux/Util.cpp
Outdated
@@ -94,6 +96,11 @@ void Util::_toneAlarm_timer_tick() { | |||
void Util::set_system_clock(uint64_t time_utc_usec) | |||
{ | |||
#if CONFIG_HAL_BOARD_SUBTYPE != HAL_BOARD_SUBTYPE_LINUX_NONE | |||
if (system_time_was_set()) { | |||
return; | |||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok, now that the checks are in other places you can remove this check. Let this decision be done by the caller and not by the hal implementation here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Leaving it in the hal and taking the checks out of vehicle seems like the better choice to me, in order to guarantee that the necessary action is always executed and prevent developer mistakes. The checks were always in vehicle, they are redundant now, and could be removed, but I don't think that this is the desirable action. I don't see a problem with one extra 'if' to be sure, and to make it easier for a human to know what is going on with the code.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
From my POV we are spreading it on different HALs in a not obvious way, so I don't agree. The checks are redundant now because each vehicle handles it. It doesn't need to be that way, though. It could be done my common vehicle code.
libraries/AP_HAL_PX4/Util.cpp
Outdated
@@ -27,6 +27,7 @@ extern bool _px4_thread_should_exit; | |||
*/ | |||
PX4Util::PX4Util(void) : Util() | |||
{ | |||
AP_HAL::Util::_system_time_was_set = false; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why using the upper class names here?
libraries/AP_HAL_PX4/Util.cpp
Outdated
@@ -98,6 +99,11 @@ enum PX4Util::safety_state PX4Util::safety_switch_state(void) | |||
|
|||
void PX4Util::set_system_clock(uint64_t time_utc_usec) | |||
{ | |||
if (AP_HAL::Util::system_time_was_set()) { | |||
return; | |||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this should be removed as well as any check on util classes.
Ok, I though this number was used only for timestamping logs, which should not require gps-clock precision. I was not aware of this use case to start missions at exactly the same time, that is a good point. It should be ok if they get their time from the same GCS. Even if missions start at exactly the same time to the microseconds, everything else from that point is non-deterministic, is there any coordination or synchronization in timing of mission commands after the mission starts? It seems like even if the clocks are off by a few seconds, it won't really make a difference in practice. Of course, a parameter won't hurt if we need it. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Besides inline comment, the only other thing I don't like is the different behavior in Plane and Tracker - I guess we need to re-think what are the reasons for only setting system time once; in any case, this is pre-existing and shouldn't hold the PR.
A better protocol for time sync would be nice, but as a first step this seems good enough to me.
ArduCopter/Copter.h
Outdated
@@ -319,14 +319,14 @@ class Copter : public AP_HAL::HAL::Callbacks { | |||
uint8_t throttle_zero : 1; // 15 // true if the throttle stick is at zero, debounced, determines if pilot intends shut-down when not using motor interlock | |||
uint8_t system_time_set : 1; // 16 // true if the system time has been set from the GPS |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should remove this since it's not needed anymore. And while at it, just remove the numbers from the comments instead of keeping updating them.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+1 those diffs are annoying
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
On Wed, 4 Apr 2018, Jacob Walser wrote:
+1 those diffs are annoying
Oh good, it wasn't just me.
|
I think @OXINARF and @peterbarker are happy now so we can merge any time right? |
hal.util->set_system_clock(packet.time_unix_usec); | ||
|
||
// update signing timestamp | ||
GCS_MAVLINK::update_signing_timestamp(packet.time_unix_usec); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This still allows time to go backwards, right? Our system time isn't zero when the first mavlink packet comes in, and if it does say zero we'll go backwards (and mavlink2 signing will suffer)
What are the implications for allowing multiple sets of the system time, but only monotonically increasing? AFAICS there's no excuse for any GCS or GPS to give us a time in the future.
Giving a time in the past I have seen; the Sonix board in the SkyViper 2450GPS throws a time estimate at the GPS which is in the past; it may later update that estimate if it gets a better one (e.g. the SkyRocket app connecting and supplying one). That better estimate should (AFAIK) always be in the future. Note that it supplied the information directly to the GPS unit, not via mavlink system_time or similar, but I think the principle is the same - setting the time forward should be allowed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
as I've mentioned in my comments, I think we need a separate RTC handling library, perhaps called AP_RTClock. I don't think the hal should be the keeper of the time since 1970.
@@ -77,6 +77,23 @@ uint64_t AP_HAL::Util::get_system_clock_ms() const | |||
#endif | |||
} | |||
|
|||
uint64_t AP_HAL::Util::get_system_clock_us() const | |||
{ | |||
#if defined(__APPLE__) && defined(__MACH__) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this looks quite odd doing ifdefs for system time inside AP_HAL/Util.cpp. Normally we'd make it a virtual function and implement in each HAL.
I actually think this isn't really the job of the HAL though, I think we need a AP_RTClock library for this work
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is the exactly same code that exist in uint64_t AP_HAL::Util::get_system_clock_ms()
. I disagree that is necessary an entire library to hold this simple PR.
libraries/AP_HAL/Util.cpp
Outdated
gettimeofday(&ts, nullptr); | ||
return ((long long)((ts.tv_sec * 1000000) + ts.tv_usec)); | ||
#elif CONFIG_HAL_BOARD == HAL_BOARD_CHIBIOS | ||
return ST2US(chVTGetSystemTime()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is bad in several ways on ChibiOS
First off, its calling a ChibiOS API that is only allowed in normal thread context from a function that users may think is OK from within a lock context or ISR. That could cause a fault (and hard crash)
Secondly, system ticks wrap really fast. So the result will wrap every few seconds on some boards.
Again, I think this should be in a AP_RTClock library, with the HAL providing the minimum information needed. Maybe a hal.util->get_initial_system_time(uint64_t &system_time_us, uint64_t &time_since_boot_us);
that would give two 64 bit timestamps, one in time since boot, the other a real time (since the epoch). It should return a bool, and return false if the system can't provide that time.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Again, this code is exactly the same that exist in uint64_t AP_HAL::Util::get_system_clock_ms()
, only converting to us. It's working with pixhawk and I believe that will work with other boards. Besides that, it's not necessary to hold this PR If modifications in chibios or the creation of a new library is necessary.
On Thu, 5 Apr 2018, Patrick José Pereira wrote:
Yes, that's true. But GPS can do the same thing as the GCS, moving the
time backwards. With the pixhawk usually it starts with 1970 or 2000,
don't remember.
You're absolutely right, and I am worried about the mavlink and HIL GPS
backends in that case.
A real GPS should never attempt to set the time in the past.
|
b4eaef6
to
5b3925b
Compare
Signed-off-by: Patrick José Pereira <patrickelectric@gmail.com>
Signed-off-by: Patrick José Pereira <patrickelectric@gmail.com>
Signed-off-by: Patrick José Pereira <patrickelectric@gmail.com>
Signed-off-by: Patrick José Pereira <patrickelectric@gmail.com>
Signed-off-by: Patrick José Pereira <patrickelectric@gmail.com>
Signed-off-by: Patrick José Pereira <patrickelectric@gmail.com>
Signed-off-by: Patrick José Pereira <patrickelectric@gmail.com>
Signed-off-by: Patrick José Pereira <patrickelectric@gmail.com>
Signed-off-by: Patrick José Pereira <patrickelectric@gmail.com>
Signed-off-by: Patrick José Pereira <patrickelectric@gmail.com>
Signed-off-by: Patrick José Pereira <patrickelectric@gmail.com>
Removed ChibiOS support. |
5b3925b
to
24f080f
Compare
mavlink/qgroundcontrol#6246 already merged. |
I think this is stuck because @tridge asked that it be reworked and added to a new AP_RTClock library instead of being in the HAL. It's possible that @peterbarker is willing to do that work, or perhaps @patrickelectric can do it after a discussion with Tridge and Peter? This is an important feature so I'm personally keen that we get it resolved. |
Closing this in favour of @peterbarker's PR which includes this one. #8121 |
Fix bluerobotics/ardusub#131