NOP0 / rustmatic

PLC programming in Rust!
Apache License 2.0
35 stars 2 forks source link

Implement IEC RTC function block #33

Open NOP0 opened 4 years ago

NOP0 commented 4 years ago

This is a function block from the standard. I think we'll need this for the blinky IEC program, since this is analog to elapsed?

The interface is like this:


FUNCTION_BLOCK RTC // Real Time Clock

VAR_INPUT
    IN : BOOL; // Preset and run
    PDT: DT; // Preset value of RTC loaded on rising edge of IN
END_VAR

VAR_OUTPUT
    Q : BOOL; // CDT output is valid
    CDT : DT; // Current time
END_VAR

// Body unimplemented!

END_FUNCTION_BLOCK
NOP0 commented 4 years ago

We also need time formats. #34

Michael-F-Bryan commented 4 years ago

I'm not sure how we'll implement components from the "standard library" and expose them to WASM.

I guess we'd define opaque structs and then various extern "C" fn() functions for invoking a function block. By using a C-style interface WASM code will easily be able to use exported functions.

Types like DateTime will (for the time being) probably need to be allocated at runtime and passed around via pointers because WASM only supports u32, u64, f32, and f64 as function parameters.

/// Opaque type representing a date and time. Can only be used via pointer operations.
struct DateTime { ... }

/// Create a new immutable `DateTime` object.
#[no_mangle]
pub extern "C" fn datetime_create(year: i32, month: u32, day: u32, hour: u32, min: u32, sec: u32, nanos: u32) -> *const DateTime { ... }

#[no_mangle]
pub extern "C" fn datetime_destrly(dt: *const DateTime) { ... }

#[no_mangle]
pub extern "C" fn datetime_year(dt: *const DateTime) -> i32 { ... }

struct RealtimeClock { ... }

#[no_mangle]
pub extern "C" fn realtime_clock_create() -> *mut RealtimeClock { ... }

#[no_mangle]
pub extern "C" fn realtime_clock_destroy(rtc: *mut RealtimeClock) { ... }

/// Poll the `RealtimeClock`.
#[no_mangle]
pub extern "C" fn realtime_clock_poll(rtc: *mut RealtimeClock, in_: bool, pdt: *const DateTime) -> (bool, *const DateTime) { ... }
NOP0 commented 4 years ago

I think your example seems like an approach worth trying.

Types like DateTime will (for the time being) probably need to be allocated at runtime and passed around via pointers because WASM only supports u32, u64, f32, and f64 as function parameters.

For the concrete case of DateTime would an internal implementation as an u64 UNIX epoch solve anything? But on the other hand, there will be other datatypes like IEC string that will need the pointer approach, so maybe better use that throughout.

Michael-F-Bryan commented 4 years ago

I guess you could do that, but using a u64 means you can't have subsecond resolution. Does the spec say whether a date-time can do fractional seconds?

NOP0 commented 4 years ago

I think the spec says:

DATE_AND_TIME#1970-01-01-00:00:00.000

But the underlying storage is specified as implementation dependent.

But googling around, I see that some vendors say that they use u32 for the storage of seconds since 1970 which is epoch. So in those systems the milliseconds are just thrown away?

I guess you could store msecs since 1970 in an u64 (when would that overflow?). Then you've got time_spec and ISO, and the rust format... so timestamps are a mess IMHO.