Skip to content

Commit 62e52a7

Browse files
author
Alex J Lennon
committed
feat: Add external RTC interrupt configuration commands
- Add new 'rtc' command group with status, config, and show subcommands - Support configuring external PCF2131 RTC interrupt actions: - none: Just log interrupt events - wake: Always wake i.MX93 on interrupt - auto: Auto-power i.MX93 if PMIC is currently off - Add JSON parsing support for RTC status responses - Update CLI documentation with v2.4.0 features - Maintain backward compatibility with existing commands This enables runtime configuration of the PMU's response to external RTC interrupts without requiring firmware updates.
1 parent 4fcdcca commit 62e52a7

File tree

5 files changed

+180
-1
lines changed

5 files changed

+180
-1
lines changed

README.md

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,19 @@ The E-ink Power CLI is a Rust-based command-line tool designed to communicate wi
1919
- **Power Management**: Control PMIC, WiFi, and display power rails
2020
- **Battery Monitoring**: Real-time LTC2959 coulomb counter readings
2121
- **System Control**: GPIO manipulation, system information, and diagnostics
22+
- **🆕 RTC Management**: External PCF2131 RTC interrupt configuration (v2.4.0+)
2223
- **🆕 Firmware Management**: Upload firmware via mcumgr with progress indication (v2.3.0)
2324
- **Board Control**: E-Ink controller reset and shutdown (WiFi+Display+PMIC)
2425
- **Automation**: JSON/CSV output formats and batch operations
2526

26-
## What's New in v2.3.0
27+
## What's New in v2.4.0
28+
29+
- **🕐 RTC Management**: External PCF2131 RTC interrupt configuration and monitoring
30+
- **⚙️ Auto-Power Mode**: Configure PMU to auto-power i.MX93 when PMIC is off
31+
- **📊 Interrupt Tracking**: Monitor external RTC interrupt events and statistics
32+
- **🔧 Runtime Configuration**: Change RTC interrupt actions without firmware updates
33+
34+
## Previous Release - v2.3.0
2735

2836
- **🚀 Firmware Management**: Complete firmware upload with mcumgr integration
2937
- **📊 Progress Indication**: Real-time upload progress and boot countdown
@@ -73,6 +81,13 @@ eink-power-cli board shutdown # WiFi+Display+PMIC power off
7381
eink-power-cli gpio get gpioa 5
7482
eink-power-cli gpio set gpiob 3 1
7583

84+
# RTC management (NEW in v2.4.0+)
85+
eink-power-cli rtc status # Show RTC status and interrupt events
86+
eink-power-cli rtc config auto # Auto-power i.MX93 if PMIC is off
87+
eink-power-cli rtc config wake # Always wake i.MX93 on interrupt
88+
eink-power-cli rtc config none # Just log interrupt events
89+
eink-power-cli rtc show # Show current configuration
90+
7691
# Get system information
7792
eink-power-cli system info
7893

@@ -145,6 +160,15 @@ eink-power-cli nfc info # Device information
145160
eink-power-cli nfc field-detect # Check field detection
146161
```
147162

163+
### RTC Management (v2.4.0+)
164+
```bash
165+
eink-power-cli rtc status # Show RTC status and interrupt events
166+
eink-power-cli rtc config none # No action - just log events
167+
eink-power-cli rtc config wake # Always wake i.MX93 on interrupt
168+
eink-power-cli rtc config auto # Auto-power i.MX93 if PMIC is off
169+
eink-power-cli rtc show # Show current configuration
170+
```
171+
148172
## Configuration
149173

150174
Create a configuration file at `~/.config/eink-power-cli/config.toml`:

src/cli/mod.rs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,10 @@ pub enum Commands {
100100
#[command(subcommand)]
101101
Pm(PowerManagementCommands),
102102

103+
/// RTC (Real-Time Clock) commands
104+
#[command(subcommand)]
105+
Rtc(RtcCommands),
106+
103107
/// Firmware management commands
104108
#[command(subcommand)]
105109
Firmware(FirmwareCommands),
@@ -314,3 +318,29 @@ pub enum MonitorAction {
314318
Start,
315319
Stop,
316320
}
321+
322+
/// RTC (Real-Time Clock) commands
323+
#[derive(Subcommand, Debug, Clone)]
324+
pub enum RtcCommands {
325+
/// Show RTC status (internal + external PCF2131)
326+
Status,
327+
/// Configure external RTC interrupt action
328+
Config {
329+
/// External RTC interrupt action
330+
#[arg(value_enum)]
331+
action: ExternalRtcAction,
332+
},
333+
/// Show external RTC interrupt configuration
334+
Show,
335+
}
336+
337+
/// External RTC interrupt actions
338+
#[derive(ValueEnum, Clone, Debug)]
339+
pub enum ExternalRtcAction {
340+
/// No action - just log the event
341+
None,
342+
/// Always wake i.MX93 when interrupt occurs
343+
Wake,
344+
/// Auto-power i.MX93 if PMIC is currently off
345+
Auto,
346+
}

src/json.rs

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,33 @@ pub struct GpioJson {
9494
pub state: Option<String>,
9595
}
9696

97+
/// RTC status information in JSON format
98+
#[derive(Debug, Serialize, Deserialize)]
99+
pub struct RtcStatusJson {
100+
pub internal_rtc: InternalRtcJson,
101+
pub external_rtc: ExternalRtcJson,
102+
pub last_wake_source: Option<String>,
103+
}
104+
105+
/// Internal RTC information
106+
#[derive(Debug, Serialize, Deserialize)]
107+
pub struct InternalRtcJson {
108+
pub wake_events: Option<u32>,
109+
pub status: Option<String>,
110+
pub function: Option<String>,
111+
}
112+
113+
/// External RTC (PCF2131) information
114+
#[derive(Debug, Serialize, Deserialize)]
115+
pub struct ExternalRtcJson {
116+
pub interrupt_events: Option<u32>,
117+
pub status: Option<String>,
118+
pub connection: Option<String>,
119+
pub i2c_address: Option<String>,
120+
pub function: Option<String>,
121+
pub interrupt_action: Option<String>,
122+
}
123+
97124
/// NFC status for JSON output
98125
#[derive(Debug, Serialize, Deserialize)]
99126
pub struct NfcJson {
@@ -371,4 +398,58 @@ impl ResponseParser {
371398

372399
gpio
373400
}
401+
402+
/// Parse RTC status response into JSON
403+
pub fn parse_rtc_status(response: &str) -> RtcStatusJson {
404+
let mut rtc = RtcStatusJson {
405+
internal_rtc: InternalRtcJson {
406+
wake_events: None,
407+
status: None,
408+
function: Some("Periodic maintenance and battery monitoring".to_string()),
409+
},
410+
external_rtc: ExternalRtcJson {
411+
interrupt_events: None,
412+
status: None,
413+
connection: Some("INTB# → PTC5 (LLWU_P9) - Active LOW".to_string()),
414+
i2c_address: Some("0x53".to_string()),
415+
function: Some("Alarms, timers, watchdog, timestamps".to_string()),
416+
interrupt_action: None,
417+
},
418+
last_wake_source: None,
419+
};
420+
421+
// Parse internal RTC wake events
422+
if let Some(caps) = regex::Regex::new(r"Internal RTC.*?Wake events:\s*(\d+)")
423+
.unwrap()
424+
.captures(response)
425+
{
426+
rtc.internal_rtc.wake_events = Some(caps[1].parse().unwrap_or(0));
427+
}
428+
429+
// Parse external RTC interrupt events
430+
if let Some(caps) = regex::Regex::new(r"External RTC.*?Interrupt events:\s*(\d+)")
431+
.unwrap()
432+
.captures(response)
433+
{
434+
rtc.external_rtc.interrupt_events = Some(caps[1].parse().unwrap_or(0));
435+
}
436+
437+
// Parse interrupt action
438+
if let Some(caps) = regex::Regex::new(r"Interrupt Action:\s*(.+)")
439+
.unwrap()
440+
.captures(response)
441+
{
442+
rtc.external_rtc.interrupt_action = Some(caps[1].trim().to_string());
443+
}
444+
445+
// Parse last wake source
446+
if let Some(caps) = regex::Regex::new(r"Last Wake Source:\s*(.+)")
447+
.unwrap()
448+
.captures(response)
449+
{
450+
rtc.last_wake_source = Some(caps[1].trim().to_string());
451+
}
452+
453+
rtc
454+
}
374455
}

src/main.rs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,10 @@ fn output_response(
131131
json::ResponseParser::parse_gpio_response(response, "unknown", 0);
132132
serde_json::to_value(gpio_data)?
133133
}
134+
cmd if cmd.contains("rtc") => {
135+
let rtc_data = json::ResponseParser::parse_rtc_status(response);
136+
serde_json::to_value(rtc_data)?
137+
}
134138
_ => {
135139
// Generic response - just wrap the raw text
136140
serde_json::json!({
@@ -474,6 +478,28 @@ async fn execute_command(
474478
}
475479
}
476480
}
481+
Commands::Rtc(rtc_cmd) => {
482+
use cli::{RtcCommands, ExternalRtcAction};
483+
match rtc_cmd {
484+
RtcCommands::Status => {
485+
let response = controller.rtc_status().await?;
486+
output_response(cli, "rtc status", &response, "🕐", "RTC Status")?;
487+
}
488+
RtcCommands::Config { action } => {
489+
let action_str = match action {
490+
ExternalRtcAction::None => "none",
491+
ExternalRtcAction::Wake => "wake",
492+
ExternalRtcAction::Auto => "auto",
493+
};
494+
let response = controller.rtc_config(action_str).await?;
495+
output_response(cli, "rtc config", &response, "⚙️", "RTC Configuration")?;
496+
}
497+
RtcCommands::Show => {
498+
let response = controller.rtc_show_config().await?;
499+
output_response(cli, "rtc show", &response, "📋", "RTC Configuration")?;
500+
}
501+
}
502+
}
477503
Commands::Firmware(firmware_cmd) => {
478504
use cli::FirmwareCommands;
479505

src/power/control.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,24 @@ impl PowerController {
185185
self.protocol.execute_nfc_command(cmd).await
186186
}
187187

188+
/// Get RTC status (internal + external PCF2131)
189+
pub async fn rtc_status(&mut self) -> Result<String> {
190+
info!("Getting RTC status");
191+
self.protocol.execute_power_command("rtc", "").await
192+
}
193+
194+
/// Configure external RTC interrupt action
195+
pub async fn rtc_config(&mut self, action: &str) -> Result<String> {
196+
info!("Configuring external RTC action: {}", action);
197+
self.protocol.execute_power_command("rtc_config", action).await
198+
}
199+
200+
/// Show external RTC interrupt configuration
201+
pub async fn rtc_show_config(&mut self) -> Result<String> {
202+
info!("Getting external RTC configuration");
203+
self.protocol.execute_power_command("rtc_config", "status").await
204+
}
205+
188206
/// Parse power statistics response
189207
fn parse_power_stats(&self, response: &str) -> Result<PowerStats> {
190208
debug!("Parsing power stats: {}", response);

0 commit comments

Comments
 (0)