Skip to content

Commit

Permalink
Merge #470
Browse files Browse the repository at this point in the history
470: Buzzer API r=jrvanwhy a=SheepSeb

## Pull Request Overview

This pull request continues the work done by `@teodorobert`

This pull request adds:
- a buzzer API, similar to the [libtock-c version]( https://github.com/tock/libtock-c/blob/master/libtock/buzzer.h ). The API provides a function that simulates a synchronous tone setting and also functions to register/unregister a listener, check for driver existence
- an example app which plays Ode of Joy
- a ```fake``` buzzer driver, for testing
- unit tests for the fake driver and for the user space library

## Testing Strategy
This PR was tested with the unit tests and by running the example app on a microbit v2 board

## Documentation Updated
no updates are required

Co-authored-by: sebastian-nae <naesebi2000@gmail.com>
Co-authored-by: Sebastian Nae <naesebi2000@gmail.com>
  • Loading branch information
bors[bot] and SheepSeb committed May 17, 2023
2 parents be72de6 + fe66077 commit c48f816
Show file tree
Hide file tree
Showing 9 changed files with 494 additions and 0 deletions.
2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ version = "0.1.0"
libtock_alarm = { path = "apis/alarm" }
libtock_ambient_light = { path = "apis/ambient_light" }
libtock_buttons = { path = "apis/buttons" }
libtock_buzzer = {path = "apis/buzzer"}
libtock_console = { path = "apis/console" }
libtock_debug_panic = { path = "panic_handlers/debug_panic" }
libtock_gpio = { path = "apis/gpio" }
Expand All @@ -39,6 +40,7 @@ members = [
"apis/alarm",
"apis/gpio",
"apis/buttons",
"apis/buzzer",
"apis/console",
"apis/leds",
"apis/low_level_debug",
Expand Down
14 changes: 14 additions & 0 deletions apis/buzzer/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
[package]
name = "libtock_buzzer"
version = "0.1.0"
authors = ["Tock Project Developers <tock-dev@googlegroups.com>"]
license = "MIT/Apache-2.0"
edition = "2021"
repository = "https://www.github.com/tock/libtock-rs"
description = "libtock buzzer driver"

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

[dev-dependencies]
libtock_unittest = { path = "../../unittest" }
173 changes: 173 additions & 0 deletions apis/buzzer/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
//! Implementation started by : https://github.com/teodorobert
//! Continued and modified by : https://github.com/SheepSeb
#![no_std]

use core::cell::Cell;
use core::time::Duration;

use libtock_platform::{
share, subscribe::OneId, DefaultConfig, ErrorCode, Subscribe, Syscalls, Upcall,
};
pub struct Buzzer<S: Syscalls>(S);

impl<S: Syscalls> Buzzer<S> {
/// Returns Ok() if the driver was present.This does not necessarily mean
/// that the driver is working.
pub fn exists() -> Result<(), ErrorCode> {
S::command(DRIVER_NUM, EXISTS, 0, 0).to_result()
}

/// Initiate a tone
pub fn tone(freq: u32, duration: Duration) -> Result<(), ErrorCode> {
S::command(DRIVER_NUM, BUZZER_ON, freq, duration.as_millis() as u32).to_result()
}

/// Register an events listener
pub fn register_listener<'share, F: Fn(u32)>(
listener: &'share BuzzerListener<F>,
subscribe: share::Handle<Subscribe<'share, S, DRIVER_NUM, 0>>,
) -> Result<(), ErrorCode> {
S::subscribe::<_, _, DefaultConfig, DRIVER_NUM, 0>(subscribe, listener)
}

/// Unregister the events listener
pub fn unregister_listener() {
S::unsubscribe(DRIVER_NUM, 0)
}

/// Initiate a synchronous tone
/// Returns Ok() if the operation was successful
pub fn tone_sync(freq: u32, duration: Duration) -> Result<(), ErrorCode> {
let buzzer_cell: Cell<Option<u32>> = Cell::new(None);
let listener = BuzzerListener(|buzzer_val| {
buzzer_cell.set(Some(buzzer_val));
});
share::scope(|subscribe| {
Self::register_listener(&listener, subscribe)?;
Self::tone(freq, duration)?;
while buzzer_cell.get() == None {
S::yield_wait();
}
match buzzer_cell.get() {
None => Err(ErrorCode::Fail),
Some(_) => Ok(()),
}
})
}
}

pub struct BuzzerListener<F: Fn(u32)>(pub F);
impl<F: Fn(u32)> Upcall<OneId<DRIVER_NUM, 0>> for BuzzerListener<F> {
fn upcall(&self, _arg0: u32, _arg1: u32, _arg2: u32) {
(self.0)(_arg0);
}
}

#[cfg(test)]
mod tests;

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

const DRIVER_NUM: u32 = 0x90000;

// Command IDs
const EXISTS: u32 = 0;
const BUZZER_ON: u32 = 1;

/// The notes that can be played by the buzzer
#[allow(unused)]
#[repr(u32)]
#[derive(Copy, Clone, Debug)]
pub enum Note {
B0 = 31,
C1 = 33,
CS1 = 35,
D1 = 37,
DS1 = 39,
E1 = 41,
F1 = 44,
FS1 = 46,
G1 = 49,
GS1 = 52,
A1 = 55,
AS1 = 58,
B1 = 62,
C2 = 65,
CS2 = 69,
D2 = 73,
DS2 = 78,
E2 = 82,
F2 = 87,
FS2 = 93,
G2 = 98,
GS2 = 104,
A2 = 110,
AS2 = 117,
B2 = 123,
C3 = 131,
CS3 = 139,
D3 = 147,
DS3 = 156,
E3 = 165,
F3 = 175,
FS3 = 185,
G3 = 196,
GS3 = 208,
A3 = 220,
AS3 = 233,
B3 = 247,
C4 = 262,
CS4 = 277,
D4 = 294,
DS4 = 311,
E4 = 330,
F4 = 349,
FS4 = 370,
G4 = 392,
GS4 = 415,
A4 = 440,
AS4 = 466,
B4 = 494,
C5 = 523,
CS5 = 554,
D5 = 587,
DS5 = 622,
E5 = 659,
F5 = 698,
FS5 = 740,
G5 = 784,
GS5 = 831,
A5 = 880,
AS5 = 932,
B5 = 988,
C6 = 1047,
CS6 = 1109,
D6 = 1175,
DS6 = 1245,
E6 = 1319,
F6 = 1397,
FS6 = 1480,
G6 = 1568,
GS6 = 1661,
A6 = 1760,
AS6 = 1865,
B6 = 1976,
C7 = 2093,
CS7 = 2217,
D7 = 2349,
DS7 = 2489,
E7 = 2637,
F7 = 2794,
FS7 = 2960,
G7 = 3136,
GS7 = 3322,
A7 = 3520,
AS7 = 3729,
B7 = 3951,
C8 = 4186,
CS8 = 4435,
D8 = 4699,
DS8 = 4978,
}
44 changes: 44 additions & 0 deletions apis/buzzer/src/tests.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
use core::time::Duration;
use libtock_platform::ErrorCode;
use libtock_unittest::fake;

type Buzzer = super::Buzzer<fake::Syscalls>;

#[test]
fn no_driver() {
let _kernel = fake::Kernel::new();
assert_eq!(Buzzer::exists(), Err(ErrorCode::NoDevice));
}

#[test]
fn driver_check() {
let kernel = fake::Kernel::new();
let driver = fake::Buzzer::new();
kernel.add_driver(&driver);

assert_eq!(Buzzer::exists(), Ok(()));
}

#[test]
fn tone() {
let kernel = fake::Kernel::new();
let driver = fake::Buzzer::new();
kernel.add_driver(&driver);
let duration = Duration::from_millis(100);
assert_eq!(Buzzer::tone(1000, duration), Ok(()));
assert!(driver.is_busy());

assert_eq!(Buzzer::tone(1000, duration), Err(ErrorCode::Busy));
}

#[test]
fn tone_sync() {
let kernel = fake::Kernel::new();
let driver = fake::Buzzer::new();
kernel.add_driver(&driver);

let duration = Duration::from_millis(100);

driver.set_tone_sync(1000, 100);
assert_eq!(Buzzer::tone_sync(1000, duration), Ok(()));
}
105 changes: 105 additions & 0 deletions examples/music.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
//! Implementation done by : https://github.com/teodorobert
//! A simple libtock-rs example. Plays Ode of Joy using the buzzer.
#![no_main]
#![no_std]

use core::fmt::Write;
use core::time::Duration;
use libtock::buzzer::{Buzzer, Note};
use libtock::console::Console;
use libtock::runtime::{set_main, stack_size};

set_main! {main}
stack_size! {0x800}

// Adapted from https://github.com/robsoncouto/arduino-songs

// Notes in the form of (note_frequency, note_delay in musical terms)
const MELODY: [(Note, i32); 62] = [
(Note::E4, 4),
(Note::E4, 4),
(Note::F4, 4),
(Note::G4, 4),
(Note::G4, 4),
(Note::F4, 4),
(Note::E4, 4),
(Note::D4, 4),
(Note::C4, 4),
(Note::C4, 4),
(Note::D4, 4),
(Note::E4, 4),
(Note::E4, -4),
(Note::D4, 8),
(Note::D4, 2),
(Note::E4, 4),
(Note::E4, 4),
(Note::F4, 4),
(Note::G4, 4),
(Note::G4, 4),
(Note::F4, 4),
(Note::E4, 4),
(Note::D4, 4),
(Note::C4, 4),
(Note::C4, 4),
(Note::D4, 4),
(Note::E4, 4),
(Note::D4, -4),
(Note::C4, 8),
(Note::C4, 2),
(Note::D4, 4),
(Note::D4, 4),
(Note::E4, 4),
(Note::C4, 4),
(Note::D4, 4),
(Note::E4, 8),
(Note::F4, 8),
(Note::E4, 4),
(Note::C4, 4),
(Note::D4, 4),
(Note::E4, 8),
(Note::F4, 8),
(Note::E4, 4),
(Note::D4, 4),
(Note::C4, 4),
(Note::D4, 4),
(Note::G3, 2),
(Note::E4, 4),
(Note::E4, 4),
(Note::F4, 4),
(Note::G4, 4),
(Note::G4, 4),
(Note::F4, 4),
(Note::E4, 4),
(Note::D4, 4),
(Note::C4, 4),
(Note::C4, 4),
(Note::D4, 4),
(Note::E4, 4),
(Note::D4, -4),
(Note::C4, 8),
(Note::C4, 2),
];

const TEMPO: u32 = 114;
const WHOLE_NOTE: u32 = (60000 * 4) / TEMPO;

fn main() {
if let Err(_) = Buzzer::exists() {
writeln!(Console::writer(), "There is no available buzzer").unwrap();
return;
}

writeln!(Console::writer(), "Ode to Joy").unwrap();

for (frequency, duration) in MELODY.iter() {
let mut note_duration: Duration =
Duration::from_millis((WHOLE_NOTE / duration.unsigned_abs()) as u64);
// let mut note_duration = WHOLE_NOTE / duration.unsigned_abs();
if duration < &0 {
note_duration = note_duration * 15 / 10;
}

let note_duration = note_duration * 9 / 10;
Buzzer::tone_sync(*frequency as u32 * 3, note_duration).unwrap();
}
}
5 changes: 5 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@ pub mod buttons {
pub type Buttons = buttons::Buttons<super::runtime::TockSyscalls>;
pub use buttons::{ButtonListener, ButtonState};
}
pub mod buzzer {
use libtock_buzzer as buzzer;
pub type Buzzer = buzzer::Buzzer<super::runtime::TockSyscalls>;
pub use buzzer::Note;
}
pub mod console {
use libtock_console as console;
pub type Console = console::Console<super::runtime::TockSyscalls>;
Expand Down
Loading

0 comments on commit c48f816

Please sign in to comment.