Skip to content

Commit 2dcde82

Browse files
author
yoshiaki-yamada
committed
Second sdcard implementation
1 parent 7607c34 commit 2dcde82

File tree

3 files changed

+175
-18
lines changed

3 files changed

+175
-18
lines changed

sdcard/Cargo.toml

+5
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,11 @@ esp-idf-hal = { version = "0.41", optional = true, default-features = false }
3434
esp-idf-svc = { version = "0.46", optional = true, default-features = false }
3535
embedded-svc = { version = "0.25", optional = true, default-features = false }
3636
embedded-sdmmc = "0.5.0"
37+
anyhow = "1.0.75"
38+
chrono = { version = "0.4.23", default-features = false, features = ["clock", "std", "wasmbind"] }
39+
time = "0.3.29"
40+
simple-ntp = "0.1.1"
41+
3742

3843
[build-dependencies]
3944
embuild = "0.31.2"

sdcard/src/main.rs

+86-18
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,55 @@
1+
use chrono::{DateTime, Datelike, Local, LocalResult, TimeZone, Timelike};
12
use embedded_sdmmc::{TimeSource, Timestamp};
23
use esp_idf_hal::{
34
gpio::PinDriver,
45
peripherals,
56
prelude::*,
67
spi::{config, SpiDeviceDriver, SpiDriver, SpiDriverConfig, SPI2},
78
};
8-
use esp_idf_sys as _; // If using the `binstart` feature of `esp-idf-sys`, always keep this module imported
9+
use esp_idf_svc::eventloop::EspSystemEventLoop;
10+
use simple_ntp::sntp;
11+
mod wifi;
12+
use wifi::wifi;
913

10-
struct Clock;
11-
impl TimeSource for Clock {
12-
fn get_timestamp(&self) -> Timestamp {}
14+
struct NtpClient<'a> {
15+
url: &'a str,
16+
port: i8,
1317
}
1418

19+
impl<'a> NtpClient<'a> {
20+
fn get_timestamp(&self) -> LocalResult<DateTime<Local>> {
21+
// Fetch current time using ntp.
22+
let duration =
23+
sntp::unix_timestamp(format!("{}:{}", &self.url, &self.port).as_str()).unwrap();
24+
println!("Timestamps in local time:");
25+
println!("{:?}", duration.as_secs());
26+
let seconds = duration.as_secs();
27+
chrono::Local.timestamp_opt(seconds as i64, 0)
28+
}
29+
}
30+
31+
struct Clock<'a> {
32+
ntp_client: NtpClient<'a>,
33+
}
34+
35+
impl TimeSource for Clock<'_> {
36+
fn get_timestamp(&self) -> Timestamp {
37+
let now = &self.ntp_client.get_timestamp().unwrap();
38+
Timestamp {
39+
year_since_1970: (now.year() - 1970) as u8,
40+
zero_indexed_month: now.month0() as u8,
41+
zero_indexed_day: now.day0() as u8,
42+
hours: now.hour() as u8,
43+
minutes: now.minute() as u8,
44+
seconds: now.second() as u8,
45+
}
46+
}
47+
}
48+
49+
// Please SSID and WIFI_PASSWORD to use wifi.
50+
const SSID: &str = "";
51+
const WIFI_PASSWORD: &str = "";
52+
1553
fn main() {
1654
// It is necessary to call this function once. Otherwise some patches to the runtime
1755
// implemented by esp-idf-sys might not link properly. See https://github.com/esp-rs/esp-idf-template/issues/71
@@ -23,6 +61,14 @@ fn main() {
2361
let gpios = peripherals.pins;
2462
let pin_cs = PinDriver::output(gpios.gpio4).unwrap();
2563

64+
// Initialize wifi.
65+
let _wifi = wifi(
66+
SSID,
67+
WIFI_PASSWORD,
68+
peripherals.modem,
69+
EspSystemEventLoop::take().unwrap(),
70+
);
71+
2672
// Initialize SPI interface
2773
let spi = peripherals.spi2;
2874
let driver = SpiDriver::new::<SPI2>(
@@ -37,34 +83,56 @@ fn main() {
3783
let spi_device_config = config::Config::new().baudrate(10.MHz().into());
3884
let spi_device = SpiDeviceDriver::new(driver, Some(gpios.gpio14), &spi_device_config).unwrap();
3985

86+
// Following is based on https://github.com/rust-embedded-community/embedded-sdmmc-rs/tree/v0.5.0#using-the-crate
87+
4088
// Build an SD Card interface out of an SPI device, a chip-select pin and a delay object
4189
let sdcard = embedded_sdmmc::SdCard::new(spi_device, pin_cs, esp_idf_hal::delay::FreeRtos);
4290
// Get the card size (this also triggers card initialisation because it's not been done yet)
4391
println!("Card size is {} bytes", sdcard.num_bytes().unwrap());
4492
// Now let's look for volumes (also known as partitions) on our block device.
4593
// To do this we need a Volume Manager. It will take ownership of the block device.
46-
let mut volume_mgr = embedded_sdmmc::VolumeManager::new(sdcard, time_source);
94+
let mut volume_mgr = embedded_sdmmc::VolumeManager::new(
95+
sdcard,
96+
Clock {
97+
ntp_client: NtpClient {
98+
url: "time.google.com",
99+
port: 123,
100+
},
101+
},
102+
);
103+
47104
// Try and access Volume 0 (i.e. the first partition).
48105
// The volume object holds information about the filesystem on that volume.
49106
// It doesn't hold a reference to the Volume Manager and so must be passed back
50107
// to every Volume Manager API call. This makes it easier to handle multiple
51108
// volumes in parallel.
52-
let volume0 = volume_mgr.get_volume(embedded_sdmmc::VolumeIdx(0))?;
109+
let mut volume0 = volume_mgr.get_volume(embedded_sdmmc::VolumeIdx(0)).unwrap();
53110
println!("Volume 0: {:?}", volume0);
54111
// Open the root directory (passing in the volume we're using).
55-
let root_dir = volume_mgr.open_root_dir(&volume0)?;
112+
let root_dir = volume_mgr.open_root_dir(&volume0).unwrap();
56113
// Open a file called "MY_FILE.TXT" in the root directory
57-
let my_file = volume_mgr
58-
.open_file_in_dir(root_dir, "MY_FILE.TXT", embedded_sdmmc::Mode::ReadOnly)
59-
.unwrap();
60-
// Print the contents of the file
61-
while !volume_mgr.file_eof(my_file).unwrap() {
62-
let mut buffer = [0u8; 32];
63-
let num_read = volume_mgr.read(&volume0, &mut my_file, &mut buffer)?;
64-
for b in &buffer[0..num_read] {
65-
print!("{}", *b as char);
114+
let my_file = volume_mgr.open_file_in_dir(
115+
&mut volume0,
116+
&root_dir,
117+
"MY_FILE.TXT",
118+
embedded_sdmmc::Mode::ReadOnly,
119+
);
120+
121+
match my_file {
122+
Ok(mut f) => {
123+
// Print the contents of the file
124+
while !f.eof() {
125+
let mut buffer = [0u8; 32];
126+
let num_read = volume_mgr.read(&volume0, &mut f, &mut buffer).unwrap();
127+
for b in &buffer[0..num_read] {
128+
print!("{}", *b as char);
129+
}
130+
}
131+
let _ = volume_mgr.close_file(&volume0, f);
132+
volume_mgr.close_dir(&volume0, root_dir);
133+
}
134+
Err(error) => {
135+
println!("Error happen while opening file {:?}", error);
66136
}
67137
}
68-
volume_mgr.close_file(&volume0, my_file);
69-
volume_mgr.close_dir(&volume0, root_dir);
70138
}

sdcard/src/wifi.rs

+84
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
// Following is based on https://github.com/esp-rs/std-training/blob/main/common/lib/wifi/src/lib.rs
2+
3+
use anyhow::{bail, Result};
4+
use embedded_svc::wifi::{
5+
AccessPointConfiguration, AuthMethod, ClientConfiguration, Configuration,
6+
};
7+
use esp_idf_hal::peripheral;
8+
use esp_idf_svc::eventloop::EspSystemEventLoop;
9+
use esp_idf_svc::{wifi::BlockingWifi, wifi::EspWifi};
10+
use log::info;
11+
12+
pub fn wifi(
13+
ssid: &str,
14+
pass: &str,
15+
modem: impl peripheral::Peripheral<P = esp_idf_hal::modem::Modem> + 'static,
16+
sysloop: EspSystemEventLoop,
17+
) -> Result<Box<EspWifi<'static>>> {
18+
let mut auth_method = AuthMethod::WPA2Personal;
19+
if ssid.is_empty() {
20+
bail!("Missing WiFi name")
21+
}
22+
if pass.is_empty() {
23+
auth_method = AuthMethod::None;
24+
info!("Wifi password is empty");
25+
}
26+
let mut esp_wifi = EspWifi::new(modem, sysloop.clone(), None)?;
27+
28+
let mut wifi = BlockingWifi::wrap(&mut esp_wifi, sysloop)?;
29+
30+
wifi.set_configuration(&Configuration::Client(ClientConfiguration::default()))?;
31+
32+
info!("Starting wifi...");
33+
34+
wifi.start()?;
35+
36+
info!("Scanning...");
37+
38+
let ap_infos = wifi.scan()?;
39+
40+
let ours = ap_infos.into_iter().find(|a| a.ssid == ssid);
41+
42+
let channel = if let Some(ours) = ours {
43+
info!(
44+
"Found configured access point {} on channel {}",
45+
ssid, ours.channel
46+
);
47+
Some(ours.channel)
48+
} else {
49+
info!(
50+
"Configured access point {} not found during scanning, will go with unknown channel",
51+
ssid
52+
);
53+
None
54+
};
55+
56+
wifi.set_configuration(&Configuration::Mixed(
57+
ClientConfiguration {
58+
ssid: ssid.into(),
59+
password: pass.into(),
60+
channel,
61+
auth_method,
62+
..Default::default()
63+
},
64+
AccessPointConfiguration {
65+
ssid: "aptest".into(),
66+
channel: channel.unwrap_or(1),
67+
..Default::default()
68+
},
69+
))?;
70+
71+
info!("Connecting wifi...");
72+
73+
wifi.connect()?;
74+
75+
info!("Waiting for DHCP lease...");
76+
77+
wifi.wait_netif_up()?;
78+
79+
let ip_info = wifi.wifi().sta_netif().get_ip_info()?;
80+
81+
info!("Wifi DHCP info: {:?}", ip_info);
82+
83+
Ok(Box::new(esp_wifi))
84+
}

0 commit comments

Comments
 (0)