| // 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) |
| } |
| } |