mirror of
https://github.com/kittywitch/esp32-c3-meepy.git
synced 2026-02-08 23:49:18 -08:00
feat: clean up part 1
This commit is contained in:
parent
6841142729
commit
77826ad4cd
4 changed files with 132 additions and 98 deletions
|
|
@ -27,3 +27,7 @@ esp-radio = { version = "0.16.0", features = ["smoltcp", "wifi", "esp32c3", "uns
|
||||||
esp-rtos = { version = "0.1.1", features = ["esp32c3", "embassy"] }
|
esp-rtos = { version = "0.1.1", features = ["esp32c3", "embassy"] }
|
||||||
ili9341 = "0.6.0"
|
ili9341 = "0.6.0"
|
||||||
static_cell = "2.1.1"
|
static_cell = "2.1.1"
|
||||||
|
|
||||||
|
# https://docs.espressif.com/projects/rust/esp-wifi/0.15.0/esp32c3/esp_wifi/index.html#optimization-level
|
||||||
|
[profile.dev.package.esp-wifi]
|
||||||
|
opt-level = 3
|
||||||
|
|
|
||||||
|
|
@ -32,6 +32,7 @@
|
||||||
buildy
|
buildy
|
||||||
pkgs.rustup
|
pkgs.rustup
|
||||||
pkgs.espflash
|
pkgs.espflash
|
||||||
|
pkgs.clippy
|
||||||
pkgs.pkg-config
|
pkgs.pkg-config
|
||||||
pkgs.stdenv.cc
|
pkgs.stdenv.cc
|
||||||
pkgs.libusb1
|
pkgs.libusb1
|
||||||
|
|
@ -45,6 +46,7 @@
|
||||||
LD_LIBRARY_PATH = "${pkgs.lib.makeLibraryPath buildInputs}";
|
LD_LIBRARY_PATH = "${pkgs.lib.makeLibraryPath buildInputs}";
|
||||||
|
|
||||||
shellHook = ''
|
shellHook = ''
|
||||||
|
export PATH="${lib.makeBinPath [pkgs.rust-analyzer]}:$PATH"
|
||||||
export PROJECT_DIR="$(pwd)";
|
export PROJECT_DIR="$(pwd)";
|
||||||
# custom bashrc stuff
|
# custom bashrc stuff
|
||||||
export PS1_PREFIX="(esp-rs)"
|
export PS1_PREFIX="(esp-rs)"
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
[toolchain]
|
[toolchain]
|
||||||
channel = "stable"
|
channel = "stable"
|
||||||
components = ["rust-src", "clippy", "rust-analyzer"]
|
components = ["rust-src", "rustc-dev"]
|
||||||
targets = ["riscv32imc-unknown-none-elf"]
|
targets = ["riscv32imc-unknown-none-elf"]
|
||||||
|
|
|
||||||
222
src/main.rs
222
src/main.rs
|
|
@ -1,5 +1,6 @@
|
||||||
#![no_std]
|
#![no_std]
|
||||||
#![no_main]
|
#![no_main]
|
||||||
|
#![feature(trait_alias)]
|
||||||
|
|
||||||
extern crate alloc;
|
extern crate alloc;
|
||||||
|
|
||||||
|
|
@ -22,7 +23,10 @@ use {
|
||||||
alignment::HorizontalAlignment as TextHorizontalAlignment,
|
alignment::HorizontalAlignment as TextHorizontalAlignment,
|
||||||
},
|
},
|
||||||
embedded_layout::{
|
embedded_layout::{
|
||||||
layout::linear::LinearLayout,
|
view_group::ViewGroup,
|
||||||
|
layout::{
|
||||||
|
linear::LinearLayout,
|
||||||
|
},
|
||||||
prelude::*,
|
prelude::*,
|
||||||
},
|
},
|
||||||
embedded_hal_bus::spi::{ExclusiveDevice, NoDelay},
|
embedded_hal_bus::spi::{ExclusiveDevice, NoDelay},
|
||||||
|
|
@ -53,34 +57,38 @@ const PASSWORD: &str = env!("WIFI_PASSWORD");
|
||||||
|
|
||||||
esp_bootloader_esp_idf::esp_app_desc!();
|
esp_bootloader_esp_idf::esp_app_desc!();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Make it easier to follow the TFT related types. .-.
|
||||||
|
*/
|
||||||
|
|
||||||
type TFTSpiDevice<'spi> = ExclusiveDevice<Spi<'spi, Blocking>, Output<'spi>, NoDelay>;
|
type TFTSpiDevice<'spi> = ExclusiveDevice<Spi<'spi, Blocking>, Output<'spi>, NoDelay>;
|
||||||
type TFTSpiInterface<'spi> =
|
type TFTSpiInterface<'spi> =
|
||||||
SPIInterface<ExclusiveDevice<Spi<'spi, Blocking>, Output<'spi>, NoDelay>, Output<'spi>>;
|
SPIInterface<ExclusiveDevice<Spi<'spi, Blocking>, Output<'spi>, NoDelay>, Output<'spi>>;
|
||||||
|
|
||||||
type Ili<'spi> = Ili9341<TFTSpiInterface<'spi>, Output<'spi>>;
|
type Ili<'spi> = Ili9341<TFTSpiInterface<'spi>, Output<'spi>>;
|
||||||
|
|
||||||
pub struct TFT<'spi> {
|
/*
|
||||||
display: Ili<'spi>,
|
Provide an type alias DColour (display colour) since Bgr565 is the actual colour ordering for my display.
|
||||||
}
|
*/
|
||||||
|
|
||||||
impl<'spi> TFT<'spi> {
|
type DColor = Bgr565;
|
||||||
fn draw_target(&mut self) -> DrawFlipper<'_, 'spi> {
|
|
||||||
DrawFlipper {
|
|
||||||
display: &mut self.display,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn candyflip(color: Bgr565) -> Rgb565 {
|
/*
|
||||||
unsafe {
|
* Provide an alias for something that can be put into a ViewGroup for the use of embedded-layout.
|
||||||
core::mem::transmute::<Bgr565, Rgb565>(color)
|
*/
|
||||||
}
|
|
||||||
}
|
trait Drawy = Drawable<Color = DColor> + ViewGroup;
|
||||||
fn flipcandy(color: Rgb565) -> Bgr565 {
|
|
||||||
unsafe {
|
/*
|
||||||
core::mem::transmute::<Rgb565, Bgr565>(color)
|
* So, my specific ILI9341-derived display doesn't JUST have wrong colour channels (Rgb vs Gbr like
|
||||||
}
|
* in the actual driver implementation).
|
||||||
}
|
*
|
||||||
|
* It also is *mirrored* horizontally. The underlying library and the driver implementation both don't
|
||||||
|
* expose anything reasonable to handle this.
|
||||||
|
*
|
||||||
|
* The driver exposes "Orientation" of Horizontal, Portrait, HorizontalFlipped and PortraitFlipped.
|
||||||
|
* This is inadequate for the problems in the implementation I have.
|
||||||
|
*/
|
||||||
|
|
||||||
struct DrawFlipper<'a, 'spi> {
|
struct DrawFlipper<'a, 'spi> {
|
||||||
display: &'a mut Ili<'spi>,
|
display: &'a mut Ili<'spi>,
|
||||||
|
|
@ -88,7 +96,7 @@ struct DrawFlipper<'a, 'spi> {
|
||||||
|
|
||||||
impl<'a, 'spi> DrawTarget for DrawFlipper<'a, 'spi> {
|
impl<'a, 'spi> DrawTarget for DrawFlipper<'a, 'spi> {
|
||||||
type Error = <Ili<'spi> as DrawTarget>::Error;
|
type Error = <Ili<'spi> as DrawTarget>::Error;
|
||||||
type Color = Bgr565;//<Ili<'spi> as DrawTarget>::Color;
|
type Color = DColor;//<Ili<'spi> as DrawTarget>::Color;
|
||||||
fn draw_iter<I>(&mut self, pixels: I) -> Result<(), Self::Error>
|
fn draw_iter<I>(&mut self, pixels: I) -> Result<(), Self::Error>
|
||||||
where
|
where
|
||||||
I: IntoIterator<Item = Pixel<Self::Color>>,
|
I: IntoIterator<Item = Pixel<Self::Color>>,
|
||||||
|
|
@ -131,20 +139,40 @@ impl<'a> Dimensions for DrawFlipper<'a, '_> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone,Copy)]
|
/*
|
||||||
enum StyleVariant {
|
* Container for implementing the TFT type
|
||||||
Header,
|
*/
|
||||||
Regular
|
|
||||||
|
pub struct TFT<'spi> {
|
||||||
|
display: Ili<'spi>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'spi> TFT<'spi> {
|
impl<'spi> TFT<'spi> {
|
||||||
const H_BG: Bgr565 = Bgr565::CSS_DARK_SLATE_GRAY;
|
fn draw_target(&mut self) -> DrawFlipper<'_, 'spi> {
|
||||||
const H_S: Bgr565 = Bgr565::CYAN;
|
DrawFlipper {
|
||||||
const H_FG: Bgr565 = Bgr565::WHITE;
|
display: &mut self.display,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const R_BG: Bgr565 = Bgr565::CSS_DARK_SLATE_GRAY;
|
/*
|
||||||
const R_S: Bgr565 = Bgr565::BLUE;
|
* Provide a decent-ish way of replacing the colour channel ordering.
|
||||||
const R_FG: Bgr565 = Bgr565::WHITE;
|
*
|
||||||
|
* Ask not questions about the drug terminology!
|
||||||
|
*/
|
||||||
|
|
||||||
|
fn candyflip(color: DColor) -> Rgb565 {
|
||||||
|
unsafe {
|
||||||
|
core::mem::transmute::<DColor, Rgb565>(color)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Implement rendering helpers for the weird display
|
||||||
|
*/
|
||||||
|
|
||||||
|
impl<'spi> TFT<'spi> {
|
||||||
|
const ROOT_BG: DColor = DColor::BLACK;
|
||||||
|
|
||||||
pub fn new(
|
pub fn new(
|
||||||
spi2: SPI2<'spi>,
|
spi2: SPI2<'spi>,
|
||||||
|
|
@ -185,43 +213,61 @@ impl<'spi> TFT<'spi> {
|
||||||
.with_mode(Mode::_0)
|
.with_mode(Mode::_0)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn clear(&mut self, color: Bgr565) {
|
pub fn clear(&mut self, color: DColor) {
|
||||||
self.display.clear(candyflip(color)).unwrap();
|
let _ = self.display.clear(candyflip(color));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn clear_root(&mut self) {
|
||||||
|
let _ = self.display.clear(candyflip(Self::ROOT_BG));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn part_clear(&mut self, x: i32, y: i32, w: u32, h: u32) {
|
pub fn part_clear(&mut self, x: i32, y: i32, w: u32, h: u32) {
|
||||||
Rectangle::new(Point::new(x, y), Size::new(w, h))
|
Rectangle::new(Point::new(x, y), Size::new(w, h))
|
||||||
.into_styled(PrimitiveStyle::with_fill(Bgr565::BLACK))
|
.into_styled(PrimitiveStyle::with_fill(DColor::BLACK))
|
||||||
.draw(&mut self.draw_target())
|
.draw(&mut self.draw_target())
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn containing_recty(&mut self, x: i32, y: i32, w: u32, h: u32, style: StyleVariant) -> Styled<Rectangle, PrimitiveStyle<Bgr565>> {
|
pub fn contained_text<'a>(text: &'a str, margin: u32) -> impl Drawy + 'a {
|
||||||
let bg = match style {
|
|
||||||
StyleVariant::Header => Self::H_BG,
|
|
||||||
StyleVariant::Regular => Self::R_BG,
|
|
||||||
};
|
|
||||||
let s = match style {
|
|
||||||
StyleVariant::Header => Self::H_S,
|
|
||||||
StyleVariant::Regular => Self::R_S,
|
|
||||||
};
|
|
||||||
let style = PrimitiveStyleBuilder::new()
|
let style = PrimitiveStyleBuilder::new()
|
||||||
.fill_color(bg)
|
.stroke_color(DColor::RED)
|
||||||
.stroke_color(s)
|
.stroke_width(3)
|
||||||
.stroke_width(1)
|
.fill_color(DColor::CSS_DARK_SLATE_GRAY)
|
||||||
.build();
|
.build();
|
||||||
Rectangle::new(Point::new(x, y), Size::new(w, h))
|
let text_style = MonoTextStyle::new(&FONT_6X10, DColor::WHITE);
|
||||||
.clone()
|
let text = Text::new(text, Point::new_equal((margin/2) as i32), text_style);
|
||||||
|
let margin_size = Size::new_equal(margin);
|
||||||
|
let bound = text.bounding_box();
|
||||||
|
let size = bound.size + margin_size;
|
||||||
|
let height_offset = Point::new(0, -((margin/2) as i32));
|
||||||
|
Chain::new(
|
||||||
|
text
|
||||||
|
).append(
|
||||||
|
Rectangle::new(height_offset, size)
|
||||||
.into_styled(style)
|
.into_styled(style)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn container(&mut self, margin: i32, y: i32, h: u32, style: StyleVariant) -> Styled<Rectangle, PrimitiveStyle<Bgr565>> {
|
pub fn fullscreen_alert(&mut self, text: &str, clear: bool) {
|
||||||
let width = self.display.bounding_box().size.width;
|
if clear {
|
||||||
self.containing_recty(margin, y, width - margin as u32, h, style)
|
let _ = self.clear_root();
|
||||||
|
}
|
||||||
|
let display_area = self.display.bounding_box();
|
||||||
|
LinearLayout::vertical(
|
||||||
|
Chain::new(
|
||||||
|
LinearLayout::horizontal(
|
||||||
|
Self::contained_text("Initialized controller!", 16)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
).with_alignment(horizontal::Center)
|
||||||
|
.arrange()
|
||||||
|
.align_to(&display_area, horizontal::Center, vertical::Center)
|
||||||
|
.draw(&mut self.draw_target())
|
||||||
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn println(&mut self, text: &str, x: i32, y: i32) {
|
pub fn println(&mut self, text: &str, x: i32, y: i32) {
|
||||||
let style = MonoTextStyle::new(&FONT_6X10, Bgr565::WHITE);
|
let style = MonoTextStyle::new(&FONT_6X10, DColor::WHITE);
|
||||||
Text::with_alignment(text, Point::new(x, y), style, Alignment::Center)
|
Text::with_alignment(text, Point::new(x, y), style, Alignment::Center)
|
||||||
.draw(&mut self.draw_target())
|
.draw(&mut self.draw_target())
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
@ -276,49 +322,53 @@ async fn net_task(mut runner: Runner<'static, WifiDevice<'static>>) {
|
||||||
}*/
|
}*/
|
||||||
|
|
||||||
|
|
||||||
fn init_heap() {
|
|
||||||
const HEAP_SIZE: usize = 64 * 1024;
|
|
||||||
static mut HEAP: core::mem::MaybeUninit<[u8; HEAP_SIZE]> = core::mem::MaybeUninit::uninit();
|
|
||||||
|
|
||||||
unsafe {
|
|
||||||
esp_alloc::HEAP.add_region(esp_alloc::HeapRegion::new(
|
|
||||||
addr_of_mut!(HEAP) as *mut u8,
|
|
||||||
HEAP_SIZE,
|
|
||||||
esp_alloc::MemoryCapability::Internal.into(),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Controller<'tft> {
|
struct Controller<'tft> {
|
||||||
pub tft: TFT<'tft>,
|
pub display: TFT<'tft>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Controller<'_> {
|
impl Controller<'_> {
|
||||||
async fn init(peripherals: Peripherals) -> Self {
|
async fn init(peripherals: Peripherals) -> Self {
|
||||||
let tft = Self::init_screen(peripherals).await;
|
let mut display = Self::init_screen(peripherals).await;
|
||||||
let controller = Self {
|
let mut controller = Self {
|
||||||
tft,
|
display,
|
||||||
};
|
};
|
||||||
|
controller.display.fullscreen_alert("Controller initialized!", true);
|
||||||
controller
|
controller
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn init_screen<'tft>(peripherals: Peripherals) -> TFT<'tft> {
|
async fn init_screen<'tft>(peripherals: Peripherals) -> TFT<'tft> {
|
||||||
let dc = peripherals.GPIO9;
|
// Refer to https://www.espboards.dev/esp32/esp32-c3-super-mini/#esp32-c3-super-mini-pinout
|
||||||
let mosi = peripherals.GPIO6;
|
let rst = peripherals.GPIO0;
|
||||||
let sclk = peripherals.GPIO4;
|
let sclk = peripherals.GPIO4;
|
||||||
let miso = peripherals.GPIO5;
|
let miso = peripherals.GPIO5;
|
||||||
|
let mosi = peripherals.GPIO6;
|
||||||
let cs = peripherals.GPIO7;
|
let cs = peripherals.GPIO7;
|
||||||
let rst = peripherals.GPIO0;
|
let dc = peripherals.GPIO9;
|
||||||
|
|
||||||
let mut tft = TFT::new(peripherals.SPI2, sclk, miso, mosi, cs, rst, dc);
|
let mut tft = TFT::new(peripherals.SPI2, sclk, miso, mosi, cs, rst, dc);
|
||||||
let _ = tft.draw_target().clear(Bgr565::BLACK);
|
|
||||||
tft
|
tft
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*struct WifiController {
|
||||||
|
timer: TimerGroup,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WifiController {
|
||||||
|
async fn init_wifi(peripherals: Peripherals) -> Self {
|
||||||
|
let timer = TimerGroup::new(peripherals.TIMG1);
|
||||||
|
let rng = Rng::new();
|
||||||
|
Self {
|
||||||
|
timer
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}*/
|
||||||
|
|
||||||
#[esp_rtos::main]
|
#[esp_rtos::main]
|
||||||
async fn main(spawner: Spawner) {
|
async fn main(spawner: Spawner) {
|
||||||
init_heap();
|
// Note that for alloc to work, `./.cargo/config.toml` should contain alloc under build-std.
|
||||||
|
esp_alloc::heap_allocator!(size: 64*1024);
|
||||||
|
|
||||||
#[cfg(feature = "log")]
|
#[cfg(feature = "log")]
|
||||||
{
|
{
|
||||||
// The default log level can be specified here.
|
// The default log level can be specified here.
|
||||||
|
|
@ -347,28 +397,6 @@ async fn main(spawner: Spawner) {
|
||||||
|
|
||||||
let mut controller = Controller::init(peripherals).await;
|
let mut controller = Controller::init(peripherals).await;
|
||||||
|
|
||||||
let display_area = controller.tft.display.bounding_box();
|
|
||||||
let text_style = MonoTextStyle::new(&FONT_6X10, Bgr565::WHITE);
|
|
||||||
let margin = 2;
|
|
||||||
let display_width = display_area.size.width;
|
|
||||||
let display_height = display_area.size.height;
|
|
||||||
|
|
||||||
LinearLayout::vertical(
|
|
||||||
Chain::new(
|
|
||||||
LinearLayout::horizontal(
|
|
||||||
Chain::new(
|
|
||||||
Text::new("Initializing~!", Point::new(margin, margin), text_style)
|
|
||||||
).append(
|
|
||||||
controller.tft.container(margin, -10, 20, StyleVariant::Header)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
).with_alignment(horizontal::Center)
|
|
||||||
.arrange()
|
|
||||||
.align_to(&display_area, horizontal::Center, vertical::Center)
|
|
||||||
.draw(&mut controller.tft.draw_target())
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
// your business logic
|
// your business logic
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue