cargo: fix fmt and clippy

This commit is contained in:
Emanuele Cesena
2026-04-18 21:48:42 -07:00
parent d8796c2f3a
commit 20421d1a8a
29 changed files with 834 additions and 852 deletions
+33
View File
@@ -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
File diff suppressed because it is too large Load Diff
+1 -5
View File
@@ -2,8 +2,4 @@
pub mod device;
pub use device::{
FM11NC08,
Configuration,
Register,
};
pub use device::{Configuration, FM11NC08, Register};
+1 -1
View File
@@ -1,4 +1,4 @@
#![no_std]
pub mod ndef;
pub use ndef::*;
pub use ndef::*;
+38 -32
View File
@@ -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),
}
}
}
+75 -99
View File
@@ -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 PICCs 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 PICCs 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 PICCs 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 PICCs 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 -1
View File
@@ -1,7 +1,7 @@
#![no_std]
pub mod types;
pub mod traits;
pub mod types;
pub mod iso14443;
pub use iso14443::*;
+2 -3
View File
@@ -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 }
}
}
}
+24 -26
View File
@@ -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;
+91 -77
View File
@@ -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();
+2 -8
View File
@@ -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;
+53 -53
View File
@@ -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)
}
}
+19 -20
View File
@@ -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());
}
+60 -61
View File
@@ -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
+8 -5
View File
@@ -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)
}
}
+57 -58
View File
@@ -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)
}
}
}
+11 -22
View File
@@ -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;
+3 -4
View File
@@ -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);
+88 -44
View File
@@ -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