-
Notifications
You must be signed in to change notification settings - Fork 109
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
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
Showing
9 changed files
with
494 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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" } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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(())); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.