forked from renet/ENC424J600
Add packet RX
This commit is contained in:
parent
4e4267e55a
commit
9b48a585cf
|
@ -13,10 +13,10 @@ volatile-register = "0.2"
|
||||||
aligned = "0.3"
|
aligned = "0.3"
|
||||||
stm32f4xx-hal = { version = "0.8" , optional = true }
|
stm32f4xx-hal = { version = "0.8" , optional = true }
|
||||||
smoltcp = { version = "0.6.0", default-features = false, features = ["proto-ipv4", "proto-ipv6", "socket-icmp", "socket-udp", "socket-tcp", "log", "verbose", "ethernet"], optional = true }
|
smoltcp = { version = "0.6.0", default-features = false, features = ["proto-ipv4", "proto-ipv6", "socket-icmp", "socket-udp", "socket-tcp", "log", "verbose", "ethernet"], optional = true }
|
||||||
log = { version = "0.4", optional = true }
|
log = { version = "0.4" }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
smoltcp-phy = ["smoltcp", "log"]
|
smoltcp-phy = ["smoltcp"]
|
||||||
stm32f407 = ["stm32f4xx-hal/stm32f407"]
|
stm32f407 = ["stm32f4xx-hal/stm32f407"]
|
||||||
default = []
|
default = []
|
||||||
|
|
||||||
|
|
151
src/lib.rs
151
src/lib.rs
|
@ -1,4 +1,155 @@
|
||||||
#![no_std]
|
#![no_std]
|
||||||
|
|
||||||
|
use core::fmt;
|
||||||
|
|
||||||
/// STM32F4xx-HAL specific implementations
|
/// STM32F4xx-HAL specific implementations
|
||||||
pub mod spi;
|
pub mod spi;
|
||||||
|
use stm32f4xx_hal::{
|
||||||
|
hal::{
|
||||||
|
blocking::spi::Transfer,
|
||||||
|
digital::v2::OutputPin,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
pub mod rx;
|
||||||
|
|
||||||
|
#[cfg(feature="smoltcp")]
|
||||||
|
pub mod smoltcp_phy;
|
||||||
|
|
||||||
|
pub trait EthController {
|
||||||
|
fn init_dev(&mut self) -> Result<(), EthControllerError>;
|
||||||
|
fn init_rxbuf(&mut self) -> Result<(), EthControllerError>;
|
||||||
|
fn receive_next(&mut self) -> Result<rx::RxPacket, EthControllerError>;
|
||||||
|
fn set_promiscuous(&mut self) -> Result<(), EthControllerError>;
|
||||||
|
fn read_from_mac(&mut self, mac: &mut [u8]) -> Result<(), EthControllerError>;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// TODO: Improve these error types
|
||||||
|
pub enum EthControllerError {
|
||||||
|
SpiPortError,
|
||||||
|
GeneralError
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<spi::SpiPortError> for EthControllerError {
|
||||||
|
fn from(e: spi::SpiPortError) -> EthControllerError {
|
||||||
|
EthControllerError::SpiPortError
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Ethernet controller using SPI interface
|
||||||
|
pub struct SpiEth<SPI: Transfer<u8>,
|
||||||
|
NSS: OutputPin> {
|
||||||
|
spi_port: spi::SpiPort<SPI, NSS>,
|
||||||
|
rx_buf: rx::RxBuffer
|
||||||
|
}
|
||||||
|
|
||||||
|
impl <SPI: Transfer<u8>,
|
||||||
|
NSS: OutputPin> SpiEth<SPI, NSS> {
|
||||||
|
pub fn new(spi: SPI, mut nss: NSS) -> Self {
|
||||||
|
SpiEth {
|
||||||
|
spi_port: spi::SpiPort::new(spi, nss),
|
||||||
|
rx_buf: rx::RxBuffer::new(),
|
||||||
|
// TODO: tx_buf
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl <SPI: Transfer<u8>,
|
||||||
|
NSS: OutputPin> EthController for SpiEth<SPI, NSS> {
|
||||||
|
fn init_dev(&mut self) -> Result<(), EthControllerError> {
|
||||||
|
// Write 0x1234 to EUDAST
|
||||||
|
self.spi_port.write_reg_16b(spi::EUDAST, 0x1234)?;
|
||||||
|
// Verify that EUDAST is 0x1234
|
||||||
|
let mut eudast = self.spi_port.read_reg_16b(spi::EUDAST)?;
|
||||||
|
if eudast != 0x1234 {
|
||||||
|
return Err(EthControllerError::GeneralError)
|
||||||
|
}
|
||||||
|
// Poll CLKRDY (ESTAT<12>) to check if it is set
|
||||||
|
loop {
|
||||||
|
let estat = self.spi_port.read_reg_16b(spi::ESTAT)?;
|
||||||
|
if estat & 0x1000 == 0x1000 { break }
|
||||||
|
}
|
||||||
|
// Set ETHRST (ECON2<4>) to 1
|
||||||
|
let econ2 = self.spi_port.read_reg_8b(spi::ECON2)?;
|
||||||
|
self.spi_port.write_reg_8b(spi::ECON2, 0x10 | (econ2 & 0b11101111))?;
|
||||||
|
// Verify that EUDAST is 0x0000
|
||||||
|
eudast = self.spi_port.read_reg_16b(spi::EUDAST)?;
|
||||||
|
if eudast != 0x0000 {
|
||||||
|
return Err(EthControllerError::GeneralError)
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn init_rxbuf(&mut self) -> Result<(), EthControllerError> {
|
||||||
|
// Set ERXST pointer
|
||||||
|
self.spi_port.write_reg_16b(spi::ERXST, self.rx_buf.get_wrap_addr());
|
||||||
|
// Set ERXTAIL pointer
|
||||||
|
self.spi_port.write_reg_16b(spi::ERXTAIL, self.rx_buf.get_tail_addr());
|
||||||
|
// Set MAMXFL to maximum number of bytes in each accepted packet
|
||||||
|
self.spi_port.write_reg_16b(spi::MAMXFL, rx::RAW_FRAME_LENGTH_MAX as u16);
|
||||||
|
// Enable RXEN (ECON1<0>)
|
||||||
|
let econ1 = self.spi_port.read_reg_16b(spi::ECON1)?;
|
||||||
|
self.spi_port.write_reg_16b(spi::ECON1, 0x1 | (econ1 & 0xfffe));
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Receive the next packet
|
||||||
|
fn receive_next(&mut self) -> Result<rx::RxPacket, EthControllerError> {
|
||||||
|
// Poll PKTIF (EIR<4>) to check if it is set
|
||||||
|
loop {
|
||||||
|
let eir = self.spi_port.read_reg_16b(spi::EIR)?;
|
||||||
|
if eir & 0x40 == 0x40 { break }
|
||||||
|
}
|
||||||
|
// Set ERXRDPT pointer to next_addr
|
||||||
|
self.spi_port.write_reg_16b(spi::ERXRDPT, self.rx_buf.get_next_addr())?;
|
||||||
|
// Read 2 bytes to update next_addr
|
||||||
|
let mut next_addr_buf = [0; 3];
|
||||||
|
self.spi_port.read_rxdat(&mut next_addr_buf, 2)?;
|
||||||
|
self.rx_buf.set_next_addr((next_addr_buf[1] as u16) | ((next_addr_buf[2] as u16) << 8));
|
||||||
|
// Read 6 bytes to update rsv
|
||||||
|
let mut rsv_buf = [0; 7];
|
||||||
|
self.spi_port.read_rxdat(&mut rsv_buf, 6)?;
|
||||||
|
// Construct an RxPacket
|
||||||
|
// TODO: can we directly assign to fields instead of using functions?
|
||||||
|
let mut rx_packet = rx::RxPacket::new();
|
||||||
|
// Get and update frame length
|
||||||
|
rx_packet.write_to_rsv(&rsv_buf[1..]);
|
||||||
|
rx_packet.update_frame_length();
|
||||||
|
// Read frame bytes
|
||||||
|
let mut frame_buf = [0; rx::RAW_FRAME_LENGTH_MAX];
|
||||||
|
self.spi_port.read_rxdat(&mut frame_buf, rx_packet.get_frame_length() as u32)?;
|
||||||
|
rx_packet.write_to_frame(&frame_buf[1..]);
|
||||||
|
// Set ERXTAIL pointer to (next_addr - 2)
|
||||||
|
if self.rx_buf.get_next_addr() > rx::ERXST_DEFAULT {
|
||||||
|
self.spi_port.write_reg_16b(spi::ERXTAIL, self.rx_buf.get_next_addr() - 2)?;
|
||||||
|
} else {
|
||||||
|
self.spi_port.write_reg_16b(spi::ERXTAIL, rx::RX_MAX_ADDRESS - 1)?;
|
||||||
|
}
|
||||||
|
// Set PKTDEC to decrement PKTCNT
|
||||||
|
let econ1_hi = self.spi_port.read_reg_8b(spi::ECON1 + 1)?;
|
||||||
|
self.spi_port.write_reg_8b(spi::ECON1 + 1, 0x01 | (econ1_hi & 0xfe))?;
|
||||||
|
// Return the RxPacket
|
||||||
|
Ok(rx_packet)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set controller to Promiscuous Mode
|
||||||
|
fn set_promiscuous(&mut self) -> Result<(), EthControllerError> {
|
||||||
|
// From ENC424J600 Data Sheet Section 10.12:
|
||||||
|
// "To accept all incoming frames regardless of content (Promiscuous mode),
|
||||||
|
// set the CRCEN, RUNTEN, UCEN, NOTMEEN and MCEN bits."
|
||||||
|
let mut erxfcon_lo = self.spi_port.read_reg_8b(spi::ERXFCON)?;
|
||||||
|
self.spi_port.write_reg_8b(spi::ERXFCON, 0b0101_1110 | (erxfcon_lo & 0b1010_0001));
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Read MAC to [u8; 6]
|
||||||
|
fn read_from_mac(&mut self, mac: &mut [u8]) -> Result<(), EthControllerError> {
|
||||||
|
mac[0] = self.spi_port.read_reg_8b(spi::MAADR1)?;
|
||||||
|
mac[1] = self.spi_port.read_reg_8b(spi::MAADR1 + 1)?;
|
||||||
|
mac[2] = self.spi_port.read_reg_8b(spi::MAADR2)?;
|
||||||
|
mac[3] = self.spi_port.read_reg_8b(spi::MAADR2 + 1)?;
|
||||||
|
mac[4] = self.spi_port.read_reg_8b(spi::MAADR3)?;
|
||||||
|
mac[5] = self.spi_port.read_reg_8b(spi::MAADR3 + 1)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,125 @@
|
||||||
|
/// SRAM Addresses
|
||||||
|
pub const ERXST_DEFAULT: u16 = 0x5340;
|
||||||
|
pub const ERXTAIL_DEFAULT: u16 = 0x5ffe;
|
||||||
|
pub const RX_MAX_ADDRESS: u16 = 0x5fff;
|
||||||
|
|
||||||
|
/// Max raw frame array size
|
||||||
|
pub const RAW_FRAME_LENGTH_MAX: usize = 0x1000;
|
||||||
|
/// Receive Status Vector Length
|
||||||
|
pub const RSV_LENGTH: usize = 6;
|
||||||
|
|
||||||
|
/// Struct for RX Buffer
|
||||||
|
/// TODO: Should be a singleton
|
||||||
|
pub struct RxBuffer {
|
||||||
|
wrap_addr: u16,
|
||||||
|
next_addr: u16,
|
||||||
|
tail_addr: u16
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RxBuffer {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
RxBuffer {
|
||||||
|
wrap_addr: ERXST_DEFAULT,
|
||||||
|
next_addr: ERXST_DEFAULT,
|
||||||
|
tail_addr: ERXTAIL_DEFAULT
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_wrap_addr(&mut self, addr: u16) {
|
||||||
|
self.wrap_addr = addr;
|
||||||
|
}
|
||||||
|
pub fn get_wrap_addr(& self) -> u16{
|
||||||
|
self.wrap_addr
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_next_addr(&mut self, addr: u16) {
|
||||||
|
self.next_addr = addr;
|
||||||
|
}
|
||||||
|
pub fn get_next_addr(& self) -> u16{
|
||||||
|
self.next_addr
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_tail_addr(&mut self, addr: u16) {
|
||||||
|
self.tail_addr = addr;
|
||||||
|
}
|
||||||
|
pub fn get_tail_addr(& self) -> u16{
|
||||||
|
self.tail_addr
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Struct for RX Packet
|
||||||
|
/// TODO: Generalise MAC addresses
|
||||||
|
pub struct RxPacket {
|
||||||
|
rsv: Rsv,
|
||||||
|
frame: [u8; RAW_FRAME_LENGTH_MAX],
|
||||||
|
frame_length: usize
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RxPacket {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
RxPacket {
|
||||||
|
rsv: Rsv::new(),
|
||||||
|
frame: [0; RAW_FRAME_LENGTH_MAX],
|
||||||
|
frame_length: 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn write_to_rsv(&mut self, raw_rsv: &[u8]) {
|
||||||
|
self.rsv.write_to_rsv(raw_rsv);
|
||||||
|
}
|
||||||
|
pub fn read_raw_rsv(&self) -> &[u8] {
|
||||||
|
self.rsv.read_raw_rsv()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn update_frame_length(&mut self) {
|
||||||
|
self.rsv.set_frame_length();
|
||||||
|
self.frame_length = self.rsv.get_frame_length() as usize;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_frame_length(&self) -> usize {
|
||||||
|
self.frame_length
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn write_to_frame(&mut self, raw_frame: &[u8]) {
|
||||||
|
for i in 0..self.frame_length {
|
||||||
|
self.frame[i] = raw_frame[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_frame_byte(&self, i: usize) -> u8 {
|
||||||
|
self.frame[i]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Struct for Receive Status Vector
|
||||||
|
/// See: Table 9-1, ENC424J600 Data Sheet
|
||||||
|
struct Rsv {
|
||||||
|
raw_rsv: [u8; RSV_LENGTH],
|
||||||
|
// TODO: Add more definitions
|
||||||
|
frame_length: u16
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Rsv {
|
||||||
|
fn new() -> Self {
|
||||||
|
Rsv {
|
||||||
|
raw_rsv: [0; RSV_LENGTH],
|
||||||
|
frame_length: 0_u16
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_to_rsv(&mut self, raw_rsv: &[u8]) {
|
||||||
|
for i in 0..RSV_LENGTH {
|
||||||
|
self.raw_rsv[i] = raw_rsv[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn read_raw_rsv(&self) -> &[u8] {
|
||||||
|
&self.raw_rsv
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_frame_length(&mut self) {
|
||||||
|
self.frame_length = (self.raw_rsv[0] as u16) | ((self.raw_rsv[1] as u16) << 8);
|
||||||
|
}
|
||||||
|
fn get_frame_length(&self) -> u16 {
|
||||||
|
self.frame_length
|
||||||
|
}
|
||||||
|
}
|
121
src/spi.rs
121
src/spi.rs
|
@ -7,6 +7,10 @@ use stm32f4xx_hal::{
|
||||||
time::MegaHertz,
|
time::MegaHertz,
|
||||||
spi,
|
spi,
|
||||||
};
|
};
|
||||||
|
///
|
||||||
|
/// FIXME: Move the following to somewhere else
|
||||||
|
///
|
||||||
|
use crate::rx;
|
||||||
|
|
||||||
/// Must use SPI mode cpol=0, cpha=0
|
/// Must use SPI mode cpol=0, cpha=0
|
||||||
pub const SPI_MODE: spi::Mode = spi::Mode {
|
pub const SPI_MODE: spi::Mode = spi::Mode {
|
||||||
|
@ -17,8 +21,29 @@ pub const SPI_MODE: spi::Mode = spi::Mode {
|
||||||
pub const SPI_CLOCK: MegaHertz = MegaHertz(14);
|
pub const SPI_CLOCK: MegaHertz = MegaHertz(14);
|
||||||
|
|
||||||
/// SPI Opcodes
|
/// SPI Opcodes
|
||||||
const RCRU: u8 = 0b00100000;
|
const RCRU: u8 = 0b0010_0000;
|
||||||
const WCRU: u8 = 0b00100010;
|
const WCRU: u8 = 0b0010_0010;
|
||||||
|
const ERXDATA: u8 = 0b0010_1100; // Treated as 8-bit opcode followed by data
|
||||||
|
|
||||||
|
/// SPI Register Mapping
|
||||||
|
/// Note: PSP interface use different address mapping
|
||||||
|
// SPI Init Reset Registers
|
||||||
|
pub const EUDAST: u8 = 0x16; // 16-bit data
|
||||||
|
pub const ESTAT: u8 = 0x1a; // 16-bit data
|
||||||
|
pub const ECON2: u8 = 0x6e; // 16-bit data
|
||||||
|
//
|
||||||
|
pub const ERXFCON: u8 = 0x34; // 16-bit data
|
||||||
|
//
|
||||||
|
pub const MAADR3: u8 = 0x60; // 16-bit data
|
||||||
|
pub const MAADR2: u8 = 0x62; // 16-bit data
|
||||||
|
pub const MAADR1: u8 = 0x64; // 16-bit data
|
||||||
|
// RX Registers
|
||||||
|
pub const ERXRDPT: u8 = 0x8a; // 16-bit data
|
||||||
|
pub const ERXST: u8 = 0x04; // 16-bit data
|
||||||
|
pub const ERXTAIL: u8 = 0x06; // 16-bit data
|
||||||
|
pub const EIR: u8 = 0x1c; // 16-bit data
|
||||||
|
pub const ECON1: u8 = 0x1e; // 16-bit data
|
||||||
|
pub const MAMXFL: u8 = 0x4a; // 16-bit data
|
||||||
|
|
||||||
/// Struct for SPI I/O interface on ENC424J600
|
/// Struct for SPI I/O interface on ENC424J600
|
||||||
/// Note: stm32f4xx_hal::spi's pins include: SCK, MISO, MOSI
|
/// Note: stm32f4xx_hal::spi's pins include: SCK, MISO, MOSI
|
||||||
|
@ -28,42 +53,60 @@ pub struct SpiPort<SPI: Transfer<u8>,
|
||||||
nss: NSS,
|
nss: NSS,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl <SPI: Transfer<u8, Error = E>,
|
pub enum SpiPortError {
|
||||||
NSS: OutputPin,
|
TransferError
|
||||||
E: fmt::Debug> SpiPort<SPI, NSS> {
|
}
|
||||||
|
|
||||||
|
impl <SPI: Transfer<u8>,
|
||||||
|
NSS: OutputPin> SpiPort<SPI, NSS> {
|
||||||
// TODO: return as Result()
|
// TODO: return as Result()
|
||||||
pub fn new(spi: SPI, mut nss: NSS) -> Self {
|
pub fn new(spi: SPI, mut nss: NSS) -> Self {
|
||||||
nss.set_high();
|
nss.set_high();
|
||||||
|
|
||||||
SpiPort {
|
SpiPort {
|
||||||
spi,
|
spi,
|
||||||
nss
|
nss
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn read_reg_8b(&mut self, addr: u8) -> Result<u8, SPI::Error> {
|
pub fn read_reg_8b(&mut self, addr: u8) -> Result<u8, SpiPortError> {
|
||||||
// Using RCRU instruction to read using unbanked (full) address
|
// Using RCRU instruction to read using unbanked (full) address
|
||||||
let mut r_data = self.transfer(RCRU, addr, 0)?;
|
let mut r_data = self.rw_addr_u8(RCRU, addr, 0)?;
|
||||||
Ok(r_data)
|
Ok(r_data)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn read_reg_16b(&mut self, lo_addr: u8) -> Result<u16, SPI::Error> {
|
pub fn read_reg_16b(&mut self, lo_addr: u8) -> Result<u16, SpiPortError> {
|
||||||
let mut r_data_lo = self.read_reg_8b(lo_addr)?;
|
let mut r_data_lo = self.read_reg_8b(lo_addr)?;
|
||||||
let mut r_data_hi = self.read_reg_8b(lo_addr + 1)?;
|
let mut r_data_hi = self.read_reg_8b(lo_addr + 1)?;
|
||||||
// Combine top and bottom 8-bit to return 16-bit
|
// Combine top and bottom 8-bit to return 16-bit
|
||||||
Ok(((r_data_hi as u16) << 8) | r_data_lo as u16)
|
Ok(((r_data_hi as u16) << 8) | r_data_lo as u16)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn write_reg_8b(&mut self, addr: u8, data: u8) -> Result<u8, SPI::Error> {
|
// Currently requires manual slicing (buf[1:]) for the data read back
|
||||||
// TODO: addr should be separated from w_data
|
pub fn read_rxdat<'a>(&mut self, buf: &'a mut [u8], data_length: u32)
|
||||||
// Using WCRU instruction to write using unbanked (full) address
|
-> Result<u8, SpiPortError> {
|
||||||
self.transfer(WCRU, addr, data)?;
|
let r_valid = self.r_n(buf, ERXDATA, data_length)?;
|
||||||
Ok(0x01) // TODO: should not be just 0x01
|
Ok(r_valid)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn transfer(&mut self, opcode: u8, addr: u8, data: u8)
|
pub fn write_reg_8b(&mut self, addr: u8, data: u8) -> Result<(), SpiPortError> {
|
||||||
-> Result<u8, SPI::Error> {
|
// TODO: addr should be separated from w_data
|
||||||
// TODO: Currently assumes read/write data is only 1-byte
|
// Using WCRU instruction to write using unbanked (full) address
|
||||||
|
self.rw_addr_u8(WCRU, addr, data)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn write_reg_16b(&mut self, lo_addr: u8, data: u16) -> Result<(), SpiPortError> {
|
||||||
|
self.write_reg_8b(lo_addr, (data & 0xff) as u8)?;
|
||||||
|
self.write_reg_8b(lo_addr + 1, ((data & 0xff00) >> 8) as u8)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Generalise transfer functions
|
||||||
|
// TODO: (Make data read/write as reference to array)
|
||||||
|
// Currently requires 1-byte addr, read/write data is only 1-byte
|
||||||
|
fn rw_addr_u8(&mut self, opcode: u8, addr: u8, data: u8)
|
||||||
|
-> Result<u8, SpiPortError> {
|
||||||
// Enable chip select
|
// Enable chip select
|
||||||
self.nss.set_low();
|
self.nss.set_low();
|
||||||
// Start writing to SLAVE
|
// Start writing to SLAVE
|
||||||
|
@ -72,13 +115,45 @@ impl <SPI: Transfer<u8, Error = E>,
|
||||||
buf[0] = opcode;
|
buf[0] = opcode;
|
||||||
buf[1] = addr;
|
buf[1] = addr;
|
||||||
buf[2] = data;
|
buf[2] = data;
|
||||||
let result = self.spi.transfer(&mut buf);
|
match self.spi.transfer(&mut buf) {
|
||||||
// Disable chip select
|
Ok(_) => {
|
||||||
self.nss.set_high();
|
// Disable chip select
|
||||||
|
self.nss.set_high();
|
||||||
|
Ok(buf[2])
|
||||||
|
},
|
||||||
|
// TODO: Maybe too naive?
|
||||||
|
Err(e) => {
|
||||||
|
// Disable chip select
|
||||||
|
self.nss.set_high();
|
||||||
|
Err(SpiPortError::TransferError)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
match result {
|
// TODO: Generalise transfer functions
|
||||||
Ok(_) => Ok(buf[2]),
|
// Currently does NOT accept addr, read data is N-byte long
|
||||||
Err(e) => Err(e),
|
// Returns a reference to the data returned
|
||||||
|
// Note: buf must be at least (data_length + 1)-byte long
|
||||||
|
// TODO: Check and raise error for array size < (data_length + 1)
|
||||||
|
fn r_n<'a>(&mut self, buf: &'a mut [u8], opcode: u8, data_length: u32)
|
||||||
|
-> Result<u8, SpiPortError> {
|
||||||
|
// Enable chip select
|
||||||
|
self.nss.set_low();
|
||||||
|
// Start writing to SLAVE
|
||||||
|
buf[0] = opcode;
|
||||||
|
match self.spi.transfer(buf) {
|
||||||
|
// TODO: Now returns a boolean, maybe use Option<u8> later on?
|
||||||
|
Ok(_) => {
|
||||||
|
// Disable chip select
|
||||||
|
self.nss.set_high();
|
||||||
|
Ok(1)
|
||||||
|
},
|
||||||
|
// TODO: Maybe too naive?
|
||||||
|
Err(e) => {
|
||||||
|
// Disable chip select
|
||||||
|
self.nss.set_high();
|
||||||
|
Err(SpiPortError::TransferError)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Reference in New Issue