mirror of
https://github.com/solokeys/solo2.git
synced 2026-06-20 13:16:13 -07:00
cargo: fix fmt and clippy
This commit is contained in:
@@ -117,3 +117,36 @@ jobs:
|
||||
override: true
|
||||
- name: Build
|
||||
run: cargo build --release
|
||||
|
||||
lint:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- name: Install Linux build dependencies
|
||||
shell: bash
|
||||
run: |
|
||||
apt-get update && apt-get install sudo
|
||||
sudo apt update -y -qq && sudo apt install -y -qq llvm libc6-dev-i386 libclang-dev build-essential clang
|
||||
- uses: fiam/arm-none-eabi-gcc@v1.0.4
|
||||
with:
|
||||
release: "9-2020-q2"
|
||||
- uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
profile: minimal
|
||||
toolchain: "1.94"
|
||||
target: thumbv8m.main-none-eabi
|
||||
override: true
|
||||
components: rustfmt, clippy
|
||||
- name: cargo fmt --check
|
||||
run: cargo fmt --all --check
|
||||
- name: cargo clippy (host)
|
||||
run: cargo clippy --all-targets -- -D warnings
|
||||
- name: cargo clippy (lpc55, board-lpcxpresso55)
|
||||
working-directory: runners/lpc55
|
||||
run: cargo clippy --release --features board-lpcxpresso55
|
||||
- name: cargo clippy (lpc55, board-solo2)
|
||||
working-directory: runners/lpc55
|
||||
run: cargo clippy --release --features board-solo2
|
||||
- name: cargo clippy (lpc55, provisioner)
|
||||
working-directory: runners/lpc55
|
||||
run: cargo clippy --release --features board-lpcxpresso55,provisioner-app,admin-app,provisioner-app/test-attestation
|
||||
|
||||
+156
-182
File diff suppressed because it is too large
Load Diff
@@ -2,8 +2,4 @@
|
||||
|
||||
pub mod device;
|
||||
|
||||
pub use device::{
|
||||
FM11NC08,
|
||||
Configuration,
|
||||
Register,
|
||||
};
|
||||
pub use device::{Configuration, FM11NC08, Register};
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#![no_std]
|
||||
|
||||
pub mod ndef;
|
||||
pub use ndef::*;
|
||||
pub use ndef::*;
|
||||
|
||||
@@ -1,32 +1,35 @@
|
||||
use iso7816::{Instruction, Status};
|
||||
use apdu_dispatch::app;
|
||||
use apdu_dispatch::app::{CommandView, Interface, VecView};
|
||||
use iso7816::{Instruction, Status};
|
||||
|
||||
pub struct App<'a>{
|
||||
reader: &'a [u8]
|
||||
pub struct App<'a> {
|
||||
reader: &'a [u8],
|
||||
}
|
||||
|
||||
impl<'a> Default for App<'a> {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> App<'a> {
|
||||
pub const CAPABILITY_CONTAINER: [u8; 15] = [
|
||||
0x00, 0x0f, /* CCEN_HI, CCEN_LOW */
|
||||
0x20, /* VERSION */
|
||||
0x20, /* VERSION */
|
||||
0x00, 0x7f, /* MLe_HI, MLe_LOW */
|
||||
0x00, 0x7f, /* MLc_HI, MLc_LOW */
|
||||
/* TLV */
|
||||
0x04,0x06,
|
||||
0xe1,0x04,
|
||||
0x00,0x7f,
|
||||
0x00,0x00,
|
||||
0x04, 0x06, 0xe1, 0x04, 0x00, 0x7f, 0x00, 0x00,
|
||||
];
|
||||
|
||||
// Externally crafted NDEF URL for "https://solokeys.com/"
|
||||
pub const NDEF : [u8; 20] = [
|
||||
0x00, 0x12, 0xd1, 0x01, 0x0e, 0x55, 0x04, 0x73, 0x6f, 0x6c,
|
||||
0x6f, 0x6b, 0x65, 0x79, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x2f
|
||||
pub const NDEF: [u8; 20] = [
|
||||
0x00, 0x12, 0xd1, 0x01, 0x0e, 0x55, 0x04, 0x73, 0x6f, 0x6c, 0x6f, 0x6b, 0x65, 0x79, 0x73,
|
||||
0x2e, 0x63, 0x6f, 0x6d, 0x2f,
|
||||
];
|
||||
|
||||
pub fn new() -> App<'a> {
|
||||
App{
|
||||
App {
|
||||
reader: &Self::NDEF,
|
||||
}
|
||||
}
|
||||
@@ -39,24 +42,31 @@ impl<'a> iso7816::App for App<'a> {
|
||||
}
|
||||
|
||||
impl<'a> app::App for App<'a> {
|
||||
|
||||
fn select(&mut self, _interface: Interface, _apdu: CommandView<'_>, _reply: &mut VecView<u8>) -> app::Result {
|
||||
fn select(
|
||||
&mut self,
|
||||
_interface: Interface,
|
||||
_apdu: CommandView<'_>,
|
||||
_reply: &mut VecView<u8>,
|
||||
) -> app::Result {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn deselect(&mut self) {}
|
||||
|
||||
fn call(&mut self, _interface: Interface, apdu: CommandView<'_>, reply: &mut VecView<u8>) -> app::Result {
|
||||
fn call(
|
||||
&mut self,
|
||||
_interface: Interface,
|
||||
apdu: CommandView<'_>,
|
||||
reply: &mut VecView<u8>,
|
||||
) -> app::Result {
|
||||
let instruction = apdu.instruction();
|
||||
let p1 = apdu.p1;
|
||||
let p2 = apdu.p2;
|
||||
let expected = apdu.expected();
|
||||
let payload = apdu.data();
|
||||
|
||||
|
||||
match instruction {
|
||||
Instruction::Select => {
|
||||
|
||||
if payload.starts_with(&[0xE1u8, 0x03]) {
|
||||
self.reader = &Self::CAPABILITY_CONTAINER;
|
||||
Ok(())
|
||||
@@ -69,24 +79,20 @@ impl<'a> app::App for App<'a> {
|
||||
}
|
||||
Instruction::ReadBinary => {
|
||||
let offset = (((p1 & 0xef) as usize) << 8) | p2 as usize;
|
||||
let len_to_read =
|
||||
if expected as usize > (self.reader.len() - offset) {
|
||||
self.reader.len() - offset
|
||||
} else {
|
||||
if expected > 0 {
|
||||
expected as usize
|
||||
} else {
|
||||
self.reader.len() - offset
|
||||
}
|
||||
};
|
||||
let len_to_read = if expected > (self.reader.len() - offset) {
|
||||
self.reader.len() - offset
|
||||
} else if expected > 0 {
|
||||
expected
|
||||
} else {
|
||||
self.reader.len() - offset
|
||||
};
|
||||
|
||||
reply.extend_from_slice(& self.reader[offset .. offset + len_to_read]).ok();
|
||||
reply
|
||||
.extend_from_slice(&self.reader[offset..offset + len_to_read])
|
||||
.ok();
|
||||
Ok(())
|
||||
}
|
||||
_ => {
|
||||
Err(Status::ConditionsOfUseNotSatisfied)
|
||||
}
|
||||
_ => Err(Status::ConditionsOfUseNotSatisfied),
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use core::mem::MaybeUninit;
|
||||
|
||||
use apdu_dispatch::interchanges;
|
||||
use defmt::{info, debug};
|
||||
use defmt::{debug, info};
|
||||
use embedded_time::duration::Milliseconds;
|
||||
use heapless::Vec;
|
||||
use interchange;
|
||||
@@ -39,11 +39,13 @@ type WtxGranted = bool;
|
||||
type Nad = Option<u8>;
|
||||
type Cid = Option<u8>;
|
||||
|
||||
#[derive(Copy,Clone)]
|
||||
// Names follow ISO 14443-4 block type terminology (I-Block, R-Block, S-Block).
|
||||
#[allow(clippy::enum_variant_names)]
|
||||
#[derive(Copy, Clone)]
|
||||
enum Block {
|
||||
IBlock(BlockNum, Nad, Cid, Chaining, Offset),
|
||||
RBlock(BlockNum, Cid, Ack, Offset),
|
||||
SBlock(Cid, WtxGranted, ),
|
||||
SBlock(Cid, WtxGranted),
|
||||
}
|
||||
|
||||
impl Block {
|
||||
@@ -63,7 +65,6 @@ impl Block {
|
||||
};
|
||||
|
||||
if (header & 0xc2) == 0x02 {
|
||||
|
||||
// NAD included
|
||||
let nad = if (header & 0x4) != 0 {
|
||||
offset += 1;
|
||||
@@ -77,7 +78,7 @@ impl Block {
|
||||
};
|
||||
Block::IBlock(block_num, nad, cid, flag, offset)
|
||||
} else if (header & 0xe2) == 0xa2 {
|
||||
// Ack or Nack
|
||||
// Ack or Nack
|
||||
Block::RBlock(block_num, cid, !flag, offset)
|
||||
} else {
|
||||
Block::SBlock(cid, (0x30 & header) == 0x30)
|
||||
@@ -106,11 +107,11 @@ pub struct Iso14443<'pipe, DEV: nfc::Device> {
|
||||
|
||||
impl<'pipe, DEV> Iso14443<'pipe, DEV>
|
||||
where
|
||||
DEV: nfc::Device
|
||||
DEV: nfc::Device,
|
||||
{
|
||||
pub fn new(device: DEV, interchange: interchanges::Requester<'pipe>) -> Self {
|
||||
Self {
|
||||
device: device,
|
||||
device,
|
||||
state: Iso14443State::Receiving,
|
||||
cid: None,
|
||||
|
||||
@@ -119,7 +120,7 @@ where
|
||||
|
||||
buffer: interchanges::Data::new(),
|
||||
|
||||
interchange: interchange,
|
||||
interchange,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -133,23 +134,17 @@ where
|
||||
length += 1;
|
||||
}
|
||||
|
||||
self.device.send(
|
||||
& packet[0 .. length]
|
||||
).ok();
|
||||
self.device.send(&packet[0..length]).ok();
|
||||
}
|
||||
|
||||
fn send_wtx(&mut self) {
|
||||
// Rule 9. The PICC is allowed to send an S(WTX) block instead of an I-block or an R(ACK) block.
|
||||
match self.cid {
|
||||
Some(cid) => {
|
||||
self.device.send(
|
||||
&[0xfa, cid, 0x01]
|
||||
).ok();
|
||||
self.device.send(&[0xfa, cid, 0x01]).ok();
|
||||
}
|
||||
_ => {
|
||||
self.device.send(
|
||||
&[0xf2, 0x01]
|
||||
).ok();
|
||||
self.device.send(&[0xf2, 0x01]).ok();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -160,13 +155,12 @@ where
|
||||
let block_header = Block::new(packet);
|
||||
match block_header {
|
||||
Block::IBlock(_block_num, _nad, _cid, chaining, offset) => {
|
||||
|
||||
if self.state != Iso14443State::Receiving {
|
||||
self.buffer.clear();
|
||||
}
|
||||
self.state = Iso14443State::Receiving;
|
||||
|
||||
self.buffer.extend_from_slice(& packet[offset .. ]).ok();
|
||||
self.buffer.extend_from_slice(&packet[offset..]).ok();
|
||||
|
||||
// Rule D. When an I-block is received (independent of its block number),
|
||||
// the PICC shall toggle its block number before sending a block.
|
||||
@@ -181,10 +175,8 @@ where
|
||||
self.wtx_requested = false;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
}
|
||||
Block::RBlock(block_num, _cid, ack, _offset) => {
|
||||
|
||||
// Rule 11. When an R(ACK) or an R(NAK) block is received,
|
||||
// if its block number is equal to the PICC’s current block
|
||||
// number, the last block shall be re-transmitted.
|
||||
@@ -193,14 +185,12 @@ where
|
||||
Iso14443State::Transmitting(last_frame_range, _remaining_data_range) => {
|
||||
info!("Retransmission requested..");
|
||||
self.send_frame(
|
||||
&Vec::from_slice(
|
||||
&self.buffer[last_frame_range]
|
||||
).unwrap()
|
||||
).ok();
|
||||
&Vec::from_slice(&self.buffer[last_frame_range]).unwrap(),
|
||||
)
|
||||
.ok();
|
||||
}
|
||||
_ => {
|
||||
info!("No recent transmissions! NAK");
|
||||
|
||||
}
|
||||
}
|
||||
return Err(SourceError::NoActivity);
|
||||
@@ -212,41 +202,41 @@ where
|
||||
self.ack();
|
||||
return Err(SourceError::NoActivity);
|
||||
} else {
|
||||
|
||||
// Rule 13. When an R(ACK) block is received,
|
||||
// if its block number is not equal to the PICC’s current block number,
|
||||
// and the PICC is in chaining, chaining shall be continued.
|
||||
|
||||
match self.state.clone() {
|
||||
Iso14443State::Transmitting(_last_frame_range, remaining_data_range) => {
|
||||
// Rule E. When an R(ACK) block with a block number not equal
|
||||
// to the current PICC’s block number is received, the
|
||||
// PICC shall toggle its block number before sending a block.
|
||||
self.block_num = !self.block_num;
|
||||
|
||||
if remaining_data_range.len() == 0 {
|
||||
info!("Error, recieved ack when this is no more data.");
|
||||
self.ack();
|
||||
self.reset_state();
|
||||
return Err(SourceError::NoActivity);
|
||||
}
|
||||
let msg = &self.buffer[remaining_data_range.clone()];
|
||||
let (next_frame, data_used) = self.construct_iblock(msg);
|
||||
self.send_frame(&next_frame).ok();
|
||||
if data_used != remaining_data_range.len() {
|
||||
info!("Next frame");
|
||||
self.state = Iso14443State::Transmitting(
|
||||
remaining_data_range.start .. remaining_data_range.start + data_used,
|
||||
remaining_data_range.start + data_used .. self.buffer.len(),
|
||||
)
|
||||
} else {
|
||||
info!("Last frame sent!");
|
||||
self.state = Iso14443State::Transmitting(
|
||||
remaining_data_range.start .. remaining_data_range.start + data_used,
|
||||
self.buffer.len() .. self.buffer.len()
|
||||
)
|
||||
}
|
||||
// Rule E. When an R(ACK) block with a block number not equal
|
||||
// to the current PICC’s block number is received, the
|
||||
// PICC shall toggle its block number before sending a block.
|
||||
self.block_num = !self.block_num;
|
||||
|
||||
if remaining_data_range.is_empty() {
|
||||
info!("Error, recieved ack when this is no more data.");
|
||||
self.ack();
|
||||
self.reset_state();
|
||||
return Err(SourceError::NoActivity);
|
||||
}
|
||||
let msg = &self.buffer[remaining_data_range.clone()];
|
||||
let (next_frame, data_used) = self.construct_iblock(msg);
|
||||
self.send_frame(&next_frame).ok();
|
||||
if data_used != remaining_data_range.len() {
|
||||
info!("Next frame");
|
||||
self.state = Iso14443State::Transmitting(
|
||||
remaining_data_range.start
|
||||
..remaining_data_range.start + data_used,
|
||||
remaining_data_range.start + data_used..self.buffer.len(),
|
||||
)
|
||||
} else {
|
||||
info!("Last frame sent!");
|
||||
self.state = Iso14443State::Transmitting(
|
||||
remaining_data_range.start
|
||||
..remaining_data_range.start + data_used,
|
||||
self.buffer.len()..self.buffer.len(),
|
||||
)
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
// (None, Iso14443State::Idle)
|
||||
@@ -254,7 +244,6 @@ where
|
||||
self.ack();
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
Err(SourceError::NoActivity)
|
||||
}
|
||||
@@ -268,9 +257,7 @@ where
|
||||
self.wtx_requested = false;
|
||||
} else {
|
||||
info!("Deselected.");
|
||||
self.device.send(
|
||||
&[0xc2]
|
||||
).ok();
|
||||
self.device.send(&[0xc2]).ok();
|
||||
self.reset_state();
|
||||
}
|
||||
Err(SourceError::NoActivity)
|
||||
@@ -278,7 +265,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
pub fn borrow<F: Fn(&mut DEV) -> () >(&mut self, func: F) {
|
||||
pub fn borrow<F: Fn(&mut DEV)>(&mut self, func: F) {
|
||||
func(&mut self.device);
|
||||
}
|
||||
|
||||
@@ -292,7 +279,7 @@ where
|
||||
|
||||
if let Some(cid) = self.cid {
|
||||
frame.push(cid).ok();
|
||||
frame[0]|= 0x08;
|
||||
frame[0] |= 0x08;
|
||||
header_length += 1;
|
||||
}
|
||||
|
||||
@@ -300,7 +287,7 @@ where
|
||||
let frame_size: usize = self.device.frame_size() - 2;
|
||||
let payload_len = core::cmp::min(frame_size - header_length, data.len());
|
||||
|
||||
frame.extend_from_slice(&data[0 .. payload_len]).ok();
|
||||
frame.extend_from_slice(&data[0..payload_len]).ok();
|
||||
|
||||
if payload_len != data.len() {
|
||||
// set chaining bit.
|
||||
@@ -330,24 +317,23 @@ where
|
||||
info!("State::NewSession");
|
||||
self.reset_state();
|
||||
x
|
||||
},
|
||||
}
|
||||
Ok(nfc::State::Continue(x)) => x,
|
||||
Err(nfc::Error::NewSession) => {
|
||||
info!("Error::NewSession");
|
||||
self.reset_state();
|
||||
return Err(SourceError::NoActivity)
|
||||
},
|
||||
return Err(SourceError::NoActivity);
|
||||
}
|
||||
_ => {
|
||||
// info!("nop");
|
||||
return Err(SourceError::NoActivity)
|
||||
return Err(SourceError::NoActivity);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
assert!(packet_len > 0);
|
||||
|
||||
// let packet = &self.packet;
|
||||
self.handle_block(&packet[.. packet_len as usize])?;
|
||||
self.handle_block(&packet[..packet_len as usize])?;
|
||||
|
||||
debug!(">>");
|
||||
debug!("{=[u8]:x}", &self.buffer);
|
||||
@@ -355,10 +341,8 @@ where
|
||||
|
||||
let command = interchanges::Data::from_slice(&self.buffer);
|
||||
self.buffer.clear();
|
||||
if command.is_ok() {
|
||||
if self.interchange.request(
|
||||
command.unwrap()
|
||||
).is_ok() {
|
||||
if let Ok(command) = command {
|
||||
if self.interchange.request(command).is_ok() {
|
||||
Ok(())
|
||||
} else {
|
||||
// Would be better to try canceling and taking on this apdu.
|
||||
@@ -368,10 +352,10 @@ where
|
||||
} else {
|
||||
let (frame, _) = self.construct_iblock(
|
||||
// UnspecifiedCheckingError
|
||||
&[0x6F, 0x00]
|
||||
&[0x6F, 0x00],
|
||||
);
|
||||
|
||||
self.send_frame( &frame )?;
|
||||
self.send_frame(&frame)?;
|
||||
Err(SourceError::NoActivity)
|
||||
}
|
||||
}
|
||||
@@ -382,7 +366,6 @@ where
|
||||
|
||||
pub fn poll(&mut self) -> Iso14443Status {
|
||||
if interchange::State::Responded == self.interchange.state() {
|
||||
|
||||
// important to wait on wtx reply from the reader.
|
||||
// If it wasn't sent, or we start replying before it's received,
|
||||
// then we could "double-send", which isn't permitted in iso14443-4.
|
||||
@@ -401,24 +384,19 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if let Some(msg) = self.interchange.take_response() {
|
||||
// if let Some(last_iblock_recv) = self.last_iblock_recv {
|
||||
info!("send!");
|
||||
let (frame, data_used) = self.construct_iblock(&msg);
|
||||
self.send_frame(
|
||||
&frame
|
||||
).ok();
|
||||
if data_used != msg.len() {
|
||||
info!("chaining response!");
|
||||
self.buffer = msg;
|
||||
self.state = Iso14443State::Transmitting(
|
||||
0 .. data_used,
|
||||
data_used .. self.buffer.len()
|
||||
);
|
||||
}
|
||||
info!("send!");
|
||||
let (frame, data_used) = self.construct_iblock(&msg);
|
||||
self.send_frame(&frame).ok();
|
||||
if data_used != msg.len() {
|
||||
info!("chaining response!");
|
||||
self.buffer = msg;
|
||||
self.state =
|
||||
Iso14443State::Transmitting(0..data_used, data_used..self.buffer.len());
|
||||
}
|
||||
// } else {
|
||||
// info!("session was dropped! dropping response.");
|
||||
// info!("session was dropped! dropping response.");
|
||||
// }
|
||||
}
|
||||
Iso14443Status::Idle
|
||||
@@ -433,10 +411,9 @@ where
|
||||
}
|
||||
|
||||
pub fn poll_wait_extensions(&mut self) -> Iso14443Status {
|
||||
|
||||
if self.wtx_requested {
|
||||
info!("warning: still awaiting wtx response.");
|
||||
return Iso14443Status::ReceivedData(Milliseconds(32))
|
||||
return Iso14443Status::ReceivedData(Milliseconds(32));
|
||||
}
|
||||
|
||||
match self.interchange.state() {
|
||||
@@ -454,22 +431,21 @@ where
|
||||
Iso14443Status::Idle
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// Write response code + APDU
|
||||
fn send_frame(&mut self, buffer: &Iso14443Frame) -> Result<(), SourceError>
|
||||
{
|
||||
let r = self.device.send( buffer );
|
||||
if !r.is_ok() {
|
||||
fn send_frame(&mut self, buffer: &Iso14443Frame) -> Result<(), SourceError> {
|
||||
let r = self.device.send(buffer);
|
||||
if r.is_err() {
|
||||
// o!("FM11 not okay!");
|
||||
return Err(SourceError::NoActivity);
|
||||
}
|
||||
|
||||
debug!("<{}< ",buffer.len());
|
||||
if buffer.len() > 0 { debug!("{=[u8]:x}", &buffer); }
|
||||
debug!("<{}< ", buffer.len());
|
||||
if !buffer.is_empty() {
|
||||
debug!("{=[u8]:x}", &buffer);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#![no_std]
|
||||
|
||||
pub mod types;
|
||||
pub mod traits;
|
||||
pub mod types;
|
||||
|
||||
pub mod iso14443;
|
||||
pub use iso14443::*;
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
pub mod nfc {
|
||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||
pub enum State {
|
||||
@@ -14,9 +13,9 @@ pub mod nfc {
|
||||
pub trait Device {
|
||||
fn read(&mut self, buf: &mut [u8]) -> Result<State, Error>;
|
||||
|
||||
fn send(&mut self,buf: &[u8]) -> Result<(), Error>;
|
||||
fn send(&mut self, buf: &[u8]) -> Result<(), Error>;
|
||||
|
||||
fn frame_size(&self) -> usize;
|
||||
// { 128 }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,16 +12,16 @@ use core::convert::TryFrom;
|
||||
use littlefs2::driver::Storage as LfsStorage;
|
||||
use littlefs2::path::PathBuf;
|
||||
|
||||
use apdu_dispatch::app::{self, CommandView, Interface, VecView};
|
||||
use defmt::info;
|
||||
use heapless::Vec;
|
||||
use iso7816::{Instruction, Status};
|
||||
use trussed::{
|
||||
Client as TrussedClient,
|
||||
store::{self, Store},
|
||||
syscall,
|
||||
types::Location,
|
||||
Client as TrussedClient,
|
||||
};
|
||||
use heapless::Vec;
|
||||
use iso7816::{Status, Instruction};
|
||||
use apdu_dispatch::app::{self, CommandView, Interface, VecView};
|
||||
|
||||
use lpc55_hal as hal;
|
||||
|
||||
@@ -136,27 +136,27 @@ where
|
||||
/// Build a serialized trussed secret key: flags(2 BE) + kind(2 BE) + material(32)
|
||||
fn serialize_secret_key(kind_code: u16, material: &[u8; 32]) -> heapless::Vec<u8, 36> {
|
||||
let mut bytes: heapless::Vec<u8, 36> = heapless::Vec::new();
|
||||
bytes.extend_from_slice(&KEY_FLAGS_LOCAL_SENSITIVE.to_be_bytes()).unwrap();
|
||||
bytes
|
||||
.extend_from_slice(&KEY_FLAGS_LOCAL_SENSITIVE.to_be_bytes())
|
||||
.unwrap();
|
||||
bytes.extend_from_slice(&kind_code.to_be_bytes()).unwrap();
|
||||
bytes.extend_from_slice(material).unwrap();
|
||||
bytes
|
||||
}
|
||||
|
||||
fn handle(
|
||||
&mut self,
|
||||
command: CommandView<'_>,
|
||||
reply: &mut VecView<u8>,
|
||||
) -> app::Result {
|
||||
fn handle(&mut self, command: CommandView<'_>, reply: &mut VecView<u8>) -> app::Result {
|
||||
match command.instruction() {
|
||||
Instruction::Select => self.do_select(command, reply),
|
||||
Instruction::WriteBinary => {
|
||||
match self.selected_buffer {
|
||||
SelectedBuffer::Filename => {
|
||||
self.buffer_filename.extend_from_slice(command.data()).unwrap()
|
||||
}
|
||||
SelectedBuffer::File => {
|
||||
self.buffer_file_contents.extend_from_slice(command.data()).unwrap()
|
||||
}
|
||||
SelectedBuffer::Filename => self
|
||||
.buffer_filename
|
||||
.extend_from_slice(command.data())
|
||||
.unwrap(),
|
||||
SelectedBuffer::File => self
|
||||
.buffer_file_contents
|
||||
.extend_from_slice(command.data())
|
||||
.unwrap(),
|
||||
};
|
||||
Ok(())
|
||||
}
|
||||
@@ -327,7 +327,9 @@ where
|
||||
}
|
||||
// Ed255 public key: no SENSITIVE flag
|
||||
let mut key_bytes: heapless::Vec<u8, 36> = heapless::Vec::new();
|
||||
key_bytes.extend_from_slice(&0x0000u16.to_be_bytes()).unwrap();
|
||||
key_bytes
|
||||
.extend_from_slice(&0x0000u16.to_be_bytes())
|
||||
.unwrap();
|
||||
key_bytes
|
||||
.extend_from_slice(&KEY_KIND_ED255.to_be_bytes())
|
||||
.unwrap();
|
||||
@@ -344,10 +346,10 @@ where
|
||||
BootToBootrom => {
|
||||
use hal::traits::flash::WriteErase;
|
||||
let flash = unsafe { hal::peripherals::flash::Flash::steal() }
|
||||
.enabled(&mut unsafe {
|
||||
hal::peripherals::syscon::Syscon::steal()
|
||||
});
|
||||
hal::drivers::flash::FlashGordon::new(flash).erase_page(0).ok();
|
||||
.enabled(&mut unsafe { hal::peripherals::syscon::Syscon::steal() });
|
||||
hal::drivers::flash::FlashGordon::new(flash)
|
||||
.erase_page(0)
|
||||
.ok();
|
||||
hal::raw::SCB::sys_reset()
|
||||
}
|
||||
#[cfg(feature = "test-attestation")]
|
||||
@@ -364,11 +366,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
fn do_select(
|
||||
&mut self,
|
||||
command: CommandView<'_>,
|
||||
_reply: &mut VecView<u8>,
|
||||
) -> app::Result {
|
||||
fn do_select(&mut self, command: CommandView<'_>, _reply: &mut VecView<u8>) -> app::Result {
|
||||
if command.data().starts_with(&TESTER_FILENAME_ID) {
|
||||
info!("select: filename buffer");
|
||||
self.selected_buffer = SelectedBuffer::Filename;
|
||||
|
||||
@@ -1,16 +1,14 @@
|
||||
use crate::hal;
|
||||
use hal::prelude::*;
|
||||
use crate::hal::{
|
||||
Adc,
|
||||
Enabled,
|
||||
Gpio,
|
||||
Iocon,
|
||||
drivers::{
|
||||
clocks::Clocks,
|
||||
pins::{self, Pin},
|
||||
},
|
||||
peripherals::adc::{self, ChannelType},
|
||||
Syscon,
|
||||
Pmc,
|
||||
drivers::{clocks::Clocks, pins::{self, Pin}},
|
||||
typestates::pin::{state, gpio:: direction},
|
||||
typestates::pin::{gpio::direction, state},
|
||||
Adc, Enabled, Gpio, Iocon, Pmc, Syscon,
|
||||
};
|
||||
use hal::prelude::*;
|
||||
|
||||
use defmt::info;
|
||||
|
||||
@@ -37,9 +35,9 @@ const ADC_VOLTAGE_HIGH: u16 = 12_700;
|
||||
|
||||
impl DynamicClockController {
|
||||
pub fn adc_configuration() -> adc::Config {
|
||||
let mut config: adc::Config = Default::default();
|
||||
config.conversion_delay = 96;
|
||||
config
|
||||
adc::Config {
|
||||
conversion_delay: 96,
|
||||
}
|
||||
}
|
||||
pub fn new(
|
||||
adc: Adc<hal::typestates::init_state::Enabled>,
|
||||
@@ -49,116 +47,131 @@ impl DynamicClockController {
|
||||
gpio: &mut Gpio<Enabled>,
|
||||
iocon: &mut Iocon<Enabled>,
|
||||
) -> DynamicClockController {
|
||||
|
||||
let signal_button = SignalPin::take().unwrap().into_gpio_pin(iocon, gpio).into_output_high();
|
||||
let signal_button = SignalPin::take()
|
||||
.unwrap()
|
||||
.into_gpio_pin(iocon, gpio)
|
||||
.into_output_high();
|
||||
|
||||
let adc = adc.release();
|
||||
|
||||
adc.ie.write(|w| w.fwmie0().set_bit());
|
||||
|
||||
adc.tctrl[ChannelType::Comparator as usize].write(|w| unsafe {
|
||||
w.hten().set_bit()
|
||||
.fifo_sel_a().fifo_sel_a_0()
|
||||
.fifo_sel_b().fifo_sel_b_0()
|
||||
.tcmd().bits(1)
|
||||
.tpri().bits(0)
|
||||
.tdly().bits(0)
|
||||
w.hten()
|
||||
.set_bit()
|
||||
.fifo_sel_a()
|
||||
.fifo_sel_a_0()
|
||||
.fifo_sel_b()
|
||||
.fifo_sel_b_0()
|
||||
.tcmd()
|
||||
.bits(1)
|
||||
.tpri()
|
||||
.bits(0)
|
||||
.tdly()
|
||||
.bits(0)
|
||||
});
|
||||
|
||||
adc.cmdl1.write(|w| unsafe { w.adch().bits(13) // 13 is internal 1v reference
|
||||
.ctype().ctype_0()
|
||||
.mode().mode_0() // 12 bit resolution
|
||||
} );
|
||||
adc.cmdl1.write(|w| unsafe {
|
||||
w.adch()
|
||||
.bits(13) // 13 is internal 1v reference
|
||||
.ctype()
|
||||
.ctype_0()
|
||||
.mode()
|
||||
.mode_0() // 12 bit resolution
|
||||
});
|
||||
|
||||
// shouldn't use more than 2^2 averages or compare seems to lock up
|
||||
adc.cmdh1.write(|w| unsafe { w.avgs().avgs_0() // average 2^2 samples
|
||||
.cmpen().bits(0b11) // compare repeatedly until true
|
||||
.loop_().bits(0) // no loop
|
||||
.next().bits(0) // no next command
|
||||
.sts().bits(2)
|
||||
} );
|
||||
adc.cmdh1.write(|w| unsafe {
|
||||
w.avgs()
|
||||
.avgs_0() // average 2^2 samples
|
||||
.cmpen()
|
||||
.bits(0b11) // compare repeatedly until true
|
||||
.loop_()
|
||||
.bits(0) // no loop
|
||||
.next()
|
||||
.bits(0) // no next command
|
||||
.sts()
|
||||
.bits(2)
|
||||
});
|
||||
|
||||
DynamicClockController {
|
||||
adc: adc,
|
||||
signal_button: signal_button,
|
||||
pmc: pmc,
|
||||
clocks: clocks,
|
||||
syscon: syscon,
|
||||
adc,
|
||||
signal_button,
|
||||
pmc,
|
||||
clocks,
|
||||
syscon,
|
||||
decrease_count: 0,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn start_low_voltage_compare(&mut self, ) {
|
||||
self.adc.cv1.write(|w| unsafe {
|
||||
w.cvl().bits(0)
|
||||
.cvh().bits(ADC_VOLTAGE_LOW)
|
||||
});
|
||||
pub fn start_low_voltage_compare(&mut self) {
|
||||
self.adc
|
||||
.cv1
|
||||
.write(|w| unsafe { w.cvl().bits(0).cvh().bits(ADC_VOLTAGE_LOW) });
|
||||
|
||||
self.adc.swtrig.write(|w| unsafe {w.bits(0)});
|
||||
self.adc.swtrig.write(|w| unsafe {w.bits(1<<(ChannelType::Comparator as usize))});
|
||||
self.adc.swtrig.write(|w| unsafe { w.bits(0) });
|
||||
self.adc
|
||||
.swtrig
|
||||
.write(|w| unsafe { w.bits(1 << (ChannelType::Comparator as usize)) });
|
||||
}
|
||||
|
||||
pub fn start_high_voltage_compare(&mut self) {
|
||||
self.adc
|
||||
.cv1
|
||||
.write(|w| unsafe { w.cvl().bits(ADC_VOLTAGE_HIGH).cvh().bits(0x7ff8) });
|
||||
|
||||
|
||||
pub fn start_high_voltage_compare(&mut self, ) {
|
||||
self.adc.cv1.write(|w| unsafe {
|
||||
w.cvl().bits(ADC_VOLTAGE_HIGH)
|
||||
.cvh().bits(0x7ff8)
|
||||
});
|
||||
|
||||
self.adc.swtrig.write(|w| unsafe {w.bits(0)});
|
||||
self.adc.swtrig.write(|w| unsafe {w.bits(1<<(ChannelType::Comparator as usize))});
|
||||
self.adc.swtrig.write(|w| unsafe { w.bits(0) });
|
||||
self.adc
|
||||
.swtrig
|
||||
.write(|w| unsafe { w.bits(1 << (ChannelType::Comparator as usize)) });
|
||||
}
|
||||
|
||||
fn decrease_clock(&mut self,){
|
||||
fn decrease_clock(&mut self) {
|
||||
#[cfg(feature = "enable-clock-controller-signal-pin")]
|
||||
self.signal_button.set_low().ok();
|
||||
|
||||
let requirements = hal::ClockRequirements::default()
|
||||
.system_frequency(12.MHz());
|
||||
let requirements = hal::ClockRequirements::default().system_frequency(12.MHz());
|
||||
|
||||
self.clocks = unsafe { requirements.reconfigure(self.clocks, &mut self.pmc, &mut self.syscon) };
|
||||
self.clocks =
|
||||
unsafe { requirements.reconfigure(self.clocks, &mut self.pmc, &mut self.syscon) };
|
||||
self.decrease_count += 1;
|
||||
}
|
||||
|
||||
fn increase_clock(&mut self,){
|
||||
fn increase_clock(&mut self) {
|
||||
#[cfg(feature = "enable-clock-controller-signal-pin")]
|
||||
self.signal_button.set_high().ok();
|
||||
|
||||
let requirements = if self.decrease_count > 2 {
|
||||
// opt for slower freq if there's too many dips in power
|
||||
hal::ClockRequirements::default()
|
||||
.system_frequency(48.MHz())
|
||||
hal::ClockRequirements::default().system_frequency(48.MHz())
|
||||
} else {
|
||||
hal::ClockRequirements::default()
|
||||
.system_frequency(96.MHz())
|
||||
hal::ClockRequirements::default().system_frequency(96.MHz())
|
||||
};
|
||||
|
||||
self.clocks = unsafe { requirements.reconfigure(self.clocks, &mut self.pmc, &mut self.syscon) };
|
||||
self.clocks =
|
||||
unsafe { requirements.reconfigure(self.clocks, &mut self.pmc, &mut self.syscon) };
|
||||
}
|
||||
|
||||
/// Used for debugging to tune the ADC points
|
||||
pub fn evaluate(&mut self){
|
||||
pub fn evaluate(&mut self) {
|
||||
info!("status = {:02X}", self.adc.stat.read().bits());
|
||||
self.adc.cmdh1.modify(|_,w| unsafe { w
|
||||
.cmpen().bits(0)
|
||||
} );
|
||||
for _ in 0 .. 50 {
|
||||
self.adc.swtrig.write(|w| unsafe {w.bits(0)});
|
||||
self.adc.swtrig.write(|w| unsafe {w.bits(1<<(ChannelType::Comparator as usize))});
|
||||
while self.adc.fctrl[0].read().fcount().bits() == 0 {
|
||||
}
|
||||
self.adc.cmdh1.modify(|_, w| unsafe { w.cmpen().bits(0) });
|
||||
for _ in 0..50 {
|
||||
self.adc.swtrig.write(|w| unsafe { w.bits(0) });
|
||||
self.adc
|
||||
.swtrig
|
||||
.write(|w| unsafe { w.bits(1 << (ChannelType::Comparator as usize)) });
|
||||
while self.adc.fctrl[0].read().fcount().bits() == 0 {}
|
||||
let result = self.adc.resfifo[0].read().bits();
|
||||
let _sample = (result & 0xffff) as u16;
|
||||
info!("Vref bias = {}", _sample);
|
||||
}
|
||||
self.adc.cmdh1.modify(|_,w| unsafe { w
|
||||
.cmpen().bits(0b11)
|
||||
} );
|
||||
self.adc
|
||||
.cmdh1
|
||||
.modify(|_, w| unsafe { w.cmpen().bits(0b11) });
|
||||
}
|
||||
|
||||
pub fn handle(&mut self) {
|
||||
|
||||
let count = self.adc.fctrl[0].read().fcount().bits();
|
||||
if count == 0 {
|
||||
info!("Error: no sample in fifo!");
|
||||
@@ -169,16 +182,17 @@ impl DynamicClockController {
|
||||
info!("Got >1 sample!");
|
||||
}
|
||||
let result = self.adc.resfifo[0].read().bits();
|
||||
if (result & 0x80000000) == 0 {
|
||||
if (result & 0x80000000) == 0 {
|
||||
panic!("underflow on compare");
|
||||
}
|
||||
let sample = (result & 0xffff) as u16;
|
||||
|
||||
self.adc.ctrl.modify(|_,w| { w.rstfifo0().set_bit().rstfifo1().set_bit() });
|
||||
self.adc
|
||||
.ctrl
|
||||
.modify(|_, w| w.rstfifo0().set_bit().rstfifo1().set_bit());
|
||||
// info!("handle ADC: {}. status: {}", sample, self.adc.stat.read().bits());
|
||||
#[cfg(not(feature = "no-clock-controller"))]
|
||||
{
|
||||
|
||||
if sample < ADC_VOLTAGE_HIGH {
|
||||
// info!("Voltage is high. increase clock rate!");
|
||||
self.increase_clock();
|
||||
|
||||
@@ -19,15 +19,9 @@ pub mod solo2;
|
||||
#[cfg(feature = "solo2")]
|
||||
pub use solo2 as specifics;
|
||||
|
||||
pub use shared::{
|
||||
CLOCK_FREQ,
|
||||
Reboot,
|
||||
};
|
||||
pub use shared::{Reboot, CLOCK_FREQ};
|
||||
|
||||
pub use specifics::{
|
||||
button::ThreeButtons,
|
||||
led::RgbLed,
|
||||
};
|
||||
pub use specifics::{button::ThreeButtons, led::RgbLed};
|
||||
|
||||
pub mod clock_controller;
|
||||
pub mod nfc;
|
||||
|
||||
@@ -1,22 +1,11 @@
|
||||
use core::convert::Infallible;
|
||||
use crate::hal::drivers::timer;
|
||||
use crate::hal::peripherals::ctimer;
|
||||
use crate::hal::traits::wg::digital::v2::InputPin;
|
||||
use crate::hal::traits::wg::timer::CountDown;
|
||||
use crate::hal::{
|
||||
self,
|
||||
drivers::pins,
|
||||
typestates::pin,
|
||||
};
|
||||
use crate::hal::drivers::timer;
|
||||
use crate::hal::peripherals::{
|
||||
ctimer,
|
||||
};
|
||||
use crate::traits::buttons::{
|
||||
Button,State,
|
||||
Press,Edge,
|
||||
};
|
||||
use crate::hal::typestates::{
|
||||
init_state,
|
||||
};
|
||||
use crate::hal::typestates::init_state;
|
||||
use crate::hal::{self, drivers::pins, typestates::pin};
|
||||
use crate::traits::buttons::{Button, Edge, Press, State};
|
||||
use core::convert::Infallible;
|
||||
use hal::time::DurationExtensions;
|
||||
pub type UserButtonPin = pins::Pio1_9;
|
||||
pub type WakeupButtonPin = pins::Pio1_18;
|
||||
@@ -29,8 +18,9 @@ pub type ThreeButtons = XpressoButtons<ctimer::Ctimer1<init_state::Enabled>>;
|
||||
// impl<P1,P2,P3, > TouchSensor<P1, P2, P3, >
|
||||
// where P1: PinId, P2: PinId, P3: PinId
|
||||
|
||||
pub struct XpressoButtons <CTIMER>
|
||||
where CTIMER: ctimer::Ctimer<init_state::Enabled>
|
||||
pub struct XpressoButtons<CTIMER>
|
||||
where
|
||||
CTIMER: ctimer::Ctimer<init_state::Enabled>,
|
||||
{
|
||||
last_state: State,
|
||||
user_button: UserButton,
|
||||
@@ -38,50 +28,55 @@ where CTIMER: ctimer::Ctimer<init_state::Enabled>
|
||||
timer: timer::Timer<CTIMER>,
|
||||
}
|
||||
|
||||
impl <CTIMER> XpressoButtons <CTIMER>
|
||||
where CTIMER: ctimer::Ctimer<init_state::Enabled>
|
||||
impl<CTIMER> XpressoButtons<CTIMER>
|
||||
where
|
||||
CTIMER: ctimer::Ctimer<init_state::Enabled>,
|
||||
{
|
||||
// pub fn new (timer: timer::Timer<CTIMER>, user_button: UserButton, wakeup_button: WakeupButton) -> XpressoButtons<CTIMER> {
|
||||
pub fn new (timer: timer::Timer<CTIMER>, gpio: &mut hal::Gpio<hal::Enabled>, iocon: &mut hal::Iocon<hal::Enabled>) -> XpressoButtons<CTIMER> {
|
||||
let user_button = UserButtonPin::take().unwrap().into_gpio_pin(iocon, gpio).into_input();
|
||||
let wakeup_button = WakeupButtonPin::take().unwrap().into_gpio_pin(iocon, gpio).into_input();
|
||||
pub fn new(
|
||||
timer: timer::Timer<CTIMER>,
|
||||
gpio: &mut hal::Gpio<hal::Enabled>,
|
||||
iocon: &mut hal::Iocon<hal::Enabled>,
|
||||
) -> XpressoButtons<CTIMER> {
|
||||
let user_button = UserButtonPin::take()
|
||||
.unwrap()
|
||||
.into_gpio_pin(iocon, gpio)
|
||||
.into_input();
|
||||
let wakeup_button = WakeupButtonPin::take()
|
||||
.unwrap()
|
||||
.into_gpio_pin(iocon, gpio)
|
||||
.into_input();
|
||||
let buts = State {
|
||||
a: user_button.is_high().ok().unwrap(),
|
||||
b: wakeup_button.is_high().ok().unwrap(),
|
||||
middle: wakeup_button.is_high().ok().unwrap(),
|
||||
};
|
||||
Self {
|
||||
user_button: user_button,
|
||||
wakeup_button: wakeup_button,
|
||||
user_button,
|
||||
wakeup_button,
|
||||
last_state: buts,
|
||||
timer: timer,
|
||||
timer,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<CTIMER> Press for XpressoButtons <CTIMER>
|
||||
where CTIMER: ctimer::Ctimer<init_state::Enabled>
|
||||
impl<CTIMER> Press for XpressoButtons<CTIMER>
|
||||
where
|
||||
CTIMER: ctimer::Ctimer<init_state::Enabled>,
|
||||
{
|
||||
|
||||
// A minimal button implementation for Xpresso
|
||||
fn is_pressed(&self, but: Button) -> bool {
|
||||
match but {
|
||||
Button::A=> {
|
||||
self.user_button.is_low().ok().unwrap()
|
||||
}
|
||||
Button::B => {
|
||||
self.wakeup_button.is_low().ok().unwrap()
|
||||
}
|
||||
_ => {
|
||||
self.wakeup_button.is_low().ok().unwrap()
|
||||
}
|
||||
Button::A => self.user_button.is_low().ok().unwrap(),
|
||||
Button::B => self.wakeup_button.is_low().ok().unwrap(),
|
||||
_ => self.wakeup_button.is_low().ok().unwrap(),
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
impl<CTIMER> XpressoButtons <CTIMER>
|
||||
where CTIMER: ctimer::Ctimer<init_state::Enabled>
|
||||
impl<CTIMER> XpressoButtons<CTIMER>
|
||||
where
|
||||
CTIMER: ctimer::Ctimer<init_state::Enabled>,
|
||||
{
|
||||
fn get_status_debounced(&mut self) -> State {
|
||||
// first, remove jitter
|
||||
@@ -93,10 +88,10 @@ where CTIMER: ctimer::Ctimer<init_state::Enabled>
|
||||
if new_state.a != new_state2.a {
|
||||
new_state.a = self.last_state.a;
|
||||
}
|
||||
if new_state.b != new_state2.b{
|
||||
if new_state.b != new_state2.b {
|
||||
new_state.b = self.last_state.b;
|
||||
}
|
||||
if new_state.middle != new_state2.middle{
|
||||
if new_state.middle != new_state2.middle {
|
||||
new_state.middle = self.last_state.middle;
|
||||
}
|
||||
|
||||
@@ -104,10 +99,10 @@ where CTIMER: ctimer::Ctimer<init_state::Enabled>
|
||||
}
|
||||
|
||||
fn read_button_edge(&mut self, but: Button, edge_type: bool) -> bool {
|
||||
|
||||
let new_state = self.get_status_debounced();
|
||||
|
||||
let mid_edge = (self.last_state.middle ^ new_state.middle) && (self.last_state.middle ^ edge_type);
|
||||
let mid_edge =
|
||||
(self.last_state.middle ^ new_state.middle) && (self.last_state.middle ^ edge_type);
|
||||
let top_edge = (self.last_state.a ^ new_state.a) && (self.last_state.a ^ edge_type);
|
||||
let bot_edge = (self.last_state.b ^ new_state.b) && (self.last_state.b ^ edge_type);
|
||||
|
||||
@@ -128,8 +123,9 @@ where CTIMER: ctimer::Ctimer<init_state::Enabled>
|
||||
}
|
||||
}
|
||||
|
||||
impl<CTIMER> Edge for XpressoButtons <CTIMER>
|
||||
where CTIMER: ctimer::Ctimer<init_state::Enabled>
|
||||
impl<CTIMER> Edge for XpressoButtons<CTIMER>
|
||||
where
|
||||
CTIMER: ctimer::Ctimer<init_state::Enabled>,
|
||||
{
|
||||
/// Non-blockingly wait for the button to be pressed.
|
||||
/// This is edge sensitive, meaning it will not complete successfully more than once
|
||||
@@ -155,7 +151,7 @@ where CTIMER: ctimer::Ctimer<init_state::Enabled>
|
||||
}
|
||||
|
||||
/// See wait_for_press
|
||||
fn wait_for_any_new_press(&mut self, ) -> nb::Result<Button, Infallible> {
|
||||
fn wait_for_any_new_press(&mut self) -> nb::Result<Button, Infallible> {
|
||||
if self.read_button_edge(Button::A, true) {
|
||||
Ok(Button::A)
|
||||
} else if self.read_button_edge(Button::B, true) {
|
||||
@@ -168,7 +164,7 @@ where CTIMER: ctimer::Ctimer<init_state::Enabled>
|
||||
}
|
||||
|
||||
/// See wait_for_release
|
||||
fn wait_for_any_new_release(&mut self, ) -> nb::Result<Button, Infallible> {
|
||||
fn wait_for_any_new_release(&mut self) -> nb::Result<Button, Infallible> {
|
||||
if self.read_button_edge(Button::A, false) {
|
||||
Ok(Button::A)
|
||||
} else if self.read_button_edge(Button::B, false) {
|
||||
@@ -180,15 +176,19 @@ where CTIMER: ctimer::Ctimer<init_state::Enabled>
|
||||
}
|
||||
}
|
||||
|
||||
fn wait_for_new_squeeze(&mut self, ) -> nb::Result<(), Infallible> {
|
||||
fn wait_for_new_squeeze(&mut self) -> nb::Result<(), Infallible> {
|
||||
let oldstate = self.last_state;
|
||||
let a = self.read_button_edge(Button::A, true);
|
||||
let b = self.read_button_edge(Button::B, true);
|
||||
if a && b {
|
||||
Ok(())
|
||||
} else {
|
||||
if a { self.last_state.a = oldstate.a; }
|
||||
if b { self.last_state.b = oldstate.b; }
|
||||
if a {
|
||||
self.last_state.a = oldstate.a;
|
||||
}
|
||||
if b {
|
||||
self.last_state.b = oldstate.b;
|
||||
}
|
||||
Err(nb::Error::WouldBlock)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,14 +3,11 @@ use crate::hal::{
|
||||
drivers::pins,
|
||||
drivers::pwm,
|
||||
peripherals::ctimer,
|
||||
traits::wg::Pwm,
|
||||
typestates::{
|
||||
init_state,
|
||||
pin::{
|
||||
self,
|
||||
function,
|
||||
},
|
||||
pin::{self, function},
|
||||
},
|
||||
traits::wg::Pwm,
|
||||
Iocon,
|
||||
};
|
||||
pub enum Color {
|
||||
@@ -34,10 +31,18 @@ pub type BlueLedPin = pins::Pio1_4;
|
||||
#[cfg(feature = "okdoe1")]
|
||||
pub type BlueLedPin = pins::Pio1_6;
|
||||
|
||||
|
||||
type RedLed = hal::Pin<RedLedPin, pin::state::Special<function::MATCH_OUTPUT1<ctimer::Ctimer2<init_state::Enabled>>>>;
|
||||
type GreenLed = hal::Pin<GreenLedPin, pin::state::Special<function::MATCH_OUTPUT2<ctimer::Ctimer2<init_state::Enabled>>>>;
|
||||
type BlueLed = hal::Pin<BlueLedPin, pin::state::Special<function::MATCH_OUTPUT1<ctimer::Ctimer2<init_state::Enabled>>>>;
|
||||
type RedLed = hal::Pin<
|
||||
RedLedPin,
|
||||
pin::state::Special<function::MATCH_OUTPUT1<ctimer::Ctimer2<init_state::Enabled>>>,
|
||||
>;
|
||||
type GreenLed = hal::Pin<
|
||||
GreenLedPin,
|
||||
pin::state::Special<function::MATCH_OUTPUT2<ctimer::Ctimer2<init_state::Enabled>>>,
|
||||
>;
|
||||
type BlueLed = hal::Pin<
|
||||
BlueLedPin,
|
||||
pin::state::Special<function::MATCH_OUTPUT1<ctimer::Ctimer2<init_state::Enabled>>>,
|
||||
>;
|
||||
|
||||
type PwmDriver = pwm::Pwm<ctimer::Ctimer2<init_state::Enabled>>;
|
||||
|
||||
@@ -46,16 +51,12 @@ pub struct RgbLed {
|
||||
}
|
||||
|
||||
impl RgbLed {
|
||||
pub fn new(
|
||||
mut pwm: PwmDriver,
|
||||
iocon: &mut Iocon<init_state::Enabled>
|
||||
) -> RgbLed{
|
||||
|
||||
pub fn new(mut pwm: PwmDriver, iocon: &mut Iocon<init_state::Enabled>) -> RgbLed {
|
||||
let red = RedLedPin::take().unwrap();
|
||||
let green = GreenLedPin::take().unwrap();
|
||||
let blue = BlueLedPin::take().unwrap();
|
||||
|
||||
pwm.set_duty(RedLed::CHANNEL,0);
|
||||
pwm.set_duty(RedLed::CHANNEL, 0);
|
||||
pwm.set_duty(GreenLed::CHANNEL, 0);
|
||||
pwm.set_duty(BlueLed::CHANNEL, 0);
|
||||
pwm.enable(RedLed::CHANNEL);
|
||||
@@ -69,18 +70,16 @@ impl RgbLed {
|
||||
|
||||
pwm.scale_max_duty_by(16);
|
||||
|
||||
Self {
|
||||
pwm,
|
||||
}
|
||||
Self { pwm }
|
||||
}
|
||||
}
|
||||
|
||||
impl rgb_led::RgbLed for RgbLed {
|
||||
fn red(&mut self, intensity: u8){
|
||||
fn red(&mut self, intensity: u8) {
|
||||
self.pwm.set_duty(RedLed::CHANNEL, intensity.into());
|
||||
}
|
||||
|
||||
fn green(&mut self, intensity: u8){
|
||||
fn green(&mut self, intensity: u8) {
|
||||
self.pwm.set_duty(GreenLed::CHANNEL, intensity.into());
|
||||
}
|
||||
|
||||
|
||||
@@ -2,25 +2,17 @@ use crate::hal::{
|
||||
self,
|
||||
drivers::{
|
||||
pins::{self, Pin},
|
||||
SpiMaster,
|
||||
Timer,
|
||||
SpiMaster, Timer,
|
||||
},
|
||||
Enabled,
|
||||
peripherals::flexcomm::Spi0,
|
||||
time::RateExtensions,
|
||||
typestates::{
|
||||
pin::{
|
||||
self,
|
||||
flexcomm::NoPio,
|
||||
},
|
||||
},
|
||||
typestates::pin::{self, flexcomm::NoPio},
|
||||
Enabled,
|
||||
};
|
||||
|
||||
use defmt::info;
|
||||
|
||||
use fm11nc08::{
|
||||
FM11NC08, Configuration, Register,
|
||||
};
|
||||
use fm11nc08::{Configuration, Register, FM11NC08};
|
||||
|
||||
pub type NfcSckPin = pins::Pio0_28;
|
||||
pub type NfcMosiPin = pins::Pio0_24;
|
||||
@@ -29,22 +21,22 @@ pub type NfcCsPin = pins::Pio1_20;
|
||||
pub type NfcIrqPin = pins::Pio0_19;
|
||||
|
||||
pub type NfcChip = FM11NC08<
|
||||
SpiMaster<
|
||||
NfcSckPin,
|
||||
NfcMosiPin,
|
||||
NfcMisoPin,
|
||||
NoPio,
|
||||
Spi0,
|
||||
(
|
||||
Pin<NfcSckPin, pin::state::Special<pin::function::FC0_SCK>>,
|
||||
Pin<NfcMosiPin, pin::state::Special<pin::function::FC0_RXD_SDA_MOSI_DATA>>,
|
||||
Pin<NfcMisoPin, pin::state::Special<pin::function::FC0_TXD_SCL_MISO_WS>>,
|
||||
pin::flexcomm::NoCs,
|
||||
)
|
||||
>,
|
||||
Pin<NfcCsPin, pin::state::Gpio<pin::gpio::direction::Output>>,
|
||||
Pin<NfcIrqPin, pin::state::Gpio<pin::gpio::direction::Input>>,
|
||||
>;
|
||||
SpiMaster<
|
||||
NfcSckPin,
|
||||
NfcMosiPin,
|
||||
NfcMisoPin,
|
||||
NoPio,
|
||||
Spi0,
|
||||
(
|
||||
Pin<NfcSckPin, pin::state::Special<pin::function::FC0_SCK>>,
|
||||
Pin<NfcMosiPin, pin::state::Special<pin::function::FC0_RXD_SDA_MOSI_DATA>>,
|
||||
Pin<NfcMisoPin, pin::state::Special<pin::function::FC0_TXD_SCL_MISO_WS>>,
|
||||
pin::flexcomm::NoCs,
|
||||
),
|
||||
>,
|
||||
Pin<NfcCsPin, pin::state::Gpio<pin::gpio::direction::Output>>,
|
||||
Pin<NfcIrqPin, pin::state::Gpio<pin::gpio::direction::Input>>,
|
||||
>;
|
||||
|
||||
pub fn try_setup(
|
||||
spi: Spi0<Enabled>,
|
||||
@@ -54,9 +46,7 @@ pub fn try_setup(
|
||||
// fm: &mut NfcChip,
|
||||
timer: &mut Timer<impl hal::peripherals::ctimer::Ctimer<hal::typestates::init_state::Enabled>>,
|
||||
always_reconfig: bool,
|
||||
) -> Option<NfcChip> {
|
||||
|
||||
|
||||
) -> Option<NfcChip> {
|
||||
let sck = NfcSckPin::take().unwrap().into_spi0_sck_pin(iocon);
|
||||
let mosi = NfcMosiPin::take().unwrap().into_spi0_mosi_pin(iocon);
|
||||
let miso = NfcMisoPin::take().unwrap().into_spi0_miso_pin(iocon);
|
||||
@@ -68,21 +58,25 @@ pub fn try_setup(
|
||||
spi,
|
||||
(sck, mosi, miso, hal::typestates::pin::flexcomm::NoCs),
|
||||
2_000_000u32.Hz(),
|
||||
spi_mode);
|
||||
spi_mode,
|
||||
);
|
||||
|
||||
// Start unselected.
|
||||
let nfc_cs = NfcCsPin::take().unwrap().into_gpio_pin(iocon, gpio).into_output_high();
|
||||
let nfc_cs = NfcCsPin::take()
|
||||
.unwrap()
|
||||
.into_gpio_pin(iocon, gpio)
|
||||
.into_output_high();
|
||||
|
||||
let mut fm = FM11NC08::new(spi, nfc_cs, nfc_irq).enabled();
|
||||
|
||||
// no limit 2mA resistor 3.3V
|
||||
const REGU_CONFIG: u8 = (0b11 << 4) | (0b10 << 2) | (0b11 << 0);
|
||||
const REGU_CONFIG: u8 = (0b11 << 4) | (0b10 << 2) | 0b11;
|
||||
let current_regu_config = fm.read_reg(fm11nc08::Register::ReguCfg);
|
||||
let current_nfc_config = fm.read_reg(fm11nc08::Register::NfcCfg);
|
||||
|
||||
// regu_config gets configured by upstream vendor testing, so we need
|
||||
// to additionally test on another value to see if eeprom is configured by us.
|
||||
let is_select_int_masked = (current_nfc_config & 1) == 1;
|
||||
let is_select_int_masked = (current_nfc_config & 1) == 1;
|
||||
|
||||
if current_regu_config == 0xff {
|
||||
// No nfc chip connected
|
||||
@@ -90,7 +84,8 @@ pub fn try_setup(
|
||||
return None;
|
||||
}
|
||||
|
||||
let reconfig = always_reconfig || (current_regu_config != REGU_CONFIG) || (is_select_int_masked);
|
||||
let reconfig =
|
||||
always_reconfig || (current_regu_config != REGU_CONFIG) || (is_select_int_masked);
|
||||
|
||||
if reconfig {
|
||||
// info_now!("{:?}", fm.dump_eeprom() );
|
||||
@@ -98,23 +93,26 @@ pub fn try_setup(
|
||||
|
||||
info!("writing EEPROM");
|
||||
|
||||
let r = fm.configure(Configuration{
|
||||
regu: REGU_CONFIG,
|
||||
ataq: 0x4400,
|
||||
sak1: 0x04,
|
||||
sak2: 0x20,
|
||||
tl: 0x05,
|
||||
// (x[7:4], FSDI[3:0]) . FSDI[2] == 32 byte frame, FSDI[8] == 256 byte frame, 7==128byte
|
||||
t0: 0x78,
|
||||
// Support different data rates for both directions
|
||||
// Support divisor 2 / 212kbps for tx and rx
|
||||
ta: 0b10010001,
|
||||
// (FWI[b4], SFGI[b4]), (256 * 16 / fc) * 2 ^ value
|
||||
tb: 0x78,
|
||||
tc: 0x00,
|
||||
let r = fm.configure(
|
||||
Configuration {
|
||||
regu: REGU_CONFIG,
|
||||
ataq: 0x4400,
|
||||
sak1: 0x04,
|
||||
sak2: 0x20,
|
||||
tl: 0x05,
|
||||
// (x[7:4], FSDI[3:0]) . FSDI[2] == 32 byte frame, FSDI[8] == 256 byte frame, 7==128byte
|
||||
t0: 0x78,
|
||||
// Support different data rates for both directions
|
||||
// Support divisor 2 / 212kbps for tx and rx
|
||||
ta: 0b10010001,
|
||||
// (FWI[b4], SFGI[b4]), (256 * 16 / fc) * 2 ^ value
|
||||
tb: 0x78,
|
||||
tc: 0x00,
|
||||
// enable P-on IRQ 14443-4 mode
|
||||
nfc: (0b0 << 1) | (0b00 << 2),
|
||||
}, timer);
|
||||
nfc: (0b00 << 2),
|
||||
},
|
||||
timer,
|
||||
);
|
||||
if r.is_err() {
|
||||
info!("Eeprom failed. No NFC chip connected?");
|
||||
return None;
|
||||
@@ -125,20 +123,21 @@ pub fn try_setup(
|
||||
|
||||
// disable all interrupts except RxStart
|
||||
fm.write_reg(Register::AuxIrqMask, 0x00);
|
||||
fm.write_reg(Register::FifoIrqMask,
|
||||
fm.write_reg(
|
||||
Register::FifoIrqMask,
|
||||
// 0x0
|
||||
0xff
|
||||
^ (1 << 3) /* water-level */
|
||||
^ (1 << 1) /* fifo-full */
|
||||
^ (1 << 1), /* fifo-full */
|
||||
);
|
||||
fm.write_reg(Register::MainIrqMask,
|
||||
fm.write_reg(
|
||||
Register::MainIrqMask,
|
||||
// 0x0
|
||||
0xff
|
||||
^ fm11nc08::device::Interrupt::RxStart as u8
|
||||
^ fm11nc08::device::Interrupt::RxDone as u8
|
||||
^ fm11nc08::device::Interrupt::TxDone as u8
|
||||
^ fm11nc08::device::Interrupt::Fifo as u8
|
||||
^ fm11nc08::device::Interrupt::Active as u8
|
||||
0xff ^ fm11nc08::device::Interrupt::RxStart as u8
|
||||
^ fm11nc08::device::Interrupt::RxDone as u8
|
||||
^ fm11nc08::device::Interrupt::TxDone as u8
|
||||
^ fm11nc08::device::Interrupt::Fifo as u8
|
||||
^ fm11nc08::device::Interrupt::Active as u8,
|
||||
);
|
||||
|
||||
// no limit rrfcfg . 3.3V
|
||||
|
||||
@@ -15,14 +15,17 @@ impl crate::traits::Reboot for Reboot {
|
||||
// Erasing the first flash page & rebooting will keep processor in bootrom persistently.
|
||||
// This is however destructive, as a valid firmware will need to be flashed.
|
||||
use hal::traits::flash::WriteErase;
|
||||
let flash = unsafe { hal::peripherals::flash::Flash::steal() }.enabled(
|
||||
&mut unsafe {hal::peripherals::syscon::Syscon::steal()}
|
||||
);
|
||||
hal::drivers::flash::FlashGordon::new(flash).erase_page(0).ok();
|
||||
let flash = unsafe { hal::peripherals::flash::Flash::steal() }
|
||||
.enabled(&mut unsafe { hal::peripherals::syscon::Syscon::steal() });
|
||||
hal::drivers::flash::FlashGordon::new(flash)
|
||||
.erase_page(0)
|
||||
.ok();
|
||||
hal::raw::SCB::sys_reset()
|
||||
}
|
||||
fn locked() -> bool {
|
||||
let seal = &unsafe { hal::raw::Peripherals::steal() }.FLASH_CMPA.sha256_digest;
|
||||
let seal = &unsafe { hal::raw::Peripherals::steal() }
|
||||
.FLASH_CMPA
|
||||
.sha256_digest;
|
||||
seal.iter().any(|word| word.read().bits() != 0)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
use core::convert::Infallible;
|
||||
use crate::hal::{
|
||||
self,
|
||||
drivers::pins,
|
||||
// drivers::Pin,
|
||||
drivers::touch::{Compare, Edge, TouchSensor, ButtonPins, TouchSensorChannel},
|
||||
drivers::touch::{ButtonPins, Compare, Edge, TouchSensor, TouchSensorChannel},
|
||||
peripherals::ctimer,
|
||||
typestates::{
|
||||
init_state,
|
||||
@@ -11,14 +10,12 @@ use crate::hal::{
|
||||
// pin::state::{Special, Analog},
|
||||
// pin::gpio::direction,
|
||||
// pin::function,
|
||||
ClocksSupportTouchToken
|
||||
ClocksSupportTouchToken,
|
||||
},
|
||||
};
|
||||
use core::convert::Infallible;
|
||||
|
||||
use crate::traits::buttons::{
|
||||
self,
|
||||
Button,
|
||||
};
|
||||
use crate::traits::buttons::{self, Button};
|
||||
|
||||
pub type ChargeMatchPin = pins::Pio1_16;
|
||||
pub type ButtonTopPin = pins::Pio0_23;
|
||||
@@ -37,15 +34,19 @@ type SampleTimer = ctimer::Ctimer2<init_state::Enabled>;
|
||||
|
||||
pub type ThreeButtons = SoloThreeTouchButtons<ButtonTopPin, ButtonBotPin, ButtonMidPin>;
|
||||
|
||||
pub struct SoloThreeTouchButtons<P1,P2,P3>
|
||||
where P1: PinId, P2: PinId, P3: PinId{
|
||||
touch_sensor: TouchSensor<P1,P2,P3>
|
||||
pub struct SoloThreeTouchButtons<P1, P2, P3>
|
||||
where
|
||||
P1: PinId,
|
||||
P2: PinId,
|
||||
P3: PinId,
|
||||
{
|
||||
touch_sensor: TouchSensor<P1, P2, P3>,
|
||||
}
|
||||
|
||||
impl SoloThreeTouchButtons<ButtonTopPin, ButtonBotPin, ButtonMidPin>
|
||||
// where P1: PinId, P2: PinId, P3: PinId
|
||||
{
|
||||
pub fn new (
|
||||
pub fn new(
|
||||
adc: Adc,
|
||||
adc_timer: AdcTimer,
|
||||
sample_timer: SampleTimer,
|
||||
@@ -62,70 +63,75 @@ impl SoloThreeTouchButtons<ButtonTopPin, ButtonBotPin, ButtonMidPin>
|
||||
let mid = ButtonMidPin::take().unwrap().into_analog_input(iocon, gpio);
|
||||
let bot = ButtonBotPin::take().unwrap().into_analog_input(iocon, gpio);
|
||||
let charge_match = ChargeMatchPin::take().unwrap().into_match_output(iocon);
|
||||
let button_pins = ButtonPins(
|
||||
top,bot,mid,
|
||||
let button_pins = ButtonPins(top, bot, mid);
|
||||
let touch_sensor = TouchSensor::new(
|
||||
[12_000, 12_000, 12_000],
|
||||
5,
|
||||
adc,
|
||||
adc_timer,
|
||||
sample_timer,
|
||||
charge_match,
|
||||
button_pins,
|
||||
);
|
||||
let touch_sensor = TouchSensor::new([
|
||||
12_000,
|
||||
12_000,
|
||||
12_000,
|
||||
], 5, adc, adc_timer, sample_timer, charge_match, button_pins);
|
||||
let touch_sensor = touch_sensor.enabled(dma, token);
|
||||
Self {
|
||||
touch_sensor
|
||||
}
|
||||
Self { touch_sensor }
|
||||
}
|
||||
|
||||
/// Map internal cmd number to Button type
|
||||
fn button_get_state (&self, button: buttons::Button, ctype: Compare) -> bool {
|
||||
fn button_get_state(&self, button: buttons::Button, ctype: Compare) -> bool {
|
||||
match button {
|
||||
Button::A => {
|
||||
self.touch_sensor.get_state(TouchSensorChannel::Channel1, ctype).is_active
|
||||
self.touch_sensor
|
||||
.get_state(TouchSensorChannel::Channel1, ctype)
|
||||
.is_active
|
||||
}
|
||||
Button::B => {
|
||||
self.touch_sensor.get_state(TouchSensorChannel::Channel2, ctype).is_active
|
||||
self.touch_sensor
|
||||
.get_state(TouchSensorChannel::Channel2, ctype)
|
||||
.is_active
|
||||
}
|
||||
Button::Middle => {
|
||||
self.touch_sensor.get_state(TouchSensorChannel::Channel3, ctype).is_active
|
||||
self.touch_sensor
|
||||
.get_state(TouchSensorChannel::Channel3, ctype)
|
||||
.is_active
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Map internal cmd number to Button type
|
||||
fn button_has_edge (&self, button: Button, edge_type: Edge,) -> bool {
|
||||
fn button_has_edge(&self, button: Button, edge_type: Edge) -> bool {
|
||||
match button {
|
||||
Button::A => {
|
||||
self.touch_sensor.has_edge(TouchSensorChannel::Channel1, edge_type)
|
||||
}
|
||||
Button::B => {
|
||||
self.touch_sensor.has_edge(TouchSensorChannel::Channel2, edge_type)
|
||||
}
|
||||
Button::Middle => {
|
||||
self.touch_sensor.has_edge(TouchSensorChannel::Channel3, edge_type)
|
||||
}
|
||||
|
||||
Button::A => self
|
||||
.touch_sensor
|
||||
.has_edge(TouchSensorChannel::Channel1, edge_type),
|
||||
Button::B => self
|
||||
.touch_sensor
|
||||
.has_edge(TouchSensorChannel::Channel2, edge_type),
|
||||
Button::Middle => self
|
||||
.touch_sensor
|
||||
.has_edge(TouchSensorChannel::Channel3, edge_type),
|
||||
}
|
||||
}
|
||||
|
||||
fn button_reset_state(&self, button: Button, offset: i32) {
|
||||
match button {
|
||||
Button::A => {
|
||||
self.touch_sensor.reset_results(TouchSensorChannel::Channel1, offset);
|
||||
self.touch_sensor
|
||||
.reset_results(TouchSensorChannel::Channel1, offset);
|
||||
}
|
||||
Button::B => {
|
||||
self.touch_sensor.reset_results(TouchSensorChannel::Channel2, offset);
|
||||
self.touch_sensor
|
||||
.reset_results(TouchSensorChannel::Channel2, offset);
|
||||
}
|
||||
Button::Middle => {
|
||||
self.touch_sensor.reset_results(TouchSensorChannel::Channel3, offset);
|
||||
self.touch_sensor
|
||||
.reset_results(TouchSensorChannel::Channel3, offset);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
impl buttons::Press for SoloThreeTouchButtons<ButtonTopPin, ButtonBotPin, ButtonMidPin>
|
||||
{
|
||||
impl buttons::Press for SoloThreeTouchButtons<ButtonTopPin, ButtonBotPin, ButtonMidPin> {
|
||||
fn is_pressed(&self, button: buttons::Button) -> bool {
|
||||
self.button_get_state(button, Compare::BelowThreshold)
|
||||
}
|
||||
@@ -135,8 +141,7 @@ impl buttons::Press for SoloThreeTouchButtons<ButtonTopPin, ButtonBotPin, Button
|
||||
}
|
||||
}
|
||||
|
||||
impl buttons::Edge for SoloThreeTouchButtons<ButtonTopPin, ButtonBotPin, ButtonMidPin>
|
||||
{
|
||||
impl buttons::Edge for SoloThreeTouchButtons<ButtonTopPin, ButtonBotPin, ButtonMidPin> {
|
||||
fn wait_for_new_press(&mut self, button: Button) -> nb::Result<(), Infallible> {
|
||||
let result = self.button_has_edge(button, Edge::Falling);
|
||||
|
||||
@@ -145,9 +150,8 @@ impl buttons::Edge for SoloThreeTouchButtons<ButtonTopPin, ButtonBotPin, ButtonM
|
||||
self.button_reset_state(button, -1);
|
||||
Ok(())
|
||||
} else {
|
||||
return Err(nb::Error::WouldBlock)
|
||||
Err(nb::Error::WouldBlock)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fn wait_for_new_release(&mut self, button: Button) -> nb::Result<(), Infallible> {
|
||||
@@ -157,18 +161,15 @@ impl buttons::Edge for SoloThreeTouchButtons<ButtonTopPin, ButtonBotPin, ButtonM
|
||||
self.button_reset_state(button, 1);
|
||||
Ok(())
|
||||
} else {
|
||||
return Err(nb::Error::WouldBlock)
|
||||
Err(nb::Error::WouldBlock)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// See wait_for_press
|
||||
fn wait_for_any_new_press(&mut self, ) -> nb::Result<Button, Infallible> {
|
||||
|
||||
fn wait_for_any_new_press(&mut self) -> nb::Result<Button, Infallible> {
|
||||
if self.wait_for_new_press(Button::A).is_ok() {
|
||||
Ok(Button::A)
|
||||
}
|
||||
else if self.wait_for_new_press(Button::B).is_ok() {
|
||||
} else if self.wait_for_new_press(Button::B).is_ok() {
|
||||
Ok(Button::B)
|
||||
} else if self.wait_for_new_press(Button::Middle).is_ok() {
|
||||
Ok(Button::Middle)
|
||||
@@ -178,11 +179,10 @@ impl buttons::Edge for SoloThreeTouchButtons<ButtonTopPin, ButtonBotPin, ButtonM
|
||||
}
|
||||
|
||||
/// See wait_for_release
|
||||
fn wait_for_any_new_release(&mut self, ) -> nb::Result<Button, Infallible> {
|
||||
fn wait_for_any_new_release(&mut self) -> nb::Result<Button, Infallible> {
|
||||
if self.wait_for_new_release(Button::A).is_ok() {
|
||||
Ok(Button::A)
|
||||
}
|
||||
else if self.wait_for_new_release(Button::B).is_ok() {
|
||||
} else if self.wait_for_new_release(Button::B).is_ok() {
|
||||
Ok(Button::B)
|
||||
} else if self.wait_for_new_release(Button::Middle).is_ok() {
|
||||
Ok(Button::Middle)
|
||||
@@ -200,8 +200,7 @@ impl buttons::Edge for SoloThreeTouchButtons<ButtonTopPin, ButtonBotPin, ButtonM
|
||||
self.button_reset_state(Button::B, -1);
|
||||
Ok(())
|
||||
} else {
|
||||
return Err(nb::Error::WouldBlock)
|
||||
Err(nb::Error::WouldBlock)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,20 +3,16 @@ use crate::hal::{
|
||||
drivers::pins,
|
||||
drivers::pwm,
|
||||
peripherals::ctimer,
|
||||
traits::wg::Pwm,
|
||||
typestates::{
|
||||
init_state,
|
||||
pin::{
|
||||
self,
|
||||
function,
|
||||
},
|
||||
pin::{self, function},
|
||||
},
|
||||
traits::wg::Pwm,
|
||||
Iocon,
|
||||
};
|
||||
|
||||
use crate::traits::rgb_led;
|
||||
|
||||
|
||||
pub enum Color {
|
||||
Red,
|
||||
Green,
|
||||
@@ -29,15 +25,15 @@ pub type BlueLedPin = pins::Pio1_19;
|
||||
|
||||
type RedLed = hal::Pin<
|
||||
RedLedPin,
|
||||
pin::state::Special<function::MATCH_OUTPUT0<ctimer::Ctimer3<init_state::Enabled>>>
|
||||
pin::state::Special<function::MATCH_OUTPUT0<ctimer::Ctimer3<init_state::Enabled>>>,
|
||||
>;
|
||||
type GreenLed = hal::Pin<
|
||||
GreenLedPin,
|
||||
pin::state::Special<function::MATCH_OUTPUT2<ctimer::Ctimer3<init_state::Enabled>>>
|
||||
pin::state::Special<function::MATCH_OUTPUT2<ctimer::Ctimer3<init_state::Enabled>>>,
|
||||
>;
|
||||
type BlueLed = hal::Pin<
|
||||
BlueLedPin,
|
||||
pin::state::Special<function::MATCH_OUTPUT1<ctimer::Ctimer3<init_state::Enabled>>>
|
||||
pin::state::Special<function::MATCH_OUTPUT1<ctimer::Ctimer3<init_state::Enabled>>>,
|
||||
>;
|
||||
|
||||
type PwmDriver = pwm::Pwm<ctimer::Ctimer3<init_state::Enabled>>;
|
||||
@@ -47,16 +43,12 @@ pub struct RgbLed {
|
||||
}
|
||||
|
||||
impl RgbLed {
|
||||
pub fn new(
|
||||
mut pwm: PwmDriver,
|
||||
iocon: &mut Iocon<init_state::Enabled>
|
||||
) -> RgbLed{
|
||||
|
||||
pub fn new(mut pwm: PwmDriver, iocon: &mut Iocon<init_state::Enabled>) -> RgbLed {
|
||||
let red = RedLedPin::take().unwrap();
|
||||
let green = GreenLedPin::take().unwrap();
|
||||
let blue = BlueLedPin::take().unwrap();
|
||||
|
||||
pwm.set_duty(RedLed::CHANNEL,0);
|
||||
pwm.set_duty(RedLed::CHANNEL, 0);
|
||||
pwm.set_duty(GreenLed::CHANNEL, 0);
|
||||
pwm.set_duty(BlueLed::CHANNEL, 0);
|
||||
pwm.enable(RedLed::CHANNEL);
|
||||
@@ -70,18 +62,16 @@ impl RgbLed {
|
||||
|
||||
pwm.scale_max_duty_by(8);
|
||||
|
||||
Self {
|
||||
pwm,
|
||||
}
|
||||
Self { pwm }
|
||||
}
|
||||
}
|
||||
|
||||
impl rgb_led::RgbLed for RgbLed {
|
||||
fn red(&mut self, intensity: u8){
|
||||
self.pwm.set_duty(RedLed::CHANNEL, (intensity/2) as u16);
|
||||
fn red(&mut self, intensity: u8) {
|
||||
self.pwm.set_duty(RedLed::CHANNEL, (intensity / 2) as u16);
|
||||
}
|
||||
|
||||
fn green(&mut self, intensity: u8){
|
||||
fn green(&mut self, intensity: u8) {
|
||||
self.pwm.set_duty(GreenLed::CHANNEL, (intensity as u16) * 3);
|
||||
}
|
||||
|
||||
@@ -89,4 +79,3 @@ impl rgb_led::RgbLed for RgbLed {
|
||||
self.pwm.set_duty(BlueLed::CHANNEL, (intensity as u16) * 8);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -28,7 +28,6 @@ pub struct State {
|
||||
///
|
||||
/// Only `is_pressed` needs to actually be implemented.
|
||||
pub trait Press {
|
||||
|
||||
/// Is the specific button currently pressed
|
||||
fn is_pressed(&self, button: Button) -> bool;
|
||||
|
||||
|
||||
@@ -7,17 +7,16 @@ pub struct Intensities {
|
||||
|
||||
impl From<u32> for Intensities {
|
||||
// set all LEDs using (R||G||B) formatted word.
|
||||
fn from(hex: u32) -> Self{
|
||||
fn from(hex: u32) -> Self {
|
||||
Intensities {
|
||||
red: ((hex & 0xff_00_00) >> 16) as _,
|
||||
red: ((hex & 0xff_00_00) >> 16) as _,
|
||||
green: ((hex & 0x00_ff_00) >> 8) as _,
|
||||
blue: (hex & 0x00_00_ff) as _,
|
||||
blue: (hex & 0x00_00_ff) as _,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait RgbLed {
|
||||
|
||||
/// Set all LEDs
|
||||
fn set(&mut self, intensities: Intensities) {
|
||||
self.red(intensities.red);
|
||||
|
||||
@@ -3,11 +3,8 @@
|
||||
|
||||
use core::time::Duration;
|
||||
|
||||
use crate::hal::{
|
||||
peripherals::rtc::Rtc,
|
||||
typestates::init_state,
|
||||
};
|
||||
use crate::traits::buttons::{Press, Edge};
|
||||
use crate::hal::{peripherals::rtc::Rtc, typestates::init_state};
|
||||
use crate::traits::buttons::{Edge, Press};
|
||||
use crate::traits::rgb_led::{Intensities, RgbLed};
|
||||
use defmt::debug;
|
||||
use micromath::F32;
|
||||
@@ -23,15 +20,14 @@ impl UserPresenceStatus {
|
||||
unsafe { WAITING = waiting };
|
||||
}
|
||||
pub fn waiting() -> bool {
|
||||
unsafe{ WAITING }
|
||||
unsafe { WAITING }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub struct UserInterface<BUTTONS, RGB>
|
||||
where
|
||||
BUTTONS: Press + Edge,
|
||||
RGB: RgbLed,
|
||||
BUTTONS: Press + Edge,
|
||||
RGB: RgbLed,
|
||||
{
|
||||
rtc: Rtc<init_state::Enabled>,
|
||||
buttons: Option<BUTTONS>,
|
||||
@@ -42,8 +38,8 @@ RGB: RgbLed,
|
||||
|
||||
impl<BUTTONS, RGB> UserInterface<BUTTONS, RGB>
|
||||
where
|
||||
BUTTONS: Press + Edge,
|
||||
RGB: RgbLed,
|
||||
BUTTONS: Press + Edge,
|
||||
RGB: RgbLed,
|
||||
{
|
||||
pub fn new(rtc: Rtc<init_state::Enabled>, _buttons: Option<BUTTONS>, rgb: Option<RGB>) -> Self {
|
||||
#[allow(unused_mut)]
|
||||
@@ -58,7 +54,9 @@ RGB: RgbLed,
|
||||
}
|
||||
};
|
||||
Self {
|
||||
rtc, buttons, rgb,
|
||||
rtc,
|
||||
buttons,
|
||||
rgb,
|
||||
status: ui::Status::Idle,
|
||||
wink_until: Duration::new(0, 0),
|
||||
}
|
||||
@@ -66,25 +64,52 @@ RGB: RgbLed,
|
||||
}
|
||||
|
||||
// color codes Conor picked
|
||||
const BLACK: Intensities = Intensities { red: 0, green: 0, blue: 0 };
|
||||
const RED: Intensities = Intensities { red: u8::MAX, green: 0, blue: 0 };
|
||||
const GREEN: Intensities = Intensities { red: 0, green: 15, blue: 0x02 };
|
||||
const BLUE: Intensities = Intensities { red: 0, green: 0, blue: 55 };
|
||||
const TEAL: Intensities = Intensities { red: 0, green: 55, blue: 20 };
|
||||
const BLACK: Intensities = Intensities {
|
||||
red: 0,
|
||||
green: 0,
|
||||
blue: 0,
|
||||
};
|
||||
const RED: Intensities = Intensities {
|
||||
red: u8::MAX,
|
||||
green: 0,
|
||||
blue: 0,
|
||||
};
|
||||
const GREEN: Intensities = Intensities {
|
||||
red: 0,
|
||||
green: 15,
|
||||
blue: 0x02,
|
||||
};
|
||||
const BLUE: Intensities = Intensities {
|
||||
red: 0,
|
||||
green: 0,
|
||||
blue: 55,
|
||||
};
|
||||
const TEAL: Intensities = Intensities {
|
||||
red: 0,
|
||||
green: 55,
|
||||
blue: 20,
|
||||
};
|
||||
#[allow(dead_code)]
|
||||
const ORANGE: Intensities = Intensities { red: u8::MAX, green: 0x7e, blue: 0 };
|
||||
const ORANGE: Intensities = Intensities {
|
||||
red: u8::MAX,
|
||||
green: 0x7e,
|
||||
blue: 0,
|
||||
};
|
||||
#[allow(dead_code)]
|
||||
const WHITE: Intensities = Intensities { red: u8::MAX, green: u8::MAX, blue: u8::MAX };
|
||||
const WHITE: Intensities = Intensities {
|
||||
red: u8::MAX,
|
||||
green: u8::MAX,
|
||||
blue: u8::MAX,
|
||||
};
|
||||
|
||||
impl<BUTTONS, RGB> trussed::platform::UserInterface for UserInterface<BUTTONS,RGB>
|
||||
impl<BUTTONS, RGB> trussed::platform::UserInterface for UserInterface<BUTTONS, RGB>
|
||||
where
|
||||
BUTTONS: Press + Edge,
|
||||
RGB: RgbLed,
|
||||
BUTTONS: Press + Edge,
|
||||
RGB: RgbLed,
|
||||
{
|
||||
fn check_user_presence(&mut self) -> consent::Level {
|
||||
match &mut self.buttons {
|
||||
Some(buttons) => {
|
||||
|
||||
// important to read state before checking for edge,
|
||||
// since reading an edge could clear the state.
|
||||
let state = buttons.state();
|
||||
@@ -110,7 +135,6 @@ RGB: RgbLed,
|
||||
}
|
||||
|
||||
fn set_status(&mut self, status: ui::Status) {
|
||||
|
||||
self.status = status;
|
||||
debug!("status set to {:?}", defmt::Debug2Format(&status));
|
||||
|
||||
@@ -137,46 +161,62 @@ RGB: RgbLed,
|
||||
let uptime = self.uptime().as_millis() as u32;
|
||||
|
||||
if let Some(rgb) = self.rgb.as_mut() {
|
||||
|
||||
let waiting_for_user = self.status == ui::Status::WaitingForUserPresence;
|
||||
let processing = self.status == ui::Status::Processing;
|
||||
let winking = uptime < self.wink_until.as_millis() as u32;
|
||||
let any_button = self.buttons.as_mut()
|
||||
let any_button = self
|
||||
.buttons
|
||||
.as_mut()
|
||||
.map(|buttons| buttons.state())
|
||||
.map(|state| state.a || state.b || state.middle)
|
||||
.unwrap_or(false);
|
||||
|
||||
let color = if waiting_for_user {
|
||||
|
||||
// breathe fast, in blue
|
||||
|
||||
let amplitude = calculate_amplitude(uptime, 2, 4, 75);
|
||||
Intensities { red: 0, green: 0, blue: amplitude }
|
||||
|
||||
Intensities {
|
||||
red: 0,
|
||||
green: 0,
|
||||
blue: amplitude,
|
||||
}
|
||||
} else if processing {
|
||||
let on = (((F32(uptime as f32) / 250.0).round().0 as u32) % 2) != 0;
|
||||
if on { GREEN } else { BLACK }
|
||||
let on = !((F32(uptime as f32) / 250.0).round().0 as u32).is_multiple_of(2);
|
||||
if on {
|
||||
GREEN
|
||||
} else {
|
||||
BLACK
|
||||
}
|
||||
} else if winking {
|
||||
|
||||
// blink rapidly
|
||||
|
||||
let on = (((F32(uptime as f32) / 250.0).round().0 as u32) % 2) != 0;
|
||||
if on { BLUE } else { BLACK }
|
||||
let on = !((F32(uptime as f32) / 250.0).round().0 as u32).is_multiple_of(2);
|
||||
if on {
|
||||
BLUE
|
||||
} else {
|
||||
BLACK
|
||||
}
|
||||
// if on { WHITE } else { BLACK }
|
||||
|
||||
} else {
|
||||
|
||||
// regular behaviour: breathe slowly
|
||||
|
||||
let amplitude = calculate_amplitude(uptime, 10, 4, 64);
|
||||
|
||||
if !any_button {
|
||||
// Use green if no button is pressed.
|
||||
Intensities { red: 0, green: amplitude, blue: 0 }
|
||||
Intensities {
|
||||
red: 0,
|
||||
green: amplitude,
|
||||
blue: 0,
|
||||
}
|
||||
// Intensities { red: amplitude, green: 0, blue: 0 }
|
||||
} else {
|
||||
// Use blue if button is pressed.
|
||||
Intensities { red: 0, green: 0, blue: amplitude }
|
||||
Intensities {
|
||||
red: 0,
|
||||
green: 0,
|
||||
blue: amplitude,
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -185,7 +225,7 @@ RGB: RgbLed,
|
||||
// crate::logger::info!("time: {}", time).ok();
|
||||
// debug_now!("amp: {:08X}", amplitude);
|
||||
// crate::logger::info!("color: {}", hex!(color)).ok();
|
||||
rgb.set(color.into());
|
||||
rgb.set(color);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -197,16 +237,20 @@ RGB: RgbLed,
|
||||
debug!("winking for {:?}", duration);
|
||||
self.wink_until = self.uptime() + duration;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fn calculate_amplitude(now_millis: u32, period_secs: u8, min_amplitude: u8, max_amplitude: u8) -> u8 {
|
||||
fn calculate_amplitude(
|
||||
now_millis: u32,
|
||||
period_secs: u8,
|
||||
min_amplitude: u8,
|
||||
max_amplitude: u8,
|
||||
) -> u8 {
|
||||
let period = Duration::new(period_secs as u64, 0).as_millis() as u32;
|
||||
let tau = F32(6.283185);
|
||||
let tau = F32(core::f32::consts::TAU);
|
||||
let angle = F32(now_millis as f32) * tau / (period as f32);
|
||||
let rel_amplitude = max_amplitude - min_amplitude;
|
||||
|
||||
// sinoidal wave on top of a baseline brightness
|
||||
let amplitude = min_amplitude + (angle.sin().abs() * (rel_amplitude as f32)).floor().0 as u8;
|
||||
amplitude
|
||||
|
||||
min_amplitude + (angle.sin().abs() * (rel_amplitude as f32)).floor().0 as u8
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user