Add AccessLpcSim for communicating with ecsim
Probably the duplicated logic in `access/lpc/*` should be factored out in some way, but it's a bit awkward to do so without defining a trait that would be part of the public API...
This commit is contained in:
parent
802bf417cc
commit
42f1b4863f
@ -17,3 +17,8 @@ mod direct;
|
|||||||
pub use self::linux::AccessLpcLinux;
|
pub use self::linux::AccessLpcLinux;
|
||||||
#[cfg(all(feature = "std", target_os = "linux"))]
|
#[cfg(all(feature = "std", target_os = "linux"))]
|
||||||
mod linux;
|
mod linux;
|
||||||
|
|
||||||
|
#[cfg(feature = "std")]
|
||||||
|
mod sim;
|
||||||
|
#[cfg(feature = "std")]
|
||||||
|
pub use self::sim::AccessLpcSim;
|
||||||
|
124
tool/src/access/lpc/sim.rs
Normal file
124
tool/src/access/lpc/sim.rs
Normal file
@ -0,0 +1,124 @@
|
|||||||
|
use std::{
|
||||||
|
io,
|
||||||
|
net::UdpSocket,
|
||||||
|
time::Duration,
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
Access,
|
||||||
|
Error,
|
||||||
|
StdTimeout,
|
||||||
|
Timeout,
|
||||||
|
timeout,
|
||||||
|
};
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
pub struct AccessLpcSim {
|
||||||
|
socket: UdpSocket,
|
||||||
|
timeout: StdTimeout,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AccessLpcSim {
|
||||||
|
pub unsafe fn new(timeout: Duration) -> Result<Self, Error> {
|
||||||
|
let socket = UdpSocket::bind("127.0.0.1:0")?;
|
||||||
|
socket.connect("127.0.0.1:8587")?;
|
||||||
|
let mut access = Self {
|
||||||
|
socket,
|
||||||
|
timeout: StdTimeout::new(timeout),
|
||||||
|
};
|
||||||
|
access.transaction(0x00, 0, 0)?;
|
||||||
|
Ok(access)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn transaction(&mut self, kind: u8, addr: u16, value: u8) -> io::Result<u8> {
|
||||||
|
let addr = addr.to_le_bytes();
|
||||||
|
let request = [kind as u8, addr[0], addr[1], value];
|
||||||
|
if self.socket.send(&request)? != request.len() {
|
||||||
|
return Err(io::Error::new(
|
||||||
|
io::ErrorKind::UnexpectedEof,
|
||||||
|
"Socket request incorrect size"
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut response = [0];
|
||||||
|
if self.socket.recv(&mut response)? != response.len() {
|
||||||
|
return Err(io::Error::new(
|
||||||
|
io::ErrorKind::UnexpectedEof,
|
||||||
|
"Socket response incorrect size"
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(response[0])
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn inb(&mut self, addr: u16) -> Result<u8, Error> {
|
||||||
|
Ok(self.transaction(0x01, addr, 0)?)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn outb(&mut self, addr: u16, value: u8) -> Result<(), Error> {
|
||||||
|
self.transaction(0x02, addr, value)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Read from the command space
|
||||||
|
unsafe fn read_cmd(&mut self, addr: u8) -> Result<u8, Error> {
|
||||||
|
self.inb(SMFI_CMD_BASE + u16::from(addr))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Write to the command space
|
||||||
|
unsafe fn write_cmd(&mut self, addr: u8, data: u8) -> Result<(), Error> {
|
||||||
|
self.outb(SMFI_CMD_BASE + u16::from(addr), data)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Read from the debug space
|
||||||
|
//TODO: better public interface
|
||||||
|
pub unsafe fn read_debug(&mut self, addr: u8) -> Result<u8, Error> {
|
||||||
|
self.inb(SMFI_DBG_BASE + u16::from(addr))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns Ok if a command can be sent
|
||||||
|
unsafe fn command_check(&mut self) -> Result<(), Error> {
|
||||||
|
if self.read_cmd(SMFI_CMD_CMD)? == 0 {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(Error::WouldBlock)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Access for AccessLpcSim {
|
||||||
|
unsafe fn command(&mut self, cmd: u8, data: &mut [u8]) -> Result<u8, Error> {
|
||||||
|
// Test data length
|
||||||
|
if data.len() > self.data_size() {
|
||||||
|
return Err(Error::DataLength(data.len()));
|
||||||
|
}
|
||||||
|
|
||||||
|
// All previous commands should be finished
|
||||||
|
self.command_check()?;
|
||||||
|
|
||||||
|
// Write data bytes, index should be valid due to length test above
|
||||||
|
for i in 0..data.len() {
|
||||||
|
self.write_cmd(i as u8 + SMFI_CMD_DATA, data[i])?;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write command byte, which starts command
|
||||||
|
self.write_cmd(SMFI_CMD_CMD, cmd as u8)?;
|
||||||
|
|
||||||
|
// Wait for command to finish with timeout
|
||||||
|
self.timeout.reset();
|
||||||
|
timeout!(self.timeout, self.command_check())?;
|
||||||
|
|
||||||
|
// Read data bytes, index should be valid due to length test above
|
||||||
|
for i in 0..data.len() {
|
||||||
|
data[i] = self.read_cmd(i as u8 + SMFI_CMD_DATA)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return response byte
|
||||||
|
self.read_cmd(SMFI_CMD_RES)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn data_size(&self) -> usize {
|
||||||
|
SMFI_CMD_SIZE - SMFI_CMD_DATA as usize
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user