Compare commits
6 Commits
3b6acbd65e
...
v0.0.2
| Author | SHA1 | Date | |
|---|---|---|---|
|
eed8db4863
|
|||
|
98b81ae274
|
|||
|
ef5cb2c876
|
|||
|
8ac6bbc7d8
|
|||
|
df191603dd
|
|||
|
77eba3071d
|
96
Cargo.lock
generated
96
Cargo.lock
generated
@@ -563,6 +563,15 @@ dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ed25519"
|
||||
version = "1.5.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "91cff35c70bba8a626e3185d8cd48cc11b5437e1a5bcd15b9b5fa3c64b6dfee7"
|
||||
dependencies = [
|
||||
"signature",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "either"
|
||||
version = "1.9.0"
|
||||
@@ -599,6 +608,7 @@ dependencies = [
|
||||
"embassy-sync",
|
||||
"embedded-storage",
|
||||
"embedded-storage-async",
|
||||
"salty",
|
||||
"signature",
|
||||
]
|
||||
|
||||
@@ -784,21 +794,6 @@ dependencies = [
|
||||
"heapless 0.7.16",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "embassy-usb"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/embassy-rs/embassy#af7c93abba768057f1d3299c7b4f4aa4501b3e56"
|
||||
dependencies = [
|
||||
"defmt",
|
||||
"embassy-futures",
|
||||
"embassy-net-driver-channel",
|
||||
"embassy-sync",
|
||||
"embassy-usb-driver",
|
||||
"heapless 0.7.16",
|
||||
"ssmarshal",
|
||||
"usbd-hid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "embassy-usb-driver"
|
||||
version = "0.1.0"
|
||||
@@ -931,12 +926,6 @@ dependencies = [
|
||||
"log",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "encode_unicode"
|
||||
version = "0.3.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f"
|
||||
|
||||
[[package]]
|
||||
name = "equivalent"
|
||||
version = "1.0.1"
|
||||
@@ -1761,7 +1750,6 @@ dependencies = [
|
||||
"const_format",
|
||||
"cortex-m",
|
||||
"cortex-m-rt",
|
||||
"crc16",
|
||||
"cyw43",
|
||||
"cyw43-pio",
|
||||
"defmt",
|
||||
@@ -1776,12 +1764,11 @@ dependencies = [
|
||||
"embassy-rp",
|
||||
"embassy-sync",
|
||||
"embassy-time",
|
||||
"embassy-usb",
|
||||
"embedded-io-async",
|
||||
"embedded-storage",
|
||||
"embedded-tls",
|
||||
"git-version",
|
||||
"heapless 0.7.16",
|
||||
"log",
|
||||
"nourl",
|
||||
"panic-probe",
|
||||
"rand",
|
||||
@@ -1866,6 +1853,16 @@ version = "1.0.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741"
|
||||
|
||||
[[package]]
|
||||
name = "salty"
|
||||
version = "0.2.0"
|
||||
source = "git+https://github.com/ycrypto/salty.git?rev=a9f17911a5024698406b75c0fac56ab5ccf6a8c7#a9f17911a5024698406b75c0fac56ab5ccf6a8c7"
|
||||
dependencies = [
|
||||
"ed25519",
|
||||
"subtle",
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "scopeguard"
|
||||
version = "1.2.0"
|
||||
@@ -1989,16 +1986,6 @@ dependencies = [
|
||||
"lock_api",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ssmarshal"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f3e6ad23b128192ed337dfa4f1b8099ced0c2bf30d61e551b65fda5916dbb850"
|
||||
dependencies = [
|
||||
"encode_unicode",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "stable_deref_trait"
|
||||
version = "1.2.0"
|
||||
@@ -2144,47 +2131,6 @@ dependencies = [
|
||||
"subtle",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "usb-device"
|
||||
version = "0.2.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1f6cc3adc849b5292b4075fc0d5fdcf2f24866e88e336dd27a8943090a520508"
|
||||
|
||||
[[package]]
|
||||
name = "usbd-hid"
|
||||
version = "0.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "975bd411f4a939986751ea09992a24fa47c4d25c6ed108d04b4c2999a4fd0132"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"ssmarshal",
|
||||
"usb-device",
|
||||
"usbd-hid-macros",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "usbd-hid-descriptors"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dcbee8c6735e90894fba04770bc41e11fd3c5256018856e15dc4dd1e6c8a3dd1"
|
||||
dependencies = [
|
||||
"bitfield",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "usbd-hid-macros"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "261079a9ada015fa1acac7cc73c98559f3a92585e15f508034beccf6a2ab75a2"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"serde",
|
||||
"syn 1.0.109",
|
||||
"usbd-hid-descriptors",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "vcell"
|
||||
version = "0.1.3"
|
||||
|
||||
17
Cargo.toml
17
Cargo.toml
@@ -28,14 +28,17 @@ embassy-rp = { version = "0.1", features = [
|
||||
"critical-section-impl",
|
||||
] }
|
||||
embassy-boot-rp = { version = "0.1", features = ["nightly", "defmt"] }
|
||||
embassy-boot = { version = "0.1", features = ["nightly", "defmt"] }
|
||||
embassy-boot = { version = "0.1", features = [
|
||||
"nightly",
|
||||
"defmt",
|
||||
"ed25519-salty",
|
||||
] }
|
||||
embassy-time = { version = "0.1", features = [
|
||||
"defmt",
|
||||
"unstable-traits",
|
||||
"defmt-timestamp-uptime",
|
||||
"nightly",
|
||||
] }
|
||||
embassy-usb = { version = "0.1", features = ["defmt"] }
|
||||
embassy-net = { version = "0.1", features = [
|
||||
"tcp",
|
||||
"dhcpv4",
|
||||
@@ -54,11 +57,9 @@ cyw43-pio = { git = "https://github.com/embassy-rs/embassy", features = [
|
||||
"defmt",
|
||||
] }
|
||||
panic-probe = { version = "0.3", features = ["print-defmt"] }
|
||||
log = "0.4"
|
||||
static_cell = { version = "1.1", features = ["nightly"] }
|
||||
heapless = { version = "0.7.16", features = ["defmt", "serde"] }
|
||||
embedded-io-async = { version = "0.5", features = ["defmt-03"] }
|
||||
crc16 = "0.4"
|
||||
dsmr5 = "0.3"
|
||||
rust-mqtt = { version = "0.1.5", features = [
|
||||
"defmt",
|
||||
@@ -84,21 +85,27 @@ reqwless = { version = "0.5.0", features = ["defmt"] }
|
||||
embedded-storage = "0.3.0"
|
||||
const_format = "0.2.31"
|
||||
git-version = "0.3.5"
|
||||
embedded-tls = { version = "0.15.0", default-features = false, features = [
|
||||
"async",
|
||||
"defmt",
|
||||
] }
|
||||
|
||||
[patch.crates-io]
|
||||
embassy-executor = { git = "https://github.com/embassy-rs/embassy" }
|
||||
embassy-rp = { git = "https://github.com/embassy-rs/embassy" }
|
||||
embassy-time = { git = "https://github.com/embassy-rs/embassy" }
|
||||
embassy-usb = { git = "https://github.com/embassy-rs/embassy" }
|
||||
embassy-net = { git = "https://github.com/embassy-rs/embassy" }
|
||||
embassy-sync = { git = "https://github.com/embassy-rs/embassy" }
|
||||
embassy-futures = { git = "https://github.com/embassy-rs/embassy" }
|
||||
embassy-boot-rp = { git = "https://github.com/embassy-rs/embassy" }
|
||||
embassy-boot = { git = "https://github.com/embassy-rs/embassy" }
|
||||
|
||||
# Updated to embedded-io 0.5.0
|
||||
rust-mqtt = { git = "https://git.huizinga.dev/Dreaded_X/rust-mqtt" }
|
||||
# Make mqtt:// and mqtts:// actually work
|
||||
nourl = { git = "https://git.huizinga.dev/Dreaded_X/nourl" }
|
||||
|
||||
# Waiting for this to get updated to embedded-io 0.5 properly
|
||||
reqwless = { path = "../reqwless" }
|
||||
|
||||
[build-dependencies]
|
||||
|
||||
9
release.sh
Executable file
9
release.sh
Executable file
@@ -0,0 +1,9 @@
|
||||
#!/bin/bash
|
||||
|
||||
mkdir -p target/firmware
|
||||
cargo objcopy --release -- -O binary target/firmware/firmware
|
||||
shasum -a 512 -b target/firmware/firmware | dd ibs=128 count=1 | xxd -p -r > target/firmware/checksum
|
||||
signify -S -m target/firmware/checksum -s ~/Projects/crypt/R0/private/keys/firmware/pico_p1.sec -x target/firmware/checksum.sig
|
||||
tail -n1 target/firmware/checksum.sig | base64 -d -i | dd ibs=10 skip=1 > target/firmware/signed
|
||||
cat target/firmware/signed > target/firmware/firmware+signed
|
||||
cat target/firmware/firmware >> target/firmware/firmware+signed
|
||||
91
src/main.rs
91
src/main.rs
@@ -6,6 +6,7 @@ use core::cell::RefCell;
|
||||
|
||||
use embassy_boot_rp::{AlignedBuffer, BlockingFirmwareUpdater, FirmwareUpdaterConfig};
|
||||
use embedded_storage::nor_flash::NorFlash;
|
||||
use embedded_tls::{Aes128GcmSha256, NoVerify, TlsConfig, TlsConnection, TlsContext};
|
||||
use heapless::{String, Vec};
|
||||
use rand::{
|
||||
rngs::{SmallRng, StdRng},
|
||||
@@ -25,9 +26,9 @@ use embassy_rp::{
|
||||
clocks::RoscRng,
|
||||
flash::{Flash, WRITE_SIZE},
|
||||
gpio::{Level, Output},
|
||||
peripherals::{DMA_CH0, PIN_23, PIN_25, PIO0, UART0},
|
||||
peripherals::{DMA_CH1, PIN_23, PIN_25, PIO0, UART0},
|
||||
pio::{self, Pio},
|
||||
uart::{self, BufferedUartRx, Parity},
|
||||
uart::{self, Async, Parity, UartRx},
|
||||
};
|
||||
use embassy_sync::{
|
||||
blocking_mutex::{raw::NoopRawMutex, Mutex},
|
||||
@@ -53,12 +54,12 @@ use serde::{Deserialize, Serialize};
|
||||
use static_cell::make_static;
|
||||
|
||||
use const_format::formatcp;
|
||||
use defmt::{debug, error, info, warn, Debug2Format};
|
||||
use defmt::{debug, error, info, trace, warn, Debug2Format};
|
||||
|
||||
use {defmt_rtt as _, panic_probe as _};
|
||||
|
||||
bind_interrupts!(struct Irqs {
|
||||
UART0_IRQ => uart::BufferedInterruptHandler<UART0>;
|
||||
UART0_IRQ => uart::InterruptHandler<UART0>;
|
||||
PIO0_IRQ_0 => pio::InterruptHandler<PIO0>;
|
||||
});
|
||||
|
||||
@@ -67,6 +68,7 @@ const TOPIC_BASE: &str = formatcp!("pico/{}", ID);
|
||||
const TOPIC_STATUS: &str = formatcp!("{}/status", TOPIC_BASE);
|
||||
const TOPIC_UPDATE: &str = formatcp!("{}/update", TOPIC_BASE);
|
||||
const VERSION: &str = git_version::git_version!();
|
||||
const PUBLIC_SIGNING_KEY: &[u8] = include_bytes!("../key.pub");
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct UpdateMessage<'a> {
|
||||
@@ -87,6 +89,7 @@ enum Status<'a> {
|
||||
PreparingUpdate,
|
||||
Erasing,
|
||||
Writing { progress: u32 },
|
||||
Verifying,
|
||||
UpdateComplete,
|
||||
}
|
||||
|
||||
@@ -102,7 +105,7 @@ async fn wifi_task(
|
||||
runner: cyw43::Runner<
|
||||
'static,
|
||||
Output<'static, PIN_23>,
|
||||
PioSpi<'static, PIN_25, PIO0, 0, DMA_CH0>,
|
||||
PioSpi<'static, PIN_25, PIO0, 0, DMA_CH1>,
|
||||
>,
|
||||
) -> ! {
|
||||
runner.run().await
|
||||
@@ -113,14 +116,14 @@ async fn net_task(stack: &'static Stack<cyw43::NetDriver<'static>>) -> ! {
|
||||
stack.run().await
|
||||
}
|
||||
|
||||
async fn get_readout(rx: &mut BufferedUartRx<'static, UART0>) -> Readout {
|
||||
async fn get_readout(rx: &mut UartRx<'static, UART0, Async>) -> Readout {
|
||||
let mut buffer: Vec<u8, 2048> = Vec::new();
|
||||
buffer.push(b'/').unwrap();
|
||||
|
||||
let mut byte = [0; 1];
|
||||
debug!("Waiting for next telegram...");
|
||||
loop {
|
||||
rx.read_exact(&mut byte).await.unwrap();
|
||||
rx.read(&mut byte).await.unwrap();
|
||||
|
||||
if byte[0] == b'/' {
|
||||
break;
|
||||
@@ -137,7 +140,7 @@ async fn get_readout(rx: &mut BufferedUartRx<'static, UART0>) -> Readout {
|
||||
debug!("Start of CRC detected");
|
||||
|
||||
let mut crc = [0; 4];
|
||||
rx.read_exact(&mut crc).await.unwrap();
|
||||
rx.read(&mut crc).await.unwrap();
|
||||
|
||||
buffer.extend_from_slice(&crc).unwrap();
|
||||
|
||||
@@ -155,7 +158,7 @@ async fn get_readout(rx: &mut BufferedUartRx<'static, UART0>) -> Readout {
|
||||
|
||||
#[embassy_executor::task]
|
||||
async fn uart_rx_task(
|
||||
mut rx: BufferedUartRx<'static, UART0>,
|
||||
mut rx: UartRx<'static, UART0, Async>,
|
||||
sender: Sender<'static, NoopRawMutex, dsmr5::state::State, 1>,
|
||||
) {
|
||||
info!("Wating for serial data");
|
||||
@@ -213,8 +216,7 @@ async fn main(spawner: Spawner) {
|
||||
config.parity = Parity::ParityNone;
|
||||
// config.invert_rx = true;
|
||||
|
||||
let buf = make_static!([0u8; 2048]);
|
||||
let rx = BufferedUartRx::new_with_rts(p.UART0, Irqs, p.PIN_1, p.PIN_3, buf, config);
|
||||
let rx = UartRx::new(p.UART0, p.PIN_17, Irqs, p.DMA_CH0, config);
|
||||
|
||||
spawner.spawn(uart_rx_task(rx, channel.sender())).unwrap();
|
||||
|
||||
@@ -229,7 +231,7 @@ async fn main(spawner: Spawner) {
|
||||
cs,
|
||||
p.PIN_24,
|
||||
p.PIN_29,
|
||||
p.DMA_CH0,
|
||||
p.DMA_CH1,
|
||||
);
|
||||
|
||||
let (fw, clm) = unsafe { get_firmware() };
|
||||
@@ -250,8 +252,7 @@ async fn main(spawner: Spawner) {
|
||||
|
||||
// Use the Ring Oscillator of the RP2040 as a source of true randomness to seed the
|
||||
// cryptographically secure PRNG
|
||||
let mut rng_rosc = RoscRng;
|
||||
let mut rng = StdRng::from_rng(&mut rng_rosc).unwrap();
|
||||
let mut rng = StdRng::from_rng(&mut RoscRng).unwrap();
|
||||
|
||||
let stack = make_static!(Stack::new(
|
||||
net_device,
|
||||
@@ -280,7 +281,7 @@ async fn main(spawner: Spawner) {
|
||||
info!("IP Address: {}", cfg.address.address());
|
||||
|
||||
let mut rx_buffer = [0; 1024];
|
||||
let mut tx_buffer = [0; 4096];
|
||||
let mut tx_buffer = [0; 1024];
|
||||
|
||||
let mut socket = TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer);
|
||||
// socket.set_timeout(Some(Duration::from_secs(10)));
|
||||
@@ -300,7 +301,7 @@ async fn main(spawner: Spawner) {
|
||||
MqttVersion::MQTTv5,
|
||||
// Use fast and simple PRNG to generate packet identifiers, there is no need for this to be
|
||||
// cryptographically secure
|
||||
SmallRng::from_rng(&mut rng_rosc).unwrap(),
|
||||
SmallRng::from_rng(&mut RoscRng).unwrap(),
|
||||
);
|
||||
|
||||
config.add_username(env!("MQTT_USERNAME"));
|
||||
@@ -312,7 +313,7 @@ async fn main(spawner: Spawner) {
|
||||
config.add_will(TOPIC_STATUS, &msg, true);
|
||||
|
||||
let mut recv_buffer = [0; 1024];
|
||||
let mut write_buffer = [0; 4096];
|
||||
let mut write_buffer = [0; 1024];
|
||||
|
||||
let mut client =
|
||||
MqttClient::<_, 5, _>::new(socket, &mut write_buffer, &mut recv_buffer, config);
|
||||
@@ -387,7 +388,7 @@ async fn main(spawner: Spawner) {
|
||||
|
||||
let url = message.get_url();
|
||||
let url = Url::parse(url.as_str()).unwrap();
|
||||
attempt_update(stack, &mut updater, &mut client, url).await;
|
||||
attempt_update(stack, &mut updater, &mut rng, &mut client, url).await;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -411,6 +412,7 @@ const FLASH_SIZE: usize = 2 * 1024 * 1024;
|
||||
async fn attempt_update<T, const MAX_PROPERTIES: usize, R, F>(
|
||||
stack: &'static Stack<cyw43::NetDriver<'static>>,
|
||||
updater: &mut BlockingFirmwareUpdater<'_, F, F>,
|
||||
rng: &mut StdRng,
|
||||
client: &mut MqttClient<'_, T, MAX_PROPERTIES, R>,
|
||||
url: Url<'_>,
|
||||
) where
|
||||
@@ -427,23 +429,33 @@ async fn attempt_update<T, const MAX_PROPERTIES: usize, R, F>(
|
||||
|
||||
let ip = stack.dns_query(url.host(), DnsQueryType::A).await.unwrap()[0];
|
||||
|
||||
let mut rx_buffer = [0; 4096 * 2];
|
||||
let mut rx_buffer = [0; 1024];
|
||||
let mut tx_buffer = [0; 1024];
|
||||
|
||||
let mut socket = TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer);
|
||||
|
||||
let addr = (ip, url.port_or_default());
|
||||
debug!("Addr: {}", addr);
|
||||
socket.connect(addr).await.unwrap();
|
||||
|
||||
debug!("Path: {}", url.path());
|
||||
Request::get(url.path())
|
||||
.build()
|
||||
.write(&mut socket)
|
||||
let mut read_record_buffer = [0; 16384 * 2];
|
||||
let mut write_record_buffer = [0; 16384];
|
||||
let mut tls: TlsConnection<TcpSocket, Aes128GcmSha256> =
|
||||
TlsConnection::new(socket, &mut read_record_buffer, &mut write_record_buffer);
|
||||
tls.open::<_, NoVerify>(TlsContext::new(&TlsConfig::new(), rng))
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let mut headers = [0; 4096];
|
||||
let resp = Response::read(&mut socket, Method::GET, &mut headers)
|
||||
debug!("Path: {}", url.path());
|
||||
Request::get(url.path())
|
||||
.host(url.host())
|
||||
.build()
|
||||
.write(&mut tls)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let mut headers = [0; 1024];
|
||||
let resp = Response::read(&mut tls, Method::GET, &mut headers)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
@@ -468,25 +480,42 @@ async fn attempt_update<T, const MAX_PROPERTIES: usize, R, F>(
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// The first 64 bytes of the file contain the signature
|
||||
let mut signature = [0; 64];
|
||||
body.read_exact(&mut signature).await.unwrap();
|
||||
|
||||
trace!("Signature: {:?}", signature);
|
||||
|
||||
let mut buffer = AlignedBuffer([0; 4096]);
|
||||
let mut offset = 0;
|
||||
let mut size = 0;
|
||||
while let Ok(read) = body.read(&mut buffer.0).await {
|
||||
if read == 0 {
|
||||
break;
|
||||
}
|
||||
debug!("Writing chunk: {}", read);
|
||||
writer.write(offset, &buffer.0[..read]).unwrap();
|
||||
offset += read as u32;
|
||||
writer.write(size, &buffer.0[..read]).unwrap();
|
||||
size += read as u32;
|
||||
|
||||
let status = Status::Writing { progress: offset }.vec();
|
||||
let status = Status::Writing { progress: size }.vec();
|
||||
client
|
||||
.send_message(TOPIC_STATUS, &status, QualityOfService::QoS1, false)
|
||||
.await
|
||||
.unwrap();
|
||||
}
|
||||
debug!("Total size: {}", offset);
|
||||
debug!("Total size: {}", size);
|
||||
|
||||
updater.mark_updated().unwrap();
|
||||
let status = Status::Verifying.vec();
|
||||
client
|
||||
.send_message(TOPIC_STATUS, &status, QualityOfService::QoS1, false)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
updater
|
||||
.verify_and_mark_updated(PUBLIC_SIGNING_KEY, &signature, size)
|
||||
.unwrap();
|
||||
|
||||
// Update mqtt message should be send using retain
|
||||
// TODO: Clear the message
|
||||
|
||||
let status = Status::UpdateComplete.vec();
|
||||
client
|
||||
|
||||
Reference in New Issue
Block a user