Skip to content

Commit 9e55a8e

Browse files
committed
Add I2C command.
1 parent 2bd6fd6 commit 9e55a8e

File tree

2 files changed

+124
-1
lines changed

2 files changed

+124
-1
lines changed

src/commands/hardware.rs

Lines changed: 123 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
33
use crate::{bios, osprintln, Ctx, API};
44

5+
use super::{parse_u8, parse_usize};
6+
57
pub static LSBLK_ITEM: menu::Item<Ctx> = menu::Item {
68
item_type: menu::ItemType::Callback {
79
function: lsblk,
@@ -65,6 +67,32 @@ pub static SHUTDOWN_ITEM: menu::Item<Ctx> = menu::Item {
6567
help: Some("Shutdown the system"),
6668
};
6769

70+
pub static I2C_ITEM: menu::Item<Ctx> = menu::Item {
71+
item_type: menu::ItemType::Callback {
72+
function: i2c,
73+
parameters: &[
74+
menu::Parameter::Mandatory {
75+
parameter_name: "bus_idx",
76+
help: Some("I2C bus index"),
77+
},
78+
menu::Parameter::Mandatory {
79+
parameter_name: "dev_addr",
80+
help: Some("7-bit I2C device address"),
81+
},
82+
menu::Parameter::Mandatory {
83+
parameter_name: "tx_bytes",
84+
help: Some("Hex string to transmit"),
85+
},
86+
menu::Parameter::Mandatory {
87+
parameter_name: "rx_count",
88+
help: Some("How many bytes to receive"),
89+
},
90+
],
91+
},
92+
command: "i2c",
93+
help: Some("Do an I2C transaction on a bus"),
94+
};
95+
6896
/// Called when the "lsblk" command is executed.
6997
fn lsblk(_menu: &menu::Menu<Ctx>, _item: &menu::Item<Ctx>, _args: &[&str], _ctx: &mut Ctx) {
7098
let api = API.get();
@@ -195,7 +223,6 @@ fn lsuart(_menu: &menu::Menu<Ctx>, _item: &menu::Item<Ctx>, _args: &[&str], _ctx
195223
/// Called when the "shutdown" command is executed.
196224
fn shutdown(_menu: &menu::Menu<Ctx>, item: &menu::Item<Ctx>, args: &[&str], _ctx: &mut Ctx) {
197225
let api = API.get();
198-
199226
if let Ok(Some(_)) = menu::argument_finder(item, args, "reboot") {
200227
osprintln!("Rebooting...");
201228
(api.power_control)(bios::PowerMode::Reset);
@@ -208,4 +235,99 @@ fn shutdown(_menu: &menu::Menu<Ctx>, item: &menu::Item<Ctx>, args: &[&str], _ctx
208235
}
209236
}
210237

238+
/// Called when the "i2c" command is executed.
239+
fn i2c(_menu: &menu::Menu<Ctx>, item: &menu::Item<Ctx>, args: &[&str], _ctx: &mut Ctx) {
240+
let bus_idx = menu::argument_finder(item, args, "bus_idx").unwrap();
241+
let dev_addr = menu::argument_finder(item, args, "dev_addr").unwrap();
242+
let tx_bytes = menu::argument_finder(item, args, "tx_bytes").unwrap();
243+
let rx_count = menu::argument_finder(item, args, "rx_count").unwrap();
244+
245+
let (Some(bus_idx), Some(dev_addr), Some(tx_bytes), Some(rx_count)) =
246+
(bus_idx, dev_addr, tx_bytes, rx_count)
247+
else {
248+
osprintln!("Missing arguments.");
249+
return;
250+
};
251+
252+
let mut tx_buffer: heapless::Vec<u8, 16> = heapless::Vec::new();
253+
254+
for hex_pair in tx_bytes.as_bytes().chunks(2) {
255+
let Some(top) = hex_digit(hex_pair[0]) else {
256+
osprintln!("Bad hex.");
257+
return;
258+
};
259+
let Some(bottom) = hex_digit(hex_pair[1]) else {
260+
osprintln!("Bad hex.");
261+
return;
262+
};
263+
let byte = top << 4 | bottom;
264+
let Ok(_) = tx_buffer.push(byte) else {
265+
osprintln!("Too much hex.");
266+
return;
267+
};
268+
}
269+
270+
let Ok(bus_idx) = parse_u8(bus_idx) else {
271+
osprintln!("Bad bus_idx");
272+
return;
273+
};
274+
275+
let Ok(dev_addr) = parse_u8(dev_addr) else {
276+
osprintln!("Bad dev_addr");
277+
return;
278+
};
279+
280+
let Ok(rx_count) = parse_usize(rx_count) else {
281+
osprintln!("Bad rx count.");
282+
return;
283+
};
284+
285+
let mut rx_buf = [0u8; 16];
286+
287+
let Some(rx_buf) = rx_buf.get_mut(0..rx_count) else {
288+
osprintln!("Too much rx.");
289+
return;
290+
};
291+
292+
let api = API.get();
293+
294+
match (api.i2c_write_read)(
295+
bus_idx,
296+
dev_addr,
297+
tx_buffer.as_slice().into(),
298+
bios::FfiByteSlice::empty(),
299+
rx_buf.into(),
300+
) {
301+
bios::FfiResult::Ok(_) => {
302+
osprintln!("Ok, got {:x?}", rx_buf);
303+
}
304+
bios::FfiResult::Err(e) => {
305+
osprintln!("Failed: {:?}", e);
306+
}
307+
}
308+
}
309+
310+
/// Convert an ASCII hex digit into a number
311+
fn hex_digit(input: u8) -> Option<u8> {
312+
match input {
313+
b'0' => Some(0),
314+
b'1' => Some(1),
315+
b'2' => Some(2),
316+
b'3' => Some(3),
317+
b'4' => Some(4),
318+
b'5' => Some(5),
319+
b'6' => Some(6),
320+
b'7' => Some(7),
321+
b'8' => Some(8),
322+
b'9' => Some(9),
323+
b'a' | b'A' => Some(10),
324+
b'b' | b'B' => Some(11),
325+
b'c' | b'C' => Some(12),
326+
b'd' | b'D' => Some(13),
327+
b'e' | b'E' => Some(14),
328+
b'f' | b'F' => Some(15),
329+
_ => None,
330+
}
331+
}
332+
211333
// End of file

src/commands/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ pub static OS_MENU: menu::Menu<Ctx> = menu::Menu {
2424
&hardware::LSI2C_ITEM,
2525
&hardware::LSMEM_ITEM,
2626
&hardware::LSUART_ITEM,
27+
&hardware::I2C_ITEM,
2728
&block::READ_ITEM,
2829
&fs::DIR_ITEM,
2930
&ram::HEXDUMP_ITEM,

0 commit comments

Comments
 (0)