Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
111 changes: 100 additions & 11 deletions lib/io/hardware_gpio.cpp
Original file line number Diff line number Diff line change
@@ -1,36 +1,125 @@
#include "hardware_gpio.hpp"

#include <fcntl.h>
#include <unistd.h>

#include <sys/mman.h>

namespace hyped::io {

std::optional<core::DigitalSignal> HardwareGpioReader::read()

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

optional with no nullopt return, so can just have return type core::DigitalSignal

{
// TODOLater: implement
throw -1;
// pinMap just 0000.... with 1 flipped in pin number.
// So AND with readAddr to extract the specific pin
const std::uint8_t out = 0;
if (*gpio_readAddr & pin_map) {
return core::DigitalSignal::kHigh;
} else {
return core::DigitalSignal::kLow;
}
}

core::Result HardwareGpioWriter::write(const core::DigitalSignal state)
{
// TODOLater: implement
throw -1;
// Set and Clear are seperate registers.
if (state == core::DigitalSignal::kHigh) {
*gpio_setAddr = pin_map;
} else {
*gpio_clearAddr = pin_map;
}
return core::Result::kSuccess;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this can't return kFailure so no reason for returning a result

}

HardwareGpio::HardwareGpio(core::ILogger &log) : log_(log)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

logger_(logger) for consistency across repo

{
// TODOLater: implement
}

std::optional<std::shared_ptr<IGpioReader>> HardwareGpio::getReader(const std::uint8_t pin)
{
// TODOLater: implement
log_.log(core::LogLevel::kFatal, "GPIO reader not implemented");
return std::nullopt;
// What happens if all shared pointers are removed and this is called?
// Map solves this, GPIO will always hold one pointer so it dosen't get destroyed.
if (initialized_readers_.count(pin) != 0) {
std::shared_ptr<IGpioReader> reader = initialized_readers_[pin];
return reader;
}

// There are 4 Bank Numbers, 0 1 2 3
// Integer divison to get bank number
const std::uint32_t bank = pin / 32;
// Modulo by 32 gets us the ID of the pin relative to the bank
const std::uint32_t pin_id = pin % 32;
// Gpio addresses contain 32 pins, so we use pinmap to specify specific pin.
const std::uint32_t pin_map = (1 << pin_id);
if (bank > 3) {
log_.log(core::LogLevel::kFatal, "invalid pin number");
return std::nullopt;
}

// Get memory address from bank address
const off_t pin_address = bank_addresses[bank];
volatile void *gpio_addr;
volatile std::uint32_t *gpio_read;

// /dev/mem and mmap is related to making the registry available as a virtual memory address.
int fd = open("/dev/mem", O_RDWR);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

const?

if (fd < 0) {
log_.log(core::LogLevel::kFatal, "opening /dev/mem failed");
return std::nullopt;
}

// Get the memory mapping of the GPIO pin.
gpio_addr = mmap(0, pin_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, pin_address);
if (gpio_addr == MAP_FAILED) {
log_.log(core::LogLevel::kFatal, "mmap failed");
return std::nullopt;
}
// Type conversion for address adding from void
const std::uint64_t base = reinterpret_cast<std::uint64_t>(gpio_addr);
// pinRead is the hardware specified address for reading.
gpio_read = reinterpret_cast<volatile std::uint32_t *>(base + pin_read);

// Keep track of intialized pins
initialized_readers_[pin]
= std::shared_ptr<HardwareGpioReader>(new HardwareGpioReader(pin_map, gpio_read));
std::shared_ptr<IGpioReader> reader = initialized_readers_[pin];
return reader;
}

std::optional<std::shared_ptr<IGpioWriter>> HardwareGpio::getWriter(const std::uint8_t pin)
{
// TODOLater: implement
log_.log(core::LogLevel::kFatal, "GPIO writer not implemented");
return std::nullopt;
// Check if pin is already initialized
if (initialized_writers_.count(pin) != 0) {
std::shared_ptr<IGpioWriter> writer = initialized_writers_[pin];
return writer;
}

const std::uint32_t bank = pin / 32;
const std::uint32_t pin_id = pin % 32;
const std::uint32_t pin_map = (1 << pin_id);

const off_t pin_address = bank_addresses[bank];
volatile void *gpio_addr;
volatile std::uint32_t *gpio_set;
volatile std::uint32_t *gpio_clear;

int fd = open("/dev/mem", O_RDWR);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

const?

if (fd < 0) { return std::nullopt; }

gpio_addr = mmap(0, pin_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, pin_address);
if (gpio_addr == MAP_FAILED) { return std::nullopt; }

const std::uint64_t base = reinterpret_cast<std::uint64_t>(gpio_addr);

// pinset is the hardware specified address for reading.
gpio_set = reinterpret_cast<volatile std::uint32_t *>(base + pin_set);

// pinclear is the hardware specified address for reading.
gpio_clear = reinterpret_cast<volatile std::uint32_t *>(base + pin_clear);

initialized_writers_[pin]
= std::shared_ptr<HardwareGpioWriter>(new HardwareGpioWriter(pin_map, gpio_set, gpio_clear));
std::shared_ptr<IGpioWriter> writer = initialized_writers_[pin];
return writer;
}

} // namespace hyped::io
43 changes: 41 additions & 2 deletions lib/io/hardware_gpio.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,31 +2,63 @@

#include "gpio.hpp"

#include <unordered_map>

#include <core/types.hpp>

namespace hyped::io {

// GPIO hardware specified addresses and sizes for read, clear, set, size, etc.
static constexpr std::uint32_t pin_size = 0x1000;
static constexpr std::uint32_t pin_read = 0x138;
static constexpr std::uint32_t pin_clear = 0x190;
static constexpr std::uint32_t pin_set = 0x194;
Comment on lines +12 to +15

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

these become private static constexprs following the style guide discussion

unless they need to be accessed outside of methods


class HardwareGpioReader : public IGpioReader {
public:
/**
* @brief Read a high or low from the GPIO pin.
*/
virtual std::optional<core::DigitalSignal> read();

private:
HardwareGpioReader();
HardwareGpioReader(const std::uint8_t pin, volatile std::uint32_t *read)
: pin_map(pin),
gpio_readAddr(read){};

const std::uint8_t pin_map;
volatile std::uint32_t *gpio_readAddr;

friend class HardwareGpio;
};

class HardwareGpioWriter : public IGpioWriter {
public:
/**
* @brief Writes a high or low to the GPIO pin.
* @param state The digital signal to write to the pin.
*/
virtual core::Result write(const core::DigitalSignal state);

private:
HardwareGpioWriter(const std::uint8_t pin);
HardwareGpioWriter(const std::uint8_t pin,
volatile std::uint32_t *set,
volatile std::uint32_t *clear)
: pin_map(pin),
gpio_setAddr(set),
gpio_clearAddr(clear){};

const std::uint8_t pin_map;
volatile std::uint32_t *gpio_setAddr;
volatile std::uint32_t *gpio_clearAddr;

friend class HardwareGpio;
};

/**
* Hardware GPIO interface, requires physical GPIO pins to be present. This should only
* be instantiated at the top level and then provided to users through the IGpio interface.
* Ensure inputted pins are defined as pin = 32*X + Y (GPIOX_Y)
*/
class HardwareGpio {
public:
Expand All @@ -37,6 +69,13 @@ class HardwareGpio {

private:
core::ILogger &log_;
// Bank Addresses are header base addresses.
// Page 211-213 Figure 6-7/8 P8 Header Pins Beaglebone Bible

const std::array<off_t, 4> bank_addresses = {0x44e07000, 0x4804c000, 0x481ac000, 0x481ae000};
std::unordered_map<std::uint8_t, std::shared_ptr<IGpioWriter>> initialized_writers_;
std::unordered_map<std::uint8_t, std::shared_ptr<IGpioReader>> initialized_readers_;
// Also hardware specified addresses and sizes for read, clear, set, size, etc.
};

} // namespace hyped::io
Empty file modified scripts/hooks/pre-commit
100755 → 100644
Empty file.
Empty file modified scripts/setup
100755 → 100644
Empty file.