Skip to content

Commit

Permalink
feat: add a volume slider on screen + adc mutex + fmt
Browse files Browse the repository at this point in the history
  • Loading branch information
Sycrosity committed Apr 26, 2024
1 parent 3f3d959 commit 0c73b6b
Show file tree
Hide file tree
Showing 5 changed files with 237 additions and 58 deletions.
152 changes: 145 additions & 7 deletions src/display.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
use crate::prelude::*;

use core::fmt::{Debug, Write};

use embedded_graphics::{pixelcolor::BinaryColor, prelude::*, primitives::PrimitiveStyleBuilder};
use ssd1306::{prelude::*, I2CDisplayInterface, Ssd1306};

use crate::prelude::*;

const MAX_CHARS: usize =
(DisplaySize128x64::WIDTH / 8) as usize * (DisplaySize128x64::HEIGHT / 8) as usize;

#[derive(Debug, Clone)]
#[allow(unused)]
enum DisplayError {
pub enum DisplayError {
Display(display_interface::DisplayError),
Format(core::fmt::Error),
TerminalModeError(ssd1306::mode::TerminalModeError),
Expand All @@ -32,16 +33,14 @@ impl From<ssd1306::mode::TerminalModeError> for DisplayError {
}

async fn screen_counter_internal(i2c: &mut SharedI2C) -> Result<(), DisplayError> {
info!("Initialising screen...");
// info!("Initialising screen...");

let i2c = I2CDisplayInterface::new(i2c);

let mut display = Ssd1306::new(i2c, DisplaySize128x64, DisplayRotation::Rotate0);
display.init().await?;

display.clear().await?;

info!("Screen Initialised!");
// info!("Screen Initialised!");

let mut display = display.into_terminal_mode();

Expand All @@ -62,6 +61,8 @@ async fn screen_counter_internal(i2c: &mut SharedI2C) -> Result<(), DisplayError
display.clear().await?;
1
};

Timer::after_millis(20).await;
}
}

Expand All @@ -70,6 +71,143 @@ pub async fn screen_counter(mut i2c: SharedI2C) {
loop {
if let Err(e) = screen_counter_internal(&mut i2c).await {
warn!("Display error: {e:?}");
}

Timer::after_secs(1).await;
}
}

async fn display_shapes_internal(i2c: &mut SharedI2C) -> Result<(), DisplayError> {
// info!("Initialising screen...");

let i2c = I2CDisplayInterface::new(i2c);

let mut display = Ssd1306::new(i2c, DisplaySize128x64, DisplayRotation::Rotate0);
display.init().await?;
display.clear().await?;

// info!("Screen Initialised!");

let mut display = display.into_buffered_graphics_mode();

let mut sub = VOLUME_CHANNEL.subscriber().unwrap();

loop {
let yoffset = 20;

let style = PrimitiveStyleBuilder::new()
.stroke_width(1)
.stroke_color(BinaryColor::On)
.build();

// screen outline
// default display size is 128x64 if you don't pass a _DisplaySize_
// enum to the _Builder_ struct
embedded_graphics::primitives::Rectangle::new(Point::new(0, 10), Size::new(127, 36))
.into_styled(style)
.draw(&mut display)
.unwrap();

// triangle
embedded_graphics::primitives::Triangle::new(
Point::new((sub.next_message_pure().await * 128.) as i32, 16 + yoffset),
Point::new(16 + 16, 16 + yoffset),
Point::new(16 + 8, yoffset),
)
.into_styled(style)
.draw(&mut display)
.unwrap();

// square
embedded_graphics::primitives::Rectangle::new(Point::new(52, yoffset), Size::new_equal(16))
.into_styled(style)
.draw(&mut display)
.unwrap();

// circle
embedded_graphics::primitives::Circle::new(Point::new(88, yoffset), 16)
.into_styled(style)
.draw(&mut display)
.unwrap();

display.flush().await?;

Timer::after_millis(20).await;
}
}

#[task]
pub async fn display_shapes(mut i2c: SharedI2C) {
loop {
if let Err(e) = display_shapes_internal(&mut i2c).await {
warn!("Display error: {e:?}");
}

Timer::after_secs(1).await;
}
}

pub async fn init_display(i2c: SharedI2C) -> Result<(), DisplayError> {
info!("Initialising screen...");

let i2c = I2CDisplayInterface::new(i2c);

let mut display = Ssd1306::new(i2c, DisplaySize128x64, DisplayRotation::Rotate0);
display.init().await?;
display.clear().await?;

info!("Screen Initialised!");

Ok(())
}

async fn display_volume_internal(i2c: &mut SharedI2C) -> Result<(), DisplayError> {
// info!("Initialising screen...");

let i2c = I2CDisplayInterface::new(i2c);

let mut display = Ssd1306::new(i2c, DisplaySize128x64, DisplayRotation::Rotate0);
display.init().await?;
display.clear().await?;
// info!("Screen Initialised!");

let mut display = display.into_buffered_graphics_mode();

let mut sub = VOLUME_CHANNEL.subscriber().unwrap();

loop {
let on_style = PrimitiveStyleBuilder::new()
.fill_color(BinaryColor::On)
.build();

let off_style = PrimitiveStyleBuilder::new()
.fill_color(BinaryColor::Off)
.build();

embedded_graphics::primitives::Rectangle::new(Point::new(0, 64 - 8), Size::new(128, 8))
.into_styled(off_style)
.draw(&mut display)
.unwrap();

embedded_graphics::primitives::Rectangle::new(
Point::new(0, 64 - 8),
Size::new((sub.next_message_pure().await * 128.) as u32, 8),
)
.into_styled(on_style)
.draw(&mut display)
.unwrap();

display.flush().await?;

Timer::after_millis(20).await;
}
}

#[task]
pub async fn display_volume(mut i2c: SharedI2C) {
loop {
if let Err(e) = display_volume_internal(&mut i2c).await {
warn!("Display error: {e:?}");
} else {
unreachable!()
}
Expand Down
45 changes: 29 additions & 16 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ pub mod errors;
pub mod logger;
#[cfg(feature = "net")]
pub mod net;
pub mod volume;

pub mod prelude {

Expand All @@ -25,38 +26,50 @@ pub mod prelude {

pub use core::f64::consts::PI;

pub use crate::errors::*;

pub use embassy_embedded_hal::shared_bus::asynch::i2c::I2cDevice;
pub use embassy_sync::{blocking_mutex::raw::NoopRawMutex, mutex::Mutex, signal::Signal};
pub use embassy_sync::{
blocking_mutex::raw::{CriticalSectionRawMutex, NoopRawMutex},
mutex::Mutex,
pubsub::PubSubChannel,
signal::Signal,
};

pub use crate::errors::*;

pub type SharedI2C =
I2cDevice<'static, NoopRawMutex, I2C<'static, esp_hal::peripherals::I2C0, Async>>;

#[allow(unused)]
pub use esp_backtrace as _;
pub static VOLUME_CHANNEL: PubSubChannel<CriticalSectionRawMutex, f32, 4, 2, 1> =
PubSubChannel::new();

pub use esp_println::{print, println};
pub static I2C_BUS: StaticCell<I2cBusMutex> = StaticCell::new();

pub use embassy_executor::task;
pub type I2cBusMutex = Mutex<NoopRawMutex, I2C<'static, esp_hal::peripherals::I2C0, Async>>;

pub static SHARED_ADC: StaticCell<ADCMutex> = StaticCell::new();

pub type ADCMutex = Mutex<CriticalSectionRawMutex, ADC<'static, esp_hal::peripherals::ADC1>>;

pub static RNG: StaticCell<Rng> = StaticCell::new();

pub use embassy_executor::task;
pub use embassy_time::{Delay, Duration, Instant, Ticker, Timer};
#[allow(unused)]
pub use esp_backtrace as _;
pub use esp_hal::{
analog::adc::ADC,
embassy,
gpio::{AnyPin, Output, PushPull},
i2c::I2C,
prelude::*,
rng::Rng,
Async,
};

pub use esp_println::{print, println};
pub use heapless::String;

pub use nb::block;

pub use embassy_time::{Delay, Duration, Instant, Ticker, Timer};

pub use log::{debug, error, info, log, trace, warn};

pub use static_cell::make_static;

pub use nb::block;
pub use ssd1306::prelude::*;
pub use static_cell::make_static;
use static_cell::StaticCell;
}
1 change: 0 additions & 1 deletion src/logger.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ use core::str::FromStr;

use esp_hal::systimer::SystemTimer;
use esp_println::println;

use log::LevelFilter;

use crate::prelude::TICKS_PER_SECOND;
Expand Down
61 changes: 27 additions & 34 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,39 +2,27 @@
#![no_main]
#![feature(type_alias_impl_trait)]

use embassy_executor::Spawner;
use embassy_net::{tcp::TcpSocket, Config, Ipv4Address, Stack, StackResources};
use esp_wifi::wifi::WifiStaDevice;
use httparse::{Header, Status};
use spotify_mini::{
blink::blink,
display::screen_counter,
net::{connection, net_task},
prelude::*,
};

use embassy_time::Ticker;
use esp_hal::{
analog::adc::{AdcCalCurve, AdcConfig, Attenuation, ADC},
clock::ClockControl,
gpio::IO,
peripherals::{Peripherals, ADC1, I2C0},
peripherals::{Peripherals, ADC1},
rng::Rng,
timer::TimerGroup,
};

use embassy_executor::Spawner;
use embassy_time::Ticker;
use esp_println::println;
use static_cell::StaticCell;
// use libm::atan2;

// #[cfg(feature = "async")]
static I2C_BUS: StaticCell<Mutex<NoopRawMutex, I2C<'static, I2C0, Async>>> = StaticCell::new();

// #[cfg(not(feature = "async"))]
// static I2C_BUS: StaticCell<Mutex<NoopRawMutex, RefCell<I2C<'static, I2C0, Blocking>>>> =
// StaticCell::new();

static RNG: StaticCell<Rng> = StaticCell::new();
use esp_wifi::wifi::WifiStaDevice;
use httparse::{Header, Status};
use spotify_mini::{
blink::blink,
display::{display_shapes, display_volume, init_display, screen_counter},
net::{connection, net_task},
prelude::*,
volume::publish_volume,
};

#[main]
async fn main(spawner: Spawner) -> ! {
Expand Down Expand Up @@ -66,10 +54,11 @@ async fn main(spawner: Spawner) -> ! {
let mut rng = *RNG.init(rng);

let pot_pin = io.pins.gpio3.into_analog();
let mut pot_pin = adc1_config
let pot_pin = adc1_config
.enable_pin_with_cal::<_, AdcCalCurve<ADC1>>(pot_pin, Attenuation::Attenuation11dB);

let mut adc1 = ADC::<ADC1>::new(peripherals.ADC1, adc1_config);
let adc1 =
&*SHARED_ADC.init_with(|| Mutex::new(ADC::<ADC1>::new(peripherals.ADC1, adc1_config)));

let timer = esp_hal::systimer::SystemTimer::new(peripherals.SYSTIMER).alarm0;
let init = esp_wifi::initialize(
Expand All @@ -81,12 +70,12 @@ async fn main(spawner: Spawner) -> ! {
)
.unwrap();

let led = io.pins.gpio8.into_push_pull_output();
let internal_led = io.pins.gpio8.into_push_pull_output();

let scl = io.pins.gpio7;
let sda = io.pins.gpio6;

let i2c_bus = &*I2C_BUS.init_with(|| {
let i2c_bus = I2C_BUS.init_with(|| {
Mutex::new(I2C::new_async(
peripherals.I2C0,
sda,
Expand All @@ -96,8 +85,15 @@ async fn main(spawner: Spawner) -> ! {
))
});

spawner.spawn(blink(led.into())).ok();
if let Err(e) = init_display(I2cDevice::new(i2c_bus)).await {
error!("Error initialising display: {e:?}");
};

spawner.spawn(blink(internal_led.into())).ok();
spawner.spawn(screen_counter(I2cDevice::new(i2c_bus))).ok();
spawner.spawn(display_shapes(I2cDevice::new(i2c_bus))).ok();
spawner.spawn(display_volume(I2cDevice::new(i2c_bus))).ok();
spawner.spawn(publish_volume(adc1, pot_pin)).ok();

let wifi = peripherals.WIFI;
let (wifi_interface, controller) =
Expand Down Expand Up @@ -126,7 +122,7 @@ async fn main(spawner: Spawner) -> ! {
let mut tx_buffer = [0; 4096];

loop {
debug!("Checking stack state...");
trace!("Checking stack state...");
if stack.is_link_up() {
debug!("Link is up!");
break;
Expand Down Expand Up @@ -265,14 +261,11 @@ async fn main(spawner: Spawner) -> ! {
let play_pause_pin = io.pins.gpio10.into_pull_down_input();
let skip_pin = io.pins.gpio9.into_pull_down_input();

let mut ticker = Ticker::every(Duration::from_millis(100));
let mut ticker = Ticker::every(Duration::from_millis(1000));

loop {
trace!("KeepAlive tick");

let pin_value = nb::block!(adc1.read_oneshot(&mut pot_pin)).unwrap();
debug!("ADC reading = {}", pin_value);

info!("Play Pause: {}", play_pause_pin.is_high());
warn!("Skip: {}", skip_pin.is_high());

Expand Down
Loading

0 comments on commit 0c73b6b

Please sign in to comment.