1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
//! Wrapper for a Display, its GPIO pins, and a timer.

use nrf51_hal::hi_res_timer::As16BitTimer;
use tiny_led_matrix::{Display, Event as DisplayEvent};
use crate::display::display_port::DisplayPort;
use crate::display::matrix::MicrobitFrame;
use crate::display::timer::MicrobitDisplayTimer;

/// The micro:bit's display, and one timer to drive it.
pub struct MicrobitDisplay<T: As16BitTimer> {
    timer: MicrobitDisplayTimer<T>,
    port: DisplayPort,
    display: Display<MicrobitFrame>,
}

impl<T: As16BitTimer> MicrobitDisplay<T> {

    /// Takes ownership of the display port and one TIMER, and returns a
    /// `MicrobitDisplay`.
    ///
    /// The `timer` parameter can be any of the three `nrf51::TIMER`*n*
    /// peripherals.
    ///
    /// Initialises the micro:bit hardware to use the display driver.
    ///
    /// The display is initially clear.
    ///
    /// # Example
    ///
    /// ```ignore
    /// use rmicrobit::prelude::*;
    /// use rmicrobit::gpio::PinsByKind;
    /// use rmicrobit::display::{DisplayPort, MicrobitDisplay};
    /// let p: nrf51::Peripherals = _;
    /// let PinsByKind {display_pins, ..} = p.GPIO.split_by_kind();
    /// let display_port = DisplayPort::new(display_pins);
    /// let mut display = MicrobitDisplay::new(display_port, p.TIMER1);
    /// ```
    pub fn new(mut port: DisplayPort, timer: T) -> MicrobitDisplay<T> {
        let mut timer = MicrobitDisplayTimer::new(timer);
        tiny_led_matrix::initialise_control(&mut port);
        tiny_led_matrix::initialise_timer(&mut timer);
        let display = Display::new();
        MicrobitDisplay {timer, port, display}
    }

    /// Gives the underlying devices back.
    ///
    /// Returns the `DisplayPort` and `nrf51::TIMER`*n* instance.
    ///
    /// Turns all the LEDs off and stops the TIMER.
    pub fn free(mut self) -> (DisplayPort, T) {
        self.port.blank();
        (self.port, self.timer.free())
    }

    /// Updates the LEDs and timer state during a timer interrupt.
    ///
    /// Call this in an interrupt handler for the `MicrobitDisplay`'s timer.
    ///
    /// See [`Display::handle_event()`] for details.
    ///
    /// Returns a [`DisplayEvent`] indicating the reason for the interrupt.
    /// You can check this if you wish to perform some other action once every
    /// 6ms.
    ///
    /// # Example
    ///
    /// In the style of `cortex-m-rtfm` v0.5:
    ///
    /// ```ignore
    /// #[task(binds = TIMER1, priority = 2, resources = [display])]
    /// fn timer1(cx: timer1::Context) {
    ///     let display_event = cx.resources.display.handle_event();
    ///     if display_event.is_new_row() {
    ///         ...
    ///     }
    /// }
    /// ```
    pub fn handle_event(&mut self) -> DisplayEvent {
        self.display.handle_event(&mut self.timer, &mut self.port)
    }

    /// Accepts a new image to be displayed.
    ///
    /// The code that calls this method must not be interrupting, or
    /// interruptable by, [`handle_event()`].
    ///
    /// After calling this, it's safe to modify the frame again (its data is
    /// copied).
    ///
    /// # Example
    ///
    /// In the style of `cortex-m-rtfm` v0.5:
    ///
    /// ```ignore
    /// #[task(binds = RTC0, priority = 1, resources = [rtc0, display])]
    /// fn rtc0(mut cx: rtc0::Context) {
    ///     static mut FRAME: MicrobitFrame = MicrobitFrame::const_default();
    ///     &cx.resources.rtc0.clear_tick_event();
    ///     FRAME.set(GreyscaleImage::blank());
    ///     cx.resources.display.lock(|display| {
    ///         display.set_frame(FRAME);
    ///     });
    /// }
    /// ```
    ///
    /// [`handle_event()`]: MicrobitDisplay::handle_event
    pub fn set_frame(&mut self, frame: &MicrobitFrame) {
        self.display.set_frame(frame);
    }

}