Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

update heapless and serde_json_core + add web #14

Merged
merged 3 commits into from
Oct 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "blues-notecard"
version = "0.3.2"
version = "0.4.0"
edition = "2021"
authors = [ "Gaute Hope <[email protected]>" ]
license = "MIT"
Expand All @@ -10,9 +10,9 @@ repository = "https://github.com/gauteh/notecard-rs"
[dependencies]
defmt = "0.3"
embedded-hal = "0.2.6"
heapless = { version = "0.7", features = [ "serde", "ufmt-impl", "defmt-impl" ] }
heapless = { version = "0.8", features = [ "serde", "ufmt", "defmt-03" ] }
serde = { version = "1", features = ["derive"], default-features = false }
serde-json-core = "0.4.0"
serde-json-core = "0.6.0"

[dev-dependencies]
base64 = { version = "0.13.0", default-features = false }
Expand Down
25 changes: 10 additions & 15 deletions src/card.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use embedded_hal::blocking::delay::DelayMs;
use embedded_hal::blocking::i2c::{Read, SevenBitAddress, Write};
use serde::{Deserialize, Serialize};

use super::{FutureResponse, NoteError, Notecard};
use super::{str_string, FutureResponse, NoteError, Notecard};

pub struct Card<'a, IOM: Write<SevenBitAddress> + Read<SevenBitAddress>, const BS: usize> {
note: &'a mut Notecard<IOM, BS>,
Expand Down Expand Up @@ -75,9 +75,9 @@ impl<'a, IOM: Write<SevenBitAddress> + Read<SevenBitAddress>, const BS: usize> C
delay,
req::LocationMode {
req: "card.location.mode",
mode: mode.map(heapless::String::from),
mode: str_string(mode)?,
seconds,
vseconds: vseconds.map(heapless::String::from),
vseconds: str_string(vseconds)?,
delete,
max,
lat,
Expand Down Expand Up @@ -108,7 +108,7 @@ impl<'a, IOM: Write<SevenBitAddress> + Read<SevenBitAddress>, const BS: usize> C
heartbeat: heartbeat.then(|| true),
sync: sync.then(|| true),
hours,
file: file.map(heapless::String::from),
file: str_string(file)?,
},
)?;

Expand All @@ -127,9 +127,9 @@ impl<'a, IOM: Write<SevenBitAddress> + Read<SevenBitAddress>, const BS: usize> C
delay,
req::Wireless {
req: "card.wireless",
mode: mode.map(heapless::String::from),
method: method.map(heapless::String::from),
apn: apn.map(heapless::String::from),
mode: str_string(mode)?,
method: str_string(method)?,
apn: str_string(apn)?,
hours,
},
)?;
Expand Down Expand Up @@ -159,7 +159,6 @@ impl<'a, IOM: Write<SevenBitAddress> + Read<SevenBitAddress>, const BS: usize> C
self.note.request(delay, req::DFU::new(name, on, stop))?;
Ok(FutureResponse::from(self.note))
}

}

pub mod req {
Expand Down Expand Up @@ -243,7 +242,7 @@ pub mod req {
Stm32Bi,
McuBoot,
#[serde(rename = "-")]
Reset
Reset,
}

#[derive(Deserialize, Serialize, defmt::Format)]
Expand All @@ -267,11 +266,7 @@ pub mod req {
}

impl DFU {
pub fn new(
name: Option<req::DFUName>,
on: Option<bool>,
stop: Option<bool>,
) -> Self {
pub fn new(name: Option<req::DFUName>, on: Option<bool>, stop: Option<bool>) -> Self {
// The `on`/`off` and `stop`/`start` parameters are exclusive
// When on is `true` we set `on` to `Some(True)` and `off` to `None`.
// When on is `false` we set `on` to `None` and `off` to `Some(True)`.
Expand Down Expand Up @@ -567,7 +562,7 @@ mod tests {
fn test_dfu_req() {
// Test basic request
let req = req::DFU::new(None, None, None);
let res: heapless::String<256> = serde_json_core::to_string(&req).unwrap();
let res: heapless::String<1024> = serde_json_core::to_string(&req).unwrap();
assert_eq!(res, r#"{"req":"card.dfu"}"#);

// Test name & on request
Expand Down
88 changes: 41 additions & 47 deletions src/dfu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@

#[allow(unused_imports)]
use defmt::{debug, error, info, trace, warn};
use embedded_hal::blocking::i2c::{Read, SevenBitAddress, Write};
use embedded_hal::blocking::delay::DelayMs;
use embedded_hal::blocking::i2c::{Read, SevenBitAddress, Write};
use serde::{Deserialize, Serialize};

use super::{FutureResponse, NoteError, Notecard};
Expand All @@ -20,12 +20,20 @@ impl<'a, IOM: Write<SevenBitAddress> + Read<SevenBitAddress>, const BS: usize> D
/// Retrieves downloaded firmware data from the Notecard.
/// Note: this request is functional only when the Notecard has been set to
/// dfu mode with a `hub.set`, `mode:dfu` request.
pub fn get<const PS: usize>(self, delay: &mut impl DelayMs<u16>, length: usize, offset: Option<usize>) -> Result<FutureResponse<'a, res::Get<PS>, IOM, BS>, NoteError> {
self.note.request(delay, req::Get {
req: "dfu.get",
length,
offset,
})?;
pub fn get<const PS: usize>(
self,
delay: &mut impl DelayMs<u16>,
length: usize,
offset: Option<usize>,
) -> Result<FutureResponse<'a, res::Get<PS>, IOM, BS>, NoteError> {
self.note.request(
delay,
req::Get {
req: "dfu.get",
length,
offset,
},
)?;

Ok(FutureResponse::from(self.note))
}
Expand All @@ -41,17 +49,12 @@ impl<'a, IOM: Write<SevenBitAddress> + Read<SevenBitAddress>, const BS: usize> D
version: Option<&str>,
vvalue: Option<&str>, // This is not JSON :(
on: Option<bool>,
err: Option<&str>
err: Option<&str>,
) -> Result<FutureResponse<'a, res::Status, IOM, BS>, NoteError> {
self.note.request(delay, req::Status::new(
name,
stop,
status,
version,
vvalue,
on,
err
))?;
self.note.request(
delay,
req::Status::new(name, stop, status, version, vvalue, on, err),
)?;

Ok(FutureResponse::from(self.note))
}
Expand All @@ -67,15 +70,14 @@ pub mod req {
pub length: usize,

#[serde(skip_serializing_if = "Option::is_none")]
pub offset: Option<usize>
pub offset: Option<usize>,
}


#[derive(Serialize, Deserialize, defmt::Format, PartialEq, Debug)]
#[serde(rename_all = "lowercase")]
pub enum StatusName {
User,
Card
Card,
}

#[derive(Serialize, Deserialize, defmt::Format)]
Expand Down Expand Up @@ -137,7 +139,7 @@ pub mod req {
version: Option<&'a str>,
vvalue: Option<&'a str>, // This is not JSON :(
on: Option<bool>,
err: Option<&'a str>
err: Option<&'a str>,
) -> Status<'a> {
// The `on`/`off` parameters are exclusive
// When on is `true` we set `on` to `Some(True)` and `off` to `None`.
Expand All @@ -163,7 +165,7 @@ pub mod res {

#[derive(Deserialize, defmt::Format)]
pub struct Get<const PS: usize> {
pub payload: heapless::String<PS>
pub payload: heapless::String<PS>,
}

#[derive(Deserialize, defmt::Format, PartialEq, Debug)]
Expand All @@ -173,7 +175,7 @@ pub mod res {
Error,
Downloading,
Ready,
Completed
Completed,
}

#[derive(Deserialize, defmt::Format)]
Expand All @@ -198,7 +200,7 @@ pub mod res {
pub on: Option<bool>,
pub off: Option<bool>,
pub pending: Option<bool>,
pub body: Option<StatusBody>
pub body: Option<StatusBody>,
}
}

Expand All @@ -208,7 +210,9 @@ mod tests {

#[test]
fn test_get() {
let (res, _) = serde_json_core::from_str::<res::Get<32>>(r#"{"payload":"THISISALOTOFBINARYDATA="}"#).unwrap();
let (res, _) =
serde_json_core::from_str::<res::Get<32>>(r#"{"payload":"THISISALOTOFBINARYDATA="}"#)
.unwrap();
assert_eq!(res.payload, r#"THISISALOTOFBINARYDATA="#);
}

Expand All @@ -223,15 +227,7 @@ mod tests {
#[test]
fn test_status_req() {
// Test basic request
let req = req::Status::new(
None,
None,
None,
None,
None,
None,
None
);
let req = req::Status::new(None, None, None, None, None, None, None);
let res: heapless::String<256> = serde_json_core::to_string(&req).unwrap();
assert_eq!(res, r#"{"req":"dfu.status"}"#);

Expand Down Expand Up @@ -260,18 +256,13 @@ mod tests {
Some("test error"),
);
let res: heapless::String<512> = serde_json_core::to_string(&req).unwrap();
assert_eq!(res, r#"{"req":"dfu.status","name":"user","stop":true,"status":"test status","version":"{\"org\":\"Organization\",\"product\":\"Product\",\"description\":\"Firmware Description\",\"firmware\":\"Firmware Name\",\"version\":\"Firmware Version 1.0.0\",\"ver_major\":1,\"ver_minor\":0,\"ver_patch\":0,\"ver_build\":12345,\"built\":\"Some Sunny Day In December\",\"builder\":\"The Compnay\"}","vvalue":"usb:1;high:1;normal:1;low:0;dead:0","on":true,"err":"test error"}"#);
assert_eq!(
res,
r#"{"req":"dfu.status","name":"user","stop":true,"status":"test status","version":"{\"org\":\"Organization\",\"product\":\"Product\",\"description\":\"Firmware Description\",\"firmware\":\"Firmware Name\",\"version\":\"Firmware Version 1.0.0\",\"ver_major\":1,\"ver_minor\":0,\"ver_patch\":0,\"ver_build\":12345,\"built\":\"Some Sunny Day In December\",\"builder\":\"The Compnay\"}","vvalue":"usb:1;high:1;normal:1;low:0;dead:0","on":true,"err":"test error"}"#
);

// Test off set
let req = req::Status::new(
None,
None,
None,
None,
None,
Some(false),
None
);
let req = req::Status::new(None, None, None, None, None, Some(false), None);
let res: heapless::String<256> = serde_json_core::to_string(&req).unwrap();
assert_eq!(res, r#"{"req":"dfu.status","off":true}"#);
}
Expand All @@ -290,7 +281,8 @@ mod tests {

#[test]
fn test_status() {
let (res, _) = serde_json_core::from_str::<res::Status>(r#"{
let (res, _) = serde_json_core::from_str::<res::Status>(
r#"{
"mode": "ready",
"status": "successfully downloaded",
"on": true,
Expand All @@ -306,7 +298,9 @@ mod tests {
"source": "stm32-new-firmware.bin",
"type": "firmware"
}
}"#).unwrap();
}"#,
)
.unwrap();

assert_eq!(res.mode, res::StatusMode::Ready);
assert_eq!(res.status.unwrap(), "successfully downloaded");
Expand All @@ -322,4 +316,4 @@ mod tests {
assert_eq!(body.source.unwrap(), "stm32-new-firmware.bin");
assert_eq!(body.bin_type.unwrap(), "firmware");
}
}
}
16 changes: 11 additions & 5 deletions src/hub.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,10 @@ impl<'a, IOM: Write<SevenBitAddress> + Read<SevenBitAddress>, const BS: usize> H

/// The [hub.get](https://dev.blues.io/api-reference/notecard-api/hub-requests/#hub-get) request
/// retrieves the current Notehub configuration for the Natecard.
pub fn get(self, delay: &mut impl DelayMs<u16>) -> Result<FutureResponse<'a, res::Hub, IOM, BS>, NoteError> {
pub fn get(
self,
delay: &mut impl DelayMs<u16>,
) -> Result<FutureResponse<'a, res::Hub, IOM, BS>, NoteError> {
self.note.request_raw(delay, b"{\"req\":\"hub.get\"}\n")?;
Ok(FutureResponse::from(self.note))
}
Expand Down Expand Up @@ -88,10 +91,13 @@ impl<'a, IOM: Write<SevenBitAddress> + Read<SevenBitAddress>, const BS: usize> H
delay: &mut impl DelayMs<u16>,
allow: bool,
) -> Result<FutureResponse<'a, res::Empty, IOM, BS>, NoteError> {
self.note.request(delay, req::HubSync {
req: "hub.sync",
allow: if allow { Some(true) } else { None }
})?;
self.note.request(
delay,
req::HubSync {
req: "hub.sync",
allow: if allow { Some(true) } else { None },
},
)?;

Ok(FutureResponse::from(self.note))
}
Expand Down
37 changes: 26 additions & 11 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,10 @@ use heapless::{String, Vec};
use serde::{de::DeserializeOwned, Deserialize, Serialize};

pub mod card;
pub mod dfu;
pub mod hub;
pub mod note;
pub mod dfu;
pub mod web;

/// Delay between polling for new response.
const RESPONSE_DELAY: u16 = 25;
Expand Down Expand Up @@ -115,6 +116,18 @@ impl NoteError {
s.push_str(msg).ok();
NoteError::DeserError(s)
}

pub fn string_err(_e: ()) -> NoteError {
NoteError::BufOverflow
}
}

pub(crate) fn str_string<const N: usize>(
a: Option<&str>,
) -> Result<Option<heapless::String<N>>, NoteError> {
a.map(heapless::String::try_from)
.transpose()
.map_err(NoteError::string_err)
}

#[derive(Deserialize, defmt::Format)]
Expand Down Expand Up @@ -572,16 +585,18 @@ impl<
"response is error response, parsing error..: {}",
core::str::from_utf8(&body).unwrap_or("[invalid utf-8]")
);
Err(serde_json_core::from_slice::<NotecardError>(body).map_or_else(
|_| {
error!(
"failed to deserialize: {}",
core::str::from_utf8(&body).unwrap_or("[invalid utf-8]")
);
NoteError::new_desererror(&body)
},
|(e, _)| NoteError::from(e),
))
Err(
serde_json_core::from_slice::<NotecardError>(body).map_or_else(
|_| {
error!(
"failed to deserialize: {}",
core::str::from_utf8(&body).unwrap_or("[invalid utf-8]")
);
NoteError::new_desererror(&body)
},
|(e, _)| NoteError::from(e),
),
)
}
Some(body) => {
trace!("response is regular, parsing..");
Expand Down
Loading
Loading