Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ libtock_platform = { path = "platform" }
libtock_proximity = { path = "apis/proximity" }
libtock_runtime = { path = "runtime" }
libtock_temperature = { path = "apis/temperature" }
libtock_touch = { path = "apis/touch" }

[profile.dev]
panic = "abort"
Expand All @@ -43,6 +44,7 @@ members = [
"apis/low_level_debug",
"apis/proximity",
"apis/temperature",
"apis/touch",
"panic_handlers/debug_panic",
"panic_handlers/small_panic",
"platform",
Expand Down
17 changes: 17 additions & 0 deletions apis/touch/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
[package]
name = "libtock_touch"
version = "0.1.0"
authors = [
"Tock Project Developers <[email protected]>",
"dcz <[email protected]>",
]
license = "MIT/Apache-2.0"
edition = "2021"
repository = "https://www.github.com/tock/libtock-rs"
description = "libtock touch driver"

[dependencies]
libtock_platform = { path = "../../platform" }

[dev-dependencies]
libtock_unittest = { path = "../../unittest" }
170 changes: 170 additions & 0 deletions apis/touch/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
#![no_std]

use core::cell::Cell;
use libtock_platform::{share, DefaultConfig, ErrorCode, Subscribe, Syscalls};
pub struct Touch<S: Syscalls>(S);

pub enum TouchStatus {
Unstarted,
Pressed,
Released,
Moved,
}

impl TouchStatus {
fn from_u32(value: u32) -> TouchStatus {
match value {
0 => TouchStatus::Released,
1 => TouchStatus::Pressed,
2 => TouchStatus::Moved,
_ => TouchStatus::Unstarted,
}
}
}

pub struct TouchEvent {
/// touch event type
pub status: TouchStatus,
/// touch (x, y) position
pub x: u16,
pub y: u16,
/// A scaled value for the size of the touch, if the touchscreen offers that information,
/// or None otherwise.
/// A larger value corresponds to a "fatter" touch.
pub area: Option<u16>,
/// A scaled value for the pressure of the touch, if the touchscreen offers that information,
/// or None otherwise.
/// A larger value corresponds to a "firmer" press.
pub pressure: Option<u16>,
}

pub enum GestureEvent {
SwipeUp,
SwipeDown,
SwipeLeft,
SwipeRight,
ZoomIn,
ZoomOut,
}

impl GestureEvent {
fn from_u32(value: u32) -> GestureEvent {
match value {
1 => GestureEvent::SwipeUp,
2 => GestureEvent::SwipeDown,
3 => GestureEvent::SwipeLeft,
4 => GestureEvent::SwipeRight,
5 => GestureEvent::ZoomIn,
_ => GestureEvent::ZoomOut,
}
}
}

impl<S: Syscalls> Touch<S> {
pub fn exists() -> Result<(), ErrorCode> {
S::command(DRIVER_NUM, command::DRIVER_CHECK, 0, 0).to_result()
}

pub fn enable_single_touch() -> Result<(), ErrorCode> {
S::command(DRIVER_NUM, command::ENABLE_SINGLE, 0, 0).to_result()
}

pub fn disable_single_touch() -> Result<(), ErrorCode> {
S::command(DRIVER_NUM, command::DISABLE_SINGLE, 0, 0).to_result()
}

pub fn register_single_touch_listener<'share>(
listener: &'share Cell<Option<(u32, u32, u32)>>,
subscribe: share::Handle<Subscribe<'share, S, DRIVER_NUM, { subscribe::SINGLE }>>,
) -> Result<(), ErrorCode> {
S::subscribe::<_, _, DefaultConfig, DRIVER_NUM, { subscribe::SINGLE }>(subscribe, listener)
}

pub fn register_gestures_listener<'share>(
listener: &'share Cell<Option<(u32,)>>,
subscribe: share::Handle<Subscribe<'share, S, DRIVER_NUM, { subscribe::GESTURES }>>,
) -> Result<(), ErrorCode> {
S::subscribe::<_, _, DefaultConfig, DRIVER_NUM, { subscribe::GESTURES }>(
subscribe, listener,
)
}

/// Waits for a single touch event, returning details about it in a TouchEvent structure:
pub fn wait_for_single_touch() -> Result<TouchEvent, ErrorCode> {
Self::enable_single_touch()?;
let listener: Cell<Option<(u32, u32, u32)>> = Cell::new(None);
share::scope(|subscribe| {
if let Ok(()) = Self::register_single_touch_listener(&listener, subscribe) {
while listener.get().is_none() {
S::yield_wait();
}
}
});
match listener.get() {
None => Err(ErrorCode::Fail),
Some(tuple) => Ok(TouchEvent {
status: TouchStatus::from_u32(tuple.0),
x: (tuple.1 >> 16) as u16,
y: tuple.1 as u16,
area: match tuple.2 as u16 {
0 => None,
val => Some(val),
},
pressure: match (tuple.2 >> 16) as u16 {
0 => None,
val => Some(val),
},
}),
}
}

/// Waits for a gesture event, returning it's type
pub fn wait_for_gesture() -> Result<GestureEvent, ErrorCode> {
let listener: Cell<Option<(u32,)>> = Cell::new(None);
share::scope(|subscribe| {
if let Ok(()) = Self::register_gestures_listener(&listener, subscribe) {
while listener.get().is_none() {
S::yield_wait();
}
}
});

match listener.get() {
None => Err(ErrorCode::Fail),
Some(val) => Ok(GestureEvent::from_u32(val.0)),
}
}

/// Returns the number of available touches
pub fn get_number_of_touches() -> Result<u32, ErrorCode> {
S::command(DRIVER_NUM, command::TOUCHES_NUM, 0, 0).to_result()
}
}

// -----------------------------------------------------------------------------
// Driver number and command IDs
// -----------------------------------------------------------------------------

const DRIVER_NUM: u32 = 589826;

// Command IDs

mod command {
pub const DRIVER_CHECK: u32 = 0;
pub const ENABLE_SINGLE: u32 = 1;
pub const DISABLE_SINGLE: u32 = 2;
pub const ACK_MULTI: u32 = 10;
pub const ENABLE_MULTI: u32 = 11;
pub const DISABLE_MULTI: u32 = 12;
pub const TOUCHES_NUM: u32 = 100;
}

mod subscribe {
pub const SINGLE: u32 = 0;
pub const GESTURES: u32 = 1;
pub const MULTI: u32 = 2;
}

mod allow_rw {
pub const MULTI: u32 = 0;
}
34 changes: 34 additions & 0 deletions examples/touch.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
//! A simple libtock-rs example. Checks for touch driver
//! and waits for single touch events, printing their location

#![no_main]
#![no_std]

use core::fmt::Write;
use libtock::console::Console;

use libtock::runtime::{set_main, stack_size};
use libtock::touch::Touch;

set_main! {main}
stack_size! {0x200}

fn main() {
if Touch::exists().is_err() {
writeln!(Console::writer(), "touch driver unavailable").unwrap();
return;
}

loop {
match Touch::wait_for_single_touch() {
Err(_) => writeln!(Console::writer(), "Error in getting touch event").unwrap(),
Ok(event) => writeln!(
Console::writer(),
"Touch event at ({}, {})",
event.x,
event.y
)
.unwrap(),
}
}
}
4 changes: 4 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,3 +47,7 @@ pub mod temperature {
pub type Temperature = temperature::Temperature<super::runtime::TockSyscalls>;
pub use temperature::TemperatureListener;
}
pub mod touch {
use libtock_touch as touch;
pub type Touch = touch::Touch<super::runtime::TockSyscalls>;
}