More code
This commit is contained in:
@@ -4,6 +4,15 @@ target = "xtensa-esp32-espidf"
|
||||
[target.xtensa-esp32-espidf]
|
||||
linker = "ldproxy"
|
||||
|
||||
[profile.release]
|
||||
# symbols are nice and they don't increase the size on Flash
|
||||
debug = true
|
||||
opt-level = "z"
|
||||
|
||||
[profile.dev]
|
||||
opt-level = "s"
|
||||
|
||||
|
||||
[unstable]
|
||||
build-std = ["std", "panic_abort"]
|
||||
build-std-features = ["panic_immediate_abort"]
|
||||
@@ -13,3 +22,7 @@ extra-link-arg = true # No longer necessary since 1.56, as it was stabilized:
|
||||
[env]
|
||||
ESP_IDF_SYS_GLOB_BASE = { value = ".", relative = true }
|
||||
|
||||
ESP_IDF_SYS_GLOB_0 = { value = "/sdkconfig.release" }
|
||||
ESP_IDF_SYS_GLOB_1 = { value = "/sdkconfig.debug" }
|
||||
ESP_IDF_SYS_GLOB_2 = { value = "/sdkconfig.defaults" }
|
||||
|
||||
20
Cargo.toml
20
Cargo.toml
@@ -1,20 +1,24 @@
|
||||
|
||||
[package]
|
||||
name = "rusty-espresso"
|
||||
version = "0.1.0"
|
||||
edition = "2018"
|
||||
|
||||
|
||||
edition = "2021"
|
||||
|
||||
[features]
|
||||
bind = []
|
||||
|
||||
[dependencies]
|
||||
log = "0.4.14"
|
||||
time = { version = "0.3.5", features = ["formatting"] }
|
||||
anyhow = {version = "1", features = ["backtrace"]}
|
||||
esp-idf-sys = { version = "0.20" }
|
||||
embedded-svc = "0.8.3"
|
||||
esp-idf-svc = { version = "0.20", features = ["binstart"] }
|
||||
esp-idf-hal = "0.20"
|
||||
esp-idf-sys = { version = "0.31.5", features = ["binstart"] }
|
||||
embedded-svc = "0.14"
|
||||
esp-idf-svc = { version = "0.41.2" }
|
||||
esp-idf-hal = "0.37.3"
|
||||
maud = "0.22.3"
|
||||
quick-protobuf = "0.8.0"
|
||||
|
||||
[build-dependencies]
|
||||
embuild = "0.24"
|
||||
embuild = "0.29.0"
|
||||
anyhow = "1"
|
||||
|
||||
|
||||
3
env.sh
3
env.sh
@@ -1,7 +1,8 @@
|
||||
#!/bin/bash
|
||||
|
||||
export PATH=$HOME/xtensa-esp32-elf-clang/bin:$PATH
|
||||
# export PATH=/home/jakob/esp/llvm-project/build/bin/clang:$PATH
|
||||
. $HOME/esp/esp-idf/export.sh
|
||||
export PATH=/home/jakob/esp/xtensa-esp32-elf-clang/bin:$PATH
|
||||
rustup default esp
|
||||
|
||||
|
||||
|
||||
@@ -4,3 +4,7 @@ CONFIG_LWIP_IPV4_NAPT=y
|
||||
#CONFIG_ESP_SYSTEM_USE_EH_FRAME=y
|
||||
#CONFIG_COMPILER_CXX_EXCEPTIONS=y
|
||||
|
||||
# Workaround for https://github.com/espressif/esp-idf/issues/7631
|
||||
CONFIG_MBEDTLS_CERTIFICATE_BUNDLE=n
|
||||
CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_DEFAULT_FULL=n
|
||||
CONFIG_HTTPD_MAX_REQ_HDR_LEN=2048
|
||||
|
||||
303
src/main.rs
303
src/main.rs
@@ -1,4 +1,303 @@
|
||||
use embedded_svc::httpd::registry::*;
|
||||
use embedded_svc::httpd::*;
|
||||
use embedded_svc::ipv4::ClientConfiguration as Ipv4ClientConfiguration;
|
||||
use embedded_svc::ipv4::DHCPClientSettings;
|
||||
use embedded_svc::storage::Storage;
|
||||
use embedded_svc::wifi::{AuthMethod, ClientConfiguration, Configuration, Wifi};
|
||||
use esp_idf_svc::httpd::Server;
|
||||
use esp_idf_svc::netif::EspNetifStack;
|
||||
use esp_idf_svc::nvs::EspDefaultNvs;
|
||||
use esp_idf_svc::nvs_storage::EspNvsStorage;
|
||||
use esp_idf_svc::sntp::*;
|
||||
use log::*;
|
||||
|
||||
fn main() {
|
||||
println!("Hello, world!");
|
||||
use std::env;
|
||||
use std::fmt;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::thread;
|
||||
use std::time::SystemTime;
|
||||
use time::{
|
||||
format_description::well_known::Rfc3339,
|
||||
OffsetDateTime };
|
||||
// use embedded_svc::anyerror::*;
|
||||
// use esp_idf_hal::prelude::*;
|
||||
use esp_idf_svc::httpd as idf_httpd;
|
||||
use esp_idf_svc::sysloop::*;
|
||||
use esp_idf_svc::wifi::*;
|
||||
use esp_idf_sys::EspError;
|
||||
use std::sync::mpsc::{channel, Receiver, Sender};
|
||||
use std::time::Duration;
|
||||
use maud::{Markup, html, DOCTYPE};
|
||||
|
||||
mod backup_manager;
|
||||
mod pid_manager;
|
||||
mod s11n;
|
||||
|
||||
use crate::backup_manager::BackupManagerTx;
|
||||
|
||||
// use std::{thread, time::Duration};
|
||||
|
||||
#[derive(Debug)]
|
||||
struct WifiData {
|
||||
ssid: String,
|
||||
password: String,
|
||||
auth: AuthMethod,
|
||||
}
|
||||
|
||||
impl fmt::Display for WifiData {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"WifiData: ({}, [password not displayed], {})",
|
||||
self.ssid,
|
||||
WifiData::authmethod_to_str(self.auth)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl WifiData {
|
||||
const auth_methods: [(&'static str, AuthMethod); 9] = [
|
||||
("None", AuthMethod::None),
|
||||
("WEP", AuthMethod::WEP),
|
||||
("WPA", AuthMethod::WPA),
|
||||
("WPA2Personal", AuthMethod::WPA2Personal),
|
||||
("WPAWPA2Personal", AuthMethod::WPAWPA2Personal),
|
||||
("WPA2Enterprise", AuthMethod::WPA2Enterprise),
|
||||
("WPA3Personal", AuthMethod::WPA3Personal),
|
||||
("WPA2WPA3Personal", AuthMethod::WPA2WPA3Personal),
|
||||
("WAPIPersonal", AuthMethod::WAPIPersonal),
|
||||
];
|
||||
|
||||
fn str_to_authmethod(s: &str) -> AuthMethod {
|
||||
WifiData::auth_methods
|
||||
.iter()
|
||||
.find(|(n, _)| s.eq(*n))
|
||||
.unwrap_or(&WifiData::auth_methods[0])
|
||||
.1
|
||||
}
|
||||
|
||||
fn authmethod_to_str(a: AuthMethod) -> &'static str {
|
||||
WifiData::auth_methods
|
||||
.iter()
|
||||
.find(|(_, k)| a == *k)
|
||||
.unwrap_or(&WifiData::auth_methods[0])
|
||||
.0
|
||||
}
|
||||
|
||||
pub fn from_nvs(nvs: BackupManagerTx) -> anyhow::Result<Self> {
|
||||
let ssid_b = get_nvs_key(&nvs, "ssid".to_string()).unwrap_or([].to_vec());
|
||||
let password_b = get_nvs_key(&nvs, "password".to_string()).unwrap_or([].to_vec());
|
||||
let auth_b = get_nvs_key(&nvs, "authmethod".to_string()).unwrap_or([].to_vec());
|
||||
let ssid = String::from_utf8(ssid_b).unwrap();
|
||||
let password = String::from_utf8(password_b).unwrap();
|
||||
let auth = WifiData::str_to_authmethod(std::str::from_utf8(&auth_b).unwrap());
|
||||
|
||||
Ok(WifiData { ssid: ssid, password: password, auth: auth })
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
pub fn from_nvs(storage: &mut EspNvsStorage) -> anyhow::Result<Self> {
|
||||
Ok(WifiData {
|
||||
ssid: String::from_utf8(storage.get_raw("ssid")?.unwrap_or([].to_vec()))?,
|
||||
password: String::from_utf8(storage.get_raw("password")?.unwrap_or([].to_vec()))?,
|
||||
auth: WifiData::str_to_authmethod(
|
||||
std::str::from_utf8(&storage.get_raw("authmethod")?.unwrap_or([].to_vec()))
|
||||
.unwrap_or(""),
|
||||
),
|
||||
})
|
||||
}
|
||||
*/
|
||||
|
||||
pub fn to_nvs(self, storage: &mut EspNvsStorage) -> anyhow::Result<()> {
|
||||
storage.put_raw("ssid", self.ssid.as_bytes())?;
|
||||
storage.put_raw("password", self.password.as_bytes())?;
|
||||
storage.put_raw(
|
||||
"authmethod",
|
||||
WifiData::authmethod_to_str(self.auth).as_bytes(),
|
||||
)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn get_nvs_key (nvs: &BackupManagerTx, key: String) -> Option<Vec<u8>> {
|
||||
let (tx, rx) = channel();
|
||||
nvs.send(backup_manager::BackupManagerMessage::Load(key, tx));
|
||||
rx.recv_timeout(Duration::from_millis(100)).unwrap()
|
||||
}
|
||||
|
||||
fn get_nvs (nvs: &BackupManagerTx) -> Arc<EspDefaultNvs> {
|
||||
let (tx, rx) = channel();
|
||||
nvs.send(backup_manager::BackupManagerMessage::GetNvs(tx));
|
||||
rx.recv().unwrap()
|
||||
}
|
||||
|
||||
|
||||
fn to_rfc3339<T>(dt: T) -> String where T: Into<OffsetDateTime> {
|
||||
dt.into().format(&Rfc3339).unwrap()
|
||||
}
|
||||
|
||||
|
||||
struct HttpdState {
|
||||
pid_data_library: pid_manager::PidManager,
|
||||
nvs_store: backup_manager::BackupManagerTx,
|
||||
}
|
||||
|
||||
fn main() -> anyhow::Result<()> {
|
||||
esp_idf_sys::link_patches();
|
||||
|
||||
env::set_var("RUST_BACKTRACE", "1");
|
||||
|
||||
esp_idf_svc::log::EspLogger::initialize_default();
|
||||
|
||||
//let mut nvs = Arc::new(EspDefaultNvs::new()?);
|
||||
//let mut nvs_store = EspNvsStorage::new_default(nvs.clone(), "data", true)?;
|
||||
|
||||
info!("EspNvsStorage done");
|
||||
thread::sleep(Duration::from_secs(10));
|
||||
let mut nvs_backup_manager = backup_manager::BackupManager::new();
|
||||
let wd = WifiData::from_nvs(nvs_backup_manager.get_sender())?;
|
||||
info!("wifidata is: {}", &wd);
|
||||
thread::sleep(Duration::from_secs(1));
|
||||
|
||||
|
||||
let mut w = wifi(wd, get_nvs(&nvs_backup_manager.get_sender()))?;
|
||||
|
||||
info!("We now have wifi -- trying to establish NTP");
|
||||
|
||||
let sntp_conf = SntpConf {
|
||||
servers: [ "0.dk.pool.ntp.org".to_string() ],
|
||||
operating_mode: OperatingMode::Poll,
|
||||
sync_mode: SyncMode::Immediate
|
||||
};
|
||||
let ntp = EspSntp::new(&sntp_conf)?;
|
||||
|
||||
thread::sleep(Duration::from_secs(1));
|
||||
|
||||
info!("Current time is: {:?}", to_rfc3339(SystemTime::now()));
|
||||
|
||||
let mut httpd_state = HttpdState {
|
||||
pid_data_library: pid_manager::PidManager::new(&nvs_backup_manager.get_sender()),
|
||||
nvs_store: nvs_backup_manager.get_sender(),
|
||||
};
|
||||
let mut h = httpd(httpd_state)?;
|
||||
|
||||
thread::sleep(Duration::from_secs(300));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
struct MyServer {
|
||||
state: i32,
|
||||
server: Option<Server>,
|
||||
}
|
||||
|
||||
fn httpd(mut state: HttpdState) -> anyhow::Result<idf_httpd::Server> {
|
||||
|
||||
fn header (page_title: &str) -> Markup {
|
||||
html! {
|
||||
head {
|
||||
title { (page_title) }
|
||||
link rel="stylesheet" href="/static/styles.css";
|
||||
link rel="icon" type="image/png" href="/favicon.png";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn web_frontpage_get(req: Request) -> anyhow::Result<Response> {
|
||||
Ok(Response::ok().body(include_str!("index.html").into()))
|
||||
}
|
||||
|
||||
let api_pid_post = move |_| {
|
||||
Ok(Response::ok()
|
||||
.content_type("application/json")
|
||||
.body(include_str!("api_pid_post.json").into()))
|
||||
};
|
||||
|
||||
fn api_pid_get(req: Request) -> anyhow::Result<Response> {
|
||||
Ok(Response::ok()
|
||||
.content_type("appliation/json")
|
||||
.body(include_str!("api_pid_get.json").into()))
|
||||
}
|
||||
|
||||
fn web_create_pid_form(req: Request) -> anyhow::Result<Response> {
|
||||
let heading = &"Create a PID Data";
|
||||
let markup = html! {
|
||||
(DOCTYPE)
|
||||
html {
|
||||
(header(heading))
|
||||
h1 { (heading) }
|
||||
body {
|
||||
form action="create-pid" method="post" {
|
||||
label for="name" { "name" }
|
||||
input type="text" name="name";
|
||||
input type="submit" value="create";
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
Ok(Response::ok().content_type("text/html").body(markup.into_string().into()))
|
||||
}
|
||||
|
||||
fn web_pid_get(req: Request, mut pid_manager_tx: pid_manager::PidManagerTx) -> anyhow::Result<Response> {
|
||||
let (tx, rx) = channel();
|
||||
pid_manager_tx.send(pid_manager::PidManagerMessage::GetLibraryItemsList(tx));
|
||||
let v = rx.recv_timeout(Duration::from_millis(100)).unwrap();
|
||||
|
||||
let heading = &"Test Maud page";
|
||||
|
||||
// try out the maud templating language
|
||||
let markup = html! {
|
||||
html {
|
||||
(header(heading))
|
||||
h1 { (heading) }
|
||||
}
|
||||
};
|
||||
Ok(Response::ok().content_type("text/html").body(markup.into_string().into()))
|
||||
}
|
||||
|
||||
fn static_png(req: Request, b: &[u8]) -> anyhow::Result<Response> {
|
||||
Ok(Response::ok().content_type("image/png").header("Cache-Control", "public, s-maxage=28800, max-age=28800").body(b.to_vec().into()))
|
||||
}
|
||||
|
||||
fn static_css_gz(req: Request, b: &[u8]) -> anyhow::Result<Response> {
|
||||
Ok(Response::ok().content_type("text/css").header("Cache-Control", "public, s-maxage=28800, max-age=28800").header("Content-Encoding", "gzip").body(b.to_vec().into()))
|
||||
}
|
||||
|
||||
let server = idf_httpd::ServerRegistry::new()
|
||||
.at("/")
|
||||
.get(web_frontpage_get)?
|
||||
.at("/favicon.png")
|
||||
.get(move |r| static_png(r, include_bytes!("static/favicon.png")))?
|
||||
.at("/static/styles.css")
|
||||
.get(move |r| static_css_gz(r, include_bytes!("static/styles.css.gz")))?
|
||||
.at("/create-pid-form")
|
||||
.get(web_create_pid_form)?
|
||||
.at("/pid")
|
||||
.get(move |r| web_pid_get(r, state.pid_data_library.tx.clone()))?
|
||||
.at("/api/v1/pid")
|
||||
.get(api_pid_get)?
|
||||
.at("/api/v1/pid")
|
||||
.post(api_pid_post)?;
|
||||
|
||||
server.start(&idf_httpd::Configuration::default())
|
||||
}
|
||||
|
||||
fn wifi(wifidata: WifiData, nvs: Arc<EspDefaultNvs>) -> anyhow::Result<EspWifi> {
|
||||
let mut wifi = EspWifi::new(
|
||||
Arc::new(EspNetifStack::new()?),
|
||||
Arc::new(EspSysLoopStack::new()?),
|
||||
nvs,
|
||||
)?;
|
||||
|
||||
wifi.set_configuration(&Configuration::Client(ClientConfiguration {
|
||||
ssid: wifidata.ssid.into(),
|
||||
password: wifidata.password.into(),
|
||||
bssid: None,
|
||||
channel: None, // unknown channel, let's see how that works :-)
|
||||
ip_conf: Some(Ipv4ClientConfiguration::DHCP(DHCPClientSettings { hostname: Some(String::from("rusty-espress-XX")) } )),
|
||||
auth_method: wifidata.auth,
|
||||
}))?;
|
||||
|
||||
Ok(wifi)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user