#[cfg(not(feature = "std"))]
use alloc::{
boxed::Box,
vec,
};
use crate::{
Access,
Error,
Spi,
SpiTarget,
};
#[derive(Clone, Copy, Debug)]
#[repr(u8)]
enum Cmd {
Probe = 1,
Board = 2,
Version = 3,
Print = 4,
Spi = 5,
Reset = 6,
FanGet = 7,
FanSet = 8,
KeymapGet = 9,
KeymapSet = 10,
LedGetValue = 11,
LedSetValue = 12,
LedGetColor = 13,
LedSetColor = 14,
LedGetMode = 15,
LedSetMode = 16,
MatrixGet = 17,
LedSave = 18,
}
const CMD_SPI_FLAG_READ: u8 = 1 << 0;
const CMD_SPI_FLAG_DISABLE: u8 = 1 << 1;
const CMD_SPI_FLAG_SCRATCH: u8 = 1 << 2;
const CMD_SPI_FLAG_BACKUP: u8 = 1 << 3;
pub struct Ec<A: Access> {
access: A,
version: u8,
}
impl<A: Access> Ec<A> {
pub unsafe fn new(access: A) -> Result<Self, Error> {
let mut ec = Ec {
access,
version: 0,
};
ec.version = ec.probe()?;
match ec.version {
1 => (),
_ => return Err(Error::Version(ec.version)),
}
Ok(ec)
}
pub unsafe fn access(&mut self) -> &mut A {
&mut self.access
}
unsafe fn command(&mut self, cmd: Cmd, data: &mut [u8]) -> Result<(), Error> {
match self.access.command(cmd as u8, data)? {
0 => Ok(()),
err => Err(Error::Protocol(err)),
}
}
pub unsafe fn probe(&mut self) -> Result<u8, Error> {
let mut data = [0; 3];
self.command(Cmd::Probe, &mut data)?;
let signature = (data[0], data[1]);
if signature == (0x76, 0xEC) {
let version = data[2];
Ok(version)
} else {
Err(Error::Signature(signature))
}
}
pub unsafe fn board(&mut self, data: &mut [u8]) -> Result<usize, Error> {
self.command(Cmd::Board, data)?;
let mut i = 0;
while i < data.len() {
if data[i] == 0 {
break;
}
i += 1;
}
Ok(i)
}
pub unsafe fn version(&mut self, data: &mut [u8]) -> Result<usize, Error> {
self.command(Cmd::Version, data)?;
let mut i = 0;
while i < data.len() {
if data[i] == 0 {
break;
}
i += 1;
}
Ok(i)
}
pub unsafe fn print(&mut self, data: &[u8]) -> Result<usize, Error> {
let flags = 0;
for chunk in data.chunks(256 - 4) {
let mut data = [0; 256 - 2];
data[0] = flags;
data[1] = chunk.len() as u8;
for i in 0..chunk.len() {
data[i + 2] = chunk[i];
}
self.command(Cmd::Print, &mut data)?;
if data[1] != chunk.len() as u8 {
return Err(Error::Verify);
}
}
Ok(data.len())
}
pub unsafe fn spi(&mut self, target: SpiTarget, scratch: bool) -> Result<EcSpi<A>, Error> {
let data_size = self.access.data_size();
let mut spi = EcSpi {
ec: self,
target,
scratch,
buffer: vec![0; data_size].into_boxed_slice(),
};
spi.reset()?;
Ok(spi)
}
pub unsafe fn reset(&mut self) -> Result<(), Error> {
self.command(Cmd::Reset, &mut [])
}
pub unsafe fn fan_get(&mut self, index: u8) -> Result<u8, Error> {
let mut data = [
index,
0
];
self.command(Cmd::FanGet, &mut data)?;
Ok(data[1])
}
pub unsafe fn fan_set(&mut self, index: u8, duty: u8) -> Result<(), Error> {
let mut data = [
index,
duty
];
self.command(Cmd::FanSet, &mut data)
}
pub unsafe fn keymap_get(&mut self, layer: u8, output: u8, input: u8) -> Result<u16, Error> {
let mut data = [
layer,
output,
input,
0,
0
];
self.command(Cmd::KeymapGet, &mut data)?;
Ok(
(data[3] as u16) |
((data[4] as u16) << 8)
)
}
pub unsafe fn keymap_set(&mut self, layer: u8, output: u8, input: u8, value: u16) -> Result<(), Error> {
let mut data = [
layer,
output,
input,
value as u8,
(value >> 8) as u8
];
self.command(Cmd::KeymapSet, &mut data)
}
pub unsafe fn led_get_value(&mut self, index: u8) -> Result<(u8, u8), Error> {
let mut data = [
index,
0,
0,
];
self.command(Cmd::LedGetValue, &mut data)?;
Ok((data[1], data[2]))
}
pub unsafe fn led_set_value(&mut self, index: u8, value: u8) -> Result<(), Error> {
let mut data = [
index,
value,
];
self.command(Cmd::LedSetValue, &mut data)
}
pub unsafe fn led_get_color(&mut self, index: u8) -> Result<(u8, u8, u8), Error> {
let mut data = [
index,
0,
0,
0,
];
self.command(Cmd::LedGetColor, &mut data)?;
Ok((
data[1],
data[2],
data[3],
))
}
pub unsafe fn led_set_color(&mut self, index: u8, red: u8, green: u8, blue: u8) -> Result<(), Error> {
let mut data = [
index,
red,
green,
blue,
];
self.command(Cmd::LedSetColor, &mut data)
}
pub unsafe fn led_get_mode(&mut self, layer: u8) -> Result<(u8, u8), Error> {
let mut data = [
layer,
0,
0,
];
self.command(Cmd::LedGetMode, &mut data)?;
Ok((
data[1],
data[2]
))
}
pub unsafe fn led_set_mode(&mut self, layer: u8, mode: u8, speed: u8) -> Result<(), Error> {
let mut data = [
layer,
mode,
speed,
];
self.command(Cmd::LedSetMode, &mut data)
}
pub unsafe fn led_save(&mut self) -> Result<(), Error> {
self.command(Cmd::LedSave, &mut [])
}
pub unsafe fn matrix_get(&mut self, matrix: &mut [u8]) -> Result<(), Error> {
self.command(Cmd::MatrixGet, matrix)
}
pub fn into_dyn(self) -> Ec<Box<dyn Access>>
where A: 'static {
Ec {
access: Box::new(self.access),
version: self.version,
}
}
}
pub struct EcSpi<'a, A: Access> {
ec: &'a mut Ec<A>,
target: SpiTarget,
scratch: bool,
buffer: Box<[u8]>,
}
impl<'a, A: Access> EcSpi<'a, A> {
fn flags(&self, read: bool, disable: bool) -> u8 {
let mut flags = 0;
if read {
flags |= CMD_SPI_FLAG_READ;
}
if disable {
flags |= CMD_SPI_FLAG_DISABLE;
}
if self.scratch {
flags |= CMD_SPI_FLAG_SCRATCH;
}
match self.target {
SpiTarget::Main => (),
SpiTarget::Backup => {
flags |= CMD_SPI_FLAG_BACKUP;
},
}
flags
}
}
impl<'a, A: Access> Spi for EcSpi<'a, A> {
fn target(&self) -> SpiTarget {
self.target
}
unsafe fn reset(&mut self) -> Result<(), Error> {
let flags = self.flags(false, true);
self.buffer[0] = flags;
self.buffer[1] = 0;
self.ec.command(Cmd::Spi, &mut self.buffer[..2])?;
if self.buffer[1] != 0 {
return Err(Error::Verify);
}
Ok(())
}
unsafe fn read(&mut self, data: &mut [u8]) -> Result<usize, Error> {
let flags = self.flags(true, false);
for chunk in data.chunks_mut(self.buffer.len() - 2) {
self.buffer[0] = flags;
self.buffer[1] = chunk.len() as u8;
self.ec.command(Cmd::Spi, &mut self.buffer[..(chunk.len() + 2)])?;
if self.buffer[1] != chunk.len() as u8 {
return Err(Error::Verify);
}
for i in 0..chunk.len() {
chunk[i] = self.buffer[i + 2];
}
}
Ok(data.len())
}
unsafe fn write(&mut self, data: &[u8]) -> Result<usize, Error> {
let flags = self.flags(false, false);
for chunk in data.chunks(self.buffer.len() - 2) {
self.buffer[0] = flags;
self.buffer[1] = chunk.len() as u8;
for i in 0..chunk.len() {
self.buffer[i + 2] = chunk[i];
}
self.ec.command(Cmd::Spi, &mut self.buffer[..(chunk.len() + 2)])?;
if self.buffer[1] != chunk.len() as u8 {
return Err(Error::Verify);
}
}
Ok(data.len())
}
}
impl<'a, A: Access> Drop for EcSpi<'a, A> {
fn drop(&mut self) {
unsafe {
let _ = self.reset();
}
}
}