-
Notifications
You must be signed in to change notification settings - Fork 3
SNS - GPIO #34
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
SNS - GPIO #34
Changes from all commits
258b43c
b83ffff
da7c525
4f5bab5
e997646
591b446
0df80f8
cbd231e
fe3cc1f
a4fb12d
f473200
e61a462
a63d7e4
e1c0bb3
9578ad5
f742e05
659e22f
07869e0
ad58a84
ed16431
032ea62
ab70cca
646a4e1
b53e8c0
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| 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() | ||
| { | ||
| // 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; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this can't return |
||
| } | ||
|
|
||
| HardwareGpio::HardwareGpio(core::ILogger &log) : log_(log) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
| { | ||
| // 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); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
| 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); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
| 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 | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -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
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. these become 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: | ||
|
|
@@ -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 | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
optional with no
nulloptreturn, so can just have return typecore::DigitalSignal