Skip to content

Commit

Permalink
Merge branch 'vereinsflieger'
Browse files Browse the repository at this point in the history
  • Loading branch information
zargony committed Oct 29, 2024
2 parents c8dff83 + 0abe32b commit 0ffde8b
Show file tree
Hide file tree
Showing 17 changed files with 770 additions and 92 deletions.
2 changes: 2 additions & 0 deletions firmware/Cargo.lock

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

2 changes: 2 additions & 0 deletions firmware/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ overflow-checks = false
git2 = { version = "0.19", default-features = false }

[dependencies]
chrono = { version = "0.4", default-features = false, features = ["alloc"] }
display-interface = "0.5"
embassy-embedded-hal = "0.2"
embassy-executor = "0.6"
Expand All @@ -63,6 +64,7 @@ esp-partition-table = "0.1"
esp-println = { version = "0.12", features = ["esp32c3", "log"] }
esp-storage = { version = "0.3", features = ["esp32c3"] }
esp-wifi = { version = "0.10", default-features = false, features = ["esp32c3", "esp-alloc", "async", "embassy-net", "log", "phy-enable-usb", "wifi"] }
hex = { version = "0.4", default-features = false, features = ["alloc"] }
log = { version = "0.4", features = ["release_max_level_info"] }
pn532 = "0.4"
rand_core = "0.6"
Expand Down
2 changes: 1 addition & 1 deletion firmware/config-example.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,5 @@
"vf-cid": 0,

// Vereinsflieger article id to use for purchases
"vf-article-id": 0
"vf-article-id": "1234"
}
17 changes: 11 additions & 6 deletions firmware/src/article.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
use alloc::string::String;

/// Article id
/// Equivalent to the Vereinsflieger `articleid` attribute
#[allow(clippy::module_name_repetitions)]
pub type ArticleId = u32;
pub type ArticleId = String;

/// Article information
#[derive(Debug, Clone, PartialEq)]
Expand Down Expand Up @@ -37,8 +38,8 @@ impl<const N: usize> Articles<N> {
}

/// Update article with given article id. Ignores article ids not in list.
pub fn update(&mut self, id: ArticleId, name: String, price: f32) {
if let Some(idx) = self.ids.iter().position(|i| *i == id) {
pub fn update(&mut self, id: &ArticleId, name: String, price: f32) {
if let Some(idx) = self.find(id) {
self.articles[idx] = Some(Article { name, price });
}
}
Expand All @@ -48,10 +49,14 @@ impl<const N: usize> Articles<N> {
self.articles.iter().filter(|a| a.is_some()).count()
}

/// Find index of article with given id
pub fn find(&self, id: &ArticleId) -> Option<usize> {
self.ids.iter().position(|i| i == id)
}

/// Look up id of article at given index
#[allow(dead_code)]
pub fn id(&self, index: usize) -> Option<ArticleId> {
self.ids.get(index).copied()
pub fn id(&self, index: usize) -> Option<&ArticleId> {
self.ids.get(index)
}

/// Look up article information at given index
Expand Down
1 change: 0 additions & 1 deletion firmware/src/buzzer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,6 @@ impl<'a> Buzzer<'a> {
}

/// Output a long denying tone
#[allow(dead_code)]
pub async fn deny(&mut self) -> Result<(), Error> {
debug!("Buzzer: Playing deny tone");
self.tone(392, Duration::from_millis(500)).await?; // G4
Expand Down
16 changes: 15 additions & 1 deletion firmware/src/http.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
use crate::json::{self, FromJson, ToJson};
use crate::time;
use crate::wifi::{DnsSocket, TcpClient, TcpConnection, Wifi};
use alloc::vec::Vec;
use chrono::{DateTime, Utc};
use core::convert::Infallible;
use core::fmt;
use core::{fmt, str};
use embedded_io_async::{BufRead, Read};
use log::debug;
use reqwless::client::{HttpClient, HttpResource, HttpResourceRequestBuilder};
Expand Down Expand Up @@ -212,6 +214,18 @@ impl<'a> Connection<'a> {
let response = request.send(rx_buf).await?;
debug!("HTTP: Status {}", response.status.0);

// Extract current date and time from response
let time = response
.headers()
.find_map(|(k, v)| (k == "Date").then_some(v))
.and_then(|v| str::from_utf8(v).ok())
.and_then(|s| DateTime::parse_from_rfc2822(s).ok())
.map(|d| d.with_timezone(&Utc));
if let Some(time) = time {
time::set(time);
}

// Check HTTP response status
if response.status.0 == 401 {
return Err(Error::Unauthorized);
} else if response.status.is_server_error() {
Expand Down
13 changes: 12 additions & 1 deletion firmware/src/json/reader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,17 @@ impl<R: BufRead> Reader<R> {
self.expect(b'l').await?;
Ok(())
}

/// Read and discard any remaining data
pub async fn discard_to_end(&mut self) -> Result<(), Error<R::Error>> {
loop {
match self.reader.fill_buf().await?.len() {
0 => break,
len => self.reader.consume(len),
}
}
Ok(())
}
}

impl<R: BufRead> Reader<R> {
Expand Down Expand Up @@ -505,7 +516,7 @@ mod tests {
}

impl FromJsonObject for Test {
type Context = ();
type Context<'ctx> = ();

async fn read_next<R: BufRead>(
&mut self,
Expand Down
6 changes: 5 additions & 1 deletion firmware/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,9 @@ mod keypad;
mod nfc;
mod pn532;
mod screen;
mod time;
mod ui;
mod user;
mod vereinsflieger;
mod wifi;

Expand Down Expand Up @@ -130,8 +132,9 @@ async fn main(spawner: Spawner) {
// Read system configuration
let config = config::Config::read().await;

// Initialize list of articles
// Initialize article and user look up tables
let mut articles = article::Articles::new([config.vf_article_id]);
let mut users = user::Users::new();

// Initialize I2C controller
let i2c = I2c::new_with_timeout_async(
Expand Down Expand Up @@ -220,6 +223,7 @@ async fn main(spawner: Spawner) {
&wifi,
&mut vereinsflieger,
&mut articles,
&mut users,
);

// Show splash screen for a while, ignore any error
Expand Down
27 changes: 26 additions & 1 deletion firmware/src/nfc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@ use crate::pn532;

use core::convert::Infallible;
use core::fmt::{self, Debug};
use core::str::FromStr;
use embassy_time::{Duration, Timer};
use embedded_hal_async::digital::Wait;
use embedded_hal_async::i2c::I2c;
use hex::FromHex;
use log::{debug, info, warn};
use pn532::{Error as Pn532Error, I2CInterfaceWithIrq, Pn532, Request, SAMMode};

Expand Down Expand Up @@ -181,6 +183,7 @@ impl<I2C: I2c, IRQ: Wait<Error = Infallible>> Nfc<I2C, IRQ> {

// Return UID if retrieved, continue looping otherwise
if let Some(uid) = maybe_uid {
debug!("NFC: Detected NFC card: {}", uid);
return Ok(uid);
}
}
Expand All @@ -192,7 +195,7 @@ impl<I2C: I2c, IRQ: Wait<Error = Infallible>> Nfc<I2C, IRQ> {
pub struct InvalidUid;

/// NFC UID
#[derive(Debug, Clone, PartialEq, Eq)]
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub enum Uid {
/// Single Size UID (4 bytes), Mifare Classic
Single([u8; 4]),
Expand All @@ -216,6 +219,28 @@ impl TryFrom<&[u8]> for Uid {
}
}

impl FromStr for Uid {
type Err = InvalidUid;

fn from_str(s: &str) -> Result<Self, Self::Err> {
match s.len() {
8 => {
let bytes = <[u8; 4]>::from_hex(s).map_err(|_e| InvalidUid)?;
Ok(Self::Single(bytes))
}
14 => {
let bytes = <[u8; 7]>::from_hex(s).map_err(|_e| InvalidUid)?;
Ok(Self::Double(bytes))
}
20 => {
let bytes = <[u8; 10]>::from_hex(s).map_err(|_e| InvalidUid)?;
Ok(Self::Triple(bytes))
}
_ => Err(InvalidUid),
}
}
}

fn write_hex_bytes(f: &mut fmt::Formatter<'_>, bytes: &[u8]) -> fmt::Result {
for b in bytes {
write!(f, "{:02x}", *b)?;
Expand Down
4 changes: 3 additions & 1 deletion firmware/src/screen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,9 @@ impl Screen for PleaseWait {
FontColor::Transparent(BinaryColor::On),
target,
)?;
Footer::new("* Abbruch", "").draw(target)?;
if let Self::WifiConnecting = self {
Footer::new("* Abbruch", "").draw(target)?;
}
Ok(())
}
}
Expand Down
43 changes: 43 additions & 0 deletions firmware/src/time.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
use chrono::{DateTime, TimeDelta, Utc};
use core::cell::RefCell;
use embassy_sync::blocking_mutex::CriticalSectionMutex;
use log::debug;

/// Calculated time of system start
static SYSTEM_START_TIME: CriticalSectionMutex<RefCell<Option<DateTime<Utc>>>> =
CriticalSectionMutex::new(RefCell::new(None));

/// Time of system start
fn start_time() -> Option<DateTime<Utc>> {
SYSTEM_START_TIME.lock(|sst| *sst.borrow())
}

/// Set time of system start
fn set_start_time(time: DateTime<Utc>) {
SYSTEM_START_TIME.lock(|sst| {
*sst.borrow_mut() = Some(time);
});
}

/// Duration of system run time
pub fn uptime() -> Option<TimeDelta> {
let millis = esp_hal::time::now().duration_since_epoch().to_millis();
TimeDelta::try_milliseconds(i64::try_from(millis).ok()?)
}

/// Current time
pub fn now() -> Option<DateTime<Utc>> {
if let (Some(start_time), Some(uptime)) = (start_time(), uptime()) {
Some(start_time + uptime)
} else {
None
}
}

/// Set current time by using the given current time to calculate the time of system start
pub fn set(now: DateTime<Utc>) {
if let Some(uptime) = uptime() {
set_start_time(now - uptime);
debug!("Time: Current time set to {}", now);
}
}
Loading

0 comments on commit 0ffde8b

Please sign in to comment.