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
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
#![no_std]

pub mod prelude;

use core::panic::PanicInfo;
use core::sync::atomic::{self, Ordering};
use mwatch_kernel_api::{CONTEXT_POINTER, CALLBACK_TABLE, Context, InputEvent};

use embedded_graphics::prelude::*;
use embedded_graphics::pixelcolor::PixelColorU16;
use embedded_graphics::drawable;

#[link_section = ".entry_point"]
#[no_mangle]
/// The pointer the watch calls to start running this application.
pub static ENTRY_POINT: extern "C" fn() -> i32 = entry_point;

#[link_section = ".update_point"]
#[no_mangle]
/// The pointer the watch calls to start running this application.
pub static UPDATE_POINT: extern "C" fn(*mut Context<'static>) -> i32 = update_point;

#[link_section = ".input_point"]
#[no_mangle]
/// The pointer the watch calls to handle input
pub static INPUT_POINT: extern "C" fn(*mut Context<'static>, input: InputEvent) -> i32 = input_point;

extern "Rust" {
    fn main() -> i32;
    fn update(system: &mut System) -> i32; // TODO pass 'Resources setup in main to this update function'
    fn input(system: &mut System, input: InputEvent) -> i32;
}

#[no_mangle]
/// The function called by the host to start us up. Does some setup, then
/// jumps to a function called `main` defined by the actual application using
/// this crate.
pub extern "C" fn entry_point() -> i32 {
    unsafe { main() }
}

#[no_mangle]
/// Calls the user update function
pub extern "C" fn update_point(raw_ctx: *mut Context<'static>) -> i32 {
    // Turn the pointer into a reference and store in a static.
    unsafe {
        CONTEXT_POINTER = Some(&mut *raw_ctx);
    };

    unsafe { update(&mut SYSTEM) }
}

#[no_mangle]
/// Calls the user update function
pub extern "C" fn input_point(raw_ctx: *mut Context<'static>, state: InputEvent) -> i32 {
    // Turn the pointer into a reference and store in a static.
    unsafe {
        CONTEXT_POINTER = Some(&mut *raw_ctx);
    };

    // match input {
    //     InputType::Left(val) => {},
    //     InputType::Middle(val) => {},
    //     InputType::Right(val) => {},
    // }

    unsafe { input(&mut SYSTEM, state) }
}

static mut SYSTEM: System = System {
    display: Display { _0: 0u8 },
    logger: Logger { _0: 0u8 },
};

#[repr(C)]
pub struct System {
    pub display: Display,
    pub logger: Logger,
}

#[repr(C)]
pub struct Display {
    _0: u8
}

#[repr(C)]
pub struct Logger {
    _0: u8
}


impl Display {
    pub fn draw<T>(&self, item_pixels: T) -> Result<(), ()>
    where
        T: Iterator<Item = Pixel<PixelColorU16>>,
    {
        let ctx = Context::get();
        let (width, height) = (128, 128);
        for drawable::Pixel(UnsignedCoord(x, y), color) in item_pixels {
            if x <= width && y <= height {
                (CALLBACK_TABLE.draw_pixel)(ctx, x as u8, y as u8, color.into_inner());
            }
        }
        Ok(())
    }
}

impl Logger {
    pub fn log_str(&mut self, args: &str) {
        use core::fmt::Write;
        self.write_str(args).unwrap();
    }

    /// Write a `format!`ed string to the itm port
    /// Using FMT bloats the binary by about 4K bytes, try to use log_str if possible
    pub fn log_fmt(&mut self, args: core::fmt::Arguments) {
        use core::fmt::Write;

        self.write_fmt(args).unwrap();
    }
}

impl core::fmt::Write for Logger {
    fn write_str(&mut self, s: &str) -> core::fmt::Result {
        let ctx = Context::get();
        (CALLBACK_TABLE.print)(ctx, s);
        Ok(())
    }
}

// TODO notify the kernel this app has crashed?
#[inline(never)]
#[panic_handler]
fn panic(_info: &PanicInfo) -> ! {
    loop {
        atomic::compiler_fence(Ordering::SeqCst);
    }
}