Skip to content
This repository has been archived by the owner on Jun 19, 2024. It is now read-only.

feat: embedded_graphics driver for the brain display #105

Open
wants to merge 9 commits into
base: main
Choose a base branch
from
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ Before releasing:
- Added support for getting motor fault flags (e.g. over-temperature, over-current, H-bridge faults).
- Added support for internal motor PID tuning. Feature gated behind `dangerous_motor_tuning`, as this can cause hardware damage and is not recommended.
- Added various constants for convenience around `Motor` and `Gearset`.
- An ``embedded_graphics`` driver in the new `pros_graphics` crate.
- New `graphics` and `embedded-graphics` features in the `pros` crate.

### Fixed

Expand Down
115 changes: 92 additions & 23 deletions flake.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

24 changes: 24 additions & 0 deletions packages/pros-graphics/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
[package]
name = "pros-graphics"
version = "0.1.0"
edition = "2021"
license = "MIT"
description = "Core functionality for pros-rs"
keywords = ["PROS", "Robotics", "graphics", "vex", "v5"]
categories = [
"api-bindings",
"no-std",
"science::robotics",
]

[dependencies]
embedded-graphics-core = { version = "0.4.0", optional = true }
pros-devices = { version = "0.1.0", path = "../pros-devices" }
pros-sys = { version = "0.7.0", path = "../pros-sys" }

[lints]
workspace = true

[features]
default = []
embedded-graphics = ["dep:embedded-graphics-core"]
94 changes: 94 additions & 0 deletions packages/pros-graphics/src/embedded_graphics.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
//! An embedded_graphics driver for VEX V5 Brain displays.

use alloc::boxed::Box;

use embedded_graphics_core::{
draw_target::DrawTarget,
geometry::{Dimensions, Point, Size},
pixelcolor::{Rgb888, RgbColor},
primitives::Rectangle,
Pixel,
};
use pros_devices::{color::Rgb, Screen};

/// An embedded_graphics driver for the V5 Brain display
pub struct V5BrainDisplay {
pixel_buffer:
Box<[u32; Screen::HORIZONTAL_RESOLUTION as usize * Screen::VERTICAL_RESOLUTION as usize]>,
}

impl V5BrainDisplay {
/// Creates a new VexDisplay from a Screen
pub fn new(_screen: Screen) -> Self {
let pixel_buffer = Box::new_zeroed();
let pixel_buffer = unsafe { pixel_buffer.assume_init() };

Self { pixel_buffer }
}

/// Draws the pixel buffer to the screen
///
/// # Note
///
/// I would use the [`Screen::draw_buffer`](pros_devices::screen::Screen::draw_buffer) API,
/// but unfortunately it stack overflows with a buffer this big and is more complicated.
fn draw_buffer(&self) {
// SAFETY: The pixel buffer is guarenteed to be large enough and live long enough and we take ownership of the screen when created.
unsafe {
pros_sys::screen_copy_area(
0,
0,
Screen::HORIZONTAL_RESOLUTION,
Screen::VERTICAL_RESOLUTION,
self.pixel_buffer.as_ptr(),
Screen::HORIZONTAL_RESOLUTION as _,
);
}
}
}

impl From<Screen> for V5BrainDisplay {
fn from(value: Screen) -> Self {
Self::new(value)
}
}

impl Dimensions for V5BrainDisplay {
fn bounding_box(&self) -> Rectangle {
Rectangle::new(
Point::new(0, 0),
Size::new(
Screen::HORIZONTAL_RESOLUTION as _,
Screen::VERTICAL_RESOLUTION as _,
),
)
}
}

impl DrawTarget for V5BrainDisplay {
type Color = Rgb888;
type Error = pros_devices::screen::ScreenError;

fn draw_iter<I>(&mut self, pixels: I) -> Result<(), Self::Error>
where
I: IntoIterator<Item = Pixel<Self::Color>>,
{
pixels
.into_iter()
.map(|pixel| (pixel.0, Rgb::new(pixel.1.r(), pixel.1.g(), pixel.1.b())))
.for_each(|(pos, color)| {
// Make sure that the coordinate is valid to index with.
if !(pos.x > Screen::HORIZONTAL_RESOLUTION as _ || pos.x < 0)
&& !(pos.y > Screen::VERTICAL_RESOLUTION as _ || pos.y < 0)
{
// SAFETY: We initialize the buffer with zeroes, so it's safe to assume it's initialized.
self.pixel_buffer[pos.y as usize * Screen::HORIZONTAL_RESOLUTION as usize
+ pos.x as usize] = color.into();
}
});

self.draw_buffer();

Ok(())
}
}
13 changes: 13 additions & 0 deletions packages/pros-graphics/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
//! Graphics driver implementations for the V5 Brain display.
//!
//! Currently supports:
//! - [embedded-graphics](https://crates.io/crates/embedded-graphics)
//! Implemented for the [`pros-rs`](https://crates.io/crates/pros) ecosystem and implemented using [pros-devices](https://crates.io/crates/pros-devices).
#![no_std]
#![cfg_attr(feature = "embedded-graphics", feature(new_uninit))]

#[cfg(feature = "embedded-graphics")]
extern crate alloc;

#[cfg(feature = "embedded-graphics")]
pub mod embedded_graphics;
4 changes: 4 additions & 0 deletions packages/pros/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ rust-version = "1.75.0"
pros-sync = { version = "0.1.0", path = "../pros-sync", optional = true }
pros-async = { version = "0.1.0", path = "../pros-async", optional = true }
pros-devices = { version = "0.1.0", path = "../pros-devices", optional = true }
pros-graphics = { version = "0.1.0", path = "../pros-graphics", optional = true }
pros-panic = { version = "0.1.0", path = "../pros-panic", optional = true }
pros-core = { version = "0.1.0", path = "../pros-core", optional = true }
pros-math = { version = "0.1.0", path = "../pros-math", optional = true }
Expand All @@ -36,6 +37,9 @@ sync = ["dep:pros-sync"]

devices = ["dep:pros-devices"]

graphics = ["dep:pros-graphics"]
embedded-graphics = ["pros-graphics/embedded-graphics"]

math = ["dep:pros-math"]

panic = ["dep:pros-panic"]
Expand Down
10 changes: 9 additions & 1 deletion packages/pros/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ pub use pros_async as async_runtime;
pub use pros_core as core;
#[cfg(feature = "devices")]
pub use pros_devices as devices;
#[cfg(feature = "graphics")]
pub use pros_graphics as graphics;
#[cfg(feature = "math")]
pub use pros_math as math;
#[cfg(feature = "panic")]
Expand All @@ -82,6 +84,10 @@ pub mod prelude {
print, println,
task::delay,
};
#[cfg(all(not(feature = "graphics"), feature = "devices"))]
pub use pros_devices::screen::{
Circle, Line, Rect, Text, TextFormat, TextPosition, TouchState,
};
#[cfg(feature = "devices")]
pub use pros_devices::{
adi::{
Expand All @@ -99,7 +105,7 @@ pub mod prelude {
color::Rgb,
peripherals::{DynamicPeripherals, Peripherals},
position::Position,
screen::{Circle, Line, Rect, Screen, Text, TextFormat, TextPosition, TouchState},
screen::Screen,
smart::{
distance::DistanceSensor,
expander::AdiExpander,
Expand All @@ -113,6 +119,8 @@ pub mod prelude {
SmartDevice, SmartPort,
},
};
#[cfg(all(feature = "graphics", feature = "embedded-graphics"))]
pub use pros_graphics::embedded_graphics::V5BrainDisplay;
#[cfg(feature = "math")]
pub use pros_math::{feedforward::MotorFeedforwardController, pid::PidController};
#[cfg(feature = "sync")]
Expand Down
Loading