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
//volatile_store is the same as `*ptr = value;` (except that the optimiser won't touch it)
#![allow(dead_code)]
#![feature(core_intrinsics)]
extern crate mmap;
extern crate core;

use std::fs::OpenOptions;
use std::os::unix::fs::OpenOptionsExt;
use mmap::{MemoryMap, MapOption};
use std::os::unix::prelude::AsRawFd;
use self::core::intrinsics::{volatile_load, volatile_store};

const BCM2708_PERI_BASE: usize = 0x3F000000;
const GPIO_BASE: usize = BCM2708_PERI_BASE + 0x200000;
const O_SYNC: u32 = 1052672;
const MAP_SHARED: i32 = 0x0001;
const BLOCK_SIZE: usize = 4 * 1024;

pub struct Cylus {
    addr_p: *const usize,
    mem_fd: ::std::fs::File,
    map: ::mmap::MemoryMap,
    addr: *mut usize,
    pin: u32 
}

impl Cylus {
    pub fn new(x: u32) -> Cylus {
        let mem_file = OpenOptions::new()
            .read(true)
            .write(true)
            .mode(O_SYNC)
            .open("/dev/mem")
            .expect("unable to open /dev/mem, Are you root?");

        let map_opts = &[
            MapOption::MapNonStandardFlags(MAP_SHARED),
            MapOption::MapReadable,
            MapOption::MapWritable,
            MapOption::MapOffset(GPIO_BASE),
            MapOption::MapFd(mem_file.as_raw_fd())
        ];

        let mmap = match MemoryMap::new(BLOCK_SIZE, map_opts) {
            Ok(mmap) => mmap,
            Err(e) => panic!("ERR: {}", e)
        };
      
        let result = Cylus {
            addr_p: &GPIO_BASE,
            mem_fd: mem_file,
            addr: mmap.data() as *mut usize,  //switch order to avoid error of moved value `mmap`
            map: mmap,
            pin: x
        };
        //setting mode for GPIO
        unsafe {
            let addr = result.addr.offset((x/10) as isize);
            let mut a = volatile_load(addr); 
            a &= !(7 << (((x) % 10) * 3));
            a |= 1 << (((x) % 10) * 3);
            volatile_store(addr, a);
        }
        result
    }
    pub fn set_alt(&self, a: usize) {
        let y = self.pin as isize;
        unsafe {
            let addr = self.addr.offset(y/10);
            let mut k = volatile_load(addr);
            k |= match a {
                a if a <= 3 => a + 4,
                4 => 3,
                _ => 2,
            } << ((y % 10) * 3);
            volatile_store(addr, k); 
       }
    }

    pub fn high(&self) { 
        let val = 1usize << self.pin;
        unsafe { volatile_store(self.addr.offset(7), val); }
    }
    pub fn low(&self) { 
        let val = 1usize << self.pin;
        unsafe { volatile_store(self.addr.offset(10), val); }
    }
    pub fn read(&self) -> usize {
        unsafe {
            let addr = self.addr.offset(13);
            let mut k = volatile_load(addr);
            k &= 1 << self.pin as isize;
            volatile_store(addr, k);
            return k
        }
    }
}

impl Drop for Cylus {
    fn drop(&mut self) {
        println!("Unmapped Peripheral {:?}", self.map.data())
    }
}