wpan/mac: further cleanup
This commit is contained in:
parent
cd592cb055
commit
582006c75c
4 changed files with 257 additions and 161 deletions
|
@ -1,3 +1,8 @@
|
||||||
|
use core::cell::RefCell;
|
||||||
|
|
||||||
|
use embassy_sync::blocking_mutex::raw::NoopRawMutex;
|
||||||
|
use embassy_sync::pubsub::{PubSubChannel, Subscriber};
|
||||||
|
|
||||||
use super::helpers::to_u16;
|
use super::helpers::to_u16;
|
||||||
use super::indications::{
|
use super::indications::{
|
||||||
AssociateIndication, BeaconNotifyIndication, CommStatusIndication, DataIndication, DisassociateIndication,
|
AssociateIndication, BeaconNotifyIndication, CommStatusIndication, DataIndication, DisassociateIndication,
|
||||||
|
@ -25,6 +30,7 @@ pub trait ParseableMacEvent {
|
||||||
Self: Sized;
|
Self: Sized;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
pub enum MacEvent {
|
pub enum MacEvent {
|
||||||
MlmeAssociateCnf(AssociateConfirm),
|
MlmeAssociateCnf(AssociateConfirm),
|
||||||
|
@ -92,3 +98,116 @@ impl TryFrom<&[u8]> for MacEvent {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO this PubSub can probably be replaced with shared memory to make it a bit more efficient.
|
||||||
|
pub type EventQueue = PubSubChannel<NoopRawMutex, Message, 2, 1, 1>;
|
||||||
|
pub type EventSubscriber<'a> = Subscriber<'a, NoopRawMutex, Message, 2, 1, 1>;
|
||||||
|
|
||||||
|
pub struct Events {
|
||||||
|
pub queue: EventQueue,
|
||||||
|
pub mask: SharedEventMask,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Events {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
queue: EventQueue::new(),
|
||||||
|
mask: SharedEventMask::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
|
pub struct Status {
|
||||||
|
pub event_type: MacEvent,
|
||||||
|
pub status: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
pub enum Payload {
|
||||||
|
None,
|
||||||
|
// BssInfo(BssInfo),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
|
||||||
|
pub struct Message {
|
||||||
|
pub header: Status,
|
||||||
|
pub payload: Payload,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Message {
|
||||||
|
pub fn new(status: Status, payload: Payload) -> Self {
|
||||||
|
Self {
|
||||||
|
header: status,
|
||||||
|
payload,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
struct EventMask {
|
||||||
|
mask: [u32; Self::WORD_COUNT],
|
||||||
|
}
|
||||||
|
|
||||||
|
impl EventMask {
|
||||||
|
const WORD_COUNT: usize = ((Event::LAST as u32 + (u32::BITS - 1)) / u32::BITS) as usize;
|
||||||
|
|
||||||
|
fn enable(&mut self, event: MacEvent) {
|
||||||
|
let n = event as u32;
|
||||||
|
let word = n / u32::BITS;
|
||||||
|
let bit = n % u32::BITS;
|
||||||
|
|
||||||
|
self.mask[word as usize] |= 1 << bit;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn disable(&mut self, event: MacEvent) {
|
||||||
|
let n = event as u32;
|
||||||
|
let word = n / u32::BITS;
|
||||||
|
let bit = n % u32::BITS;
|
||||||
|
|
||||||
|
self.mask[word as usize] &= !(1 << bit);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_enabled(&self, event: MacEvent) -> bool {
|
||||||
|
let n = event as u32;
|
||||||
|
let word = n / u32::BITS;
|
||||||
|
let bit = n % u32::BITS;
|
||||||
|
|
||||||
|
self.mask[word as usize] & (1 << bit) > 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
|
||||||
|
pub struct SharedEventMask {
|
||||||
|
mask: RefCell<EventMask>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SharedEventMask {
|
||||||
|
pub fn enable(&self, events: &[MacEvent]) {
|
||||||
|
let mut mask = self.mask.borrow_mut();
|
||||||
|
for event in events {
|
||||||
|
mask.enable(*event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn disable(&self, events: &[MacEvent]) {
|
||||||
|
let mut mask = self.mask.borrow_mut();
|
||||||
|
for event in events {
|
||||||
|
mask.disable(*event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn disable_all(&self) {
|
||||||
|
let mut mask = self.mask.borrow_mut();
|
||||||
|
mask.mask = Default::default();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_enabled(&self, event: MacEvent) -> bool {
|
||||||
|
let mask = self.mask.borrow();
|
||||||
|
mask.is_enabled(event)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
124
embassy-stm32-wpan/src/mac/ioctl.rs
Normal file
124
embassy-stm32-wpan/src/mac/ioctl.rs
Normal file
|
@ -0,0 +1,124 @@
|
||||||
|
use core::cell::{Cell, RefCell};
|
||||||
|
use core::future::poll_fn;
|
||||||
|
use core::task::{Poll, Waker};
|
||||||
|
|
||||||
|
use embassy_sync::waitqueue::WakerRegistration;
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
pub enum IoctlType {
|
||||||
|
Get = 0,
|
||||||
|
Set = 2,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
pub struct PendingIoctl {
|
||||||
|
pub buf: *mut [u8],
|
||||||
|
pub kind: IoctlType,
|
||||||
|
pub cmd: u32,
|
||||||
|
pub iface: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
enum IoctlStateInner {
|
||||||
|
Pending(PendingIoctl),
|
||||||
|
Sent { buf: *mut [u8] },
|
||||||
|
Done { resp_len: usize },
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Wakers {
|
||||||
|
control: WakerRegistration,
|
||||||
|
runner: WakerRegistration,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for Wakers {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
control: WakerRegistration::new(),
|
||||||
|
runner: WakerRegistration::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct IoctlState {
|
||||||
|
state: Cell<IoctlStateInner>,
|
||||||
|
wakers: RefCell<Wakers>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IoctlState {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
state: Cell::new(IoctlStateInner::Done { resp_len: 0 }),
|
||||||
|
wakers: Default::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn wake_control(&self) {
|
||||||
|
self.wakers.borrow_mut().control.wake();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn register_control(&self, waker: &Waker) {
|
||||||
|
self.wakers.borrow_mut().control.register(waker);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn wake_runner(&self) {
|
||||||
|
self.wakers.borrow_mut().runner.wake();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn register_runner(&self, waker: &Waker) {
|
||||||
|
self.wakers.borrow_mut().runner.register(waker);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn wait_complete(&self) -> usize {
|
||||||
|
poll_fn(|cx| {
|
||||||
|
if let IoctlStateInner::Done { resp_len } = self.state.get() {
|
||||||
|
Poll::Ready(resp_len)
|
||||||
|
} else {
|
||||||
|
self.register_control(cx.waker());
|
||||||
|
Poll::Pending
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn wait_pending(&self) -> PendingIoctl {
|
||||||
|
let pending = poll_fn(|cx| {
|
||||||
|
if let IoctlStateInner::Pending(pending) = self.state.get() {
|
||||||
|
Poll::Ready(pending)
|
||||||
|
} else {
|
||||||
|
self.register_runner(cx.waker());
|
||||||
|
Poll::Pending
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.await;
|
||||||
|
|
||||||
|
self.state.set(IoctlStateInner::Sent { buf: pending.buf });
|
||||||
|
pending
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn cancel_ioctl(&self) {
|
||||||
|
self.state.set(IoctlStateInner::Done { resp_len: 0 });
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn do_ioctl(&self, kind: IoctlType, cmd: u32, iface: u32, buf: &mut [u8]) -> usize {
|
||||||
|
self.state
|
||||||
|
.set(IoctlStateInner::Pending(PendingIoctl { buf, kind, cmd, iface }));
|
||||||
|
self.wake_runner();
|
||||||
|
self.wait_complete().await
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn ioctl_done(&self, response: &[u8]) {
|
||||||
|
if let IoctlStateInner::Sent { buf } = self.state.get() {
|
||||||
|
// trace!("IOCTL Response: {:02x}", Bytes(response));
|
||||||
|
|
||||||
|
// TODO fix this
|
||||||
|
(unsafe { &mut *buf }[..response.len()]).copy_from_slice(response);
|
||||||
|
|
||||||
|
self.state.set(IoctlStateInner::Done {
|
||||||
|
resp_len: response.len(),
|
||||||
|
});
|
||||||
|
self.wake_control();
|
||||||
|
} else {
|
||||||
|
warn!("IOCTL Response but no pending Ioctl");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,6 +4,7 @@ pub mod control;
|
||||||
pub mod event;
|
pub mod event;
|
||||||
mod helpers;
|
mod helpers;
|
||||||
pub mod indications;
|
pub mod indications;
|
||||||
|
mod ioctl;
|
||||||
mod macros;
|
mod macros;
|
||||||
mod opcodes;
|
mod opcodes;
|
||||||
pub mod responses;
|
pub mod responses;
|
||||||
|
@ -14,11 +15,10 @@ use core::slice;
|
||||||
|
|
||||||
use embassy_net_driver_channel as ch;
|
use embassy_net_driver_channel as ch;
|
||||||
|
|
||||||
use crate::bus::Bus;
|
|
||||||
pub use crate::bus::SpiBusCyw43;
|
|
||||||
pub use crate::mac::control::{Control, Error as ControlError};
|
pub use crate::mac::control::{Control, Error as ControlError};
|
||||||
pub use crate::runner::Runner;
|
use crate::mac::event::Events;
|
||||||
pub use crate::structs::BssInfo;
|
use crate::mac::ioctl::IoctlState;
|
||||||
|
pub use crate::mac::runner::Runner;
|
||||||
use crate::sub::mac::Mac;
|
use crate::sub::mac::Mac;
|
||||||
|
|
||||||
const MTU: usize = 1514;
|
const MTU: usize = 1514;
|
||||||
|
@ -76,15 +76,15 @@ impl PowerManagementMode {
|
||||||
|
|
||||||
pub type NetDriver<'a> = ch::Device<'a, MTU>;
|
pub type NetDriver<'a> = ch::Device<'a, MTU>;
|
||||||
|
|
||||||
pub async fn new<'a, PWR, SPI>(
|
pub async fn new<'a>(
|
||||||
state: &'a mut State,
|
state: &'a mut State,
|
||||||
mac_subsystem: Mac,
|
mac_subsystem: Mac,
|
||||||
firmware: &[u8],
|
firmware: &[u8],
|
||||||
) -> (NetDriver<'a>, Control<'a>, Runner<'a, PWR, SPI>) {
|
) -> (NetDriver<'a>, Control<'a>, Runner<'a>) {
|
||||||
let (ch_runner, device) = ch::new(&mut state.ch, [0; 6]);
|
let (ch_runner, device) = ch::new(&mut state.ch, [0; 6]);
|
||||||
let state_ch = ch_runner.state_runner();
|
let state_ch = ch_runner.state_runner();
|
||||||
|
|
||||||
let mut runner = Runner::new(ch_runner, Bus::new(pwr, spi), &state.ioctl_state, &state.events);
|
let mut runner = Runner::new(ch_runner, mac_subsystem, &state.ioctl_state, &state.events);
|
||||||
|
|
||||||
runner.init(firmware).await;
|
runner.init(firmware).await;
|
||||||
|
|
||||||
|
|
|
@ -2,29 +2,12 @@ use embassy_futures::select::{select3, Either3};
|
||||||
use embassy_net_driver_channel as ch;
|
use embassy_net_driver_channel as ch;
|
||||||
use embassy_sync::pubsub::PubSubBehavior;
|
use embassy_sync::pubsub::PubSubBehavior;
|
||||||
|
|
||||||
|
use crate::mac::event::Events;
|
||||||
|
use crate::mac::ioctl::{IoctlState, PendingIoctl};
|
||||||
|
use crate::mac::MTU;
|
||||||
use crate::sub::mac::Mac;
|
use crate::sub::mac::Mac;
|
||||||
|
|
||||||
#[cfg(feature = "firmware-logs")]
|
pub struct Runner<'a> {
|
||||||
struct LogState {
|
|
||||||
addr: u32,
|
|
||||||
last_idx: usize,
|
|
||||||
buf: [u8; 256],
|
|
||||||
buf_count: usize,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "firmware-logs")]
|
|
||||||
impl Default for LogState {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self {
|
|
||||||
addr: Default::default(),
|
|
||||||
last_idx: Default::default(),
|
|
||||||
buf: [0; 256],
|
|
||||||
buf_count: Default::default(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Runner<'a, PWR, SPI> {
|
|
||||||
ch: ch::Runner<'a, MTU>,
|
ch: ch::Runner<'a, MTU>,
|
||||||
mac: Mac,
|
mac: Mac,
|
||||||
|
|
||||||
|
@ -34,32 +17,18 @@ pub struct Runner<'a, PWR, SPI> {
|
||||||
sdpcm_seq_max: u8,
|
sdpcm_seq_max: u8,
|
||||||
|
|
||||||
events: &'a Events,
|
events: &'a Events,
|
||||||
|
|
||||||
#[cfg(feature = "firmware-logs")]
|
|
||||||
log: LogState,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, PWR, SPI> Runner<'a, PWR, SPI>
|
impl<'a> Runner<'a> {
|
||||||
where
|
pub(crate) fn new(ch: ch::Runner<'a, MTU>, mac: Mac, ioctl_state: &'a IoctlState, events: &'a Events) -> Self {
|
||||||
PWR: OutputPin,
|
|
||||||
SPI: SpiBusCyw43,
|
|
||||||
{
|
|
||||||
pub(crate) fn new(
|
|
||||||
ch: ch::Runner<'a, MTU>,
|
|
||||||
bus: Bus<PWR, SPI>,
|
|
||||||
ioctl_state: &'a IoctlState,
|
|
||||||
events: &'a Events,
|
|
||||||
) -> Self {
|
|
||||||
Self {
|
Self {
|
||||||
ch,
|
ch,
|
||||||
bus,
|
mac,
|
||||||
ioctl_state,
|
ioctl_state,
|
||||||
ioctl_id: 0,
|
ioctl_id: 0,
|
||||||
sdpcm_seq: 0,
|
sdpcm_seq: 0,
|
||||||
sdpcm_seq_max: 1,
|
sdpcm_seq_max: 1,
|
||||||
events,
|
events,
|
||||||
#[cfg(feature = "firmware-logs")]
|
|
||||||
log: LogState::default(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -72,60 +41,6 @@ where
|
||||||
debug!("wifi init done");
|
debug!("wifi init done");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "firmware-logs")]
|
|
||||||
async fn log_init(&mut self) {
|
|
||||||
// Initialize shared memory for logging.
|
|
||||||
|
|
||||||
let addr = CHIP.atcm_ram_base_address + CHIP.chip_ram_size - 4 - CHIP.socram_srmem_size;
|
|
||||||
let shared_addr = self.bus.bp_read32(addr).await;
|
|
||||||
debug!("shared_addr {:08x}", shared_addr);
|
|
||||||
|
|
||||||
let mut shared = [0; SharedMemData::SIZE];
|
|
||||||
self.bus.bp_read(shared_addr, &mut shared).await;
|
|
||||||
let shared = SharedMemData::from_bytes(&shared);
|
|
||||||
|
|
||||||
self.log.addr = shared.console_addr + 8;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "firmware-logs")]
|
|
||||||
async fn log_read(&mut self) {
|
|
||||||
// Read log struct
|
|
||||||
let mut log = [0; SharedMemLog::SIZE];
|
|
||||||
self.bus.bp_read(self.log.addr, &mut log).await;
|
|
||||||
let log = SharedMemLog::from_bytes(&log);
|
|
||||||
|
|
||||||
let idx = log.idx as usize;
|
|
||||||
|
|
||||||
// If pointer hasn't moved, no need to do anything.
|
|
||||||
if idx == self.log.last_idx {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read entire buf for now. We could read only what we need, but then we
|
|
||||||
// run into annoying alignment issues in `bp_read`.
|
|
||||||
let mut buf = [0; 0x400];
|
|
||||||
self.bus.bp_read(log.buf, &mut buf).await;
|
|
||||||
|
|
||||||
while self.log.last_idx != idx as usize {
|
|
||||||
let b = buf[self.log.last_idx];
|
|
||||||
if b == b'\r' || b == b'\n' {
|
|
||||||
if self.log.buf_count != 0 {
|
|
||||||
let s = unsafe { core::str::from_utf8_unchecked(&self.log.buf[..self.log.buf_count]) };
|
|
||||||
debug!("LOGS: {}", s);
|
|
||||||
self.log.buf_count = 0;
|
|
||||||
}
|
|
||||||
} else if self.log.buf_count < self.log.buf.len() {
|
|
||||||
self.log.buf[self.log.buf_count] = b;
|
|
||||||
self.log.buf_count += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
self.log.last_idx += 1;
|
|
||||||
if self.log.last_idx == 0x400 {
|
|
||||||
self.log.last_idx = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn run(mut self) -> ! {
|
pub async fn run(mut self) -> ! {
|
||||||
let mut buf = [0; 512];
|
let mut buf = [0; 512];
|
||||||
loop {
|
loop {
|
||||||
|
@ -424,66 +339,4 @@ where
|
||||||
|
|
||||||
self.bus.wlan_write(&buf[..total_len / 4]).await;
|
self.bus.wlan_write(&buf[..total_len / 4]).await;
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn core_disable(&mut self, core: Core) {
|
|
||||||
let base = core.base_addr();
|
|
||||||
|
|
||||||
// Dummy read?
|
|
||||||
let _ = self.bus.bp_read8(base + AI_RESETCTRL_OFFSET).await;
|
|
||||||
|
|
||||||
// Check it isn't already reset
|
|
||||||
let r = self.bus.bp_read8(base + AI_RESETCTRL_OFFSET).await;
|
|
||||||
if r & AI_RESETCTRL_BIT_RESET != 0 {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
self.bus.bp_write8(base + AI_IOCTRL_OFFSET, 0).await;
|
|
||||||
let _ = self.bus.bp_read8(base + AI_IOCTRL_OFFSET).await;
|
|
||||||
|
|
||||||
block_for(Duration::from_millis(1));
|
|
||||||
|
|
||||||
self.bus
|
|
||||||
.bp_write8(base + AI_RESETCTRL_OFFSET, AI_RESETCTRL_BIT_RESET)
|
|
||||||
.await;
|
|
||||||
let _ = self.bus.bp_read8(base + AI_RESETCTRL_OFFSET).await;
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn core_reset(&mut self, core: Core) {
|
|
||||||
self.core_disable(core).await;
|
|
||||||
|
|
||||||
let base = core.base_addr();
|
|
||||||
self.bus
|
|
||||||
.bp_write8(base + AI_IOCTRL_OFFSET, AI_IOCTRL_BIT_FGC | AI_IOCTRL_BIT_CLOCK_EN)
|
|
||||||
.await;
|
|
||||||
let _ = self.bus.bp_read8(base + AI_IOCTRL_OFFSET).await;
|
|
||||||
|
|
||||||
self.bus.bp_write8(base + AI_RESETCTRL_OFFSET, 0).await;
|
|
||||||
|
|
||||||
Timer::after(Duration::from_millis(1)).await;
|
|
||||||
|
|
||||||
self.bus
|
|
||||||
.bp_write8(base + AI_IOCTRL_OFFSET, AI_IOCTRL_BIT_CLOCK_EN)
|
|
||||||
.await;
|
|
||||||
let _ = self.bus.bp_read8(base + AI_IOCTRL_OFFSET).await;
|
|
||||||
|
|
||||||
Timer::after(Duration::from_millis(1)).await;
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn core_is_up(&mut self, core: Core) -> bool {
|
|
||||||
let base = core.base_addr();
|
|
||||||
|
|
||||||
let io = self.bus.bp_read8(base + AI_IOCTRL_OFFSET).await;
|
|
||||||
if io & (AI_IOCTRL_BIT_FGC | AI_IOCTRL_BIT_CLOCK_EN) != AI_IOCTRL_BIT_CLOCK_EN {
|
|
||||||
debug!("core_is_up: returning false due to bad ioctrl {:02x}", io);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
let r = self.bus.bp_read8(base + AI_RESETCTRL_OFFSET).await;
|
|
||||||
if r & (AI_RESETCTRL_BIT_RESET) != 0 {
|
|
||||||
debug!("core_is_up: returning false due to bad resetctrl {:02x}", r);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue