Commit 6d34a1f5 authored by Astro's avatar Astro
Browse files

Merge branch 'task/add_bhi160_error_handling' into 'master'

Add erorr handling for BHI160  sensors.

See merge request astro/rust-card10!8
parents b313cf15 77f2e073
Pipeline #3350 passed with stage
in 9 minutes and 55 seconds
#![no_std]
#![no_main]
use core::fmt::Write;
use card10_l0dable::*;
use core::fmt::{self, Write};
main!(main);
fn main() {
writeln!(UART, "Hello from Rust\r").unwrap();
let result = run();
if let Err(error) = result {
writeln!(UART, "error: {}\r", error).unwrap();
}
}
fn run() -> Result<(), Error> {
writeln!(UART, "Hello from Rust\r")?;
let bme = BME680::start();
let a = BHI160::<Accelerometer>::start();
let g = BHI160::<Gyroscope>::start();
let o = BHI160::<Orientation>::start();
let a = BHI160::<Accelerometer>::start()?;
let g = BHI160::<Gyroscope>::start()?;
let o = BHI160::<Orientation>::start()?;
let display = Display::open();
let light = LightSensor::start();
for t in 0..Display::W {
writeln!(UART, "BME: {:?}\r", bme.read()).unwrap();
writeln!(UART, "A:\r").unwrap();
for d in &a.read() {
writeln!(UART, " - {:?}\r", d).unwrap();
writeln!(UART, "BME: {:?}\r", bme.read())?;
writeln!(UART, "A:\r")?;
for d in &a.read()? {
writeln!(UART, " - {:?}\r", d)?;
}
writeln!(UART, "O:\r").unwrap();
for d in &o.read() {
writeln!(UART, " - {:?}\r", d).unwrap();
writeln!(UART, "O:\r")?;
for d in &o.read()? {
writeln!(UART, " - {:?}\r", d)?;
}
writeln!(UART, "G:\r").unwrap();
for d in &g.read() {
writeln!(UART, " - {:?}\r", d).unwrap();
writeln!(UART, "G:\r")?;
for d in &g.read()? {
writeln!(UART, " - {:?}\r", d)?;
}
display.clear(Color::yellow());
display.print(160 - t, 10, b"Hello Rust\0", Color::white(), Color::black());
......@@ -49,8 +62,41 @@ fn main() {
if b.right_top() {
display.print(80, 30, b"Reset\0", Color::red(), Color::black());
}
writeln!(UART, "Light: {:?}\r", light.get()).unwrap();
writeln!(UART, "Light: {:?}\r", light.get())?;
display.update();
}
Ok(())
}
// -----------------------------------------------------------------------------
// Error
// -----------------------------------------------------------------------------
#[derive(Debug)]
pub enum Error {
UartWriteFailed(fmt::Error),
SensorInteractionFailed(BHI160Error),
}
impl From<fmt::Error> for Error {
fn from(error: fmt::Error) -> Self {
Error::UartWriteFailed(error)
}
}
impl From<BHI160Error> for Error {
fn from(error: BHI160Error) -> Self {
Error::SensorInteractionFailed(error)
}
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Error::UartWriteFailed(error) => error.fmt(f),
Error::SensorInteractionFailed(error) => error.fmt(f),
}
}
}
use core::mem::uninitialized;
use core::marker::PhantomData;
use super::bindings::*;
use core::{
fmt::{self, Display, Write},
marker::PhantomData,
mem::MaybeUninit,
};
use core::fmt::Write;
use crate::{bindings::*, errno};
pub trait SensorType {
/// sensor_type in C, sensor_id in Python
......@@ -48,43 +50,64 @@ pub struct Sensor<S: SensorType> {
}
impl<S: SensorType> Sensor<S> {
pub fn start() -> Self {
fn new(stream_id: i32) -> Self {
Self {
stream_id,
_kind: PhantomData,
}
}
pub fn start() -> Result<Self, Error> {
let mut cfg = bhi160_sensor_config {
sample_buffer_len: 200,
sample_rate: 4,
dynamic_range: 2,
_padding: [0u8; 8],
};
let stream_id = unsafe {
epic_bhi160_enable_sensor(S::sensor_type(), &mut cfg)
};
Sensor {
stream_id,
_kind: PhantomData,
let stream_id = unsafe { epic_bhi160_enable_sensor(S::sensor_type(), &mut cfg) };
if stream_id < 0 {
let error = match -stream_id {
errno::EBUSY => Error::DriverBusy,
_ => Error::Unknown(stream_id),
};
return Err(error);
}
Ok(Sensor::new(stream_id))
}
pub fn read(&self) -> SensorData<S> {
let mut buf: [bhi160_data_vector; DATA_MAX] = unsafe {
uninitialized()
};
let n = unsafe {
epic_stream_read(self.stream_id, buf.as_mut_ptr() as *mut _, buf.len())
};
if n < 0 {
panic!("epic_stream_read fail");
pub fn read(&self) -> Result<SensorData<S>, Error> {
let mut buffer = MaybeUninit::<[bhi160_data_vector; DATA_MAX]>::zeroed();
let buffer_pointer = buffer.as_mut_ptr() as *mut _;
let packet_count = unsafe { epic_stream_read(self.stream_id, buffer_pointer, DATA_MAX) };
if packet_count < 0 {
let error = match -packet_count {
errno::ENODEV => Error::SensorUnavailable,
errno::EBADF => Error::SensorDescriptorUnknown,
errno::EINVAL => Error::InvalidSampleCount,
errno::EBUSY => Error::CouldNotAcquireLock,
_ => Error::Unknown(packet_count),
};
return Err(error);
}
let n = n as usize;
SensorData {
buf, n,
Ok(SensorData {
buf: unsafe { buffer.assume_init() },
n: packet_count as usize,
_kind: PhantomData,
}
})
}
}
impl<S: SensorType> Drop for Sensor<S> {
fn drop(&mut self) {
unsafe { epic_bhi160_disable_sensor(S::sensor_type()); }
unsafe {
epic_bhi160_disable_sensor(S::sensor_type());
}
}
}
......@@ -97,11 +120,9 @@ pub struct SensorData<S> {
impl<'a, S: SensorType> IntoIterator for &'a SensorData<S> {
type Item = SensorDataItem;
type IntoIter = SensorDataIter<'a, S>;
fn into_iter(self) -> Self::IntoIter {
SensorDataIter {
data: self,
pos: 0,
}
SensorDataIter { data: self, pos: 0 }
}
}
......@@ -112,22 +133,27 @@ pub struct SensorDataIter<'a, S> {
impl<'a, S: SensorType> Iterator for SensorDataIter<'a, S> {
type Item = SensorDataItem;
fn next(&mut self) -> Option<Self::Item> {
while self.pos < self.data.n {
let vec = &self.data.buf[self.pos];
self.pos += 1;
if vec.data_type == DATA_TYPE_VECTOR {
let item = SensorDataItem {
x: S::convert_single(vec.x),
y: S::convert_single(vec.y),
z: S::convert_single(vec.z),
status: vec.status,
};
return Some(item);
} else {
writeln!(crate::UART, "Sensor: skip type {}\r", vec.data_type).unwrap();
let vec = &self.data.buf[self.pos];
if vec.data_type != DATA_TYPE_VECTOR {
writeln!(crate::UART, "Sensor: skip type {}\r", vec.data_type).ok();
continue;
}
let item = SensorDataItem {
x: S::convert_single(vec.x),
y: S::convert_single(vec.y),
z: S::convert_single(vec.z),
status: vec.status,
};
return Some(item);
}
None
}
}
......@@ -152,3 +178,38 @@ pub struct bhi160_data_vector {
}
const DATA_TYPE_VECTOR: u8 = 0;
// -----------------------------------------------------------------------------
// BHI160 Error
// -----------------------------------------------------------------------------
#[derive(Debug)]
pub enum Error {
/// The descriptor table lock could not be acquired.
CouldNotAcquireLock,
/// The BHI160 driver is currently busy with other tasks and could not be
/// acquired for enabling a sensor.
DriverBusy,
/// The requested sample `count` is not a multiple of the sensor's sample
/// size.
InvalidSampleCount,
/// The given sensor descriptor is unknown.
SensorDescriptorUnknown,
/// Sensor is not currently available.
SensorUnavailable,
/// Not yet documented and therefore unknown error types.
Unknown(i32),
}
impl Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
Error::CouldNotAcquireLock => writeln!(f, "Could not acquire BHI160 lock."),
Error::DriverBusy => writeln!(f, "The BHI160 Driver is busy."),
Error::InvalidSampleCount => writeln!(f, "Sample couldn't invalid."),
Error::SensorDescriptorUnknown => writeln!(f, "Unknown BHI160 sensor descriptor."),
Error::SensorUnavailable => writeln!(f, "The BHI160 sensor is currently unavailable."),
Error::Unknown(id) => writeln!(f, "Unknown error id: {}", id),
}
}
}
......@@ -58,6 +58,50 @@ pub mod ctypes {
pub use core::ffi::c_void;
}
pub mod errno {
#![allow(non_snake_case)]
use crate::ctypes::c_int;
pub const EPERM: c_int = 1; // Operation not permitted
pub const ENOENT: c_int = 2; // No such file or directory
pub const ESRCH: c_int = 3; // No such process
pub const EINTR: c_int = 4; // Interrupted system call
pub const EIO: c_int = 5; // I/O error
pub const ENXIO: c_int = 6; // No such device or address
pub const E2BIG: c_int = 7; // Argument list too long
pub const ENOEXEC: c_int = 8; // Exec format error
pub const EBADF: c_int = 9; // Bad file number
pub const ECHILD: c_int = 10; // No child processes
pub const EAGAIN: c_int = 11; // Try again
pub const ENOMEM: c_int = 12; //Out of memory
pub const EACCES: c_int = 13; //Permission denied
pub const EFAULT: c_int = 14; //Bad address
pub const ENOTBLK: c_int = 15; //Block device required
pub const EBUSY: c_int = 16; //Device or resource busy
pub const EEXIST: c_int = 17; //File exists
pub const EXDEV: c_int = 18; //Cross-device link
pub const ENODEV: c_int = 19; //No such device
pub const ENOTDIR: c_int = 20; //Not a directory
pub const EISDIR: c_int = 21; //Is a directory
pub const EINVAL: c_int = 22; //Invalid argument
pub const ENFILE: c_int = 23; //File table overflow
pub const EMFILE: c_int = 24; //Too many open files
pub const ENOTTY: c_int = 25; //Not a typewriter
pub const ETXTBSY: c_int = 26; //Text file busy
pub const EFBIG: c_int = 27; //File too large
pub const ENOSPC: c_int = 28; //No space left on device
pub const ESPIPE: c_int = 29; //Illegal seek
pub const EROFS: c_int = 30; //Read-only file system
pub const EMLINK: c_int = 31; //Too many links
pub const EPIPE: c_int = 32; //Broken pipe
pub const EDOM: c_int = 33; //Math argument out of domain of func
pub const ERANGE: c_int = 34; //Math result not representable
pub const EAFNOSUPPORT: c_int = 97; //Address family not supported by protocol
pub const ECONNRESET: c_int = 104; //Connection timed out
pub const ETIMEDOUT: c_int = 110; //Connection timed out
pub const EINPROGRESS: c_int = 115; //Operation now in progress
}
pub mod bindings {
#![allow(non_upper_case_globals)]
#![allow(non_camel_case_types)]
......@@ -86,5 +130,8 @@ pub use fmt_buffer::{FmtBuffer, str_to_cstr};
mod bme680;
pub use bme680::BME680;
mod bhi160;
pub use bhi160::{Sensor as BHI160, Accelerometer, Orientation, Gyroscope, SensorData as BHI160Data};
pub use bhi160::{
Accelerometer, Error as BHI160Error, Gyroscope, Orientation, Sensor as BHI160,
SensorData as BHI160Data,
};
pub mod fs;
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment