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
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
//! LVGL API for Rust. Contains Rust bindings for LVGL API for C, generated by `bindgen`.
//! Also includes safe versions of LVGL APIs created specially for Rust.

#![no_std]                        //  Don't link with standard Rust library, which is not compatible with embedded systems
#![feature(trace_macros)]         //  Enable tracing of macros
#![feature(proc_macro_hygiene)]   //  Allow proc macros to be unhygienic

extern crate macros as lvgl_macros;  //  Import Procedural Macros from `macros` library

/// Export Mynewt API
#[cfg(feature = "mynewt_os")]     //  If building for Mynewt OS...
pub use mynewt;                   //  Export Mynewt API

#[allow(unused_imports)]          //  Allow unused imports
pub mod core;                     //  Lvgl Core API. Export folder `core` as Rust module `lvgl::core`

#[allow(unused_imports)]          //  Allow unused imports
pub mod draw;                     //  Lvgl Draw API. Export folder `draw` as Rust module `lvgl::draw`

#[allow(unused_imports)]          //  Allow unused imports
pub mod font;                     //  Lvgl Font API. Export folder `font` as Rust module `lvgl::font`

#[allow(unused_imports)]          //  Allow unused imports
pub mod hal;                      //  Lvgl HAL API. Export folder `hal` as Rust module `lvgl::hal`

#[allow(unused_imports)]          //  Allow unused imports
pub mod misc;                     //  Lvgl Misc API. Export folder `misc` as Rust module `lvgl::misc`

#[allow(unused_imports)]          //  Allow unused imports
pub mod themes;                   //  Lvgl Themes API. Export folder `themes` as Rust module `lvgl::themes`

#[allow(unused_imports)]          //  Allow unused imports
pub mod widgets;                  //  Lvgl Widgets API. Export folder `widgets` as Rust module `lvgl::widgets`

//  TODO: pub mod themes;         //  Lvgl Themes API. Export folder `themes` as Rust module `lvgl::themes`

#[macro_use]                      //  Allow macros from Rust module `util`
pub mod util;                     //  Lvgl Utility API. Export folder `util` as Rust module `lvgl::util`

#[cfg(feature = "riot_os")]       //  If building for RIOT OS...
pub mod console;                  //  Lvgl Console API. Export `console.rs` as Rust module `lvgl::console`

/// Return type and error codes for Lvgl API
#[cfg(feature = "riot_os")]       //  If building for RIOT OS...
pub mod result {
    /// Common return type for Lvgl API.  If no error, returns `Ok(val)` where val has type T.
    /// Upon error, returns `Err(err)` where err is the LvglError error code.
    pub type LvglResult<T> = ::core::result::Result<T, LvglError>;

    /// Error codes for Lvgl API
    #[repr(i32)]
    #[derive(PartialEq)]
    #[allow(non_camel_case_types)]    //  Allow type names to have non-camel case
    pub enum LvglError {
        /// Error code 0 means no error.
        SYS_EOK         = 0,
        SYS_EUNKNOWN    = 1,
    }

    /// Cast `LvglError` to `i32`
    impl From<LvglError> for i32 {
        /// Cast `LvglError` to `i32`
        fn from(err: LvglError) -> Self {
            err as i32
        }
    }

    /// Cast `i32` to `LvglError`
    impl From<i32> for LvglError {
        /// Cast `i32` to `LvglError`
        fn from(num: i32) -> Self {
            unsafe { 
                ::core::mem::transmute::
                    <i32, LvglError>
                    (num)
            }  
        }
    }

    /// Cast `()` to `LvglError`
    impl From<()> for LvglError {
        /// Cast `()` to `LvglError`
        fn from(_: ()) -> Self {
            LvglError::SYS_EUNKNOWN
        }
    }

    /// Implement formatted output for LvglError
    impl core::fmt::Debug for LvglError {
        fn fmt(&self, _fmt: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
            //  TODO
            Ok(())
        }
    }
}

/// Represents a null-terminated string, suitable for passing to Lvgl APIs as `* const char`.
/// The string could be a null-terminated byte string created in Rust, or a pointer to a null-terminated string returned by C.
/// Pointer may be null.
#[cfg(feature = "riot_os")] //  If building for RIOT OS...
#[derive(Clone, Copy)]      //  Strn may be copied
pub struct Strn {
    /// Either a byte string terminated with null, or a pointer to a null-terminated string
    pub rep: StrnRep
}

/// Either a byte string or a string pointer
#[cfg(feature = "riot_os")] //  If building for RIOT OS...
#[derive(Clone, Copy)]      //  StrnRep may be copied
#[repr(u8)]
pub enum StrnRep {
    /// Byte string terminated with null
    ByteStr(&'static [u8]),
    /// Pointer to a null-terminated string
    CStr(*const u8),
}

#[cfg(feature = "riot_os")] //  If building for RIOT OS...
impl Strn {
    /// Create a new `Strn` with a byte string. Fail if the last byte is not zero.
    /// ```
    /// Strn::new(b"network\0")
    /// strn!("network")
    /// ```
    pub fn new(bs: &'static [u8]) -> Strn {
        assert_eq!(bs.last(), Some(&0u8), "no null");  //  Last byte must be 0.
        Strn { 
            rep: StrnRep::ByteStr(bs)
        }
    }

    /// Create a new `Strn` with a null-terminated string pointer returned by C.
    pub fn from_cstr(cstr: *const u8) -> Strn {
        Strn { 
            rep: StrnRep::CStr(cstr)
        }
    }

    /// Return a pointer to the string
    pub fn as_ptr(&self) -> *const u8 {
        match self.rep {
            StrnRep::ByteStr(bs) => { bs.as_ptr() }
            StrnRep::CStr(cstr)  => { cstr }
        }
    }

    /// Return the length of the string, excluding the terminating null. For safety, we limit to 128.
    pub fn len(&self) -> usize {
        match self.rep {
            StrnRep::ByteStr(bs) => { 
                assert_eq!(bs.last(), Some(&0u8), "no null");  //  Last byte must be 0.
                bs.len() - 1  //  Don't count the terminating null.
            }
            StrnRep::CStr(cstr)  => { 
                //  Look for the null termination.
                if cstr.is_null() { return 0; }
                for len in 0..127 {
                    let ptr: *const u8 =  ((cstr as u32) + len) as *const u8;
                    if unsafe { *ptr } == 0 { return len as usize; }                    
                }
                assert!(false, "big strn");  //  String too long
                return 128 as usize;
            }
        }
    }

    /// Return true if the string is empty
    pub fn is_empty(&self) -> bool {
        self.len() == 0
    }

    /// Return the byte string as a null-terminated `* const char` C-style string.
    /// Fail if the last byte is not zero.
    pub fn as_cstr(&self) -> *const u8 {
        match self.rep {
            StrnRep::ByteStr(bs) => { 
                assert_eq!(bs.last(), Some(&0u8), "no null");  //  Last byte must be 0.
                bs.as_ptr() as *const u8
            }
            StrnRep::CStr(cstr)  => { cstr }
        }
    }

    /// Return the byte string.
    /// Fail if the last byte is not zero.
    pub fn as_bytestr(&self) -> &'static [u8] {
        match self.rep {
            StrnRep::ByteStr(bs) => {                
                assert_eq!(bs.last(), Some(&0u8), "no null");  //  Last byte must be 0.
                &bs
            }
            StrnRep::CStr(_cstr)  => { 
                assert!(false, "strn cstr");  //  Not implemented
                b"\0"
            }
        }
    }

    /// Fail if the last byte is not zero.
    pub fn validate(&self) {
        match self.rep {
            StrnRep::ByteStr(bs) => {         
                assert_eq!(bs.last(), Some(&0u8), "no null");  //  Last byte must be 0.
            }
            StrnRep::CStr(_cstr)  => {}
        }
    }

    /// Fail if the last byte is not zero.
    pub fn validate_bytestr(bs: &'static [u8]) {
        assert_eq!(bs.last(), Some(&0u8), "no null");  //  Last byte must be 0.
    }
}

///  Allow threads to share Strn, since it is static.
#[cfg(feature = "riot_os")] //  If building for RIOT OS...
unsafe impl Send for Strn {}

///  Allow threads to share Strn, since it is static.
#[cfg(feature = "riot_os")] //  If building for RIOT OS...
unsafe impl Sync for Strn {}

///  Declare a pointer that will be used by C functions to return a value
#[cfg(feature = "riot_os")] //  If building for RIOT OS...
pub type Out<T> = &'static mut T;

///  Declare a `void *` pointer that will be passed to C functions
#[cfg(feature = "riot_os")] //  If building for RIOT OS...
pub type Ptr = *mut ::cty::c_void;

///  Declare a `NULL` pointer that will be passed to C functions
#[cfg(feature = "riot_os")] //  If building for RIOT OS...
pub const NULL: Ptr = ::core::ptr::null_mut();

///  Pointer to mutable LVGL object `lv_obj_t`
pub type Ptr = *mut core::obj::lv_obj_t;