blob: 1c6577f5da0e5da4ee1b770d989058477dd40578 [file] [log] [blame]
// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
use anyhow::Result;
use erased_serde::Serialize;
use std::any::Any;
use structopt::StructOpt;
use opentitanlib::app::command::CommandDispatch;
use opentitanlib::app::TransportWrapper;
use opentitanlib::io::i2c::{I2cParams, Transfer};
use opentitanlib::transport::Capability;
/// Read plain data bytes from a I2C device.
#[derive(Debug, StructOpt)]
pub struct I2cRawRead {
#[structopt(short = "n", long, help = "Number of bytes to read.")]
length: usize,
}
#[derive(Debug, serde::Serialize)]
pub struct I2cRawReadResponse {
hexdata: String,
}
impl CommandDispatch for I2cRawRead {
fn run(
&self,
context: &dyn Any,
transport: &TransportWrapper,
) -> Result<Option<Box<dyn Serialize>>> {
transport.capabilities()?.request(Capability::I2C).ok()?;
let context = context.downcast_ref::<I2cCommand>().unwrap();
let i2c_bus = context.params.create(transport)?;
let mut v = vec![0u8; self.length];
i2c_bus.run_transaction(context.addr, &mut [Transfer::Read(&mut v)])?;
Ok(Some(Box::new(I2cRawReadResponse {
hexdata: hex::encode(v),
})))
}
}
/// Write plain data bytes to a I2C device.
#[derive(Debug, StructOpt)]
pub struct I2cRawWrite {
#[structopt(short, long, help = "Hex data bytes to write.")]
hexdata: String,
}
impl CommandDispatch for I2cRawWrite {
fn run(
&self,
context: &dyn Any,
transport: &TransportWrapper,
) -> Result<Option<Box<dyn Serialize>>> {
transport.capabilities()?.request(Capability::I2C).ok()?;
let context = context.downcast_ref::<I2cCommand>().unwrap();
let i2c_bus = context.params.create(transport)?;
i2c_bus.run_transaction(
context.addr,
&mut [Transfer::Write(&hex::decode(&self.hexdata)?)],
)?;
Ok(None)
}
}
/// Commands for interacting with a generic I2C bus.
#[derive(Debug, StructOpt, CommandDispatch)]
pub enum InternalI2cCommand {
RawRead(I2cRawRead),
RawWrite(I2cRawWrite),
}
#[derive(Debug, StructOpt)]
pub struct I2cCommand {
#[structopt(flatten)]
params: I2cParams,
#[structopt(short, long, help = "7-bit address of I2C device (0..0x7F).")]
addr: u8,
#[structopt(subcommand)]
command: InternalI2cCommand,
}
impl CommandDispatch for I2cCommand {
fn run(
&self,
_context: &dyn Any,
transport: &TransportWrapper,
) -> Result<Option<Box<dyn Serialize>>> {
// None of the I2C commands care about the prior context, but they do
// care about the `bus` parameter in the current node.
self.command.run(self, transport)
}
}