Skip to content
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

✨ Expose VEXos' time and date functions #127

Merged
merged 41 commits into from
Oct 18, 2022
Merged

Conversation

baylessj
Copy link
Contributor

@baylessj baylessj commented Mar 3, 2019

Summary:

Adds functionality for retrieving the Date and Time stored in VEXos.

Motivation:

I'm working on setting up a logging utility for the BLRS robots and discovered that it would be helpful to set the log file's name as the current date and time to distinguish between the logs more easily.

Test Plan:

pros::date_s_t d = pros::get_date();
pros::time_s_t t = pros::get_time();
printf("%d %d %d %d %d %d %d\n", d.year, d.month, d.day, t.hour, t.min, t.sec, t.sec_hund);
d = pros::c::get_date();
t = pros::c::get_time();
printf("%d %d %d %d %d %d %d\n", d.year, d.month, d.day, t.hour, t.min, t.sec, t.sec_hund);
  • Compiles
  • Run test code on a V5
    I printed the output from the functions and got 0:0:0 for time and 11/16/2016 for the date every time.
  • [ ] Get accurate data from date/time functions

@baylessj baylessj changed the title Expose VEXos' time and date functions ✨ Expose VEXos' time and date functions Mar 3, 2019
@baylessj baylessj changed the title ✨ Expose VEXos' time and date functions ✨ Expose VEXos' time and date functions Mar 3, 2019
@baylessj baylessj added p: normal Normal priority enhancement This builds on top of an existing feature feature A brand new feature in testing This is currently in testing labels Mar 3, 2019
@baylessj baylessj added this to the 3.1.7 milestone Mar 3, 2019
@edjubuh
Copy link
Member

edjubuh commented Mar 3, 2019

I think there are some newlib stubs we can implement while we're at it. The added bonus is that functions like time(2) are now implemented and I'm fairly certain that some functions from std::chrono will come for free by adding this function.

The function is _gettimeofday(struct timeval *tv, struct timezone *tz). We can ignore tz since it's deprecated. Just need to fill

struct timeval {
    time_t      tv_sec;     /* seconds */
    suseconds_t tv_usec;    /* microseconds */
};

should be straightforward math to convert year/month/day/hours/minutes to seconds since 1970-01-01 00:00:00 (epoch). VEX seems to be nice enough to have given a different epoch year smh but we just need to add 10.

Won't be able to get microsecond precision, only millisecond precision but that's 🆗

@edjubuh edjubuh self-requested a review March 3, 2019 20:24
@HotelCalifornia
Copy link
Contributor

I think there are some newlib stubs we can implement while we're at it.

Are you saying this in addition to the "raw" passthrough functions to vexOS? Or instead of those?

@HotelCalifornia HotelCalifornia added in progress This is currently being worked on and removed enhancement This builds on top of an existing feature in testing This is currently in testing labels Mar 4, 2019
@HotelCalifornia HotelCalifornia added this to In Progress in PROS Non-Versioned Kernel Development via automation Mar 4, 2019
@baylessj
Copy link
Contributor Author

Read back through the SDK documentation a bit ago and discovered that these functions have not been implemented in the SDK yet, and there's no real indication of when they will be implemented. Not sure if/when that will happen, so there won't be any more progress with this PR until then.

@edjubuh edjubuh removed this from the 3.1.7 milestone Apr 29, 2019
@edjubuh edjubuh closed this Apr 29, 2019
@HotelCalifornia HotelCalifornia added on hold This may be revisited in the future p: wishlist This should be worked on when there's time and removed in progress This is currently being worked on p: normal Normal priority labels Apr 29, 2019
@HotelCalifornia HotelCalifornia moved this from In Progress to Backlog in PROS Non-Versioned Kernel Development Apr 29, 2019
@HotelCalifornia
Copy link
Contributor

I think there are some newlib stubs we can implement while we're at it. The added bonus is that functions like time(2) are now implemented and I'm fairly certain that some functions from std::chrono will come for free by adding this function.

The function is _gettimeofday(struct timeval *tv, struct timezone *tz). We can ignore tz since it's deprecated. Just need to fill

struct timeval {
    time_t      tv_sec;     /* seconds */
    suseconds_t tv_usec;    /* microseconds */
};

should be straightforward math to convert year/month/day/hours/minutes to seconds since 1970-01-01 00:00:00 (epoch). VEX seems to be nice enough to have given a different epoch year smh but we just need to add 10.

Won't be able to get microsecond precision, only millisecond precision but that's

Instead of _gettimeofday I think we can implement clock_gettime(clockid_t clk_id, struct timespec* t) :

Sufficiently recent versions of GNU libc and the Linux kernel support the following clocks:

CLOCK_REALTIME
System-wide realtime clock. Setting this clock requires appropriate privileges.
CLOCK_MONOTONIC
Clock that cannot be set and represents monotonic time since some unspecified starting point.
CLOCK_PROCESS_CPUTIME_ID
High-resolution per-process timer from the CPU.
CLOCK_THREAD_CPUTIME_ID
Thread-specific CPU-time clock.

We'd want to just handle CLOCK_MONOTONIC (and maybe CLOCK_PROCESS_CPUTIME_ID CLOCK_THREAD_CPUTIME_ID)-- others can just set errno to EINVAL.

Why CLOCK_MONOTONIC? Because that's what std::chrono::steady_clock calls to get its time (also pros::millis is a monotonic clock).

How would CLOCK_PROCESS_CPUTIME_ID or CLOCK_THREAD_CPUTIME_ID work? We'd want to add another TLSP and set the conter in each task to zero on creation, then increment it on each clock tick (hmm this sounds suspiciously familiar to CS 354 Lab 3... @xrex110). Actually now that I think about it, this is already stored on the task's control block as ulRunTimeCounter. I don't think std::chrono has interfaces for this so it's a bit lower priority but it would be nice to have.

@baylessj
Copy link
Contributor Author

Is it possible to implement the newlib stubs without an RTC of any sort on the brain? Last I heard, there isn't the hardware to support time and date functions...

@nathan-moore
Copy link
Member

There are a lot of times where the brain wouldn't have power, so any clock with a non-local frame of reference can't really be implemented. The ones alex was talking about can just be the output of a timer we get from VexOS, since they only care about the time period.

@HotelCalifornia
Copy link
Contributor

HotelCalifornia commented Mar 16, 2020

Yeah, like Nathan said: Linux and friends also provide ways to get system time since boot in milliseconds (that's the CLOCK_MONOTONIC thing or std::chrono::steady_clock), and the other two I mentioned are computed by the scheduler.

Also if we want to go for POSIX compliance too, there are symbols we can define

@Richard-Stump
Copy link
Contributor

Finished, the robot now displays an approximated time based off of a compiled timestamp and how long the program has been running. This was tested with several time zones.

Time-Robot
Time-Terminal

include/api.h Outdated Show resolved Hide resolved
include/pros/misc.hpp Outdated Show resolved Hide resolved
src/main.cpp Outdated Show resolved Hide resolved
src/system/hot.c Outdated Show resolved Hide resolved
version Outdated Show resolved Hide resolved
int _gettimeofday(struct timeval* tp, void* tzvp) {
if (competition_is_connected()) {
tp->tv_sec = vexSystemTimeGet() * 1000;
tp->tv_usec = vexSystemHighResTimeGet();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

honestly the times in its current form are probably atomic enough given he's getting the seconds and then the microseconds.

PROS Non-Versioned Kernel Development automation moved this from In Progress to In Review Aug 27, 2022
@sb-msoe
Copy link

sb-msoe commented Aug 27, 2022

Hi, I'm from Raider Robotics, and I'm working on a port of micro-ROS to the V5 Brain that I hope to release in the near future. micro-ROS has a dependency on clock_gettime for timed callbacks and exchanging messages with a ROS 2 device, among other reasons. Browsing the code, micro-ROS appears to require CLOCK_MONOTONIC and CLOCK_REALTIME to function correctly. So far, I've gotten it to publish messages to the ROS 2 network by, among other things, partially implementing clock_gettime. Below is my implementation (a simplified and adapted version of this), though it only handles the CLOCK_MONOTONIC case.

#include <sys/time.h>
#include "api.h"
int clock_gettime(clockid_t unused, struct timespec *tp)
{
    (void)unused;

    uint64_t m = micros();

    tp->tv_sec = m / 1000000;
    tp->tv_nsec = (m % 1000000) * 1000;

    return 0;
}

Currently, I believe this PR will cause micro-ROS to crash, as calling clock_gettime with CLOCK_MONOTONIC will result in an error and a return value of -1, as will calling clock_gettime with CLOCK_REALTIME while not connected to the new field system. I can work around the latter (by only running the code while connected to the field), but not the former. Would it be possible to at least implement CLOCK_MONOTONIC before this gets merged? If my above code isn't flawed, it should be as simple as that. As for CLOCK_REALTIME without being connected to the field, I wonder it would be possible to get the time using an external RTC, or, in my case, from the ROS 2 device I'm communicating with. If so, it would be great if clock_settime were also implemented, even if in a future PR.

I'm really excited to see that CLOCK_REALTIME can be implemented with VEX's new field system, as I'm having issues with micro-ROS's Executor system that might be fixed with a working CLOCK_REALTIME implementation. If the above issues are fixed, this could really help.

Thanks!

@WillXuCodes
Copy link
Member

Hi, I'm from Raider Robotics, and I'm working on a port of micro-ROS to the V5 Brain that I hope to release in the near future. micro-ROS has a dependency on clock_gettime for timed callbacks and exchanging messages with a ROS 2 device, among other reasons. Browsing the code, micro-ROS appears to require CLOCK_MONOTONIC and CLOCK_REALTIME to function correctly. So far, I've gotten it to publish messages to the ROS 2 network by, among other things, partially implementing clock_gettime. Below is my implementation (a simplified and adapted version of this), though it only handles the CLOCK_MONOTONIC case.

#include <sys/time.h>
#include "api.h"
int clock_gettime(clockid_t unused, struct timespec *tp)
{
    (void)unused;

    uint64_t m = micros();

    tp->tv_sec = m / 1000000;
    tp->tv_nsec = (m % 1000000) * 1000;

    return 0;
}

Currently, I believe this PR will cause micro-ROS to crash, as calling clock_gettime with CLOCK_MONOTONIC will result in an error and a return value of -1, as will calling clock_gettime with CLOCK_REALTIME while not connected to the new field system. I can work around the latter (by only running the code while connected to the field), but not the former. Would it be possible to at least implement CLOCK_MONOTONIC before this gets merged? If my above code isn't flawed, it should be as simple as that. As for CLOCK_REALTIME without being connected to the field, I wonder it would be possible to get the time using an external RTC, or, in my case, from the ROS 2 device I'm communicating with. If so, it would be great if clock_settime were also implemented, even if in a future PR.

I'm really excited to see that CLOCK_REALTIME can be implemented with VEX's new field system, as I'm having issues with micro-ROS's Executor system that might be fixed with a working CLOCK_REALTIME implementation. If the above issues are fixed, this could really help.

Thanks!

Hi MSOE,

Thanks for the heads up, I'm willing to delay this until 3.7.1 to get CLOCK_MONOTONIC. Glad to see you guys on here and checking in w/ development.

Keep in touch on the midwest discord!

-Will

int _gettimeofday(struct timeval* tp, void* tzvp) {
if (competition_is_connected()) {
tp->tv_sec = vexSystemTimeGet() * 1000;
tp->tv_usec = vexSystemHighResTimeGet();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mean, the bigger issue is that tv_sec != tv_usec /1000 since the vex docs indicate that vexSystemHighResTimeGet comes from a timer. I'd personally just give msec precision here and tell users to call a monotonic timer if they need any more precision.

src/system/newlib_stubs.c Outdated Show resolved Hide resolved
src/system/newlib_stubs.c Show resolved Hide resolved
@WillXuCodes WillXuCodes added this to In Progress in Kernel Version 3.7.1 Aug 29, 2022
@Richard-Stump Richard-Stump self-assigned this Sep 5, 2022
@Richard-Stump
Copy link
Contributor

I added/fixed the things requested and tested it on real hardware:

  • CLOCK_REALTIME works properly from the compiled timestamp
  • CLOCK_REALTIME can be set with clock_settime(). This correctly changes the the time to the time in GDT.
  • CLOCK_MONOTONIC is now available and correctly counts the number of seconds and microseconds. We do not have a fine enough clock to count nanoseconds like struct timespec has.

image

@WillXuCodes WillXuCodes merged commit b0590f7 into develop Oct 18, 2022
WillXuCodes added a commit that referenced this pull request Oct 18, 2022
* Expose VEXos' get time and date functions

* wip: add clock_gettime impl

* wip: fix errors with clock_gettime impl

* wip: add _gettimeofday impl

* Push code to build test for time implementation

* Add integer timestamp to the generated timestamp info

* Fix compile errors

* Fix compile errors 2

* Change _PROS_COMPILE_TIMESTAMP_INT to be an actual integer

* Test linking against _pros_ld_timestamp.o variables

* Test linking against _pros_ld_timestamp.o variables 2

* Test linking against _pros_ld_timestamp.o variables 3

* Test linking against _pros_ld_timestamp.o variables 4

* Convert _PROS_COMPILE_TIMESTAMP_INT back into a string

* Try using HOT_TABLE rather than the timestamp directly

* Make _PROS_COMPILESTAMP_INT a weak symbol

* Fix compiler error

* Attempt to use functions to subvert linking issues

* Try switching _PROS_COMPILE_TIMESTAMP_INT to an integer again

* Revert back to hacky callback solution

* Fix compile error

* Fix compile error 2

* Fix compile error 3

* Fix compile error 4

* Fix?

* Fix microsecond calculation

* Account for timezones when generating _PROS_COMPILE_TIMESTAMP_INT

* Fix formatting and accidental changes

* Commit for applying template

* Fix compilation errors and begin implementing clock_settime()

* Update firmware

* Update common.mk to allow POSIX functions in time.h

* Add CLOCK_MONOTONIC to clock_gettime()

* Add comment

* Fix version

Co-authored-by: Alex Brooke <akb.sbc@gmail.com>
Co-authored-by: WillXuCodes <xu.z.william@gmail.com>
Co-authored-by: Richard Stump <rnstump@purdue.edu>
@WillXuCodes WillXuCodes mentioned this pull request Oct 18, 2022
@WillXuCodes WillXuCodes deleted the feature/date-time branch March 8, 2023 05:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature A brand new feature p: wishlist This should be worked on when there's time
Projects
No open projects
Development

Successfully merging this pull request may close these issues.

None yet

8 participants