Clock trait (#596)
* adds generic Env parameters * adds Clock type to Env * use new Clock * TockTimer improvements * new Clock interface * addressed comments * renames constants to milliseconds, other style fixes * removes all cargo fmt artifacts
This commit is contained in:
118
src/env/tock/clock.rs
vendored
Normal file
118
src/env/tock/clock.rs
vendored
Normal file
@@ -0,0 +1,118 @@
|
||||
// Copyright 2022-2023 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use crate::api::clock::Clock;
|
||||
use libtock_drivers::timer::{get_clock_frequency, get_ticks};
|
||||
|
||||
/// 56-bits timestamp (valid for 70k+ years)
|
||||
#[derive(Clone, Copy, Debug, Default, PartialOrd, Ord, PartialEq, Eq)]
|
||||
struct Timestamp {
|
||||
epoch: usize, // 32-bits
|
||||
tick: usize, // 24-bits (32kHz)
|
||||
}
|
||||
|
||||
impl Timestamp {
|
||||
/// Adds (potentially more than 24 bit of) ticks to this timestamp.
|
||||
pub fn add_ticks(&mut self, ticks: usize) {
|
||||
// Saturating should never happen, but it fails gracefully.
|
||||
let sum = self.tick.saturating_add(ticks);
|
||||
self.epoch += sum >> 24;
|
||||
self.tick = sum & 0xff_ffff;
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct TockTimer {
|
||||
deadline: Timestamp,
|
||||
}
|
||||
|
||||
/// Clock that produces timers through Tock syscalls.
|
||||
///
|
||||
/// To guarantee correctness, you have to call any of its functions at least once per full tick
|
||||
/// counter wrap. In our case, 24 bit ticks with a 32 kHz frequency wrap after 512 seconds. If you
|
||||
/// can't guarantee to regularly create or check timers, call tickle at least every 8 minutes.
|
||||
#[derive(Default)]
|
||||
pub struct TockClock {
|
||||
now: Timestamp,
|
||||
}
|
||||
|
||||
impl TockClock {
|
||||
/// Elapses timers before the clock wraps.
|
||||
///
|
||||
/// Call this regularly to timeout reliably despite wrapping clock ticks.
|
||||
pub fn tickle(&mut self) {
|
||||
let cur_tick = get_ticks().ok().unwrap();
|
||||
if cur_tick < self.now.tick {
|
||||
self.now.epoch += 1;
|
||||
}
|
||||
self.now.tick = cur_tick;
|
||||
}
|
||||
}
|
||||
|
||||
impl Clock for TockClock {
|
||||
type Timer = TockTimer;
|
||||
|
||||
fn make_timer(&mut self, milliseconds: usize) -> Self::Timer {
|
||||
self.tickle();
|
||||
let clock_frequency = get_clock_frequency().ok().unwrap();
|
||||
let delta_tick = match milliseconds.checked_mul(clock_frequency) {
|
||||
Some(x) => x / 1000,
|
||||
// All CTAP timeouts are multiples of 100 so far. Worst case we timeout too early.
|
||||
None => (milliseconds / 100).saturating_mul(clock_frequency / 10),
|
||||
};
|
||||
let mut deadline = self.now;
|
||||
deadline.add_ticks(delta_tick);
|
||||
Self::Timer { deadline }
|
||||
}
|
||||
|
||||
fn is_elapsed(&mut self, timer: &Self::Timer) -> bool {
|
||||
self.tickle();
|
||||
self.now >= timer.deadline
|
||||
}
|
||||
|
||||
#[cfg(feature = "debug_ctap")]
|
||||
fn timestamp_us(&mut self) -> usize {
|
||||
let clock_frequency = get_clock_frequency().ok().unwrap();
|
||||
let total_ticks = 0x100_0000u64 * self.now.epoch as u64 + self.now.tick as u64;
|
||||
(total_ticks.wrapping_mul(1_000_000u64) / clock_frequency as u64) as usize
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_timestamp_add_ticks() {
|
||||
let mut timestamp = Timestamp::default();
|
||||
timestamp.add_ticks(1);
|
||||
let expected = Timestamp { epoch: 0, tick: 1 };
|
||||
assert_eq!(timestamp, expected);
|
||||
timestamp.add_ticks(0xff_ffff);
|
||||
let expected = Timestamp { epoch: 1, tick: 0 };
|
||||
assert_eq!(timestamp, expected);
|
||||
timestamp.add_ticks(0x100_0000);
|
||||
let expected = Timestamp { epoch: 2, tick: 0 };
|
||||
assert_eq!(timestamp, expected);
|
||||
timestamp.add_ticks(0x1ff_ffff);
|
||||
let expected = Timestamp {
|
||||
epoch: 3,
|
||||
tick: 0xff_ffff,
|
||||
};
|
||||
assert_eq!(timestamp, expected);
|
||||
timestamp.add_ticks(1);
|
||||
let expected = Timestamp { epoch: 4, tick: 0 };
|
||||
assert_eq!(timestamp, expected);
|
||||
}
|
||||
}
|
||||
29
src/env/tock/mod.rs
vendored
29
src/env/tock/mod.rs
vendored
@@ -19,12 +19,10 @@ use crate::api::customization::{CustomizationImpl, DEFAULT_CUSTOMIZATION};
|
||||
use crate::api::firmware_protection::FirmwareProtection;
|
||||
use crate::api::user_presence::{UserPresence, UserPresenceError, UserPresenceResult};
|
||||
use crate::api::{attestation_store, key_store};
|
||||
use crate::clock::{ClockInt, KEEPALIVE_DELAY_MS};
|
||||
use crate::env::Env;
|
||||
use clock::TockClock;
|
||||
use core::cell::Cell;
|
||||
use core::sync::atomic::{AtomicBool, Ordering};
|
||||
use embedded_time::duration::Milliseconds;
|
||||
use embedded_time::fixed_point::FixedPoint;
|
||||
use libtock_core::result::{CommandError, EALREADY};
|
||||
use libtock_drivers::buttons::{self, ButtonState};
|
||||
use libtock_drivers::console::Console;
|
||||
@@ -35,6 +33,7 @@ use libtock_drivers::{crp, led, timer};
|
||||
use persistent_store::{StorageResult, Store};
|
||||
use rng256::TockRng256;
|
||||
|
||||
mod clock;
|
||||
mod storage;
|
||||
|
||||
pub struct TockHidConnection {
|
||||
@@ -42,14 +41,10 @@ pub struct TockHidConnection {
|
||||
}
|
||||
|
||||
impl HidConnection for TockHidConnection {
|
||||
fn send_and_maybe_recv(
|
||||
&mut self,
|
||||
buf: &mut [u8; 64],
|
||||
timeout: Milliseconds<ClockInt>,
|
||||
) -> SendOrRecvResult {
|
||||
fn send_and_maybe_recv(&mut self, buf: &mut [u8; 64], timeout_ms: usize) -> SendOrRecvResult {
|
||||
match usb_ctap_hid::send_or_recv_with_timeout(
|
||||
buf,
|
||||
timer::Duration::from_ms(timeout.integer() as isize),
|
||||
Duration::from_ms(timeout_ms as isize),
|
||||
self.endpoint,
|
||||
) {
|
||||
Ok(usb_ctap_hid::SendOrRecvStatus::Timeout) => Ok(SendOrRecvStatus::Timeout),
|
||||
@@ -70,6 +65,7 @@ pub struct TockEnv {
|
||||
#[cfg(feature = "vendor_hid")]
|
||||
vendor_connection: TockHidConnection,
|
||||
blink_pattern: usize,
|
||||
clock: TockClock,
|
||||
}
|
||||
|
||||
impl TockEnv {
|
||||
@@ -95,6 +91,7 @@ impl TockEnv {
|
||||
endpoint: UsbEndpoint::VendorHid,
|
||||
},
|
||||
blink_pattern: 0,
|
||||
clock: TockClock::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -115,8 +112,9 @@ impl UserPresence for TockEnv {
|
||||
fn check_init(&mut self) {
|
||||
self.blink_pattern = 0;
|
||||
}
|
||||
fn wait_with_timeout(&mut self, timeout: Milliseconds<ClockInt>) -> UserPresenceResult {
|
||||
if timeout.integer() == 0 {
|
||||
|
||||
fn wait_with_timeout(&mut self, timeout_ms: usize) -> UserPresenceResult {
|
||||
if timeout_ms == 0 {
|
||||
return Err(UserPresenceError::Timeout);
|
||||
}
|
||||
blink_leds(self.blink_pattern);
|
||||
@@ -141,7 +139,7 @@ impl UserPresence for TockEnv {
|
||||
});
|
||||
let mut keepalive = keepalive_callback.init().flex_unwrap();
|
||||
let keepalive_alarm = keepalive
|
||||
.set_alarm(timer::Duration::from_ms(timeout.integer() as isize))
|
||||
.set_alarm(Duration::from_ms(timeout_ms as isize))
|
||||
.flex_unwrap();
|
||||
|
||||
// Wait for a button touch or an alarm.
|
||||
@@ -224,6 +222,7 @@ impl Env for TockEnv {
|
||||
type Storage = TockStorage;
|
||||
type KeyStore = Self;
|
||||
type AttestationStore = Self;
|
||||
type Clock = TockClock;
|
||||
type UpgradeStorage = TockUpgradeStorage;
|
||||
type FirmwareProtection = Self;
|
||||
type Write = Console;
|
||||
@@ -250,6 +249,10 @@ impl Env for TockEnv {
|
||||
self
|
||||
}
|
||||
|
||||
fn clock(&mut self) -> &mut Self::Clock {
|
||||
&mut self.clock
|
||||
}
|
||||
|
||||
fn upgrade_storage(&mut self) -> Option<&mut Self::UpgradeStorage> {
|
||||
self.upgrade_storage.as_mut()
|
||||
}
|
||||
@@ -324,5 +327,3 @@ pub fn switch_off_leds() {
|
||||
led::get(l).flex_unwrap().off().flex_unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
pub const KEEPALIVE_DELAY_TOCK: Duration<isize> = Duration::from_ms(KEEPALIVE_DELAY_MS as isize);
|
||||
|
||||
Reference in New Issue
Block a user