| Index: pkg/raspberry_pi/lib/raspberry_pi.dart
|
| diff --git a/pkg/raspberry_pi/lib/raspberry_pi.dart b/pkg/raspberry_pi/lib/raspberry_pi.dart
|
| index d0a8df0fdfe1734c3b51483b878361a8b2771fdc..9734327377fe91aaa21173298b66b207abe22677 100644
|
| --- a/pkg/raspberry_pi/lib/raspberry_pi.dart
|
| +++ b/pkg/raspberry_pi/lib/raspberry_pi.dart
|
| @@ -5,9 +5,15 @@
|
| /// Library for the basic Raspberry Pi features.
|
| library raspberry_pi;
|
|
|
| +import 'dart:fletch.ffi';
|
| import 'dart:typed_data';
|
|
|
| import 'package:file/file.dart';
|
| +import 'package:gpio/gpio.dart' as gpio;
|
| +
|
| +// Foreign functions used.
|
| +final ForeignFunction _open = ForeignLibrary.main.lookup('open');
|
| +final ForeignFunction _mmap = ForeignLibrary.main.lookup('mmap');
|
|
|
| /// Possible modes of the on-board LEDs
|
| enum OnboardLEDMode {
|
| @@ -23,6 +29,34 @@ enum OnboardLEDMode {
|
|
|
| /// Class for accessing Raspberry Pi features.
|
| ///
|
| +/// Use GPIO through the memory mapped interface:
|
| +///
|
| +/// ```
|
| +/// import 'package:raspberry_pi/raspberry_pi.dart';
|
| +/// import 'package:gpio/gpio.dart';
|
| +///
|
| +/// main() {
|
| +/// RaspberryPi pi = new RaspberryPi();
|
| +/// GPIO gpio = pi.memoryMappedGPIO; // Selecting memory mapped GPIO.
|
| +/// gpio.setMode(4, Mode.output);
|
| +/// gpio.setPin(4, true);
|
| +/// }
|
| +/// ```
|
| +///
|
| +/// Use GPIO through the sysfs interface:
|
| +///
|
| +/// ```
|
| +/// import 'package:raspberry_pi/raspberry_pi.dart';
|
| +/// import 'package:gpio/gpio.dart';
|
| +///
|
| +/// main() {
|
| +/// RaspberryPi pi = new RaspberryPi();
|
| +/// GPIO gpio = pi.sysfsGPIO; // Selecting sysfs GPIO.
|
| +/// gpio.setMode(4, Mode.output);
|
| +/// gpio.setPin(4, true);
|
| +/// }
|
| +/// ```
|
| +///
|
| /// Change the activity LED to heartbeat mode:
|
| ///
|
| /// ```
|
| @@ -49,10 +83,176 @@ enum OnboardLEDMode {
|
| /// }
|
| /// ```
|
| class RaspberryPi {
|
| + /// The number of GPIO pins on the Raspberry Pi 2.
|
| + static const int gpioPins = 54;
|
| + var _memoryMappedGPIO;
|
| + var _sysfsGPIO;
|
| +
|
| /// Provide access to the on-board LEDs.
|
| final OnBoardLEDs leds = new OnBoardLEDs._();
|
|
|
| RaspberryPi();
|
| +
|
| + get memoryMappedGPIO {
|
| + if (_memoryMappedGPIO == null) {
|
| + _memoryMappedGPIO = new PiMemoryMappedGPIO();
|
| + }
|
| + return _memoryMappedGPIO;
|
| + }
|
| +
|
| + get sysfsGPIO {
|
| + if (_sysfsGPIO == null) {
|
| + _sysfsGPIO = new gpio.SysfsGPIO(gpioPins);
|
| + }
|
| + return _sysfsGPIO;
|
| +
|
| + }
|
| +}
|
| +
|
| +/// Pull-up/down resistor state.
|
| +enum PullUpDown {
|
| + floating,
|
| + pullDown,
|
| + pullUp,
|
| +}
|
| +
|
| +/// Provide GPIO access on Raspberry Pi using direct memory access.
|
| +///
|
| +/// The following code shows how to turn on GPIO pin 4:
|
| +///
|
| +/// ```
|
| +/// PiMemoryMappedGPIO gpio = new PiMemoryMappedGPIO();
|
| +/// gpio.setMode(4, Mode.output);
|
| +/// gpio.setPin(4, true));
|
| +/// ```
|
| +///
|
| +/// The following code shows how to read GPIO pin 17:
|
| +///
|
| +/// ```
|
| +/// PiMemoryMappedGPIO gpio = new PiMemoryMappedGPIO();
|
| +/// gpio.setMode(17, Mode.input);
|
| +/// print(gpio.getPin(17));
|
| +/// ```
|
| +class PiMemoryMappedGPIO extends gpio.GPIOBase {
|
| + // See datasheet:
|
| + // https://www.raspberrypi.org/wp-content/uploads/2012/02/BCM2835-ARM-Peripherals.pdf
|
| +
|
| + // Raspberry Pi model 1 (A/A+/B)
|
| + // BCM2708 / BCM 2835
|
| +
|
| + // Raspberry Pi model 2
|
| + // BCM2709 / BCM 2836
|
| +
|
| + // Peripherals base address.
|
| + static const int _baseAddressModel1 = 0x20000000;
|
| + static const int _baseAddressModel2 = 0x3F000000;
|
| + static const int _baseAddressGPIOOffset = 0x00200000;
|
| +
|
| + // Size of the peripherals area.
|
| + static const int _blockSize = 4096;
|
| +
|
| + // Offsets (in bytes) to various areas.
|
| + static const int _gpioFunctionSelectBase = 0 << 2;
|
| + static const int _gpioOutputSetBase = 7 << 2;
|
| + static const int _gpioOutputClearBase = 10 << 2;
|
| + static const int _gpioPinLevelBase = 13 << 2;
|
| + static const int _gpioPullUpPullDown = 37 << 2;
|
| + static const int _gpioPullUpPullDownClockBase = 38 << 2;
|
| +
|
| + // All alternative functions are mapped to `Mode.other` for now.
|
| + static const _functionToMode =
|
| + [gpio.Mode.input, gpio.Mode.output,
|
| + gpio.Mode.other, gpio.Mode.other,
|
| + gpio.Mode.other, gpio.Mode.other, gpio.Mode.other];
|
| +
|
| + int _fd; // File descriptor for /dev/mem.
|
| + ForeignPointer _addr;
|
| + ForeignMemory _mem;
|
| +
|
| + PiMemoryMappedGPIO(): super(RaspberryPi.gpioPins) {
|
| + // From /usr/include/x86_64-linux-gnu/bits/fcntl-linux.h.
|
| + const int oRDWR = 02; // O_RDWR
|
| + // Found from C code 'printf("%x\n", O_SYNC);'.
|
| + const int oSync = 0x101000; // O_SYNC
|
| +
|
| + // Open /dev/mem to get to the physical memory.
|
| + var devMem = new ForeignMemory.fromStringAsUTF8('/dev/mem');
|
| + _fd = _open.icall$2Retry(devMem, oRDWR | oSync);
|
| + if (_fd < 0) {
|
| + throw new gpio.GPIOException("Failed to open '/dev/mem'", Foreign.errno);
|
| + }
|
| + devMem.free();
|
| +
|
| + // From /usr/include/x86_64-linux-gnu/bits/mman-linux.h.
|
| + const int protRead = 0x1; // PROT_READ.
|
| + const int protWrite = 0x2; // PROT_WRITE.
|
| + const int mapShared = 0x01; // MAP_SHARED.
|
| +
|
| + _addr = _mmap.pcall$6(0, _blockSize, protRead | protWrite, mapShared,
|
| + _fd, _baseAddressModel2 + _baseAddressGPIOOffset);
|
| + _mem = new ForeignMemory.fromAddress(_addr.address, _blockSize);
|
| + }
|
| +
|
| + void setMode(int pin, gpio.Mode mode) {
|
| + checkPinRange(pin);
|
| + // GPIO function select registers each have 3 bits for 10 pins.
|
| + var fsel = (pin ~/ 10);
|
| + var shift = (pin % 10) * 3;
|
| + var function = mode == gpio.Mode.input ? 0 : 1;
|
| + var offset = _gpioFunctionSelectBase + (fsel << 2);
|
| + var value = _mem.getUint32(offset);
|
| + value = (value & ~(0x07 << shift)) | function << shift;
|
| + _mem.setUint32(offset, value);
|
| + }
|
| +
|
| + gpio.Mode getMode(int pin) {
|
| + checkPinRange(pin);
|
| + // GPIO function select registers each have 3 bits for 10 pins.
|
| + var fsel = (pin ~/ 10);
|
| + var shift = (pin % 10) * 3;
|
| + var offset = _gpioFunctionSelectBase + (fsel << 2);
|
| + var function = (_mem.getUint32(offset) >> shift) & 0x07;
|
| + return _functionToMode[function];
|
| + }
|
| +
|
| + void setPin(int pin, bool value) {
|
| + checkPinRange(pin);
|
| + // GPIO output set and output clear registers each have 1 bits for 32 pins.
|
| + int register = pin ~/ 32;
|
| + int shift = pin % 32;
|
| + if (value) {
|
| + _mem.setUint32(_gpioOutputSetBase + (register << 2), 1 << shift);
|
| + } else {
|
| + _mem.setUint32(_gpioOutputClearBase + (register << 2), 1 << shift);
|
| + }
|
| + }
|
| +
|
| + bool getPin(int pin) {
|
| + checkPinRange(pin);
|
| + // GPIO pin level registers each have 1 bits for 32 pins.
|
| + int register = pin ~/ 32;
|
| + int shift = pin % 32;
|
| + return
|
| + (_mem.getUint32(_gpioPinLevelBase + (register << 2)) & 1 << shift) != 0;
|
| + }
|
| +
|
| + /// Set the floating/pull-up/pull-down state of [pin].
|
| + ///
|
| + /// Use `0` for floating, `1` for pull down and `2` for pull-up.
|
| + void setPullUpDown(int pin, PullUpDown pullUpDown) {
|
| + checkPinRange(pin);
|
| + int register = pin ~/ 32;
|
| + int shift = pin % 32;
|
| + // First set the value in the update register.
|
| + _mem.setUint32(_gpioPullUpPullDown, pullUpDown.index);
|
| + sleep(1); // Datasheet says: "Wait for 150 cycles".
|
| + // Then set the clock bit.
|
| + _mem.setUint32(_gpioPullUpPullDownClockBase + (register << 2), 1 << shift);
|
| + sleep(1); // Datasheet says: "Wait for 150 cycles".
|
| + // Clear value and clock bit.
|
| + _mem.setUint32(_gpioPullUpPullDown, 0);
|
| + _mem.setUint32(_gpioPullUpPullDownClockBase + (register << 2), 0);
|
| + }
|
| }
|
|
|
| // The on-board LEDs.
|
|
|