diff --git a/boards/components/src/st77xx.rs b/boards/components/src/st77xx.rs index b2d73b7bc6..87789813e3 100644 --- a/boards/components/src/st77xx.rs +++ b/boards/components/src/st77xx.rs @@ -39,7 +39,7 @@ //! ``` use capsules_core::virtualizers::virtual_alarm::{MuxAlarm, VirtualMuxAlarm}; -use capsules_extra::bus; +use capsules_extra::bus::{self, BusAddr8}; use capsules_extra::st77xx::{ST77XXScreen, ST77XX}; use core::mem::MaybeUninit; use kernel::component::Component; @@ -72,7 +72,7 @@ macro_rules! st77xx_component_static { pub struct ST77XXComponent< A: 'static + time::Alarm<'static>, - B: 'static + bus::Bus<'static>, + B: 'static + bus::Bus<'static, BusAddr8>, P: 'static + gpio::Pin, > { alarm_mux: &'static MuxAlarm<'static, A>, @@ -82,8 +82,11 @@ pub struct ST77XXComponent< screen: &'static ST77XXScreen, } -impl, B: 'static + bus::Bus<'static>, P: 'static + gpio::Pin> - ST77XXComponent +impl< + A: 'static + time::Alarm<'static>, + B: 'static + bus::Bus<'static, BusAddr8>, + P: 'static + gpio::Pin, + > ST77XXComponent { pub fn new( alarm_mux: &'static MuxAlarm<'static, A>, @@ -102,8 +105,11 @@ impl, B: 'static + bus::Bus<'static>, P: 'stat } } -impl, B: 'static + bus::Bus<'static>, P: 'static + gpio::Pin> - Component for ST77XXComponent +impl< + A: 'static + time::Alarm<'static>, + B: 'static + bus::Bus<'static, BusAddr8>, + P: 'static + gpio::Pin, + > Component for ST77XXComponent { type StaticInput = ( &'static mut MaybeUninit>, diff --git a/capsules/extra/src/bus.rs b/capsules/extra/src/bus.rs index b547fb6263..7f71e27361 100644 --- a/capsules/extra/src/bus.rs +++ b/capsules/extra/src/bus.rs @@ -29,15 +29,25 @@ use core::cell::Cell; use kernel::debug; -use kernel::hil::bus8080::{self, Bus8080}; +use kernel::hil::bus8080::{self, Bus8080, BusAddr8080}; use kernel::hil::i2c::{Error, I2CClient, I2CDevice}; use kernel::hil::spi::{ClockPhase, ClockPolarity, SpiMasterClient, SpiMasterDevice}; use kernel::utilities::cells::OptionalCell; use kernel::utilities::leasable_buffer::SubSliceMut; use kernel::ErrorCode; -/// Bus width used for address width and data width -pub enum BusWidth { +// Buses, such as I2C or SPI, are generally serial and transmit data byte by byte, +// without taking endianness into account. The receiving device—in this case, +// the screen—interprets the data and determines the endianness. +// In Tock, the lower-level screen driver sets the address endianness. +// For most buses, with the exception of the parallel 8080 bus, endianness +// is largely transparent. +// We store addresses using primitive data types like `u8`, `u16`, `u32`, and `u64`. + +/// The `DataWidth` enum and associated `BusAddr` structs define the width +/// of the data transmitted over a bus. The `BusAddr::bytes`` function transforms +/// the address into the specified endianness and returns an iterator. +pub enum DataWidth { Bits8, Bits16LE, Bits16BE, @@ -47,31 +57,158 @@ pub enum BusWidth { Bits64BE, } -impl BusWidth { +/// Each `BusAddr` struct represents a specific data width and endianness. + +/// 8 bit Bus Address +pub struct BusAddr8(u8); + +/// 16 bit Big Endian Bus Address +pub struct BusAddr16BE(u16); + +/// 16 bit Little Endian Bus Address +pub struct BusAddr16LE(u16); + +/// 32 bit Big Endian Bus Address +pub struct BusAddr32BE(u32); + +/// 32 bit Little Endian Bus Address +pub struct BusAddr32LE(u32); + +/// 64 bit Big Endian Bus Address +pub struct BusAddr64BE(u64); + +/// 64 bit Little Endian Bus Address +pub struct BusAddr64LE(u64); + +impl From for BusAddr8080 { + fn from(value: BusAddr8) -> Self { + BusAddr8080::BusAddr8(value.0) + } +} +impl From for BusAddr8080 { + fn from(value: BusAddr16BE) -> Self { + BusAddr8080::BusAddr16BE(value.0) + } +} +impl From for BusAddr8080 { + fn from(value: BusAddr16LE) -> Self { + BusAddr8080::BusAddr16LE(value.0) + } +} + +impl From for BusAddr8 { + fn from(value: u8) -> Self { + Self(value) + } +} +impl From for BusAddr16BE { + fn from(value: u16) -> Self { + Self(value) + } +} +impl From for BusAddr16LE { + fn from(value: u16) -> Self { + Self(value) + } +} +impl From for BusAddr32BE { + fn from(value: u32) -> Self { + Self(value) + } +} +impl From for BusAddr32LE { + fn from(value: u32) -> Self { + Self(value) + } +} +impl From for BusAddr64BE { + fn from(value: u64) -> Self { + Self(value) + } +} +impl From for BusAddr64LE { + fn from(value: u64) -> Self { + Self(value) + } +} + +/// The `BusAddr` trait is implemented for each BusAddr struct. +/// It provides information about the data width and a way +/// to access the underlying byte representation. +pub trait BusAddr { + const DATA_WIDTH: DataWidth; + fn len(&self) -> usize { + Self::DATA_WIDTH.width_in_bytes() + } + fn bytes(&self) -> impl Iterator; +} +impl BusAddr for BusAddr8 { + const DATA_WIDTH: DataWidth = DataWidth::Bits8; + fn bytes(&self) -> impl Iterator { + self.0.to_be_bytes().into_iter() + } +} +impl BusAddr for BusAddr16BE { + const DATA_WIDTH: DataWidth = DataWidth::Bits16BE; + fn bytes(&self) -> impl Iterator { + self.0.to_be_bytes().into_iter() + } +} +impl BusAddr for BusAddr16LE { + const DATA_WIDTH: DataWidth = DataWidth::Bits16LE; + fn bytes(&self) -> impl Iterator { + self.0.to_le_bytes().into_iter() + } +} +impl BusAddr for BusAddr32BE { + const DATA_WIDTH: DataWidth = DataWidth::Bits32BE; + fn bytes(&self) -> impl Iterator { + self.0.to_be_bytes().into_iter() + } +} +impl BusAddr for BusAddr32LE { + const DATA_WIDTH: DataWidth = DataWidth::Bits32LE; + fn bytes(&self) -> impl Iterator { + self.0.to_le_bytes().into_iter() + } +} +impl BusAddr for BusAddr64BE { + const DATA_WIDTH: DataWidth = DataWidth::Bits64BE; + fn bytes(&self) -> impl Iterator { + self.0.to_be_bytes().into_iter() + } +} +impl BusAddr for BusAddr64LE { + const DATA_WIDTH: DataWidth = DataWidth::Bits64LE; + fn bytes(&self) -> impl Iterator { + self.0.to_le_bytes().into_iter() + } +} + +impl DataWidth { pub fn width_in_bytes(&self) -> usize { match self { - BusWidth::Bits8 => 1, - BusWidth::Bits16BE | BusWidth::Bits16LE => 2, - BusWidth::Bits32BE | BusWidth::Bits32LE => 3, - BusWidth::Bits64BE | BusWidth::Bits64LE => 4, + DataWidth::Bits8 => 1, + DataWidth::Bits16BE | DataWidth::Bits16LE => 2, + DataWidth::Bits32BE | DataWidth::Bits32LE => 4, + DataWidth::Bits64BE | DataWidth::Bits64LE => 8, } } } -pub trait Bus<'a> { +pub trait Bus<'a, A: BusAddr> { /// Set the address to write to /// /// If the underlying bus does not support addresses (eg UART) /// this function returns ENOSUPPORT - fn set_addr(&self, addr_width: BusWidth, addr: usize) -> Result<(), ErrorCode>; - + fn set_addr(&self, addr: A) -> Result<(), ErrorCode>; /// Write data items to the previously set address /// /// data_width specifies the encoding of the data items placed in the buffer /// len specifies the number of data items (the number of bytes is len * data_width.width_in_bytes) fn write( &self, - data_width: BusWidth, + data_width: DataWidth, buffer: &'static mut [u8], len: usize, ) -> Result<(), (ErrorCode, &'static mut [u8])>; @@ -82,7 +219,7 @@ pub trait Bus<'a> { /// len specifies the number of data items (the number of bytes is len * data_width.width_in_bytes) fn read( &self, - data_width: BusWidth, + data_width: DataWidth, buffer: &'static mut [u8], len: usize, ) -> Result<(), (ErrorCode, &'static mut [u8])>; @@ -149,34 +286,38 @@ impl<'a, S: SpiMasterDevice<'a>> SpiMasterBus<'a, S> { } } -impl<'a, S: SpiMasterDevice<'a>> Bus<'a> for SpiMasterBus<'a, S> { - fn set_addr(&self, addr_width: BusWidth, addr: usize) -> Result<(), ErrorCode> { - match addr_width { - BusWidth::Bits8 => { - self.addr_buffer - .take() - .map_or(Err(ErrorCode::NOMEM), |mut buffer| { - self.status.set(BusStatus::SetAddress); - buffer.reset(); - buffer.slice(0..1); - buffer[0] = addr as u8; - if let Err((error, buffer, _)) = self.spi.read_write_bytes(buffer, None) { - self.status.set(BusStatus::Idle); - self.addr_buffer.replace(buffer); - Err(error) - } else { - Ok(()) - } - }) - } - - _ => Err(ErrorCode::NOSUPPORT), - } +impl<'a, A: BusAddr, S: SpiMasterDevice<'a>> Bus<'a, A> for SpiMasterBus<'a, S> { + fn set_addr(&self, addr: A) -> Result<(), ErrorCode> { + self.addr_buffer + .take() + .map_or(Err(ErrorCode::NOMEM), |mut buffer| { + let bytes = addr.bytes(); + if buffer.len() >= addr.len() { + buffer.reset(); + buffer.slice(0..addr.len()); + self.status.set(BusStatus::SetAddress); + buffer + .as_slice() + .iter_mut() + .zip(bytes) + .for_each(|(d, s)| *d = s); + if let Err((error, buffer, _)) = self.spi.read_write_bytes(buffer, None) { + self.status.set(BusStatus::Idle); + self.addr_buffer.replace(buffer); + Err(error) + } else { + Ok(()) + } + } else { + self.addr_buffer.replace(buffer); + Err(ErrorCode::SIZE) + } + }) } fn write( &self, - data_width: BusWidth, + data_width: DataWidth, buffer: &'static mut [u8], len: usize, ) -> Result<(), (ErrorCode, &'static mut [u8])> { @@ -200,7 +341,7 @@ impl<'a, S: SpiMasterDevice<'a>> Bus<'a> for SpiMasterBus<'a, S> { fn read( &self, - data_width: BusWidth, + data_width: DataWidth, buffer: &'static mut [u8], len: usize, ) -> Result<(), (ErrorCode, &'static mut [u8])> { @@ -295,31 +436,32 @@ impl<'a, I: I2CDevice> I2CMasterBus<'a, I> { } } -impl<'a, I: I2CDevice> Bus<'a> for I2CMasterBus<'a, I> { - fn set_addr(&self, addr_width: BusWidth, addr: usize) -> Result<(), ErrorCode> { - match addr_width { - BusWidth::Bits8 => self - .addr_buffer - .take() - .map_or(Err(ErrorCode::NOMEM), |buffer| { - buffer[0] = addr as u8; - self.status.set(BusStatus::SetAddress); - match self.i2c.write(buffer, 1) { +impl<'a, A: BusAddr, I: I2CDevice> Bus<'a, A> for I2CMasterBus<'a, I> { + fn set_addr(&self, addr: A) -> Result<(), ErrorCode> { + self.addr_buffer + .take() + .map_or(Err(ErrorCode::NOMEM), |buffer| { + self.status.set(BusStatus::SetAddress); + let bytes = addr.bytes(); + if buffer.len() >= addr.len() { + let () = buffer.iter_mut().zip(bytes).for_each(|(d, s)| *d = s); + match self.i2c.write(buffer, addr.len()) { Ok(()) => Ok(()), Err((error, buffer)) => { self.addr_buffer.replace(buffer); Err(error.into()) } } - }), - - _ => Err(ErrorCode::NOSUPPORT), - } + } else { + self.addr_buffer.replace(buffer); + Err(ErrorCode::SIZE) + } + }) } fn write( &self, - data_width: BusWidth, + data_width: DataWidth, buffer: &'static mut [u8], len: usize, ) -> Result<(), (ErrorCode, &'static mut [u8])> { @@ -341,7 +483,7 @@ impl<'a, I: I2CDevice> Bus<'a> for I2CMasterBus<'a, I> { fn read( &self, - data_width: BusWidth, + data_width: DataWidth, buffer: &'static mut [u8], len: usize, ) -> Result<(), (ErrorCode, &'static mut [u8])> { @@ -408,28 +550,25 @@ impl<'a, B: Bus8080<'static>> Bus8080Bus<'a, B> { } } - fn to_bus8080_width(bus_width: BusWidth) -> Option { + fn to_bus8080_width(bus_width: DataWidth) -> Option { match bus_width { - BusWidth::Bits8 => Some(bus8080::BusWidth::Bits8), - BusWidth::Bits16LE => Some(bus8080::BusWidth::Bits16LE), - BusWidth::Bits16BE => Some(bus8080::BusWidth::Bits16BE), + DataWidth::Bits8 => Some(bus8080::BusWidth::Bits8), + DataWidth::Bits16LE => Some(bus8080::BusWidth::Bits16LE), + DataWidth::Bits16BE => Some(bus8080::BusWidth::Bits16BE), _ => None, } } } -impl<'a, B: Bus8080<'static>> Bus<'a> for Bus8080Bus<'a, B> { - fn set_addr(&self, addr_width: BusWidth, addr: usize) -> Result<(), ErrorCode> { - if let Some(bus_width) = Self::to_bus8080_width(addr_width) { - self.bus.set_addr(bus_width, addr) - } else { - Err(ErrorCode::INVAL) - } +impl<'a, A: BusAddr + Into, B: Bus8080<'static>> Bus<'a, A> for Bus8080Bus<'a, B> { + fn set_addr(&self, addr: A) -> Result<(), ErrorCode> { + let _ = self.bus.set_addr(addr.into()); + Ok(()) } fn write( &self, - data_width: BusWidth, + data_width: DataWidth, buffer: &'static mut [u8], len: usize, ) -> Result<(), (ErrorCode, &'static mut [u8])> { @@ -442,7 +581,7 @@ impl<'a, B: Bus8080<'static>> Bus<'a> for Bus8080Bus<'a, B> { fn read( &self, - data_width: BusWidth, + data_width: DataWidth, buffer: &'static mut [u8], len: usize, ) -> Result<(), (ErrorCode, &'static mut [u8])> { diff --git a/capsules/extra/src/st77xx.rs b/capsules/extra/src/st77xx.rs index 83171160bd..c8f5bd88a5 100644 --- a/capsules/extra/src/st77xx.rs +++ b/capsules/extra/src/st77xx.rs @@ -34,7 +34,7 @@ //! ); //! ``` -use crate::bus::{self, Bus, BusWidth}; +use crate::bus::{self, Bus, BusAddr8, DataWidth}; use core::cell::Cell; use kernel::hil::gpio::Pin; use kernel::hil::screen::{ @@ -206,7 +206,7 @@ pub enum SendCommand { Slice(&'static Command, usize), } -pub struct ST77XX<'a, A: Alarm<'a>, B: Bus<'a>, P: Pin> { +pub struct ST77XX<'a, A: Alarm<'a>, B: Bus<'a, BusAddr8>, P: Pin> { bus: &'a B, alarm: &'a A, dc: Option<&'a P>, @@ -234,7 +234,7 @@ pub struct ST77XX<'a, A: Alarm<'a>, B: Bus<'a>, P: Pin> { screen: &'static ST77XXScreen, } -impl<'a, A: Alarm<'a>, B: Bus<'a>, P: Pin> ST77XX<'a, A, B, P> { +impl<'a, A: Alarm<'a>, B: Bus<'a, BusAddr8>, P: Pin> ST77XX<'a, A, B, P> { pub fn new( bus: &'a B, alarm: &'a A, @@ -336,14 +336,14 @@ impl<'a, A: Alarm<'a>, B: Bus<'a>, P: Pin> ST77XX<'a, A, B, P> { self.command.set(cmd); self.status.set(Status::SendCommand(position, len, repeat)); self.dc.map(|dc| dc.clear()); - let _ = self.bus.set_addr(BusWidth::Bits8, cmd.id as usize); + let _ = self.bus.set_addr(cmd.id.into()); } fn send_command_slice(&self, cmd: &'static Command, len: usize) { self.command.set(cmd); self.dc.map(|dc| dc.clear()); self.status.set(Status::SendCommandSlice(len)); - let _ = self.bus.set_addr(BusWidth::Bits8, cmd.id as usize); + let _ = self.bus.set_addr(cmd.id.into()); } fn send_parameters(&self, position: usize, len: usize, repeat: usize) { @@ -359,7 +359,7 @@ impl<'a, A: Alarm<'a>, B: Bus<'a>, P: Pin> ST77XX<'a, A, B, P> { } } self.dc.map(|dc| dc.set()); - let _ = self.bus.write(BusWidth::Bits8, buffer, len); + let _ = self.bus.write(DataWidth::Bits8, buffer, len); }, ); } else { @@ -373,7 +373,7 @@ impl<'a, A: Alarm<'a>, B: Bus<'a>, P: Pin> ST77XX<'a, A, B, P> { |buffer| { self.status.set(Status::SendParametersSlice); self.dc.map(|dc| dc.set()); - let _ = self.bus.write(BusWidth::Bits16BE, buffer, len / 2); + let _ = self.bus.write(DataWidth::Bits16BE, buffer, len / 2); }, ); } @@ -683,7 +683,9 @@ impl<'a, A: Alarm<'a>, B: Bus<'a>, P: Pin> ST77XX<'a, A, B, P> { } } -impl<'a, A: Alarm<'a>, B: Bus<'a>, P: Pin> screen::ScreenSetup<'a> for ST77XX<'a, A, B, P> { +impl<'a, A: Alarm<'a>, B: Bus<'a, BusAddr8>, P: Pin> screen::ScreenSetup<'a> + for ST77XX<'a, A, B, P> +{ fn set_client(&self, setup_client: &'a dyn ScreenSetupClient) { self.setup_client.set(setup_client); } @@ -741,7 +743,7 @@ impl<'a, A: Alarm<'a>, B: Bus<'a>, P: Pin> screen::ScreenSetup<'a> for ST77XX<'a } } -impl<'a, A: Alarm<'a>, B: Bus<'a>, P: Pin> screen::Screen<'a> for ST77XX<'a, A, B, P> { +impl<'a, A: Alarm<'a>, B: Bus<'a, BusAddr8>, P: Pin> screen::Screen<'a> for ST77XX<'a, A, B, P> { fn get_resolution(&self) -> (usize, usize) { (self.width.get(), self.height.get()) } @@ -853,13 +855,13 @@ impl<'a, A: Alarm<'a>, B: Bus<'a>, P: Pin> screen::Screen<'a> for ST77XX<'a, A, } } -impl<'a, A: Alarm<'a>, B: Bus<'a>, P: Pin> time::AlarmClient for ST77XX<'a, A, B, P> { +impl<'a, A: Alarm<'a>, B: Bus<'a, BusAddr8>, P: Pin> time::AlarmClient for ST77XX<'a, A, B, P> { fn alarm(&self) { self.do_next_op(); } } -impl<'a, A: Alarm<'a>, B: Bus<'a>, P: Pin> bus::Client for ST77XX<'a, A, B, P> { +impl<'a, A: Alarm<'a>, B: Bus<'a, BusAddr8>, P: Pin> bus::Client for ST77XX<'a, A, B, P> { fn command_complete( &self, buffer: Option<&'static mut [u8]>, diff --git a/chips/stm32f4xx/src/fsmc.rs b/chips/stm32f4xx/src/fsmc.rs index a01ed99530..4664326579 100644 --- a/chips/stm32f4xx/src/fsmc.rs +++ b/chips/stm32f4xx/src/fsmc.rs @@ -5,7 +5,7 @@ use crate::clocks::{phclk, Stm32f4Clocks}; use core::cell::Cell; use kernel::deferred_call::{DeferredCall, DeferredCallClient}; -use kernel::hil::bus8080::{Bus8080, BusWidth, Client}; +use kernel::hil::bus8080::{Bus8080, BusAddr8080, BusWidth, Client}; use kernel::platform::chip::ClockInterface; use kernel::utilities::cells::{OptionalCell, TakeCell}; use kernel::utilities::registers::interfaces::{ReadWriteable, Readable}; @@ -315,9 +315,9 @@ impl ClockInterface for FsmcClock<'_> { } impl Bus8080<'static> for Fsmc<'_> { - fn set_addr(&self, addr_width: BusWidth, addr: usize) -> Result<(), ErrorCode> { - match addr_width { - BusWidth::Bits8 => { + fn set_addr(&self, addr: BusAddr8080) -> Result<(), ErrorCode> { + match addr { + BusAddr8080::BusAddr8(addr) => { self.write_reg(FsmcBanks::Bank1, addr as u16); self.deferred_call.set(); Ok(()) diff --git a/kernel/src/hil/bus8080.rs b/kernel/src/hil/bus8080.rs index e608f1deb5..6407641157 100644 --- a/kernel/src/hil/bus8080.rs +++ b/kernel/src/hil/bus8080.rs @@ -12,6 +12,18 @@ pub enum BusWidth { Bits16LE, Bits16BE, } +/// The enum represents the address of a bus-attached device. +/// +/// For addresses larger than a single byte the enum variant +/// captures the endianess used by the device on the bus. +/// The address is stored in the host endianess in the u16 and +/// must be converted to the correct endianess before using the +/// address on the bus. +pub enum BusAddr8080 { + BusAddr8(u8), + BusAddr16BE(u16), + BusAddr16LE(u16), +} impl BusWidth { pub fn width_in_bytes(&self) -> usize { @@ -24,8 +36,7 @@ impl BusWidth { pub trait Bus8080<'a> { /// Set the address to write to - fn set_addr(&self, addr_width: BusWidth, addr: usize) -> Result<(), ErrorCode>; - + fn set_addr(&self, addr: BusAddr8080) -> Result<(), ErrorCode>; /// Write data items to the previously set address fn write( &self,