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
109
110
111
112
113
114
115
116
117
118
119
120
121
use crate::mmio;
use bit_field::BitField;

const BANK_0_MODE: u8 = 0x00;
const BANK_0_DATA: u8 = 0x01;
const BANK_0_INTR_EN: u8 = 0x02;
const BANK_0_INTR_MODE: u8 = 0x03;
const BANK_0_INTR_TRIG: u8 = 0x04;
const BANK_0_INTR_ACK: u8 = 0x05;

#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum PinMode {
    Input,
    Output,
}

#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum IntrMode {
    RisingEdge,
    FallingEdge,
}

#[repr(transparent)]
#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
pub struct IoPin(pub u32);

impl IoPin {
    pub fn get_mode(&self) -> PinMode {
        assert!(self.0 < 32);
        let is_input = unsafe {
            mmio::read(BANK_0_MODE)
        }.get_bit(self.0 as _);
        if is_input {
            PinMode::Input
        } else {
            PinMode::Output
        }
    }

    pub fn set_mode(&self, mode: PinMode) {
        assert!(self.0 < 32);
        let mut bank = unsafe {
            mmio::read(BANK_0_MODE)
        };
        bank.set_bit(self.0 as _, match mode {
            PinMode::Input => true,
            PinMode::Output => false,
        });
        unsafe {
            mmio::write(BANK_0_MODE, bank);
        }
    }

    pub fn read(&self) -> bool {
        assert!(self.0 < 32);
        unsafe {
            mmio::read(BANK_0_DATA)
        }.get_bit(self.0 as _)
    }

    pub fn write(&self, value: bool) {
        assert!(self.0 < 32);
        let mut bank = unsafe {
            mmio::read(BANK_0_DATA)
        };
        bank.set_bit(self.0 as _, value);
        unsafe {
            mmio::write(BANK_0_DATA, bank);
        }
    }

    pub fn enable_interrupt(&self, mode: IntrMode) {
        let mut bank = unsafe {
            mmio::read(BANK_0_INTR_MODE)
        };
        let mode_bit = match mode {
            IntrMode::RisingEdge => false,
            IntrMode::FallingEdge => true,
        };
        bank.set_bit(self.0 as _, mode_bit);
        unsafe {
            mmio::write(BANK_0_INTR_MODE, bank);
        }

        let mut bank = unsafe {
            mmio::read(BANK_0_INTR_EN)
        };
        bank.set_bit(self.0 as _, true);
        unsafe {
            mmio::write(BANK_0_INTR_EN, bank);
        }
    }

    pub fn disable_interrupt(&self) {
        let mut bank = unsafe {
            mmio::read(BANK_0_INTR_EN)
        };
        bank.set_bit(self.0 as _, false);
        unsafe {
            mmio::write(BANK_0_INTR_EN, bank);
        }
    }

    pub fn ack_interrupt(&self) {
        unsafe {
            mmio::write(BANK_0_INTR_ACK, (1 << self.0));
        }
    }
}

pub fn first_interrupt_pin() -> Option<IoPin> {
    let bank = unsafe {
        mmio::read(BANK_0_INTR_TRIG)
    };
    for i in 0..32u32 {
        if bank.get_bit(i as usize) {
            return Some(IoPin(i));
        }
    }
    None
}