Skip to content

Commit

Permalink
Merge pull request #675 from fadushin/set_time_of_day
Browse files Browse the repository at this point in the history
Add support for `atomvm:posix_clock_settime/2`

These changes are made under both the "Apache 2.0" and the "GNU Lesser General
Public License 2.1 or later" license terms (dual license).

SPDX-License-Identifier: Apache-2.0 OR LGPL-2.1-or-later
  • Loading branch information
bettio committed Oct 3, 2023
2 parents 6a84835 + 1d9e911 commit 0b7f132
Show file tree
Hide file tree
Showing 6 changed files with 89 additions and 2 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Added heap growth strategies as a fine-tuning option to `spawn_opt/2,4`
- Added `crypto:crypto_one_time/4,5` on ESP32
- Improved nif and port support on STM32
- Added support for `atomvm:posix_clock_settime/2`

### Fixed

Expand Down
10 changes: 9 additions & 1 deletion doc/src/programmers-guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -581,7 +581,15 @@ Use `erlang:universaltime/0` to get the current time at second resolution, to ob
%% erlang
{{Year, Month, Day}, {Hour, Minute, Second}} = erlang:universaltime().

> Note. Setting the system time is done in a platform-specific manner. For information about how to set system time on the ESP32, see the [Network Programming Guide](./network-programming-guide.md).
On some platforms, you can use the `atomvm:posix_clock_settime/2` to set the system time. Supply a clock id (currently, the only supported clock id is the atom `realtime`) and a time value as a tuple, containing seconds and nanoseconds since the UNIX epoch (midnight, January 1, 1970). For example,

%% erlang
SecondsSinceUnixEpoch = ... %% acquire the time
atomvm:posix_clock_settime(realtime, {SecondsSinceUnixEpoch, 0})

> Note. This operation is not supported yet on the `stm32` platform. On most UNIX platforms, you typically need `root` permission to set the system time.
On the ESP32 platform, you can use the Wifi network to set the system time automatically. For information about how to set system time on the ESP32 using SNTP, see the [Network Programming Guide](./network-programming-guide.md).

To convert a time (in seconds, milliseconds, or microseconds from the UNIX epoch) to a date-time, use the `calendar:system_time_to_universal_time/2` function. For example,

Expand Down
25 changes: 24 additions & 1 deletion libs/eavmlib/src/atomvm.erl
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,8 @@
posix_open/3,
posix_close/1,
posix_read/2,
posix_write/2
posix_write/2,
posix_clock_settime/2
]).

-export_type([
Expand Down Expand Up @@ -267,3 +268,25 @@ posix_read(_File, _Count) ->
{ok, non_neg_integer()} | {error, posix_error()}.
posix_write(_File, _Data) ->
erlang:nif_error(undefined).

%%
%% @param ClockId The clock id
%% @param ValueSinceUnixEpoch The value, in specified seconds and nanoseconds,
%% since the UNIX epoch (Jan 1, 1970)
%% @return `ok' or an error tuple
%% @doc Set the system time.
%%
%% This function sets the system time to the specified value, expressed as a
%% tuple containing seconds and nanoseconds since the UNIX epoch (Jan 1, 1970).
%% Coordinates are all in UTC.
%%
%% Note. Some systems may require special permissions to call this function.
%% @end
%%
-spec posix_clock_settime(
ClockId :: realtime,
ValueSinceUnixEpoch :: {Seconds :: integer(), Nanoseconds :: integer()}
) ->
ok | {error, Reason :: posix_error()}.
posix_clock_settime(_ClockId, _Time) ->
erlang:nif_error(undefined).
1 change: 1 addition & 0 deletions src/libAtomVM/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,7 @@ define_if_symbol_exists(libAtomVM O_NOFOLLOW "fcntl.h" PRIVATE HAVE_O_NOFOLLOW)
define_if_symbol_exists(libAtomVM O_RSYNC "fcntl.h" PRIVATE HAVE_O_RSYNC)
define_if_symbol_exists(libAtomVM O_SEARCH "fcntl.h" PRIVATE HAVE_O_SEARCH)
define_if_symbol_exists(libAtomVM O_TTY_INIT "fcntl.h" PRIVATE HAVE_O_TTY_INIT)
define_if_symbol_exists(libAtomVM clock_settime "sys/time.h" PRIVATE HAVE_CLOCK_SETTIME)

if (AVM_USE_32BIT_FLOAT)
target_compile_definitions(libAtomVM PUBLIC AVM_USE_SINGLE_PRECISION)
Expand Down
53 changes: 53 additions & 0 deletions src/libAtomVM/nifs.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@

#include "nifs.h"

#include <errno.h>
#include <fenv.h>
#include <math.h>
#include <stdio.h>
Expand Down Expand Up @@ -158,6 +159,7 @@ static term nif_atomvm_add_avm_pack_file(Context *ctx, int argc, term argv[]);
static term nif_atomvm_close_avm_pack(Context *ctx, int argc, term argv[]);
static term nif_atomvm_get_start_beam(Context *ctx, int argc, term argv[]);
static term nif_atomvm_read_priv(Context *ctx, int argc, term argv[]);
static term nif_atomvm_posix_clock_settime(Context *ctx, int argc, term argv[]);
static term nif_console_print(Context *ctx, int argc, term argv[]);
static term nif_base64_encode(Context *ctx, int argc, term argv[]);
static term nif_base64_decode(Context *ctx, int argc, term argv[]);
Expand Down Expand Up @@ -658,6 +660,11 @@ static const struct Nif atomvm_read_priv_nif =
.base.type = NIFFunctionType,
.nif_ptr = nif_atomvm_read_priv
};
static const struct Nif atomvm_posix_clock_settime_nif =
{
.base.type = NIFFunctionType,
.nif_ptr = nif_atomvm_posix_clock_settime
};
static const struct Nif console_print_nif =
{
.base.type = NIFFunctionType,
Expand Down Expand Up @@ -3803,6 +3810,52 @@ static term nif_atomvm_read_priv(Context *ctx, int argc, term argv[])
return result;
}

static term nif_atomvm_posix_clock_settime(Context *ctx, int argc, term argv[])
{
UNUSED(argc);

VALIDATE_VALUE(argv[0], term_is_atom);
if (globalcontext_is_term_equal_to_atom_string(ctx->global, argv[0], ATOM_STR("\x8", "realtime"))) {
RAISE_ERROR(BADARG_ATOM);
}

VALIDATE_VALUE(argv[1], term_is_tuple);
if (term_get_tuple_arity(argv[1]) != 2) {
RAISE_ERROR(BADARG_ATOM);
}

#ifdef HAVE_CLOCK_SETTIME

term secs = term_get_tuple_element(argv[1], 0);
VALIDATE_VALUE(secs, term_is_any_integer);
avm_int64_t s = term_maybe_unbox_int64(secs);

term nsecs = term_get_tuple_element(argv[1], 1);
VALIDATE_VALUE(nsecs, term_is_any_integer);
avm_int64_t ns = term_maybe_unbox_int64(nsecs);

struct timespec tp = {
.tv_sec = s,
.tv_nsec = ns
};

int res = clock_settime(CLOCK_REALTIME, &tp);
if (res != 0) {
if (UNLIKELY(memory_ensure_free(ctx, TUPLE_SIZE(2)) != MEMORY_GC_OK)) {
RAISE_ERROR(OUT_OF_MEMORY_ATOM);
}
term error = term_alloc_tuple(2, &ctx->heap);
term_put_tuple_element(error, 0, ERROR_ATOM);
term_put_tuple_element(error, 1, posix_errno_to_term(errno, ctx->global));
return error;
} else {
return OK_ATOM;
}
#else
RAISE_ERROR(UNDEF_ATOM);
#endif
}

static term nif_console_print(Context *ctx, int argc, term argv[])
{
UNUSED(argc);
Expand Down
1 change: 1 addition & 0 deletions src/libAtomVM/nifs.gperf
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ atomvm:posix_select_write/3, IF_HAVE_OPEN_CLOSE(&atomvm_posix_select_write_nif)
atomvm:posix_select_stop/1, IF_HAVE_OPEN_CLOSE(&atomvm_posix_select_stop_nif)
atomvm:posix_mkfifo/2, IF_HAVE_MKFIFO(&atomvm_posix_mkfifo_nif)
atomvm:posix_unlink/1, IF_HAVE_UNLINK(&atomvm_posix_unlink_nif)
atomvm:posix_clock_settime/2, &atomvm_posix_clock_settime_nif
code:load_abs/1, &code_load_abs_nif
code:load_binary/3, &code_load_binary_nif
console:print/1, &console_print_nif
Expand Down

0 comments on commit 0b7f132

Please sign in to comment.