diff --git a/Cargo.lock b/Cargo.lock
index 5d6371d45..7232df761 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -142,6 +142,8 @@ dependencies = [
"heapless",
"log",
"log-server",
+ "ticktimer-server",
+ "typenum",
"utralib",
"xous",
]
diff --git a/emulation/renode.svd b/emulation/renode.svd
index 740dff62c..10bbc3176 100644
--- a/emulation/renode.svd
+++ b/emulation/renode.svd
@@ -12,68 +12,9 @@
0xFFFFFFFF
-
- CTRL
- 0xF0000000
- CTRL
-
-
- RESET
-
- 0x0000
- 0x00
- 32
-
-
- reset
- 0
- [0:0]
- 0
-
-
-
-
- SCRATCH
-
- 0x0004
- 0x12345678
- 32
-
-
- scratch
- 31
- [31:0]
- 0
-
-
-
-
- BUS_ERRORS
-
- 0x0008
- 0x00
- 32
-
-
- bus_errors
- 31
- [31:0]
- 0
-
-
-
-
-
- 0
- 0xc
- registers
-
-
IDENTIFIER_MEM
- 0xF0002000
+ 0xF0001000
IDENTIFIER_MEM
@@ -100,7 +41,7 @@ to the Wishbone/CSR bus are working correctly. The initial reset value of
TIMER0
- 0xF0003000
+ 0xF0002000
TIMER0
@@ -246,17 +187,19 @@ register to disable individual events.]]>
REBOOT
- 0xF0004000
+ 0xF0003000
REBOOT
- CTRL
+ SOC_RESET
+
0x0000
0x00
32
- ctrl
+ soc_reset
7
[7:0]
0
@@ -265,6 +208,7 @@ register to disable individual events.]]>
ADDR
+
0x0004
0x00
32
@@ -277,16 +221,32 @@ register to disable individual events.]]>
+
+ CPU_RESET
+
+ 0x0008
+ 0x00
+ 32
+
+
+ cpu_reset
+ 0
+ [0:0]
+ 0
+
+
+
0
- 0x8
+ 0xc
registers
CRG
- 0xF0005000
+ 0xF0004000
CRG
@@ -410,7 +370,7 @@ register to disable individual events.]]>
GPIO
- 0xF0006000
+ 0xF0005000
GPIO
@@ -724,7 +684,7 @@ register to disable individual events.]]>
UART_PHY
- 0xF0007000
+ 0xF0006000
UART_PHY
@@ -750,7 +710,7 @@ register to disable individual events.]]>
UART
- 0xF0008000
+ 0xF0007000
UART
@@ -908,7 +868,7 @@ register to disable individual events.]]>
CONSOLE_PHY
- 0xF0009000
+ 0xF0008000
CONSOLE_PHY
@@ -934,7 +894,7 @@ register to disable individual events.]]>
CONSOLE
- 0xF000A000
+ 0xF0009000
CONSOLE
@@ -1092,7 +1052,7 @@ register to disable individual events.]]>
SERVER0_PHY
- 0xF000B000
+ 0xF000A000
SERVER0_PHY
@@ -1118,7 +1078,7 @@ register to disable individual events.]]>
SERVER0
- 0xF000C000
+ 0xF000B000
SERVER0
@@ -1276,7 +1236,7 @@ register to disable individual events.]]>
SERVER1_PHY
- 0xF000D000
+ 0xF000C000
SERVER1_PHY
@@ -1302,7 +1262,7 @@ register to disable individual events.]]>
SERVER1
- 0xF000E000
+ 0xF000D000
SERVER1
@@ -1460,7 +1420,7 @@ register to disable individual events.]]>
INFO
- 0xF000F000
+ 0xF000E000
INFO
@@ -1856,7 +1816,7 @@ VCCBRAM (V) = ``Value`` x 3 / 4096.]]>
SRAM_EXT
- 0xF0010000
+ 0xF000F000
SRAM_EXT
@@ -1898,7 +1858,7 @@ VCCBRAM (V) = ``Value`` x 3 / 4096.]]>
MEMLCD
- 0xF0011000
+ 0xF0010000
MEMLCD
@@ -2014,7 +1974,7 @@ register to disable individual events.]]>
COM
- 0xF0012000
+ 0xF0011000
COM
@@ -2171,10 +2131,14 @@ register to disable individual events.]]>
0x1c
registers
+
+ com
+ 6
+
I2C
- 0xF0013000
+ 0xF0012000
I2C
@@ -2422,12 +2386,12 @@ register to disable individual events.]]>
i2c
- 6
+ 7
BTEVENTS
- 0xF0014000
+ 0xF0013000
BTEVENTS
@@ -2511,12 +2475,12 @@ register to disable individual events.]]>
btevents
- 7
+ 8
MESSIBLE
- 0xF0015000
+ 0xF0014000
MESSIBLE
@@ -2582,7 +2546,7 @@ register advances the read pointer automatically.]]>
MESSIBLE2
- 0xF0016000
+ 0xF0015000
MESSIBLE2
@@ -2648,7 +2612,7 @@ register advances the read pointer automatically.]]>
TICKTIMER
- 0xF0017000
+ 0xF0016000
TICKTIMER
@@ -2793,12 +2757,12 @@ register to disable individual events.]]>
ticktimer
- 8
+ 9
POWER
- 0xF0018000
+ 0xF0017000
POWER
@@ -2958,7 +2922,7 @@ reset fashion]]>
SPINOR
- 0xF0019000
+ 0xF0018000
SPINOR
@@ -3239,7 +3203,7 @@ checked]]>
KEYBOARD
- 0xF001A000
+ 0xF0019000
KEYBOARD
@@ -3449,19 +3413,19 @@ again until the interrupt is serviced.]]>
keyboard
- 9
+ 10
SEED
- 0xF001B000
+ 0xF001A000
SEED
SEED1
0x0000
- 0x20483d3b
+ 0x2c552c3f
32
@@ -3476,7 +3440,7 @@ again until the interrupt is serviced.]]>
SEED0
0x0004
- 0x1febda0d
+ 0x3e20093a
32
@@ -3496,7 +3460,7 @@ again until the interrupt is serviced.]]>
ROMTEST
- 0xF001C000
+ 0xF001B000
ROMTEST
@@ -3538,7 +3502,7 @@ again until the interrupt is serviced.]]>
AUDIO
- 0xF001D000
+ 0xF001C000
AUDIO
@@ -3905,12 +3869,12 @@ I2S_FORMAT.I2S_STANDARD is I2S standard]]>
audio
- 10
+ 11
TRNG_OSC
- 0xF001E000
+ 0xF001D000
TRNG_OSC
@@ -3996,7 +3960,7 @@ reading the `rand` register]]>
AES
- 0xF001F000
+ 0xF001E000
AES
@@ -4459,7 +4423,7 @@ automatically on data and IV ready]]>
SHA512
- 0xF0020000
+ 0xF001F000
SHA512
@@ -4949,12 +4913,12 @@ in bits]]>
sha512
- 11
+ 12
ENGINE
- 0xF0021000
+ 0xF0020000
ENGINE
@@ -5178,12 +5142,12 @@ exactly reflects the binary layout of an Engine instruction.]]>
engine
- 12
+ 13
JTAG
- 0xF0022000
+ 0xF0021000
JTAG
diff --git a/services/com/Cargo.toml b/services/com/Cargo.toml
index f87c066cb..3c4b7fea9 100644
--- a/services/com/Cargo.toml
+++ b/services/com/Cargo.toml
@@ -9,9 +9,12 @@ description = "COM interface to the EC"
xous = { path = "../../xous-rs" }
heapless = "0.5"
log-server = { path = "../log-server" }
+ticktimer-server = { path = "../ticktimer-server" }
log = "0.4"
com_rs = { path = "com_rs" }
-#[target.'cfg(not(any(windows,unix)))'.dependencies]
+typenum = "1.12"
+
+[target.'cfg(not(any(windows,unix)))'.dependencies]
utralib = { path = "../../utralib"}
[target.'cfg(any(windows,unix))'.dependencies]
diff --git a/services/com/src/api.rs b/services/com/src/api.rs
index 60570d545..b6b0e5320 100644
--- a/services/com/src/api.rs
+++ b/services/com/src/api.rs
@@ -4,12 +4,44 @@ use xous::{Message, ScalarMessage};
// It's just a convenient abuse of already-defined constants. However, it's intended that
// the COM server on the SoC side abstracts much of the EC bus complexity away.
use com_rs::*;
+#[derive(Debug, Default)]
+pub struct BattStats {
+ /// instantaneous voltage in mV
+ pub voltage: u16,
+ /// state of charge in %, as inferred by impedance tracking
+ pub soc: u8,
+ /// instantaneous current draw in mA
+ pub current: i16,
+ /// remaining capacity in mA, as measured by coulomb counting
+ pub remaining_capacity: u16,
+}
+
+impl From<[usize; 2]> for BattStats {
+ fn from(a: [usize; 2]) -> BattStats {
+ BattStats {
+ voltage: (a[0] & 0xFFFF) as u16,
+ soc: ((a[0] >> 16) & 0xFF) as u8,
+ current: ((a[1] >> 16) & 0xFFFF) as i16,
+ remaining_capacity: (a[1] & 0xFFFF) as u16,
+ }
+ }
+}
+
+impl Into<[usize; 2]> for BattStats {
+ fn into(self) -> [usize; 2] {
+ [ (self.voltage as usize & 0xffff) | ((self.soc as usize) << 16) & 0xFF_0000,
+ (self.remaining_capacity as usize & 0xffff) | ((self.current as usize) << 16) & 0xffff_0000 ]
+ }
+}
#[derive(Debug)]
pub enum Opcode {
/// Battery stats
BattStats,
+ /// Query Full charge capacity of the battery
+ BattFullCapacity,
+
/// Turn Boost Mode On
BoostOn,
diff --git a/services/com/src/lib.rs b/services/com/src/lib.rs
index cffcdd08b..8071ec2a1 100644
--- a/services/com/src/lib.rs
+++ b/services/com/src/lib.rs
@@ -1,13 +1,27 @@
#![cfg_attr(target_os = "none", no_std)]
+/// This is the API that other servers use to call the COM. Read this code as if you
+/// are calling these functions inside a different process.
+
pub mod api;
+use api::BattStats;
use xous::{send_message, Error, CID};
pub fn power_off_soc(cid: CID) -> Result<(), xous::Error> {
send_message(cid, api::Opcode::PowerOffSoc.into()).map(|_| ())
}
+pub fn get_batt_stats(cid: CID) -> Result {
+ let response = send_message(cid, api::Opcode::BattStats.into())?;
+ if let xous::Result::Scalar2(upper, lower) = response {
+ let raw_stats: [usize; 2] = [lower, upper];
+ Ok(raw_stats.into())
+ } else {
+ panic!("unexpected return value: {:#?}", response);
+ }
+}
+
/*
pub fn elapsed_ms(cid: CID) -> Result {
let response = send_message(cid, api::Opcode::ElapsedMs.into())?;
diff --git a/services/com/src/main.rs b/services/com/src/main.rs
index e7e3a5159..f0c8d4c93 100644
--- a/services/com/src/main.rs
+++ b/services/com/src/main.rs
@@ -10,28 +10,39 @@ use api::Opcode;
use core::convert::TryFrom;
-/*
-use heapless::binary_heap::{BinaryHeap, Min};
-use heapless::Vec;
-use heapless::consts::*;
-type U1280 = UInt, B0>, B1>, B0>, B0>, B0>, B0>, B0>, B0>, B0>, B0>;
-*/
-
use log::{error, info};
use com_rs::*;
-//#[cfg(target_os = "none")]
+#[cfg(target_os = "none")]
mod implementation {
+ use crate::api::BattStats;
+ use ticktimer_server::*;
+ use com_rs::*;
use utralib::generated::*;
+ use xous::CID;
+
+ /*
+ #[macro_use]
+ use heapless::Vec;
+
+ use typenum::{UInt, UTerm};
+ use typenum::bit::{B0, B1};
+ type U1280 = UInt, B0>, B1>, B0>, B0>, B0>, B0>, B0>, B0>, B0>, B0>;
+ */
+
+ const STD_TIMEOUT: u32 = 100;
pub struct XousCom {
csr: utralib::CSR,
+ ticktimer: CID,
}
fn handle_irq(_irq_no: usize, arg: *mut usize) {
- let _xc = unsafe { &mut *(arg as *mut XousCom) };
+ let xc = unsafe { &mut *(arg as *mut XousCom) };
println!("COM IRQ");
+ // just clear the pending request, as this is used as a "wait" until request function
+ xc.csr.wo(utra::com::EV_PENDING, xc.csr.r(utra::com::EV_PENDING));
}
impl XousCom {
@@ -44,8 +55,15 @@ mod implementation {
)
.expect("couldn't map COM CSR range");
+ let ticktimer_server_id = xous::SID::from_bytes(b"ticktimer-server").unwrap();
+ let ticktimer_conn = xous::connect(ticktimer_server_id).unwrap();
+
let mut xc = XousCom {
csr: CSR::new(csr.as_mut_ptr() as *mut u32),
+ ticktimer: ticktimer_conn,
+ //tx_queue: Vec::new(),
+ //rx_queue: Vec::new(),
+ //in_progress: false,
};
xous::claim_interrupt(
@@ -68,12 +86,53 @@ mod implementation {
// grab the RX value and return it
self.csr.rf(utra::com::RX_RX) as u16
}
+
+ pub fn wait_txrx(&mut self, tx: u16, timeout: Option) -> u16 {
+ self.csr.wfo(utra::com::EV_ENABLE_SPI_HOLD, 1);
+ if timeout.is_some() {
+ let curtime = ticktimer_server::elapsed_ms(self.ticktimer).expect("couldn't connect to ticktimer");
+ let mut timed_out = false;
+ let to = timeout.unwrap() as u64;
+ // timeout after 0.25 second to avoid hangs in case of a bug in the protocol
+ while self.csr.rf(utra::com::STATUS_HOLD) == 1 && !timed_out {
+ if (ticktimer_server::elapsed_ms(self.ticktimer).expect("couldn't connect to ticktimer") - curtime) > to {
+ timed_out = true;
+ }
+ xous::wait_event();
+ }
+ } else {
+ while self.csr.rf(utra::com::STATUS_HOLD) == 1 {
+ xous::wait_event();
+ }
+ }
+ self.csr.wfo(utra::com::EV_ENABLE_SPI_HOLD, 0);
+
+ self.txrx(tx)
+ }
+
+ pub fn get_battstats(&mut self) -> BattStats {
+ let mut stats = BattStats::default();
+
+ self.txrx(ComState::GAS_GAUGE.verb);
+ stats.current = self.wait_txrx(ComState::LINK_READ.verb, Some(STD_TIMEOUT)) as i16;
+ self.wait_txrx(ComState::LINK_READ.verb, Some(100)); // stby_current, not used here
+ stats.voltage = self.wait_txrx(ComState::LINK_READ.verb, Some(STD_TIMEOUT));
+ self.wait_txrx(ComState::LINK_READ.verb, Some(100)); // power register value, not used
+
+ self.txrx(ComState::GG_SOC.verb);
+ stats.soc = self.wait_txrx(ComState::LINK_READ.verb, Some(STD_TIMEOUT)) as u8;
+ self.txrx(ComState::GG_REMAINING.verb);
+ stats.remaining_capacity = self.wait_txrx(ComState::LINK_READ.verb, Some(STD_TIMEOUT));
+
+ stats
+ }
}
}
// a stub to try to avoid breaking hosted mode for as long as possible.
#[cfg(not(target_os = "none"))]
mod implementation {
+ use crate::api::BattStats;
pub struct XousCom {
}
@@ -83,9 +142,18 @@ mod implementation {
}
}
- pub fn txrx(tx: u16) -> u16 {
+ pub fn txrx(&mut self, _tx: u16) -> u16 {
0xDEAD as u16
}
+
+ pub fn get_battstats(&mut self) -> BattStats {
+ BattStats {
+ voltage: 3700,
+ current: -150,
+ soc: 50,
+ remaining_capacity: 750,
+ }
+ }
}
}
@@ -113,6 +181,17 @@ fn xmain() -> ! {
info!("COM: power off called");
com.txrx(ComState::POWER_OFF.verb);
}
+ Opcode::BattStats => {
+ info!("COM: batt stats request received");
+ let stats = com.get_battstats();
+ let raw_stats: [usize; 2] = stats.into();
+ xous::return_scalar2(
+ envelope.sender,
+ raw_stats[1],
+ raw_stats[0]
+ ).expect("COM: couldn't return batt stats request");
+ info!("COM: done returning batt stats request");
+ }
_ => error!("unknown opcode"),
}
} else {
@@ -120,5 +199,3 @@ fn xmain() -> ! {
}
}
}
-
-// xous::wait_event()
diff --git a/services/log-server/Cargo.toml b/services/log-server/Cargo.toml
index 9341019dc..c0d5faf5a 100644
--- a/services/log-server/Cargo.toml
+++ b/services/log-server/Cargo.toml
@@ -14,5 +14,5 @@ utralib = { path = "../../utralib"}
[features]
debugprint = []
-default = []
-#default = ["debugprint"]
+#default = []
+default = ["debugprint"]
diff --git a/services/shell/src/main.rs b/services/shell/src/main.rs
index f7db2c346..6108aa067 100644
--- a/services/shell/src/main.rs
+++ b/services/shell/src/main.rs
@@ -12,6 +12,8 @@ use log::{error, info};
use xous::String;
use graphics_server::Point;
use graphics_server::GlyphSet;
+use com::api::BattStats;
+use com::*;
// fn print_and_yield(index: *mut usize) -> ! {
// let num = index as usize;
@@ -148,8 +150,6 @@ fn shell_main() -> ! {
let screensize = graphics_server::screen_size(graphics_conn).expect("Couldn't get screen size");
- // let mut counter: usize = 0;
- let mut ls = logstr::LogStr::new();
let dark = graphics_server::Color::from(0);
let light = graphics_server::Color::from(!0);
let mut bouncyball = Bounce::new(14,
@@ -157,8 +157,10 @@ fn shell_main() -> ! {
Point::new(screensize.x as _, screensize.y as i16 - 1)));
bouncyball.update();
+ let mut batt_stats: BattStats = BattStats::default();
+
#[cfg(baremetal)]
- {
+ { // use this to select which UART to monitor in the main loop
use utralib::generated::*;
let gpio_base = xous::syscall::map_memory(
xous::MemoryAddress::new(utra::gpio::HW_GPIO_BASE),
@@ -183,40 +185,19 @@ fn shell_main() -> ! {
ticktimer_server::reset(ticktimer_conn).unwrap();
let mut string_buffer = String::new(4096);
loop {
- // a message passing demo -- checking time
+ // update battery status periodically
if let Ok(elapsed_time) = ticktimer_server::elapsed_ms(ticktimer_conn) {
info!("SHELL: {}ms", elapsed_time);
- if elapsed_time - last_time > 40 {
+ if elapsed_time - last_time > 500 {
last_time = elapsed_time;
- /*
- xous::try_send_message(log_conn,
- xous::Message::Scalar(xous::ScalarMessage{id:256, arg1: elapsed_time as usize, arg2: 257, arg3: 258, arg4: 259}));
- */
- info!("Preparing a mutable borrow message");
-
- ls.clear();
- write!(
- ls,
- "Hello, Server! This memory is borrowed from another process. Elapsed: {}",
- elapsed_time as usize
- )
- .expect("couldn't send hello message");
-
- let mm = ls
- .as_memory_message(0)
- .expect("couldn't form memory message");
-
- info!("Sending a mutable borrow message");
-
- xous::syscall::send_message(log_conn, xous::Message::MutableBorrow(mm))
- .expect("couldn't send memory message");
+ batt_stats = get_batt_stats(com_conn).expect("Can't get battery stats from COM");
}
} else {
error!("error requesting ticktimer!")
}
string_buffer.clear();
- write!(&mut string_buffer, "Uptime: {:.2}s", last_time as f32 / 1000f32).expect("Can't write");
+ write!(&mut string_buffer, "{}mV Uptime: {:.2}s", batt_stats.voltage, last_time as f32 / 1000f32).expect("Can't write");
graphics_server::set_glyph(graphics_conn, GlyphSet::Small).expect("unable to set glyph");
let (_, h) = graphics_server::query_glyph(graphics_conn).expect("unable to query glyph");
graphics_server::clear_region(graphics_conn, 0, 0, screensize.x as usize - 1, h)
@@ -225,9 +206,6 @@ fn shell_main() -> ! {
graphics_server::draw_string(graphics_conn, &string_buffer).expect("unable to draw string");
// ticktimer_server::sleep_ms(ticktimer_conn, 500).expect("couldn't sleep");
- if last_time > 10_000 { // after 10 seconds issue a shutdown command
- com::power_off_soc(com_conn).expect("Couldn't issue powerdown command to COM");
- }
// draw the ball
bouncyball.update();