blob: 7a4bfaab1b461935ffb14f4b402cd06cb27ffb8e [file] [log] [blame]
use callback::CallbackSubscription;
use callback::SubscribableCallback;
use core::cell::Cell;
use core::isize;
use result;
use result::TockResult;
use result::TockValue;
use syscalls;
const DRIVER_NUMBER: usize = 0x00000;
mod command_nr {
pub const IS_DRIVER_AVAILABLE: usize = 0;
pub const GET_CLOCK_FREQUENCY: usize = 1;
pub const GET_CLOCK_VALUE: usize = 2;
pub const STOP_ALARM: usize = 3;
pub const SET_ALARM: usize = 4;
}
mod subscribe_nr {
pub const SUBSCRIBE_CALLBACK: usize = 0;
}
pub fn sleep(duration: Duration) {
let expired = Cell::new(false);
let mut with_callback = with_callback(|_, _| expired.set(true));
let mut timer = with_callback.init().unwrap();
timer.set_alarm(duration).unwrap();
syscalls::yieldk_for(|| expired.get());
}
pub fn with_callback<CB>(callback: CB) -> WithCallback<CB> {
WithCallback {
callback,
clock_frequency: ClockFrequency { hz: 0 },
}
}
pub struct WithCallback<CB> {
callback: CB,
clock_frequency: ClockFrequency,
}
impl<CB: FnMut(ClockValue, Alarm)> SubscribableCallback for WithCallback<CB> {
fn call_rust(&mut self, clock_value: usize, alarm_id: usize, _: usize) {
(self.callback)(
ClockValue {
num_ticks: clock_value as isize,
clock_frequency: self.clock_frequency,
},
Alarm { alarm_id },
);
}
}
impl<CB> WithCallback<CB>
where
Self: SubscribableCallback,
{
pub fn init(&mut self) -> TockResult<Timer, TimerError> {
let num_notifications =
unsafe { syscalls::command(DRIVER_NUMBER, command_nr::IS_DRIVER_AVAILABLE, 0, 0) };
if num_notifications < 1 {
return Err(TockValue::Expected(TimerError::NotSupported));
}
let clock_frequency =
unsafe { syscalls::command(DRIVER_NUMBER, command_nr::GET_CLOCK_FREQUENCY, 0, 0) };
if clock_frequency < 1 {
return Err(TockValue::Expected(TimerError::ErroneousClockFrequency(
clock_frequency,
)));
}
let clock_frequency = ClockFrequency {
hz: clock_frequency as usize,
};
self.clock_frequency = clock_frequency;
let subscription =
syscalls::subscribe(DRIVER_NUMBER, subscribe_nr::SUBSCRIBE_CALLBACK, self);
match subscription {
Ok(subscription) => Ok(Timer {
num_notifications: num_notifications as usize,
clock_frequency,
subscription,
}),
Err(result::ENOMEM) => Err(TockValue::Expected(TimerError::SubscriptionFailed)),
Err(unexpected) => Err(TockValue::Unexpected(unexpected)),
}
}
}
pub struct Timer<'a> {
num_notifications: usize,
clock_frequency: ClockFrequency,
#[allow(dead_code)] // Used in drop
subscription: CallbackSubscription<'a>,
}
#[derive(Copy, Clone, Debug)]
pub enum TimerError {
NotSupported,
ErroneousClockFrequency(isize),
SubscriptionFailed,
}
impl<'a> Timer<'a> {
pub fn num_notifications(&self) -> usize {
self.num_notifications
}
pub fn clock_frequency(&self) -> ClockFrequency {
self.clock_frequency
}
pub fn get_current_clock(&self) -> ClockValue {
let num_ticks =
unsafe { syscalls::command(DRIVER_NUMBER, command_nr::GET_CLOCK_VALUE, 0, 0) };
ClockValue {
num_ticks,
clock_frequency: self.clock_frequency,
}
}
pub fn stop_alarm(&mut self, alarm: Alarm) -> TockResult<(), StopAlarmError> {
let return_code =
unsafe { syscalls::command(DRIVER_NUMBER, command_nr::STOP_ALARM, alarm.alarm_id, 0) };
match return_code {
result::SUCCESS => Ok(()),
result::EALREADY => Err(TockValue::Expected(StopAlarmError::AlreadyDisabled)),
unexpected => Err(TockValue::Unexpected(unexpected)),
}
}
pub fn set_alarm(&mut self, duration: Duration) -> TockResult<Alarm, SetAlarmError> {
let now = self.get_current_clock();
let alarm_instant =
now.num_ticks() as usize + (duration.ms() as usize * self.clock_frequency.hz()) / 1000;
let alarm_id =
unsafe { syscalls::command(DRIVER_NUMBER, command_nr::SET_ALARM, alarm_instant, 0) };
match alarm_id {
_ if alarm_id >= 0 => Ok(Alarm {
alarm_id: alarm_id as usize,
}),
result::ENOMEM => Err(TockValue::Expected(SetAlarmError::NoMemoryAvailable)),
unexpected => Err(TockValue::Unexpected(unexpected)),
}
}
}
#[derive(Copy, Clone, Debug)]
pub struct ClockFrequency {
hz: usize,
}
impl ClockFrequency {
pub fn hz(&self) -> usize {
self.hz
}
}
#[derive(Copy, Clone, Debug)]
pub struct ClockValue {
num_ticks: isize,
clock_frequency: ClockFrequency,
}
impl ClockValue {
pub fn num_ticks(&self) -> isize {
self.num_ticks
}
pub fn ms(&self) -> isize {
if self.num_ticks.abs() < isize::MAX / 1000 {
(1000 * self.num_ticks) / self.clock_frequency.hz() as isize
} else {
1000 * (self.num_ticks / self.clock_frequency.hz() as isize)
}
}
}
pub struct Alarm {
alarm_id: usize,
}
impl Alarm {
pub fn alarm_id(&self) -> usize {
self.alarm_id
}
}
#[derive(Clone, Copy, Debug)]
pub enum StopAlarmError {
AlreadyDisabled,
}
#[derive(Clone, Copy, Debug)]
pub enum SetAlarmError {
NoMemoryAvailable,
}
#[derive(Copy, Clone, Debug)]
pub struct Duration {
ms: isize,
}
impl Duration {
pub fn from_ms(ms: isize) -> Duration {
Duration { ms }
}
pub fn ms(&self) -> isize {
self.ms
}
}