mirror of
				https://github.com/Djeeberjr/fw-anwesenheit.git
				synced 2025-11-03 23:24:10 +00:00 
			
		
		
		
	Merge branch 'feature/newlib'
This commit is contained in:
		
						commit
						16ea1db55f
					
				
							
								
								
									
										924
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										924
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										74
									
								
								Cargo.toml
									
									
									
									
									
								
							
							
						
						
									
										74
									
								
								Cargo.toml
									
									
									
									
									
								
							@ -12,64 +12,44 @@ bench = false
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
[dependencies]
 | 
					[dependencies]
 | 
				
			||||||
esp-bootloader-esp-idf = "0.1.0"
 | 
					esp-bootloader-esp-idf = "0.1.0"
 | 
				
			||||||
embassy-net = { version = "0.7.0", features = [
 | 
					esp-hal = { version = "1.0.0-rc.1", features = ["esp32c6", "unstable"] } 
 | 
				
			||||||
  "dhcpv4",
 | 
					esp-alloc = "0.9.0"
 | 
				
			||||||
  "medium-ethernet",
 | 
					esp-println = { version = "0.16.0", features = ["esp32c6", "log-04"] }
 | 
				
			||||||
  "tcp",
 | 
					esp-radio = { version = "0.16.0", features = ["esp32c6","esp-alloc", "wifi", "log-04", "smoltcp","unstable"]}
 | 
				
			||||||
  "udp",
 | 
					esp-rtos = { version = "0.1.1", features = ["esp32c6", "embassy", "esp-radio", "esp-alloc"] }
 | 
				
			||||||
] }
 | 
					
 | 
				
			||||||
embedded-hal = "=1.0.0"
 | 
					 | 
				
			||||||
embedded-io = "0.6.1"
 | 
					 | 
				
			||||||
embedded-io-async = "0.6.1"
 | 
					 | 
				
			||||||
esp-alloc = "0.8.0"
 | 
					 | 
				
			||||||
esp-hal = { version = "1.0.0-beta.1", features = ["esp32c6", "unstable"] } 
 | 
					 | 
				
			||||||
smoltcp = { version = "0.12.0", default-features = false, features = [
 | 
					 | 
				
			||||||
  "medium-ethernet",
 | 
					 | 
				
			||||||
  "multicast",
 | 
					 | 
				
			||||||
  "proto-dhcpv4",
 | 
					 | 
				
			||||||
  "proto-dns",
 | 
					 | 
				
			||||||
  "proto-ipv4",
 | 
					 | 
				
			||||||
  "socket-dns",
 | 
					 | 
				
			||||||
  "socket-icmp",
 | 
					 | 
				
			||||||
  "socket-raw",
 | 
					 | 
				
			||||||
  "socket-tcp",
 | 
					 | 
				
			||||||
  "socket-udp",
 | 
					 | 
				
			||||||
] }
 | 
					 | 
				
			||||||
# for more networking protocol support see https://crates.io/crates/edge-net
 | 
					 | 
				
			||||||
bleps = { git = "https://github.com/bjoernQ/bleps", package = "bleps", rev = "a5148d8ae679e021b78f53fd33afb8bb35d0b62e", features = [
 | 
					 | 
				
			||||||
  "async",
 | 
					 | 
				
			||||||
  "macros",
 | 
					 | 
				
			||||||
] }
 | 
					 | 
				
			||||||
critical-section = "1.2.0"
 | 
					critical-section = "1.2.0"
 | 
				
			||||||
embassy-executor = { version = "0.7.0", features = ["nightly"] }
 | 
					 | 
				
			||||||
embassy-time = { version = "0.4.0", features = ["generic-queue-8"] }
 | 
					 | 
				
			||||||
esp-hal-embassy = { version = "0.9.0", features = ["esp32c6"] } 
 | 
					 | 
				
			||||||
esp-wifi = { version = "0.15.0", features = [ 
 | 
					 | 
				
			||||||
  "wifi",
 | 
					 | 
				
			||||||
  "builtin-scheduler",
 | 
					 | 
				
			||||||
  "esp-alloc",
 | 
					 | 
				
			||||||
  "esp32c6",
 | 
					 | 
				
			||||||
  "log-04",
 | 
					 | 
				
			||||||
] } 
 | 
					 | 
				
			||||||
heapless = { version = "0.8.0", default-features = false }
 | 
					 | 
				
			||||||
static_cell = { version = "2.1.0", features = ["nightly"] }
 | 
					 | 
				
			||||||
esp-println = { version = "0.15.0", features = ["esp32c6", "log-04"] }
 | 
					 | 
				
			||||||
log = { version = "0.4" }
 | 
					log = { version = "0.4" }
 | 
				
			||||||
 | 
					static_cell = { version = "2.1.1", features = ["nightly"] }
 | 
				
			||||||
 | 
					heapless = { version = "0.8.0", default-features = false }
 | 
				
			||||||
 | 
					chrono = { version = "0.4.41", default-features = false } 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					embedded-hal = "1.0.0"
 | 
				
			||||||
 | 
					embedded-io = "0.7.1"
 | 
				
			||||||
 | 
					embedded-io-async = "0.7.0"
 | 
				
			||||||
 | 
					embassy-executor = { version = "0.9.0", features = [] }
 | 
				
			||||||
 | 
					embassy-time = { version = "0.5.0", features = [] }
 | 
				
			||||||
 | 
					embassy-futures = { version = "0.1.2", features = ["log"] }
 | 
				
			||||||
 | 
					embassy-sync = { version = "0.7.2", features = ["log"] }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					embassy-net = { version = "0.7.0", features = [ "dhcpv4", "medium-ethernet", "tcp", "udp" ] }
 | 
				
			||||||
 | 
					smoltcp = { version = "0.12.0", default-features = false, features = [ "medium-ethernet", "multicast", "proto-dhcpv4", "proto-dns", "proto-ipv4", "socket-dns", "socket-icmp", "socket-raw", "socket-tcp", "socket-udp" ] }
 | 
				
			||||||
 | 
					bleps = { git = "https://github.com/bjoernQ/bleps", package = "bleps", rev = "a5148d8ae679e021b78f53fd33afb8bb35d0b62e", features = [ "async", "macros" ] }
 | 
				
			||||||
edge-dhcp = { version = "0.6.0", features = ["log"] }
 | 
					edge-dhcp = { version = "0.6.0", features = ["log"] }
 | 
				
			||||||
edge-nal = "0.5.0"
 | 
					edge-nal = "0.5.0"
 | 
				
			||||||
edge-nal-embassy = { version = "0.6.0", features = ["log"] }
 | 
					edge-nal-embassy = { version = "0.6.0", features = ["log"] }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
picoserve = { git = "https://github.com/sammhicks/picoserve.git", rev = "400df53f61137e1bb2883ec610fc191bfe551a3a", features = ["embassy", "log", "json"] }
 | 
					picoserve = { git = "https://github.com/sammhicks/picoserve.git", rev = "400df53f61137e1bb2883ec610fc191bfe551a3a", features = ["embassy", "log", "json"] }
 | 
				
			||||||
embassy-sync = { version = "0.7.0", features = ["log"] }
 | 
					 | 
				
			||||||
ds3231 = { version = "0.3.0", features = ["async", "temperature_f32"] }
 | 
					 | 
				
			||||||
chrono = { version = "0.4.41", default-features = false } 
 | 
					 | 
				
			||||||
dir-embed = "0.3.0"
 | 
					dir-embed = "0.3.0"
 | 
				
			||||||
 | 
					serde = { version = "1.0.219", default-features = false, features = ["derive", "alloc"] }
 | 
				
			||||||
 | 
					serde_json = { version = "1.0.143", default-features = false, features = ["alloc"]}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ds3231 = { version = "0.3.0", features = ["async", "temperature_f32"] }
 | 
				
			||||||
esp-hal-smartled = { git = "https://github.com/esp-rs/esp-hal-community.git", package = "esp-hal-smartled", branch = "main", features = ["esp32c6"]}
 | 
					esp-hal-smartled = { git = "https://github.com/esp-rs/esp-hal-community.git", package = "esp-hal-smartled", branch = "main", features = ["esp32c6"]}
 | 
				
			||||||
smart-leds = "0.4.0"
 | 
					smart-leds = "0.4.0"
 | 
				
			||||||
serde = { version = "1.0.219", default-features = false, features = ["derive", "alloc"] }
 | 
					
 | 
				
			||||||
embedded-sdmmc = "0.8.0"
 | 
					embedded-sdmmc = "0.8.0"
 | 
				
			||||||
embedded-hal-bus = "0.3.0"
 | 
					embedded-hal-bus = "0.3.0"
 | 
				
			||||||
serde_json = { version = "1.0.143", default-features = false, features = ["alloc"]}
 | 
					 | 
				
			||||||
embassy-futures = { version = "0.1.2", features = ["log"] }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
[profile.dev]
 | 
					[profile.dev]
 | 
				
			||||||
# Rust debug is too slow.
 | 
					# Rust debug is too slow.
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										111
									
								
								src/feedback.rs
									
									
									
									
									
								
							
							
						
						
									
										111
									
								
								src/feedback.rs
									
									
									
									
									
								
							@ -1,11 +1,12 @@
 | 
				
			|||||||
use embassy_time::{Duration, Timer};
 | 
					use embassy_time::{Duration, Timer};
 | 
				
			||||||
use esp_hal::{peripherals, rmt::ConstChannelAccess};
 | 
					use esp_hal::peripherals;
 | 
				
			||||||
use esp_hal_smartled::SmartLedsAdapterAsync;
 | 
					use esp_hal_smartled::SmartLedsAdapterAsync;
 | 
				
			||||||
use log::debug;
 | 
					use log::debug;
 | 
				
			||||||
use smart_leds::SmartLedsWriteAsync;
 | 
					use smart_leds::SmartLedsWriteAsync;
 | 
				
			||||||
use smart_leds::colors::{BLACK, GREEN, RED, YELLOW};
 | 
					use smart_leds::colors::{BLACK, GREEN, RED, YELLOW};
 | 
				
			||||||
use smart_leds::{brightness, colors::BLUE};
 | 
					use smart_leds::{brightness, colors::BLUE};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use crate::init::hardware;
 | 
				
			||||||
use crate::{FEEDBACK_STATE, init};
 | 
					use crate::{FEEDBACK_STATE, init};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Copy, Clone, Debug)]
 | 
					#[derive(Copy, Clone, Debug)]
 | 
				
			||||||
@ -24,10 +25,7 @@ const LED_LEVEL: u8 = 255;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#[embassy_executor::task]
 | 
					#[embassy_executor::task]
 | 
				
			||||||
pub async fn feedback_task(
 | 
					pub async fn feedback_task(
 | 
				
			||||||
    mut led: SmartLedsAdapterAsync<
 | 
					    mut led: SmartLedsAdapterAsync<'static, { hardware::LED_BUFFER_SIZE }>,
 | 
				
			||||||
        ConstChannelAccess<esp_hal::rmt::Tx, 0>,
 | 
					 | 
				
			||||||
        { init::hardware::LED_BUFFER_SIZE },
 | 
					 | 
				
			||||||
    >,
 | 
					 | 
				
			||||||
    buzzer: peripherals::GPIO21<'static>,
 | 
					    buzzer: peripherals::GPIO21<'static>,
 | 
				
			||||||
) {
 | 
					) {
 | 
				
			||||||
    debug!("Starting feedback task");
 | 
					    debug!("Starting feedback task");
 | 
				
			||||||
@ -134,106 +132,3 @@ pub async fn feedback_task(
 | 
				
			|||||||
        debug!("Feedback state: {:?}", feedback_state);
 | 
					        debug!("Feedback state: {:?}", feedback_state);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					 | 
				
			||||||
// async fn beep_ack() {
 | 
					 | 
				
			||||||
//     buzzer.set_high();
 | 
					 | 
				
			||||||
//     buzzer.set_low();
 | 
					 | 
				
			||||||
//     //Timer::after(Duration::from_millis(100)).await;
 | 
					 | 
				
			||||||
// }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* pub async fn failure(&mut self) {
 | 
					 | 
				
			||||||
    let buzzer_handle = Self::beep_nak(&mut self.buzzer);
 | 
					 | 
				
			||||||
    let led_handle = Self::flash_led_for_duration(&mut self.led, RED, LED_BLINK_DURATION);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    let (buzzer_result, _) = join!(buzzer_handle, led_handle);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    buzzer_result.unwrap_or_else(|err| {            error!("Failed to buzz: {err}");
 | 
					 | 
				
			||||||
    });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    let _ = self.led_to_status();
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
pub async fn activate_error_state(&mut self) -> Result<()> {
 | 
					 | 
				
			||||||
    self.led.turn_on(RED)?;
 | 
					 | 
				
			||||||
    Self::beep_nak(&mut self.buzzer).await?;
 | 
					 | 
				
			||||||
    Ok(())
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
pub async fn startup(&mut self){
 | 
					 | 
				
			||||||
    self.device_status = DeviceStatus::Ready;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    let led_handle = Self::flash_led_for_duration(&mut self.led, GREEN, Duration::from_secs(1));
 | 
					 | 
				
			||||||
    let buzzer_handle = Self::beep_startup(&mut self.buzzer);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    let (buzzer_result, led_result) = join!(buzzer_handle, led_handle);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    buzzer_result.unwrap_or_else(|err| {
 | 
					 | 
				
			||||||
        error!("Failed to buzz: {err}");
 | 
					 | 
				
			||||||
    });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    led_result.unwrap_or_else(|err| {
 | 
					 | 
				
			||||||
        error!("Failed to blink led: {err}");
 | 
					 | 
				
			||||||
    });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    let _ = self.led_to_status();
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
async fn flash_led_for_duration(led: &mut L, color: RGB8, duration: Duration) -> Result<()> {
 | 
					 | 
				
			||||||
    led.turn_on(color)?;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    sleep(duration).await;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    led.turn_off()?;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    Ok(())
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
async fn beep_ack(buzzer: &mut B) -> Result<()> {
 | 
					 | 
				
			||||||
    buzzer
 | 
					 | 
				
			||||||
        .modulated_tone(1200.0, Duration::from_millis(100))
 | 
					 | 
				
			||||||
        .await?;
 | 
					 | 
				
			||||||
    sleep(Duration::from_millis(10)).await;
 | 
					 | 
				
			||||||
    buzzer
 | 
					 | 
				
			||||||
        .modulated_tone(2000.0, Duration::from_millis(50))
 | 
					 | 
				
			||||||
        .await?;
 | 
					 | 
				
			||||||
    Ok(())
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
async fn beep_nak(buzzer: &mut B) -> Result<()> {
 | 
					 | 
				
			||||||
    buzzer
 | 
					 | 
				
			||||||
        .modulated_tone(600.0, Duration::from_millis(150))
 | 
					 | 
				
			||||||
        .await?;
 | 
					 | 
				
			||||||
    sleep(Duration::from_millis(100)).await;
 | 
					 | 
				
			||||||
    buzzer
 | 
					 | 
				
			||||||
        .modulated_tone(600.0, Duration::from_millis(150))
 | 
					 | 
				
			||||||
        .await?;
 | 
					 | 
				
			||||||
    Ok(())
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
async fn beep_startup(buzzer: &mut B) -> Result<()> {
 | 
					 | 
				
			||||||
    buzzer
 | 
					 | 
				
			||||||
        .modulated_tone(523.0, Duration::from_millis(150))
 | 
					 | 
				
			||||||
        .await?;
 | 
					 | 
				
			||||||
    buzzer
 | 
					 | 
				
			||||||
        .modulated_tone(659.0, Duration::from_millis(150))
 | 
					 | 
				
			||||||
        .await?;
 | 
					 | 
				
			||||||
    buzzer
 | 
					 | 
				
			||||||
        .modulated_tone(784.0, Duration::from_millis(150))
 | 
					 | 
				
			||||||
        .await?;
 | 
					 | 
				
			||||||
    buzzer
 | 
					 | 
				
			||||||
        .modulated_tone(1046.0, Duration::from_millis(200))
 | 
					 | 
				
			||||||
        .await?;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    sleep(Duration::from_millis(100)).await;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    buzzer
 | 
					 | 
				
			||||||
        .modulated_tone(784.0, Duration::from_millis(100))
 | 
					 | 
				
			||||||
        .await?;
 | 
					 | 
				
			||||||
    buzzer
 | 
					 | 
				
			||||||
        .modulated_tone(880.0, Duration::from_millis(200))
 | 
					 | 
				
			||||||
        .await?;
 | 
					 | 
				
			||||||
    Ok(())
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
 | 
				
			|||||||
@ -11,7 +11,7 @@ use esp_hal::peripherals::{
 | 
				
			|||||||
    GPIO0, GPIO1, GPIO16, GPIO17, GPIO18, GPIO19, GPIO20, GPIO21, GPIO22, GPIO23, I2C0, RMT, SPI2,
 | 
					    GPIO0, GPIO1, GPIO16, GPIO17, GPIO18, GPIO19, GPIO20, GPIO21, GPIO22, GPIO23, I2C0, RMT, SPI2,
 | 
				
			||||||
    UART1,
 | 
					    UART1,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
use esp_hal::rmt::{ConstChannelAccess, Rmt};
 | 
					use esp_hal::rmt::Rmt;
 | 
				
			||||||
use esp_hal::spi::master::{Config as Spi_config, Spi};
 | 
					use esp_hal::spi::master::{Config as Spi_config, Spi};
 | 
				
			||||||
use esp_hal::system::software_reset;
 | 
					use esp_hal::system::software_reset;
 | 
				
			||||||
use esp_hal::time::Rate;
 | 
					use esp_hal::time::Rate;
 | 
				
			||||||
@ -50,7 +50,7 @@ use crate::init::wifi;
 | 
				
			|||||||
 *************************************************/
 | 
					 *************************************************/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub const NUM_LEDS: usize = 1;
 | 
					pub const NUM_LEDS: usize = 1;
 | 
				
			||||||
pub const LED_BUFFER_SIZE: usize = NUM_LEDS * 25;
 | 
					pub const LED_BUFFER_SIZE: usize = buffer_size_async(NUM_LEDS);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static SD_DET: Mutex<RefCell<Option<Input>>> = Mutex::new(RefCell::new(None));
 | 
					static SD_DET: Mutex<RefCell<Option<Input>>> = Mutex::new(RefCell::new(None));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -65,32 +65,33 @@ fn panic(info: &core::panic::PanicInfo) -> ! {
 | 
				
			|||||||
esp_bootloader_esp_idf::esp_app_desc!();
 | 
					esp_bootloader_esp_idf::esp_app_desc!();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub async fn hardware_init(
 | 
					pub async fn hardware_init(
 | 
				
			||||||
    spawner: &mut Spawner,
 | 
					    spawner: Spawner,
 | 
				
			||||||
) -> (
 | 
					) -> (
 | 
				
			||||||
    Uart<'static, Async>,
 | 
					    Uart<'static, Async>,
 | 
				
			||||||
    Stack<'static>,
 | 
					    Stack<'static>,
 | 
				
			||||||
    I2c<'static, Async>,
 | 
					    I2c<'static, Async>,
 | 
				
			||||||
    SmartLedsAdapterAsync<ConstChannelAccess<esp_hal::rmt::Tx, 0>, LED_BUFFER_SIZE>,
 | 
					 | 
				
			||||||
    GPIO21<'static>,
 | 
					    GPIO21<'static>,
 | 
				
			||||||
    GPIO0<'static>,
 | 
					    GPIO0<'static>,
 | 
				
			||||||
 | 
					    SmartLedsAdapterAsync<'static, LED_BUFFER_SIZE>,
 | 
				
			||||||
    SDCardPersistence,
 | 
					    SDCardPersistence,
 | 
				
			||||||
) {
 | 
					) {
 | 
				
			||||||
    let config = esp_hal::Config::default().with_cpu_clock(CpuClock::max());
 | 
					    let config = esp_hal::Config::default().with_cpu_clock(CpuClock::max());
 | 
				
			||||||
    let peripherals = esp_hal::init(config);
 | 
					    let peripherals = esp_hal::init(config);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    esp_alloc::heap_allocator!(size: 72 * 1024);
 | 
					    esp_alloc::heap_allocator!(#[unsafe(link_section = ".dram2_uninit")] size: 65536);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let timer0 = SystemTimer::new(peripherals.SYSTIMER);
 | 
					    let timg0 = TimerGroup::new(peripherals.TIMG0);
 | 
				
			||||||
    esp_hal_embassy::init(timer0.alarm0);
 | 
					    let sw_interrupt =
 | 
				
			||||||
 | 
					        esp_hal::interrupt::software::SoftwareInterruptControl::new(peripherals.SW_INTERRUPT);
 | 
				
			||||||
 | 
					    esp_rtos::start(timg0.timer0, sw_interrupt.software_interrupt0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    init_logger(log::LevelFilter::Debug);
 | 
					    init_logger(log::LevelFilter::Debug);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let timer1 = TimerGroup::new(peripherals.TIMG0);
 | 
					    let rng = esp_hal::rng::Rng::new();
 | 
				
			||||||
    let mut rng = esp_hal::rng::Rng::new(peripherals.RNG);
 | 
					 | 
				
			||||||
    let network_seed = (rng.random() as u64) << 32 | rng.random() as u64;
 | 
					    let network_seed = (rng.random() as u64) << 32 | rng.random() as u64;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    wifi::set_antenna_mode(peripherals.GPIO3, peripherals.GPIO14).await;
 | 
					    wifi::set_antenna_mode(peripherals.GPIO3, peripherals.GPIO14).await;
 | 
				
			||||||
    let interfaces = wifi::setup_wifi(timer1.timer0, rng, peripherals.WIFI, spawner);
 | 
					    let interfaces = wifi::setup_wifi(peripherals.WIFI, spawner);
 | 
				
			||||||
    let stack = network::setup_network(network_seed, interfaces.ap, spawner);
 | 
					    let stack = network::setup_network(network_seed, interfaces.ap, spawner);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    Timer::after(Duration::from_millis(1)).await;
 | 
					    Timer::after(Duration::from_millis(1)).await;
 | 
				
			||||||
@ -118,19 +119,19 @@ pub async fn hardware_init(
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    let buzzer_gpio = peripherals.GPIO21;
 | 
					    let buzzer_gpio = peripherals.GPIO21;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    Timer::after(Duration::from_millis(500)).await;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    let led = setup_led(peripherals.RMT, peripherals.GPIO1);
 | 
					    let led = setup_led(peripherals.RMT, peripherals.GPIO1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Timer::after(Duration::from_millis(500)).await;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    debug!("hardware init done");
 | 
					    debug!("hardware init done");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    (
 | 
					    (
 | 
				
			||||||
        uart_device,
 | 
					        uart_device,
 | 
				
			||||||
        stack,
 | 
					        stack,
 | 
				
			||||||
        i2c_device,
 | 
					        i2c_device,
 | 
				
			||||||
        led,
 | 
					 | 
				
			||||||
        buzzer_gpio,
 | 
					        buzzer_gpio,
 | 
				
			||||||
        sd_det_gpio,
 | 
					        sd_det_gpio,
 | 
				
			||||||
 | 
					        led,
 | 
				
			||||||
        vol_mgr,
 | 
					        vol_mgr,
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -189,11 +190,10 @@ pub fn setup_buzzer(buzzer_gpio: GPIO21<'static>) -> Output<'static> {
 | 
				
			|||||||
    buzzer
 | 
					    buzzer
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fn setup_led(
 | 
					fn setup_led<'a>(
 | 
				
			||||||
    rmt: RMT<'static>,
 | 
					    rmt: RMT<'a>,
 | 
				
			||||||
    led_gpio: GPIO1<'static>,
 | 
					    led_gpio: GPIO1<'a>,
 | 
				
			||||||
) -> SmartLedsAdapterAsync<ConstChannelAccess<esp_hal::rmt::Tx, 0>, LED_BUFFER_SIZE> {
 | 
					) -> esp_hal_smartled::SmartLedsAdapterAsync<'a, LED_BUFFER_SIZE> {
 | 
				
			||||||
    debug!("setup led");
 | 
					 | 
				
			||||||
    let rmt: Rmt<'_, esp_hal::Async> = {
 | 
					    let rmt: Rmt<'_, esp_hal::Async> = {
 | 
				
			||||||
        let frequency: Rate = Rate::from_mhz(80);
 | 
					        let frequency: Rate = Rate::from_mhz(80);
 | 
				
			||||||
        Rmt::new(rmt, frequency)
 | 
					        Rmt::new(rmt, frequency)
 | 
				
			||||||
@ -202,10 +202,7 @@ fn setup_led(
 | 
				
			|||||||
    .into_async();
 | 
					    .into_async();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let rmt_channel = rmt.channel0;
 | 
					    let rmt_channel = rmt.channel0;
 | 
				
			||||||
    let rmt_buffer = [0_u32; buffer_size_async(NUM_LEDS)];
 | 
					    let rmt_buffer = [esp_hal::rmt::PulseCode::default(); LED_BUFFER_SIZE];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let led: SmartLedsAdapterAsync<_, LED_BUFFER_SIZE> =
 | 
					    SmartLedsAdapterAsync::new(rmt_channel, led_gpio, rmt_buffer)
 | 
				
			||||||
        SmartLedsAdapterAsync::new(rmt_channel, led_gpio, rmt_buffer);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    led
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -2,15 +2,15 @@ use core::{net::Ipv4Addr, str::FromStr};
 | 
				
			|||||||
use embassy_executor::Spawner;
 | 
					use embassy_executor::Spawner;
 | 
				
			||||||
use embassy_net::{Ipv4Cidr, Runner, Stack, StackResources, StaticConfigV4};
 | 
					use embassy_net::{Ipv4Cidr, Runner, Stack, StackResources, StaticConfigV4};
 | 
				
			||||||
use embassy_time::{Duration, Timer};
 | 
					use embassy_time::{Duration, Timer};
 | 
				
			||||||
use esp_wifi::wifi::WifiDevice;
 | 
					use esp_radio::wifi::WifiDevice;
 | 
				
			||||||
use static_cell::make_static;
 | 
					use static_cell::make_static;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use crate::webserver::WEB_TAKS_SIZE;
 | 
					use crate::webserver::WEB_TAKS_SIZE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub const NETWORK_STACK_SIZE: usize = WEB_TAKS_SIZE + 2; // + 2 for other network taks. Breaks
 | 
					pub const NETWORK_STACK_SIZE: usize = WEB_TAKS_SIZE + 2; // + 2 for other network taks. Breaks
 | 
				
			||||||
                                                         // without
 | 
					// without
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub fn setup_network<'a>(seed: u64, wifi: WifiDevice<'static>, spawner: &mut Spawner) -> Stack<'a> {
 | 
					pub fn setup_network<'a>(seed: u64, wifi: WifiDevice<'static>, spawner: Spawner) -> Stack<'a> {
 | 
				
			||||||
    let gw_ip_addr_str = "192.168.2.1";
 | 
					    let gw_ip_addr_str = "192.168.2.1";
 | 
				
			||||||
    let gw_ip_addr = Ipv4Addr::from_str(gw_ip_addr_str).expect("failed to parse gateway ip");
 | 
					    let gw_ip_addr = Ipv4Addr::from_str(gw_ip_addr_str).expect("failed to parse gateway ip");
 | 
				
			||||||
    let config = embassy_net::Config::ipv4_static(StaticConfigV4 {
 | 
					    let config = embassy_net::Config::ipv4_static(StaticConfigV4 {
 | 
				
			||||||
@ -19,12 +19,10 @@ pub fn setup_network<'a>(seed: u64, wifi: WifiDevice<'static>, spawner: &mut Spa
 | 
				
			|||||||
        dns_servers: Default::default(),
 | 
					        dns_servers: Default::default(),
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let (stack, runner) = embassy_net::new(
 | 
					    let nw_stack: &'static mut StackResources<NETWORK_STACK_SIZE> =
 | 
				
			||||||
        wifi,
 | 
					        make_static!(StackResources::<NETWORK_STACK_SIZE>::new());
 | 
				
			||||||
        config,
 | 
					
 | 
				
			||||||
        make_static!(StackResources::<NETWORK_STACK_SIZE>::new()),
 | 
					    let (stack, runner) = embassy_net::new(wifi, config, nw_stack, seed);
 | 
				
			||||||
        seed,
 | 
					 | 
				
			||||||
    );
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    spawner.must_spawn(net_task(runner));
 | 
					    spawner.must_spawn(net_task(runner));
 | 
				
			||||||
    spawner.must_spawn(run_dhcp(stack, gw_ip_addr_str));
 | 
					    spawner.must_spawn(run_dhcp(stack, gw_ip_addr_str));
 | 
				
			||||||
 | 
				
			|||||||
@ -2,11 +2,14 @@ use embassy_executor::Spawner;
 | 
				
			|||||||
use embassy_time::{Duration, Timer};
 | 
					use embassy_time::{Duration, Timer};
 | 
				
			||||||
use esp_hal::gpio::{Output, OutputConfig};
 | 
					use esp_hal::gpio::{Output, OutputConfig};
 | 
				
			||||||
use esp_hal::peripherals::{GPIO3, GPIO14, WIFI};
 | 
					use esp_hal::peripherals::{GPIO3, GPIO14, WIFI};
 | 
				
			||||||
use esp_wifi::wifi::{
 | 
					use esp_radio::Controller;
 | 
				
			||||||
    AccessPointConfiguration, Configuration, WifiController, WifiEvent, WifiState,
 | 
					use esp_radio::wifi::{
 | 
				
			||||||
 | 
					    AccessPointConfig, Interfaces, ModeConfig, WifiApState, WifiController, WifiEvent,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
use esp_wifi::{EspWifiRngSource, EspWifiTimerSource, wifi::Interfaces};
 | 
					use log::debug;
 | 
				
			||||||
use static_cell::make_static;
 | 
					use static_cell::StaticCell;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static ESP_WIFI_CTRL: StaticCell<Controller<'static>> = StaticCell::new();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub async fn set_antenna_mode(gpio3: GPIO3<'static>, gpio14: GPIO14<'static>) {
 | 
					pub async fn set_antenna_mode(gpio3: GPIO3<'static>, gpio14: GPIO14<'static>) {
 | 
				
			||||||
    let mut rf_switch = Output::new(gpio3, esp_hal::gpio::Level::Low, OutputConfig::default());
 | 
					    let mut rf_switch = Output::new(gpio3, esp_hal::gpio::Level::Low, OutputConfig::default());
 | 
				
			||||||
@ -20,26 +23,23 @@ pub async fn set_antenna_mode(gpio3: GPIO3<'static>, gpio14: GPIO14<'static>) {
 | 
				
			|||||||
    antenna_mode.set_low();
 | 
					    antenna_mode.set_low();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub fn setup_wifi<'d: 'static>(
 | 
					pub fn setup_wifi<'d: 'static>(wifi: WIFI<'static>, spawner: Spawner) -> Interfaces<'d> {
 | 
				
			||||||
    timer: impl EspWifiTimerSource + 'd,
 | 
					    let esp_wifi_ctrl = ESP_WIFI_CTRL.init(esp_radio::init().unwrap());
 | 
				
			||||||
    rng: impl EspWifiRngSource + 'd,
 | 
					 | 
				
			||||||
    wifi: WIFI<'static>,
 | 
					 | 
				
			||||||
    spawner: &mut Spawner,
 | 
					 | 
				
			||||||
) -> Interfaces<'d> {
 | 
					 | 
				
			||||||
    let esp_wifi_ctrl = make_static!(esp_wifi::init(timer, rng).unwrap());
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let (controller, interfaces) = esp_wifi::wifi::new(esp_wifi_ctrl, wifi).unwrap();
 | 
					    let config = esp_radio::wifi::Config::default();
 | 
				
			||||||
 | 
					    let (controller, interfaces) = esp_radio::wifi::new(esp_wifi_ctrl, wifi, config).unwrap();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    spawner.must_spawn(connection(controller));
 | 
					    spawner.must_spawn(connection(controller));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    interfaces
 | 
					    interfaces
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					 | 
				
			||||||
#[embassy_executor::task]
 | 
					#[embassy_executor::task]
 | 
				
			||||||
async fn connection(mut controller: WifiController<'static>) {
 | 
					async fn connection(mut controller: WifiController<'static>) {
 | 
				
			||||||
 | 
					    debug!("start connection task");
 | 
				
			||||||
 | 
					    debug!("Device capabilities: {:?}", controller.capabilities());
 | 
				
			||||||
    loop {
 | 
					    loop {
 | 
				
			||||||
        match esp_wifi::wifi::wifi_state() {
 | 
					        match esp_radio::wifi::ap_state() {
 | 
				
			||||||
            WifiState::ApStarted => {
 | 
					            WifiApState::Started => {
 | 
				
			||||||
                // wait until we're no longer connected
 | 
					                // wait until we're no longer connected
 | 
				
			||||||
                controller.wait_for_event(WifiEvent::ApStop).await;
 | 
					                controller.wait_for_event(WifiEvent::ApStop).await;
 | 
				
			||||||
                Timer::after(Duration::from_millis(5000)).await
 | 
					                Timer::after(Duration::from_millis(5000)).await
 | 
				
			||||||
@ -47,14 +47,16 @@ async fn connection(mut controller: WifiController<'static>) {
 | 
				
			|||||||
            _ => {}
 | 
					            _ => {}
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        if !matches!(controller.is_started(), Ok(true)) {
 | 
					        if !matches!(controller.is_started(), Ok(true)) {
 | 
				
			||||||
            let client_config = Configuration::AccessPoint(AccessPointConfiguration {
 | 
					            let client_config = ModeConfig::AccessPoint(
 | 
				
			||||||
                ssid: env!("WIFI_SSID").try_into().unwrap(),
 | 
					                AccessPointConfig::default()
 | 
				
			||||||
                password: env!("WIFI_PASSWD").try_into().unwrap(),
 | 
					                    .with_ssid(env!("WIFI_SSID").try_into().unwrap())
 | 
				
			||||||
                auth_method: esp_wifi::wifi::AuthMethod::WPA2Personal,
 | 
					                    .with_password(env!("WIFI_PASSWD").try_into().unwrap())
 | 
				
			||||||
                ..Default::default()
 | 
					                    .with_auth_method(esp_radio::wifi::AuthMethod::Wpa2Personal),
 | 
				
			||||||
            });
 | 
					            );
 | 
				
			||||||
            controller.set_configuration(&client_config).unwrap();
 | 
					            controller.set_config(&client_config).unwrap();
 | 
				
			||||||
 | 
					            debug!("Starting wifi");
 | 
				
			||||||
            controller.start_async().await.unwrap();
 | 
					            controller.start_async().await.unwrap();
 | 
				
			||||||
 | 
					            debug!("Wifi started!");
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										17
									
								
								src/main.rs
									
									
									
									
									
								
							
							
						
						
									
										17
									
								
								src/main.rs
									
									
									
									
									
								
							@ -2,7 +2,6 @@
 | 
				
			|||||||
#![no_main]
 | 
					#![no_main]
 | 
				
			||||||
#![feature(type_alias_impl_trait)]
 | 
					#![feature(type_alias_impl_trait)]
 | 
				
			||||||
#![feature(impl_trait_in_assoc_type)]
 | 
					#![feature(impl_trait_in_assoc_type)]
 | 
				
			||||||
 | 
					 | 
				
			||||||
#![warn(clippy::unwrap_used)]
 | 
					#![warn(clippy::unwrap_used)]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use alloc::rc::Rc;
 | 
					use alloc::rc::Rc;
 | 
				
			||||||
@ -21,7 +20,7 @@ use embassy_time::{Duration, Timer};
 | 
				
			|||||||
use esp_hal::gpio::Input;
 | 
					use esp_hal::gpio::Input;
 | 
				
			||||||
use esp_hal::{gpio::InputConfig, peripherals};
 | 
					use esp_hal::{gpio::InputConfig, peripherals};
 | 
				
			||||||
use log::{debug, info};
 | 
					use log::{debug, info};
 | 
				
			||||||
use static_cell::make_static;
 | 
					use static_cell::StaticCell;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
extern crate alloc;
 | 
					extern crate alloc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -44,10 +43,12 @@ type TallyPublisher = Publisher<'static, NoopRawMutex, TallyID, 8, 2, 1>;
 | 
				
			|||||||
type TallySubscriber = Subscriber<'static, NoopRawMutex, TallyID, 8, 2, 1>;
 | 
					type TallySubscriber = Subscriber<'static, NoopRawMutex, TallyID, 8, 2, 1>;
 | 
				
			||||||
type UsedStore = IDStore<SDCardPersistence>;
 | 
					type UsedStore = IDStore<SDCardPersistence>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[esp_hal_embassy::main]
 | 
					static CHAN: StaticCell<TallyChannel> = StaticCell::new();
 | 
				
			||||||
async fn main(mut spawner: Spawner) {
 | 
					
 | 
				
			||||||
    let (uart_device, stack, i2c, led, buzzer_gpio, sd_det_gpio, persistence_layer) =
 | 
					#[esp_rtos::main]
 | 
				
			||||||
        init::hardware::hardware_init(&mut spawner).await;
 | 
					async fn main(spawner: Spawner) -> ! {
 | 
				
			||||||
 | 
					    let (uart_device, stack, i2c, buzzer_gpio, sd_det_gpio, led, persistence_layer) =
 | 
				
			||||||
 | 
					        init::hardware::hardware_init(spawner).await;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    info!("Starting up...");
 | 
					    info!("Starting up...");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -56,13 +57,13 @@ async fn main(mut spawner: Spawner) {
 | 
				
			|||||||
    let store: UsedStore = IDStore::new_from_storage(persistence_layer).await;
 | 
					    let store: UsedStore = IDStore::new_from_storage(persistence_layer).await;
 | 
				
			||||||
    let shared_store = Rc::new(Mutex::new(store));
 | 
					    let shared_store = Rc::new(Mutex::new(store));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let chan: &'static mut TallyChannel = make_static!(PubSubChannel::new());
 | 
					    let chan: &'static mut TallyChannel = CHAN.init(PubSubChannel::new());
 | 
				
			||||||
    let publisher: TallyPublisher = chan.publisher().unwrap();
 | 
					    let publisher: TallyPublisher = chan.publisher().unwrap();
 | 
				
			||||||
    let mut sub: TallySubscriber = chan.subscriber().unwrap();
 | 
					    let mut sub: TallySubscriber = chan.subscriber().unwrap();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    wait_for_stack_up(stack).await;
 | 
					    wait_for_stack_up(stack).await;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    start_webserver(&mut spawner, stack, shared_store.clone(), chan);
 | 
					    start_webserver(spawner, stack, shared_store.clone(), chan);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /****************************** Spawning tasks ***********************************/
 | 
					    /****************************** Spawning tasks ***********************************/
 | 
				
			||||||
    debug!("spawing NFC reader task...");
 | 
					    debug!("spawing NFC reader task...");
 | 
				
			||||||
 | 
				
			|||||||
@ -1,4 +1,3 @@
 | 
				
			|||||||
use esp_println::dbg;
 | 
					 | 
				
			||||||
use log::error;
 | 
					use log::error;
 | 
				
			||||||
use picoserve::{
 | 
					use picoserve::{
 | 
				
			||||||
    extract::{Json, Query, State},
 | 
					    extract::{Json, Query, State},
 | 
				
			||||||
@ -7,7 +6,7 @@ use picoserve::{
 | 
				
			|||||||
use serde::Deserialize;
 | 
					use serde::Deserialize;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use crate::{
 | 
					use crate::{
 | 
				
			||||||
    store::{self, Name, day::Day, tally_id::TallyID},
 | 
					    store::{Name, day::Day, tally_id::TallyID},
 | 
				
			||||||
    webserver::{app::AppState, sse::IDEvents},
 | 
					    webserver::{app::AppState, sse::IDEvents},
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -38,7 +38,7 @@ impl<State, CurrentPathParameters>
 | 
				
			|||||||
                );
 | 
					                );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                response_writer
 | 
					                response_writer
 | 
				
			||||||
                    .write_response(request.body_connection.finalize().await.unwrap(), response)
 | 
					                    .write_response(request.body_connection.finalize().await?, response)
 | 
				
			||||||
                    .await
 | 
					                    .await
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            None => {
 | 
					            None => {
 | 
				
			||||||
@ -68,10 +68,7 @@ impl Content for StaticAsset {
 | 
				
			|||||||
        self.0.len()
 | 
					        self.0.len()
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    async fn write_content<W: embedded_io_async::Write>(
 | 
					    async fn write_content<W: edge_nal::io::Write>(self, mut writer: W) -> Result<(), W::Error> {
 | 
				
			||||||
        self,
 | 
					 | 
				
			||||||
        mut writer: W,
 | 
					 | 
				
			||||||
    ) -> Result<(), W::Error> {
 | 
					 | 
				
			||||||
        writer.write_all(self.0).await
 | 
					        writer.write_all(self.0).await
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -16,10 +16,10 @@ mod app;
 | 
				
			|||||||
mod assets;
 | 
					mod assets;
 | 
				
			||||||
mod sse;
 | 
					mod sse;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub const WEB_TAKS_SIZE: usize = 3; // Up this number if request start fail with Timeouts.
 | 
					pub const WEB_TAKS_SIZE: usize = 5; // Up this number if request start fail with Timeouts.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub fn start_webserver(
 | 
					pub fn start_webserver(
 | 
				
			||||||
    spawner: &mut Spawner,
 | 
					    spawner: Spawner,
 | 
				
			||||||
    stack: Stack<'static>,
 | 
					    stack: Stack<'static>,
 | 
				
			||||||
    store: Rc<Mutex<CriticalSectionRawMutex, UsedStore>>,
 | 
					    store: Rc<Mutex<CriticalSectionRawMutex, UsedStore>>,
 | 
				
			||||||
    chan: &'static TallyChannel,
 | 
					    chan: &'static TallyChannel,
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user