1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
extern crate linux_embedded_hal;
pub use linux_embedded_hal::sysfs_gpio::{Direction, Error as PinError};
pub use linux_embedded_hal::{
    spidev, spidev::SpiModeFlags, Delay, SpidevDevice, SysfsPin as Pindev,
};

use super::*;

pub struct LinuxDriver;

impl LinuxDriver {
    /// Load an SPI device using the provided configuration
    pub fn new(path: &str, spi: &SpiConfig, pins: &PinConfig) -> Result<HalInst, HalError> {
        let mut flags = match spi.mode {
            0 => SpiModeFlags::SPI_MODE_0,
            1 => SpiModeFlags::SPI_MODE_1,
            2 => SpiModeFlags::SPI_MODE_2,
            3 => SpiModeFlags::SPI_MODE_3,
            _ => return Err(HalError::InvalidSpiMode),
        };

        flags |= SpiModeFlags::SPI_NO_CS;

        debug!(
            "Conecting to spi: {} at {} baud with mode: {:?}",
            path, spi.baud, flags
        );

        let spi = load_spi(path, spi.baud, flags)?;

        let pins = Self::load_pins(pins)?;

        Ok(HalInst {
            base: HalBase::None,
            spi: HalSpi::Linux(spi),
            pins,
        })
    }

    /// Load pins using the provided config
    fn load_pins(pins: &PinConfig) -> Result<HalPins, HalError> {
        let chip_select = load_pin(pins.chip_select, Direction::Out)?;

        let reset = load_pin(pins.reset, Direction::Out)?;

        let busy = match pins.busy {
            Some(p) => HalInputPin::Linux(load_pin(p, Direction::In)?),
            None => HalInputPin::None,
        };

        let ready = match pins.ready {
            Some(p) => HalInputPin::Linux(load_pin(p, Direction::In)?),
            None => HalInputPin::None,
        };

        let led0 = match pins.led0 {
            Some(p) => HalOutputPin::Linux(load_pin(p, Direction::Out)?),
            None => HalOutputPin::None,
        };

        let led1 = match pins.led1 {
            Some(p) => HalOutputPin::Linux(load_pin(p, Direction::Out)?),
            None => HalOutputPin::None,
        };

        let pins = HalPins {
            cs: HalOutputPin::Linux(chip_select),
            reset: HalOutputPin::Linux(reset),
            busy,
            ready,
            led0,
            led1,
        };

        Ok(pins)
    }
}

/// Load an SPI device using the provided configuration
fn load_spi(path: &str, baud: u32, mode: spidev::SpiModeFlags) -> Result<SpidevDevice, HalError> {
    debug!(
        "Conecting to spi: {} at {} baud with mode: {:?}",
        path, baud, mode
    );

    let mut spi = SpidevDevice::open(path)?;

    let mut config = spidev::SpidevOptions::new();
    config.mode(SpiModeFlags::SPI_MODE_0 | SpiModeFlags::SPI_NO_CS);
    config.max_speed_hz(baud);
    spi.configure(&config)?;

    Ok(spi)
}

/// Load a Pin using the provided configuration
fn load_pin(index: u64, direction: Direction) -> Result<Pindev, HalError> {
    debug!(
        "Connecting to pin: {} with direction: {:?}",
        index, direction
    );

    let p = Pindev::new(index);
    p.export()?;
    p.set_direction(direction)?;

    Ok(p)
}