mirror of
https://github.com/saymrwulf/xous-core.git
synced 2026-11-08 04:56:43 +00:00
Merge branch 'hardware-no-cb' into rkyv-refactor
Bring the two branches up to date, while also laying the groundwork for XousServerName to be used as a native index type in xous-names so we aren't burdening xous::String with a hasher
This commit is contained in:
commit
8fbd900a4c
16 changed files with 457 additions and 176 deletions
4
Cargo.lock
generated
4
Cargo.lock
generated
|
|
@ -654,7 +654,7 @@ dependencies = [
|
|||
"heapless",
|
||||
"log",
|
||||
"log-server",
|
||||
"rkyv 0.4.1",
|
||||
"rkyv 0.3.1",
|
||||
"ticktimer-server",
|
||||
"utralib",
|
||||
"xous",
|
||||
|
|
@ -1589,8 +1589,6 @@ version = "0.1.2"
|
|||
dependencies = [
|
||||
"bitflags",
|
||||
"compiler_builtins",
|
||||
"hash32",
|
||||
"hash32-derive",
|
||||
"hex",
|
||||
"lazy_static",
|
||||
"log",
|
||||
|
|
|
|||
|
|
@ -1328,10 +1328,10 @@ register to disable individual events.]]></description>
|
|||
<register>
|
||||
<name>GIT_GITREV</name>
|
||||
<description><![CDATA[First 32-bits of the git revision. This documentation was built from git rev
|
||||
``d77dca2f``, so this value is 3615345199, which should be enough to check out
|
||||
``2a2abe5e``, so this value is 707444318, which should be enough to check out
|
||||
the exact git version used to build this firmware.]]></description>
|
||||
<addressOffset>0x0014</addressOffset>
|
||||
<resetValue>0xd77dca2f</resetValue>
|
||||
<resetValue>0x2a2abe5e</resetValue>
|
||||
<size>32</size>
|
||||
<fields>
|
||||
<field>
|
||||
|
|
@ -1348,7 +1348,7 @@ the exact git version used to build this firmware.]]></description>
|
|||
is ``1``, then the repository this was built from has one additional commit
|
||||
beyond the tag indicated in `MAJOR`, `MINOR`, and `REVISION`.]]></description>
|
||||
<addressOffset>0x0018</addressOffset>
|
||||
<resetValue>0x0d</resetValue>
|
||||
<resetValue>0x0e</resetValue>
|
||||
<size>32</size>
|
||||
<fields>
|
||||
<field>
|
||||
|
|
@ -1957,8 +1957,7 @@ upon the completion of one byte of data transfer.]]></description>
|
|||
</register>
|
||||
<register>
|
||||
<name>EV_STATUS</name>
|
||||
<description><![CDATA[This register contains the current raw level of the i2c_int event trigger.
|
||||
Writes to this register have no effect.]]></description>
|
||||
<description><![CDATA[Triggered on the falling edge of TIP]]></description>
|
||||
<addressOffset>0x0018</addressOffset>
|
||||
<resetValue>0x00</resetValue>
|
||||
<size>32</size>
|
||||
|
|
@ -1970,12 +1969,18 @@ Writes to this register have no effect.]]></description>
|
|||
<lsb>0</lsb>
|
||||
<description><![CDATA[Level of the ``i2c_int`` event]]></description>
|
||||
</field>
|
||||
<field>
|
||||
<name>txrx_done</name>
|
||||
<msb>1</msb>
|
||||
<bitRange>[1:1]</bitRange>
|
||||
<lsb>1</lsb>
|
||||
<description><![CDATA[Level of the ``txrx_done`` event]]></description>
|
||||
</field>
|
||||
</fields>
|
||||
</register>
|
||||
<register>
|
||||
<name>EV_PENDING</name>
|
||||
<description><![CDATA[When a i2c_int event occurs, the corresponding bit will be set in this
|
||||
register. To clear the Event, set the corresponding bit in this register.]]></description>
|
||||
<description><![CDATA[Triggered on the falling edge of TIP]]></description>
|
||||
<addressOffset>0x001c</addressOffset>
|
||||
<resetValue>0x00</resetValue>
|
||||
<size>32</size>
|
||||
|
|
@ -1985,14 +1990,20 @@ register. To clear the Event, set the corresponding bit in this register.]]></d
|
|||
<msb>0</msb>
|
||||
<bitRange>[0:0]</bitRange>
|
||||
<lsb>0</lsb>
|
||||
<description><![CDATA[`1` if a `i2c_int` event occurred. This Event is triggered on a **rising** edge.]]></description>
|
||||
<description><![CDATA[Triggered when arbitration is lost]]></description>
|
||||
</field>
|
||||
<field>
|
||||
<name>txrx_done</name>
|
||||
<msb>1</msb>
|
||||
<bitRange>[1:1]</bitRange>
|
||||
<lsb>1</lsb>
|
||||
<description><![CDATA[Triggered on the falling edge of TIP]]></description>
|
||||
</field>
|
||||
</fields>
|
||||
</register>
|
||||
<register>
|
||||
<name>EV_ENABLE</name>
|
||||
<description><![CDATA[This register enables the corresponding i2c_int events. Write a ``0`` to this
|
||||
register to disable individual events.]]></description>
|
||||
<description><![CDATA[Triggered on the falling edge of TIP]]></description>
|
||||
<addressOffset>0x0020</addressOffset>
|
||||
<resetValue>0x00</resetValue>
|
||||
<size>32</size>
|
||||
|
|
@ -2004,6 +2015,13 @@ register to disable individual events.]]></description>
|
|||
<lsb>0</lsb>
|
||||
<description><![CDATA[Write a ``1`` to enable the ``i2c_int`` Event]]></description>
|
||||
</field>
|
||||
<field>
|
||||
<name>txrx_done</name>
|
||||
<msb>1</msb>
|
||||
<bitRange>[1:1]</bitRange>
|
||||
<lsb>1</lsb>
|
||||
<description><![CDATA[Write a ``1`` to enable the ``txrx_done`` Event]]></description>
|
||||
</field>
|
||||
</fields>
|
||||
</register>
|
||||
</registers>
|
||||
|
|
@ -3038,7 +3056,7 @@ again until the interrupt is serviced.]]></description>
|
|||
<name>SEED1</name>
|
||||
<description><![CDATA[Bits 32-63 of `SEED_SEED`. Seed used for the build]]></description>
|
||||
<addressOffset>0x0000</addressOffset>
|
||||
<resetValue>0x48f7dee1</resetValue>
|
||||
<resetValue>0x1a7a2a66</resetValue>
|
||||
<size>32</size>
|
||||
<fields>
|
||||
<field>
|
||||
|
|
@ -3053,7 +3071,7 @@ again until the interrupt is serviced.]]></description>
|
|||
<name>SEED0</name>
|
||||
<description><![CDATA[Bits 0-31 of `SEED_SEED`.]]></description>
|
||||
<addressOffset>0x0004</addressOffset>
|
||||
<resetValue>0xc2db130</resetValue>
|
||||
<resetValue>0x4b326b1e</resetValue>
|
||||
<size>32</size>
|
||||
<fields>
|
||||
<field>
|
||||
|
|
|
|||
|
|
@ -576,7 +576,12 @@ pub fn idle() -> bool {
|
|||
crate::arch::process::set_current_pid(pid);
|
||||
|
||||
let mut process = Process::current();
|
||||
let mut response_vec = Vec::new();
|
||||
let mut capacity = 9 * core::mem::size_of::<usize>();
|
||||
if let Some(mem) = response.memory() {
|
||||
capacity += mem.len();
|
||||
}
|
||||
let mut response_vec = Vec::with_capacity(capacity);
|
||||
|
||||
response_vec.extend_from_slice(&thread_id.to_le_bytes());
|
||||
for word in response.to_args().iter_mut() {
|
||||
response_vec.extend_from_slice(&word.to_le_bytes());
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ const USER_AREA_END: usize = 0xff00_0000;
|
|||
// and therefore are limited to 4 MB.
|
||||
const EXCEPTION_STACK_TOP: usize = 0xffff_0000;
|
||||
const KERNEL_LOAD_OFFSET: usize = 0xffd0_0000;
|
||||
const KERNEL_STACK_PAGE_COUNT: usize = 1;
|
||||
const KERNEL_ARGUMENT_OFFSET: usize = 0xffc0_0000;
|
||||
|
||||
const FLG_VALID: usize = 0x1;
|
||||
|
|
@ -421,7 +422,7 @@ impl ProgramDescription {
|
|||
allocator.change_owner(pid as XousPid, pt_addr as usize);
|
||||
|
||||
// Allocate stack pages.
|
||||
for i in 0..STACK_PAGE_COUNT {
|
||||
for i in 0..if is_kernel { KERNEL_STACK_PAGE_COUNT} else { STACK_PAGE_COUNT } {
|
||||
let sp_page = allocator.alloc() as usize;
|
||||
allocator.map_page(
|
||||
satp,
|
||||
|
|
|
|||
|
|
@ -12,11 +12,7 @@ log-server = { path = "../log-server" }
|
|||
ticktimer-server = { path = "../ticktimer-server" }
|
||||
xous-names = { path = "../xous-names" }
|
||||
log = "0.4"
|
||||
|
||||
[dependencies.rkyv]
|
||||
version = "0.4.1"
|
||||
default-features = false
|
||||
features = ["const_generics"]
|
||||
rkyv = { version = "0.3.1", default_features = false }
|
||||
|
||||
[target.'cfg(not(any(windows,unix)))'.dependencies]
|
||||
utralib = { path = "../../utralib"}
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ impl Into<u32> for UartType {
|
|||
|
||||
/////////////////////// I2C
|
||||
// a small book-keeping struct used to report back to I2C requestors as to the status of a transaction
|
||||
#[derive(Debug, Copy, Clone, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
|
||||
#[derive(Debug, Copy, Clone, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize, Eq, PartialEq)]
|
||||
pub enum I2cStatus {
|
||||
/// used only as the default, should always be set to one of the below before sending
|
||||
Uninitialized,
|
||||
|
|
@ -67,15 +67,15 @@ pub enum I2cStatus {
|
|||
}
|
||||
#[derive(Debug, Copy, Clone, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
|
||||
pub struct I2cTransaction {
|
||||
bus_addr: u8,
|
||||
pub bus_addr: u8,
|
||||
// write address and read address are encoded in the packet field below
|
||||
txbuf: Option<[u8; 258]>, // up to 258 bytes total packet length; note cost is "same" b/c these are sent via 4kiB page remaps
|
||||
txlen: u32,
|
||||
rxbuf: Option<[u8; 258]>,
|
||||
rxlen: u32,
|
||||
timeout_ms: u32,
|
||||
pub txbuf: Option<[u8; 31]>, // limited by trait types available in Rkyv
|
||||
pub txlen: u32,
|
||||
pub rxbuf: Option<[u8; 31]>,
|
||||
pub rxlen: u32,
|
||||
pub timeout_ms: u32,
|
||||
// response field to the calling server
|
||||
status: I2cStatus,
|
||||
pub status: I2cStatus,
|
||||
}
|
||||
impl I2cTransaction {
|
||||
pub fn new() -> Self {
|
||||
|
|
|
|||
233
services/llio/src/i2c.rs
Normal file
233
services/llio/src/i2c.rs
Normal file
|
|
@ -0,0 +1,233 @@
|
|||
use heapless::Vec;
|
||||
use heapless::consts::*;
|
||||
|
||||
use llio::api::*;
|
||||
use llio::send_i2c_response;
|
||||
|
||||
#[cfg(target_os = "none")]
|
||||
use utralib::*;
|
||||
|
||||
#[derive(Eq, PartialEq)]
|
||||
enum I2cState {
|
||||
Idle,
|
||||
Write,
|
||||
Read,
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "none"))]
|
||||
pub struct I2cStateMachine {
|
||||
}
|
||||
#[cfg(not(target_os = "none"))]
|
||||
impl I2cStateMachine {
|
||||
pub fn new(_ticktimer: xous::CID, _i2c_base: *mut u32) -> Self {
|
||||
I2cStateMachine {}
|
||||
}
|
||||
pub fn initiate(&mut self, _transaction: I2cTransaction ) -> I2cStatus {
|
||||
I2cStatus::ResponseInProgress
|
||||
}
|
||||
pub fn register_listener(&mut self, _listener: xous::CID) -> Result<(), xous::CID> {
|
||||
Ok(())
|
||||
}
|
||||
pub fn handler(&mut self) {
|
||||
}
|
||||
}
|
||||
#[cfg(target_os = "none")]
|
||||
pub struct I2cStateMachine {
|
||||
transaction: I2cTransaction,
|
||||
state: I2cState,
|
||||
index: u32, // index of the current buffer in the state machine
|
||||
timestamp: u64, // timestamp of the last transaction
|
||||
ticktimer: xous::CID, // a connection to the ticktimer so we can measure timeouts
|
||||
i2c_csr: utralib::CSR<u32>,
|
||||
listeners: Vec<xous::CID, U32>,
|
||||
}
|
||||
#[cfg(target_os = "none")]
|
||||
impl I2cStateMachine {
|
||||
pub fn new(ticktimer: xous::CID, i2c_base: *mut u32) -> Self {
|
||||
I2cStateMachine {
|
||||
transaction: I2cTransaction::new(),
|
||||
state: I2cState::Idle,
|
||||
timestamp: ticktimer_server::elapsed_ms(ticktimer).unwrap(),
|
||||
ticktimer,
|
||||
i2c_csr: CSR::new(i2c_base),
|
||||
index: 0,
|
||||
listeners: Vec::new(),
|
||||
}
|
||||
}
|
||||
pub fn initiate(&mut self, transaction: I2cTransaction ) -> I2cStatus {
|
||||
// sanity-check the bounds limits, currently imposed by trait implementations available in rkyv
|
||||
if transaction.txlen > 31 || transaction.rxlen > 31 {
|
||||
return I2cStatus::ResponseFormatError
|
||||
}
|
||||
|
||||
let now = ticktimer_server::elapsed_ms(self.ticktimer).unwrap();
|
||||
if self.state != I2cState::Idle && ((now - self.timestamp) < self.transaction.timeout_ms as u64) {
|
||||
// we're in a transaction that hadn't timed out, can't accept a new one
|
||||
I2cStatus::ResponseBusy
|
||||
} else {
|
||||
if self.state != I2cState::Idle {
|
||||
// we're in a transaction, but previous transaction had timed out...
|
||||
self.report_timeout();
|
||||
// reset our state parameter
|
||||
self.state = I2cState::Idle;
|
||||
self.index = 0;
|
||||
// now we're ready to move on and try a new transaction. We hope! Maybe the block should be reset?? TBD. Need to understand the nature of the timeouts better, if and when they do happen.
|
||||
}
|
||||
self.timestamp = now;
|
||||
self.transaction = transaction.clone();
|
||||
|
||||
if self.transaction.status == I2cStatus::RequestIncoming {
|
||||
self.transaction.status = I2cStatus::ResponseInProgress;
|
||||
// now do the BusAddr stuff, so that the we can get the irq response
|
||||
if let Some(_txbuf) = self.transaction.txbuf {
|
||||
// initiate bus address with write bit set
|
||||
self.state = I2cState::Write;
|
||||
self.i2c_csr.wfo(utra::i2c::TXR_TXR, (self.transaction.bus_addr << 1 | 0) as u32);
|
||||
self.index = 0;
|
||||
self.i2c_csr.wo(utra::i2c::COMMAND,
|
||||
self.i2c_csr.ms(utra::i2c::COMMAND_WR, 1) |
|
||||
self.i2c_csr.ms(utra::i2c::COMMAND_STA, 1)
|
||||
);
|
||||
I2cStatus::ResponseInProgress
|
||||
} else if let Some(_rxbuf) = self.transaction.rxbuf {
|
||||
// initiate bus address with read bit set
|
||||
self.state = I2cState::Read;
|
||||
self.i2c_csr.wfo(utra::i2c::TXR_TXR, (self.transaction.bus_addr << 1 | 1) as u32);
|
||||
self.index = 0;
|
||||
self.i2c_csr.wo(utra::i2c::COMMAND,
|
||||
self.i2c_csr.ms(utra::i2c::COMMAND_WR, 1) |
|
||||
self.i2c_csr.ms(utra::i2c::COMMAND_STA, 1)
|
||||
);
|
||||
I2cStatus::ResponseInProgress
|
||||
} else {
|
||||
// no buffers specified, erase everything and go to idle
|
||||
self.state = I2cState::Idle;
|
||||
self.transaction = I2cTransaction::new();
|
||||
I2cStatus::ResponseFormatError
|
||||
}
|
||||
} else {
|
||||
I2cStatus::ResponseFormatError // the status field was not formatted correctly to accept the transaction
|
||||
}
|
||||
}
|
||||
}
|
||||
fn report_nack(&mut self) {
|
||||
// report the NACK situation to all the listeners
|
||||
let mut nack = I2cTransaction::new();
|
||||
nack.status = I2cStatus::ResponseNack;
|
||||
for &listener in self.listeners.iter() {
|
||||
send_i2c_response(listener, nack).expect("LLIO|I2C: couldn't send NACK to listeners");
|
||||
}
|
||||
}
|
||||
fn report_timeout(&mut self) {
|
||||
let mut timeout = I2cTransaction::new();
|
||||
timeout.status = I2cStatus::ResponseTimeout;
|
||||
for &listener in self.listeners.iter() {
|
||||
send_i2c_response(listener, timeout).expect("LLIO|I2c: couldn't send timeout error to liseners");
|
||||
}
|
||||
}
|
||||
fn report_write_done(&mut self) {
|
||||
// report the end of a write-only transaction to all the listeners
|
||||
let mut ack = I2cTransaction::new();
|
||||
ack.status = I2cStatus::ResponseWriteOk;
|
||||
for &listener in self.listeners.iter() {
|
||||
send_i2c_response(listener, ack).expect("LLIO|I2C: couldn't send write ACK to listeners");
|
||||
}
|
||||
}
|
||||
fn report_read_done(&mut self) {
|
||||
// report the result of a read transaction to all the listeners
|
||||
self.transaction.status = I2cStatus::ResponseReadOk;
|
||||
for &listener in self.listeners.iter() {
|
||||
send_i2c_response(listener, self.transaction).expect("LLIO|I2C: couldn't send read response to listeners");
|
||||
}
|
||||
}
|
||||
pub fn register_listener(&mut self, listener: xous::CID) -> Result<(), xous::CID> {
|
||||
self.listeners.push(listener)
|
||||
}
|
||||
pub fn handler(&mut self) {
|
||||
// check if the transaction had actually timed out
|
||||
let now = ticktimer_server::elapsed_ms(self.ticktimer).unwrap();
|
||||
if now - self.timestamp > self.transaction.timeout_ms as u64 {
|
||||
// previous transaction had timed out...
|
||||
self.report_timeout();
|
||||
// reset our state parameter
|
||||
self.state = I2cState::Idle;
|
||||
self.index = 0;
|
||||
self.timestamp = now;
|
||||
return;
|
||||
}
|
||||
self.timestamp = now;
|
||||
|
||||
match self.state {
|
||||
I2cState::Write => {
|
||||
if let Some(txbuf) = self.transaction.txbuf {
|
||||
// check ack bit
|
||||
if self.i2c_csr.rf(utra::i2c::STATUS_RXACK) != 1 {
|
||||
self.state = I2cState::Idle;
|
||||
self.transaction = I2cTransaction::new();
|
||||
self.report_nack();
|
||||
}
|
||||
// send next byte if there is one
|
||||
if self.index < self.transaction.txlen {
|
||||
self.i2c_csr.wfo(utra::i2c::TXR_TXR, txbuf[self.index as usize] as u32);
|
||||
if self.index == (self.transaction.txlen - 1) && self.transaction.rxbuf.is_none() {
|
||||
// send a stop bit if this is the very last in the series
|
||||
self.i2c_csr.wo(utra::i2c::COMMAND,
|
||||
self.i2c_csr.ms(utra::i2c::COMMAND_WR, 1) |
|
||||
self.i2c_csr.ms(utra::i2c::COMMAND_STO, 1)
|
||||
);
|
||||
} else {
|
||||
self.i2c_csr.wfo(utra::i2c::COMMAND_WR, 1);
|
||||
}
|
||||
self.index += 1;
|
||||
} else {
|
||||
if let Some(_rxbuf) = self.transaction.rxbuf {
|
||||
// initiate bus address with read bit set
|
||||
self.state = I2cState::Read;
|
||||
self.i2c_csr.wfo(utra::i2c::TXR_TXR, (self.transaction.bus_addr << 1 | 1) as u32);
|
||||
self.index = 0;
|
||||
self.i2c_csr.wo(utra::i2c::COMMAND,
|
||||
self.i2c_csr.ms(utra::i2c::COMMAND_WR, 1) |
|
||||
self.i2c_csr.ms(utra::i2c::COMMAND_STA, 1)
|
||||
);
|
||||
} else {
|
||||
self.report_write_done();
|
||||
self.state = I2cState::Idle;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// we should never get here, because txbuf was checked as Some() by the setup routine
|
||||
log::error!("LLIO|I2C: illegal write state");
|
||||
}
|
||||
},
|
||||
I2cState::Read => {
|
||||
if let Some(mut rxbuf) = self.transaction.rxbuf {
|
||||
if self.index > 0 {
|
||||
// we are re-entering from a previous call, store the read value from the previous call
|
||||
rxbuf[self.index as usize - 1] = self.i2c_csr.rf(utra::i2c::RXR_RXR) as u8;
|
||||
}
|
||||
if self.index < self.transaction.rxlen {
|
||||
if self.index == (self.transaction.rxlen - 1) {
|
||||
self.i2c_csr.wo(utra::i2c::COMMAND,
|
||||
self.i2c_csr.ms(utra::i2c::COMMAND_RD, 1) |
|
||||
self.i2c_csr.ms(utra::i2c::COMMAND_STO, 1) |
|
||||
self.i2c_csr.ms(utra::i2c::COMMAND_ACK, 1)
|
||||
);
|
||||
} else {
|
||||
self.i2c_csr.wfo(utra::i2c::COMMAND_RD, 1);
|
||||
}
|
||||
self.index += 1;
|
||||
} else {
|
||||
self.report_read_done();
|
||||
self.state = I2cState::Idle;
|
||||
}
|
||||
} else {
|
||||
// we should never get here, because rxbuf was checked as Some() by the setup routine
|
||||
log::error!("LLIO|I2C: illegal read state");
|
||||
}
|
||||
},
|
||||
I2cState::Idle => {
|
||||
log::error!("LLIO|I2C: received interrupt event when no transaciton pending!");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -34,9 +34,8 @@ pub fn send_i2c_request(cid: CID, transaction: I2cTransaction) -> Result<I2cStat
|
|||
|
||||
let returned = unsafe { rkyv::archived_value::<api::Opcode>(buf.as_ref(), pos)};
|
||||
if let rkyv::Archived::<api::Opcode>::I2cTxRx(result) = returned {
|
||||
use core::ops::DerefMut;
|
||||
transaction.deref_mut() = result.as_slice();
|
||||
Ok(transaction.status)
|
||||
let transaction = result.deserialise();
|
||||
Ok(transaction.status())
|
||||
} else {
|
||||
log::info!("send_i2c_request saw an unhandled return type of {:?}", buf);
|
||||
Err(xous::Error::InternalError)
|
||||
|
|
|
|||
|
|
@ -2,22 +2,23 @@
|
|||
#![cfg_attr(target_os = "none", no_main)]
|
||||
|
||||
mod api;
|
||||
use api::*;
|
||||
use llio::api::*;
|
||||
mod i2c;
|
||||
use i2c::*;
|
||||
|
||||
use core::convert::TryFrom;
|
||||
use core::pin::Pin;
|
||||
use rkyv::archived_value;
|
||||
use rkyv::Unarchive;
|
||||
|
||||
use log::{error, info};
|
||||
|
||||
#[cfg(target_os = "none")]
|
||||
mod implementation {
|
||||
use crate::api::*;
|
||||
use llio::api::*;
|
||||
use log::{error, info};
|
||||
use utralib::generated::*;
|
||||
|
||||
const STD_TIMEOUT: u32 = 100;
|
||||
|
||||
pub struct Llio {
|
||||
reboot_csr: utralib::CSR<u32>,
|
||||
crg_csr: utralib::CSR<u32>,
|
||||
|
|
@ -25,7 +26,7 @@ mod implementation {
|
|||
info_csr: utralib::CSR<u32>,
|
||||
identifier_csr: utralib::CSR<u32>,
|
||||
i2c_csr: utralib::CSR<u32>,
|
||||
handler_conn: xous::CID,
|
||||
handler_conn: Option<xous::CID>,
|
||||
event_csr: utralib::CSR<u32>,
|
||||
power_csr: utralib::CSR<u32>,
|
||||
seed_csr: utralib::CSR<u32>,
|
||||
|
|
@ -49,8 +50,8 @@ mod implementation {
|
|||
// ASSUME: we are only ever handling txrx done interrupts. If implementing ARB interrupts, this needs to be refactored to read the source and dispatch accordingly.
|
||||
fn handle_i2c_irq(_irq_no: usize, arg: *mut usize) {
|
||||
let xl = unsafe { &mut *(arg as *mut Llio) };
|
||||
if let Some(conn) = xl.i2c_conn {
|
||||
xous::try_send_message(xl.handler_conn, Opcode::IrqI2cTxrxDone.into()).map(|_| ()).unwrap();
|
||||
if let Some(conn) = xl.handler_conn {
|
||||
xous::try_send_message(conn, Opcode::IrqI2cTxrxDone.into()).map(|_| ()).unwrap();
|
||||
} else {
|
||||
log::error!("LLIO|handle_i2c_irq: TXRX done interrupt, but no connection for notification!");
|
||||
}
|
||||
|
|
@ -59,7 +60,9 @@ mod implementation {
|
|||
}
|
||||
|
||||
impl Llio {
|
||||
pub fn new(local_conn: xous::CID) -> Llio {
|
||||
pub fn get_i2c_base(&self) -> *mut u32 { self.i2c_csr.base }
|
||||
|
||||
pub fn new(handler_conn: xous::CID) -> Llio {
|
||||
let reboot_csr = xous::syscall::map_memory(
|
||||
xous::MemoryAddress::new(utra::reboot::HW_REBOOT_BASE),
|
||||
None,
|
||||
|
|
@ -102,7 +105,6 @@ mod implementation {
|
|||
xous::MemoryFlags::R | xous::MemoryFlags::W,
|
||||
)
|
||||
.expect("couldn't map I2C CSR range");
|
||||
let i2c_sid = xous::create_server_id().expect("LLIO: couldn't get random server ID for I2C");
|
||||
let event_csr = xous::syscall::map_memory(
|
||||
xous::MemoryAddress::new(utra::btevents::HW_BTEVENTS_BASE),
|
||||
None,
|
||||
|
|
@ -142,7 +144,7 @@ mod implementation {
|
|||
info_csr: CSR::new(info_csr.as_mut_ptr() as *mut u32),
|
||||
identifier_csr: CSR::new(identifier_csr.as_mut_ptr() as *mut u32),
|
||||
i2c_csr: CSR::new(i2c_csr.as_mut_ptr() as *mut u32),
|
||||
handler_conn, // connection for messages from IRQ handler
|
||||
handler_conn: Some(handler_conn), // connection for messages from IRQ handler
|
||||
event_csr: CSR::new(event_csr.as_mut_ptr() as *mut u32),
|
||||
power_csr: CSR::new(power_csr.as_mut_ptr() as *mut u32),
|
||||
seed_csr: CSR::new(seed_csr.as_mut_ptr() as *mut u32),
|
||||
|
|
@ -176,8 +178,12 @@ mod implementation {
|
|||
)
|
||||
.expect("couldn't claim I2C irq");
|
||||
|
||||
// initialize i2c
|
||||
i2c_init(&mut xl, utralib::LITEX_CONFIG_CLOCK_FREQUENCY);
|
||||
// initialize i2c clocks
|
||||
// set the prescale assuming 100MHz cpu operation: 100MHz / ( 5 * 100kHz ) - 1 = 199
|
||||
let clkcode = (utralib::LITEX_CONFIG_CLOCK_FREQUENCY as u32) / (5 * 100_000) - 1;
|
||||
xl.i2c_csr.wfo(utra::i2c::PRESCALE_PRESCALE, clkcode & 0xFFFF);
|
||||
// enable the block
|
||||
xl.i2c_csr.rmwf(utra::i2c::CONTROL_EN, 1);
|
||||
// clear any interrupts pending, just in case something went pear-shaped during initialization
|
||||
xl.i2c_csr.wo(utra::i2c::EV_PENDING, xl.i2c_csr.r(utra::i2c::EV_PENDING));
|
||||
// now enable interrupts
|
||||
|
|
@ -348,33 +354,24 @@ mod implementation {
|
|||
pub fn xadc_gpio2(&self) -> u16 {
|
||||
self.xadc_csr.rf(utra::trng::XADC_GPIO2_XADC_GPIO2) as u16
|
||||
}
|
||||
|
||||
|
||||
fn i2c_init(&mut self, clock_hz: u32) {
|
||||
// set the prescale assuming 100MHz cpu operation: 100MHz / ( 5 * 100kHz ) - 1 = 199
|
||||
let clkcode: u32 = clock_hz / (5 * 100_000) - 1;
|
||||
self.i2c_csr.wfo(utra::i2c::PRESCALE_PRESCALE, clkcode & 0xFFFF);
|
||||
|
||||
// enable the block
|
||||
self.i2c_csr.rmwf(utra::i2c::CONTROL_EN, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// a stub to try to avoid breaking hosted mode for as long as possible.
|
||||
#[cfg(not(target_os = "none"))]
|
||||
mod implementation {
|
||||
use crate::api::*;
|
||||
use llio::api::*;
|
||||
use log::{error, info};
|
||||
|
||||
pub struct Llio {
|
||||
}
|
||||
|
||||
impl Llio {
|
||||
pub fn new() -> Llio {
|
||||
pub fn new(_handler_conn: xous::CID) -> Llio {
|
||||
Llio {
|
||||
}
|
||||
}
|
||||
pub fn get_i2c_base(&self) -> *mut u32 { 0 as *mut u32 }
|
||||
|
||||
pub fn reboot(&self, _reboot_soc: bool) {}
|
||||
pub fn set_reboot_vector(&self, _vector: u32) {}
|
||||
|
|
@ -435,8 +432,6 @@ mod implementation {
|
|||
fn xmain() -> ! {
|
||||
let debug1 = false;
|
||||
use crate::implementation::Llio;
|
||||
//use heapless::Vec;
|
||||
//use heapless::consts::*;
|
||||
|
||||
log_server::init_wait().unwrap();
|
||||
info!("LLIO: my PID is {}", xous::process::id());
|
||||
|
|
@ -452,7 +447,7 @@ fn xmain() -> ! {
|
|||
let ticktimer_server_id = xous::SID::from_bytes(b"ticktimer-server").unwrap();
|
||||
let ticktimer_conn = xous::connect(ticktimer_server_id).unwrap();
|
||||
// create an i2c state machine handler
|
||||
let mut i2c_machine = I2cStateMachine::new(ticktimer_conn, llio.i2c_csr);
|
||||
let mut i2c_machine = I2cStateMachine::new(ticktimer_conn, llio.get_i2c_base());
|
||||
|
||||
if debug1{info!("LLIO: starting main loop");}
|
||||
let mut reboot_requested: bool = false;
|
||||
|
|
@ -590,7 +585,7 @@ fn xmain() -> ! {
|
|||
},
|
||||
Opcode::IrqI2cTxrxDone => {
|
||||
// I2C state machine handler irq received
|
||||
ic2_machine.handler();
|
||||
i2c_machine.handler();
|
||||
},
|
||||
_ => error!("LLIO: no handler for opcode"),
|
||||
}
|
||||
|
|
@ -602,7 +597,7 @@ fn xmain() -> ! {
|
|||
};
|
||||
match &*value {
|
||||
rkyv::Archived::<Opcode>::I2cTxRx(rkyv_i2c) => {
|
||||
let i2c_txrx: I2cTransaction = rkyv_i2c.deserialize();
|
||||
let mut i2c_txrx: I2cTransaction = rkyv_i2c.deserialize();
|
||||
|
||||
let status = i2c_machine.initiate(i2c_txrx);
|
||||
|
||||
|
|
@ -610,19 +605,20 @@ fn xmain() -> ! {
|
|||
// pack our data back into the buffer to return
|
||||
use rkyv::Write;
|
||||
let mut writer = rkyv::ArchiveBuffer::new(buf);
|
||||
writer.archive(&api::Opcode::I2cTxRx(i2c_txrx)).expect("LLIO: couldn't re-archive return value to I2cTxRx");
|
||||
writer.archive(&Opcode::I2cTxRx(i2c_txrx)).expect("LLIO: couldn't re-archive return value to I2cTxRx");
|
||||
},
|
||||
_ => panic!("LLIO: invalid MutableBorrow memory message")
|
||||
};
|
||||
} else if let xous::Message::Borrow(m) = &envelope.body {
|
||||
let buf = unsafe { buffer::XousBuffer::from_memory_message(m) };
|
||||
let buf = unsafe { xous::XousBuffer::from_memory_message(m) };
|
||||
let bytes = Pin::new(buf.as_ref());
|
||||
let value = unsafe {
|
||||
archived_value::<api::Opcode>(&bytes, m.id as usize)
|
||||
};
|
||||
match &*value {
|
||||
rkyv::Archived::<api::Opcode>::I2cSubscribe(registration) => {
|
||||
let cid = xous_names::request_connection_blocking(registration.as_str()).expect("KBD: can't connect to requested listener for reporting events");
|
||||
let reg: xous::String::<64> = registration.unarchive();
|
||||
let cid = xous_names::request_connection_blocking(reg.to_str()).expect("KBD: can't connect to requested listener for reporting events");
|
||||
i2c_machine.register_listener(cid).expect("LLIO: probably ran out of slots for I2C event reporting");
|
||||
},
|
||||
_ => panic!("LLIO: invalid Borrow memory message"),
|
||||
|
|
|
|||
|
|
@ -1,15 +1,10 @@
|
|||
use xous::{String, MessageEnvelope};
|
||||
use xous::String;
|
||||
use core::fmt::Write;
|
||||
/////////////////////////// Common items to all commands
|
||||
pub trait ShellCmdApi<'a> {
|
||||
// user implemented:
|
||||
// called to process the command with the remainder of the string attached
|
||||
fn process(&mut self, args: String::<1024>, env: &mut CommonEnv) -> Result<Option<String::<1024>>, xous::Error>;
|
||||
// called to process incoming messages that may have been origniated by the most recently issued command
|
||||
fn callback(&mut self, msg: &MessageEnvelope, _env: &mut CommonEnv) -> Result<Option<String::<1024>>, xous::Error> {
|
||||
log::info!("SHCH: received unhandled message {:?}", msg);
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
// created with cmd_api! macro
|
||||
// checks if the command matches the current verb in question
|
||||
|
|
@ -33,7 +28,6 @@ macro_rules! cmd_api {
|
|||
};
|
||||
}
|
||||
|
||||
|
||||
/////////////////////////// Command shell integration
|
||||
#[derive(Debug)]
|
||||
pub struct CommonEnv {
|
||||
|
|
@ -61,17 +55,14 @@ mod echo; use echo::*;
|
|||
mod test; use test::*;
|
||||
mod sleep; use sleep::*;
|
||||
mod sensors; use sensors::*;
|
||||
mod callback; use callback::*;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct CmdEnv {
|
||||
common_env: CommonEnv,
|
||||
lastverb: String::<256>,
|
||||
///// 2. declare storage for your command here.
|
||||
test_cmd: Test,
|
||||
sleep_cmd: Sleep,
|
||||
sensors_cmd: Sensors,
|
||||
callback_cmd: CallBack,
|
||||
}
|
||||
impl CmdEnv {
|
||||
pub fn new(gam: xous::CID) -> CmdEnv {
|
||||
|
|
@ -83,16 +74,14 @@ impl CmdEnv {
|
|||
ticktimer: xous::connect(ticktimer_server_id).unwrap(),
|
||||
gam,
|
||||
},
|
||||
lastverb: String::<256>::new(),
|
||||
///// 3. initialize your storage, by calling new()
|
||||
test_cmd: Test::new(),
|
||||
sleep_cmd: Sleep::new(),
|
||||
sensors_cmd: Sensors::new(),
|
||||
callback_cmd: CallBack::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn dispatch(&mut self, maybe_cmdline: Option<&mut String::<1024>>, maybe_callback: Option<&MessageEnvelope>) -> Result<Option<String::<1024>>, xous::Error> {
|
||||
pub fn dispatch(&mut self, cmdline: &mut String::<1024>) -> Result<Option<String::<1024>>, xous::Error> {
|
||||
let mut ret = String::<1024>::new();
|
||||
|
||||
let mut echo_cmd = Echo {}; // this command has no persistent storage, so we can "create" it every time we call dispatch (but it's a zero-cost absraction so this doesn't actually create any instructions)
|
||||
|
|
@ -102,59 +91,38 @@ impl CmdEnv {
|
|||
&mut self.test_cmd,
|
||||
&mut self.sleep_cmd,
|
||||
&mut self.sensors_cmd,
|
||||
&mut self.callback_cmd,
|
||||
];
|
||||
|
||||
if let Some(cmdline) = maybe_cmdline {
|
||||
let maybe_verb = tokenize(cmdline);
|
||||
let maybe_verb = tokenize(cmdline);
|
||||
|
||||
let mut cmd_ret: Result<Option<String::<1024>>, xous::Error> = Ok(None);
|
||||
if let Some(verb_string) = maybe_verb {
|
||||
let verb = verb_string.to_str();
|
||||
let mut cmd_ret: Result<Option<String::<1024>>, xous::Error> = Ok(None);
|
||||
if let Some(verb_string) = maybe_verb {
|
||||
let verb = verb_string.to_str();
|
||||
|
||||
// search through the list of commands linearly until one matches,
|
||||
// then run it.
|
||||
let mut match_found = false;
|
||||
for cmd in commands.iter_mut() {
|
||||
if cmd.matches(verb) {
|
||||
match_found = true;
|
||||
cmd_ret = cmd.process(*cmdline, &mut self.common_env);
|
||||
self.lastverb.clear();
|
||||
write!(self.lastverb, "{}", verb).expect("SHCH: couldn't record last verb");
|
||||
};
|
||||
}
|
||||
|
||||
// if none match, create a list of available commands
|
||||
if !match_found {
|
||||
let mut first = true;
|
||||
write!(ret, "Commands: ").unwrap();
|
||||
for cmd in commands.iter() {
|
||||
if !first {
|
||||
ret.append(", ")?;
|
||||
}
|
||||
ret.append(cmd.verb())?;
|
||||
first = false;
|
||||
}
|
||||
Ok(Some(ret))
|
||||
} else {
|
||||
cmd_ret
|
||||
}
|
||||
} else {
|
||||
Ok(None)
|
||||
// search through the list of commands linearly until one matches,
|
||||
// then run it.
|
||||
let mut match_found = false;
|
||||
for cmd in commands.iter_mut() {
|
||||
if cmd.matches(verb) {
|
||||
match_found = true;
|
||||
cmd_ret = cmd.process(*cmdline, &mut self.common_env);
|
||||
};
|
||||
}
|
||||
} else if let Some(callback) = maybe_callback {
|
||||
let mut cmd_ret: Result<Option<String::<1024>>, xous::Error> = Ok(None);
|
||||
if self.lastverb.len() > 0 {
|
||||
let verb = self.lastverb.to_str();
|
||||
for cmd in commands.iter_mut() {
|
||||
if cmd.matches(verb) {
|
||||
cmd_ret = cmd.callback(callback, &mut self.common_env);
|
||||
break;
|
||||
};
|
||||
|
||||
// if none match, create a list of available commands
|
||||
if !match_found {
|
||||
let mut first = true;
|
||||
write!(ret, "Commands: ").unwrap();
|
||||
for cmd in commands.iter() {
|
||||
if !first {
|
||||
ret.append(", ")?;
|
||||
}
|
||||
ret.append(cmd.verb())?;
|
||||
first = false;
|
||||
}
|
||||
cmd_ret
|
||||
Ok(Some(ret))
|
||||
} else {
|
||||
Ok(None)
|
||||
cmd_ret
|
||||
}
|
||||
} else {
|
||||
Ok(None)
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
#![cfg_attr(target_os = "none", no_std)]
|
||||
#![cfg_attr(target_os = "none", no_main)]
|
||||
|
||||
use log::info;
|
||||
use log::{error, info};
|
||||
|
||||
use core::fmt::Write;
|
||||
use core::convert::TryFrom;
|
||||
|
|
@ -16,8 +16,6 @@ use graphics_server::{Gid, Point, Rectangle, TextBounds, TextView, DrawStyle, Gl
|
|||
use heapless::spsc::Queue;
|
||||
use heapless::consts::U16;
|
||||
|
||||
use xous::MessageEnvelope;
|
||||
|
||||
mod cmds;
|
||||
use cmds::*;
|
||||
|
||||
|
|
@ -34,8 +32,7 @@ struct Repl {
|
|||
// optional structures that indicate new input to the Repl loop per iteration
|
||||
// an input string
|
||||
input: Option<xous::String<1024>>,
|
||||
// messages from other servers
|
||||
msg: Option<MessageEnvelope>,
|
||||
// examples of future inputs: returned values via other services
|
||||
|
||||
// record our input history
|
||||
history: Queue<History, U16>,
|
||||
|
|
@ -60,7 +57,6 @@ impl Repl{
|
|||
let screensize = gam::get_canvas_bounds(gam_conn, content).expect("SHCH: couldn't get dimensions of content canvas");
|
||||
Repl {
|
||||
input: None,
|
||||
msg: None,
|
||||
history: Queue::new(),
|
||||
content,
|
||||
gam: gam_conn,
|
||||
|
|
@ -84,10 +80,6 @@ impl Repl{
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn msg(&mut self, message: MessageEnvelope) {
|
||||
self.msg = Some(message);
|
||||
}
|
||||
|
||||
fn circular_push(&mut self, item: History) {
|
||||
if self.history.len() == self.history.capacity() {
|
||||
self.history.dequeue().expect("SHCH: couldn't dequeue historye");
|
||||
|
|
@ -116,17 +108,7 @@ impl Repl{
|
|||
|
||||
// take the input and pass it on to the various command parsers, and attach result
|
||||
if let Some(mut local) = self.input {
|
||||
if let Some(res) = self.env.dispatch(Some(&mut local), None).expect("SHCH: command dispatch failed") {
|
||||
let mut response = xous::String::<1024>::new();
|
||||
write!(response, "{}", res).expect("SHCH: can't copy result to history");
|
||||
let output_history = History {
|
||||
text: response,
|
||||
is_input: false
|
||||
};
|
||||
self.circular_push(output_history);
|
||||
}
|
||||
} else if let Some(msg) = &self.msg {
|
||||
if let Some(res) = self.env.dispatch(None, Some(msg)).expect("SCHC: callback failed") {
|
||||
if let Some(res) = self.env.dispatch(&mut local).expect("SHCH: command dispatch failed") {
|
||||
let mut response = xous::String::<1024>::new();
|
||||
write!(response, "{}", res).expect("SHCH: can't copy result to history");
|
||||
let output_history = History {
|
||||
|
|
@ -139,7 +121,6 @@ impl Repl{
|
|||
|
||||
// clear all the inputs to the loop, so we don't process them twice
|
||||
self.input = None;
|
||||
self.msg = None;
|
||||
// redraw UI now that we've responded
|
||||
self.redraw().expect("SHCH: can't redraw");
|
||||
|
||||
|
|
@ -252,8 +233,7 @@ fn xmain() -> ! {
|
|||
}
|
||||
}
|
||||
} else {
|
||||
repl.msg(envelope);
|
||||
update_repl = true;
|
||||
error!("SHCH: couldn't convert message");
|
||||
}
|
||||
|
||||
if update_repl {
|
||||
|
|
|
|||
|
|
@ -59,3 +59,82 @@ impl Authenticate {
|
|||
ID_AUTHENTICATE as u32
|
||||
}
|
||||
}
|
||||
|
||||
// We keep XousServerName around because want to be able to index off the server name, without
|
||||
// burdening the Kernel String type with the Hash32 methods
|
||||
|
||||
// --------------------- Taken from rkyv docs https://docs.rs/rkyv/0.3.0/rkyv/trait.Archive.html //
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct XousServerName {
|
||||
value: [u8; 64],
|
||||
length: u32,
|
||||
}
|
||||
|
||||
impl Default for XousServerName {
|
||||
fn default() -> Self {
|
||||
XousServerName {
|
||||
value: [0u8; 64],
|
||||
length: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl XousServerName {
|
||||
pub fn to_str(&self) -> &str {
|
||||
core::str::from_utf8(unsafe {
|
||||
core::slice::from_raw_parts(self.value.as_ptr(), self.length as usize)
|
||||
})
|
||||
.unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
// Allow using the `write!()` macro to write into a `&XousServerName`
|
||||
impl core::fmt::Write for XousServerName {
|
||||
fn write_str(&mut self, s: &str) -> core::result::Result<(), core::fmt::Error> {
|
||||
self.length = 0;
|
||||
let b = s.bytes();
|
||||
|
||||
// Ensure the length is acceptable
|
||||
if b.len() > self.value.len() {
|
||||
Err(core::fmt::Error)?;
|
||||
}
|
||||
self.length = b.len() as u32;
|
||||
|
||||
// Copy the string into this variable
|
||||
for (dest, src) in self.value.iter_mut().zip(s.bytes()) {
|
||||
*dest = src;
|
||||
}
|
||||
|
||||
// Attempt to convert the string to UTF-8 to validate it's correct UTF-8
|
||||
core::str::from_utf8(unsafe {
|
||||
core::slice::from_raw_parts(self.value.as_ptr(), self.length as usize)
|
||||
})
|
||||
.map_err(|_| core::fmt::Error)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl hash32::Hash for XousServerName {
|
||||
fn hash<H>(&self, state: &mut H)
|
||||
where
|
||||
H: Hasher,
|
||||
{
|
||||
Hash::hash(&self.value[..self.length as usize], state);
|
||||
Hash::hash(&self.length, state)
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for XousServerName {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.value[..self.length as usize] == other.value[..other.length as usize]
|
||||
&& self.length == other.length
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for XousServerName {}
|
||||
|
||||
impl core::fmt::Display for XousServerName {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
write!(f, "{}", self.to_str())
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1328,10 +1328,10 @@ register to disable individual events.]]></description>
|
|||
<register>
|
||||
<name>GIT_GITREV</name>
|
||||
<description><![CDATA[First 32-bits of the git revision. This documentation was built from git rev
|
||||
``d77dca2f``, so this value is 3615345199, which should be enough to check out
|
||||
``2a2abe5e``, so this value is 707444318, which should be enough to check out
|
||||
the exact git version used to build this firmware.]]></description>
|
||||
<addressOffset>0x0014</addressOffset>
|
||||
<resetValue>0xd77dca2f</resetValue>
|
||||
<resetValue>0x2a2abe5e</resetValue>
|
||||
<size>32</size>
|
||||
<fields>
|
||||
<field>
|
||||
|
|
@ -1348,7 +1348,7 @@ the exact git version used to build this firmware.]]></description>
|
|||
is ``1``, then the repository this was built from has one additional commit
|
||||
beyond the tag indicated in `MAJOR`, `MINOR`, and `REVISION`.]]></description>
|
||||
<addressOffset>0x0018</addressOffset>
|
||||
<resetValue>0x0d</resetValue>
|
||||
<resetValue>0x0e</resetValue>
|
||||
<size>32</size>
|
||||
<fields>
|
||||
<field>
|
||||
|
|
@ -1957,8 +1957,7 @@ upon the completion of one byte of data transfer.]]></description>
|
|||
</register>
|
||||
<register>
|
||||
<name>EV_STATUS</name>
|
||||
<description><![CDATA[This register contains the current raw level of the i2c_int event trigger.
|
||||
Writes to this register have no effect.]]></description>
|
||||
<description><![CDATA[Triggered on the falling edge of TIP]]></description>
|
||||
<addressOffset>0x0018</addressOffset>
|
||||
<resetValue>0x00</resetValue>
|
||||
<size>32</size>
|
||||
|
|
@ -1970,12 +1969,18 @@ Writes to this register have no effect.]]></description>
|
|||
<lsb>0</lsb>
|
||||
<description><![CDATA[Level of the ``i2c_int`` event]]></description>
|
||||
</field>
|
||||
<field>
|
||||
<name>txrx_done</name>
|
||||
<msb>1</msb>
|
||||
<bitRange>[1:1]</bitRange>
|
||||
<lsb>1</lsb>
|
||||
<description><![CDATA[Level of the ``txrx_done`` event]]></description>
|
||||
</field>
|
||||
</fields>
|
||||
</register>
|
||||
<register>
|
||||
<name>EV_PENDING</name>
|
||||
<description><![CDATA[When a i2c_int event occurs, the corresponding bit will be set in this
|
||||
register. To clear the Event, set the corresponding bit in this register.]]></description>
|
||||
<description><![CDATA[Triggered on the falling edge of TIP]]></description>
|
||||
<addressOffset>0x001c</addressOffset>
|
||||
<resetValue>0x00</resetValue>
|
||||
<size>32</size>
|
||||
|
|
@ -1985,14 +1990,20 @@ register. To clear the Event, set the corresponding bit in this register.]]></d
|
|||
<msb>0</msb>
|
||||
<bitRange>[0:0]</bitRange>
|
||||
<lsb>0</lsb>
|
||||
<description><![CDATA[`1` if a `i2c_int` event occurred. This Event is triggered on a **rising** edge.]]></description>
|
||||
<description><![CDATA[Triggered when arbitration is lost]]></description>
|
||||
</field>
|
||||
<field>
|
||||
<name>txrx_done</name>
|
||||
<msb>1</msb>
|
||||
<bitRange>[1:1]</bitRange>
|
||||
<lsb>1</lsb>
|
||||
<description><![CDATA[Triggered on the falling edge of TIP]]></description>
|
||||
</field>
|
||||
</fields>
|
||||
</register>
|
||||
<register>
|
||||
<name>EV_ENABLE</name>
|
||||
<description><![CDATA[This register enables the corresponding i2c_int events. Write a ``0`` to this
|
||||
register to disable individual events.]]></description>
|
||||
<description><![CDATA[Triggered on the falling edge of TIP]]></description>
|
||||
<addressOffset>0x0020</addressOffset>
|
||||
<resetValue>0x00</resetValue>
|
||||
<size>32</size>
|
||||
|
|
@ -2004,6 +2015,13 @@ register to disable individual events.]]></description>
|
|||
<lsb>0</lsb>
|
||||
<description><![CDATA[Write a ``1`` to enable the ``i2c_int`` Event]]></description>
|
||||
</field>
|
||||
<field>
|
||||
<name>txrx_done</name>
|
||||
<msb>1</msb>
|
||||
<bitRange>[1:1]</bitRange>
|
||||
<lsb>1</lsb>
|
||||
<description><![CDATA[Write a ``1`` to enable the ``txrx_done`` Event]]></description>
|
||||
</field>
|
||||
</fields>
|
||||
</register>
|
||||
</registers>
|
||||
|
|
@ -3038,7 +3056,7 @@ again until the interrupt is serviced.]]></description>
|
|||
<name>SEED1</name>
|
||||
<description><![CDATA[Bits 32-63 of `SEED_SEED`. Seed used for the build]]></description>
|
||||
<addressOffset>0x0000</addressOffset>
|
||||
<resetValue>0x48f7dee1</resetValue>
|
||||
<resetValue>0x1a7a2a66</resetValue>
|
||||
<size>32</size>
|
||||
<fields>
|
||||
<field>
|
||||
|
|
@ -3053,7 +3071,7 @@ again until the interrupt is serviced.]]></description>
|
|||
<name>SEED0</name>
|
||||
<description><![CDATA[Bits 0-31 of `SEED_SEED`.]]></description>
|
||||
<addressOffset>0x0004</addressOffset>
|
||||
<resetValue>0xc2db130</resetValue>
|
||||
<resetValue>0x4b326b1e</resetValue>
|
||||
<size>32</size>
|
||||
<fields>
|
||||
<field>
|
||||
|
|
|
|||
|
|
@ -13,9 +13,6 @@ log = { version = "0.4", optional = true }
|
|||
core = { version = '1.0.0', optional = true, package = 'rustc-std-workspace-core' }
|
||||
compiler_builtins = { version = '0.1.0', optional = true }
|
||||
|
||||
# for allowing strings to be used as indexes in hash maps
|
||||
hash32 = "0.1.0"
|
||||
hash32-derive = "0.1.0"
|
||||
# for sending strings
|
||||
[dependencies.rkyv]
|
||||
version = "0.4.1"
|
||||
|
|
|
|||
|
|
@ -665,7 +665,12 @@ fn _xous_syscall_to(
|
|||
// );
|
||||
|
||||
// Send the packet to the server
|
||||
let mut pkt = vec![];
|
||||
let mut capacity = 9 * core::mem::size_of::<usize>();
|
||||
if let Some(mem) = call.memory() {
|
||||
capacity += mem.len();
|
||||
}
|
||||
|
||||
let mut pkt = Vec::with_capacity(capacity);
|
||||
THREAD_ID.with(|tid| pkt.extend_from_slice(&tid.borrow().to_le_bytes()));
|
||||
for word in &[nr, a1, a2, a3, a4, a5, a6, a7] {
|
||||
pkt.extend_from_slice(&word.to_le_bytes());
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@ use rkyv::ser::Serializer;
|
|||
use rkyv::archived_value;
|
||||
use rkyv::ArchiveUnsized;
|
||||
use rkyv::SerializeUnsized;
|
||||
use hash32::{Hash, Hasher};
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct String<const N: usize> {
|
||||
|
|
@ -276,17 +275,6 @@ impl<S: rkyv::ser::Serializer + ?Sized, const N: usize> rkyv::Serialize<S> for S
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
impl<const N: usize> hash32::Hash for String<N> {
|
||||
fn hash<H>(&self, state: &mut H)
|
||||
where
|
||||
H: Hasher,
|
||||
{
|
||||
Hash::hash(&self.bytes[..self.len as usize], state);
|
||||
Hash::hash(&self.len, state)
|
||||
}
|
||||
}
|
||||
|
||||
impl<const N: usize> PartialEq for String<N> {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.bytes[..self.len as usize] == other.bytes[..other.len as usize]
|
||||
|
|
|
|||
Loading…
Reference in a new issue