Skip to content

Commit

Permalink
gpio: source code locations of locks / unlocks
Browse files Browse the repository at this point in the history
sorted in a reverse order of when they were called
refactor gpio module itself, so our `namespace { ... }` stays consistent

using GCC `__builtin_{LINE,FILE,FUNC}()`
https://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html#index-_005f_005fbuiltin_005fLINE
https://en.cppreference.com/w/cpp/utility/source_location
  • Loading branch information
mcspr committed Sep 8, 2022
1 parent 59686a8 commit 5f6df82
Show file tree
Hide file tree
Showing 4 changed files with 99 additions and 31 deletions.
55 changes: 36 additions & 19 deletions code/espurna/gpio.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,10 @@ Copyright (C) 2017-2019 by Xose Pérez <xose dot perez at gmail dot com>
#include "ws.h"

namespace espurna {
namespace peripherals {
namespace {

namespace peripherals {

// TODO: `struct Register { ... }` with additional size params?
// e.g. GPIO IN / OUT register is techically u16, and we don't detect writing past the allowed 'mask'
// something with direct field access may be useful, too; like handling function-select for io mux
Expand All @@ -47,8 +48,6 @@ void reg_apply(uintptr_t address, T&& func) {
reg_write(address, func(reg_read(address)));
}

} // namespace

// At the time of writing this...
// Current version of Arduino Core uses NONOS, plus a set of "AVR-Style" macros
// - https://github.com/esp8266/Arduino/blob/3.0.2/cores/esp8266/esp8266_peri.h
Expand Down Expand Up @@ -97,8 +96,6 @@ static constexpr uintptr_t Data3 { AddressBase + 0xc };

using Data = std::array<uint32_t, 4>;

namespace {

inline Data data() {
return {{
reg_read(Data0),
Expand All @@ -108,7 +105,6 @@ inline Data data() {
}};
}

} // namespace
} // namespace efuse

namespace rtc {
Expand All @@ -128,8 +124,6 @@ static constexpr uint32_t FunctionSelectMask { (1 << 6) | (1 << 1) | 1 };
// no other pin allows pulldown
static constexpr uint32_t Pulldown { (1 << 3) };

namespace {

inline bool gpio16_get() __attribute__((always_inline));
bool gpio16_get() {
return reg_read(GpioInput) & 0b1;
Expand Down Expand Up @@ -188,7 +182,6 @@ void gpio16_mode(int8_t mode) {
});
}

} // namespace
} // namespace rtc

namespace pin {
Expand Down Expand Up @@ -244,8 +237,6 @@ static constexpr uint32_t WakeupEnabled { (1 << 10) }; // ^ should set this bit
static constexpr uint32_t InterruptMask { (1 << 9) | (1 << 8) | (1 << 7) };
static constexpr uint32_t ControlMask { WakeupEnabled | InterruptMask | Driver | Source };

namespace {

// ref. PERIPHS_IO_MUX_...
constexpr uintptr_t ioMuxOffset(uint8_t pin) {
return (pin == 0) ? 0x34 :
Expand Down Expand Up @@ -407,14 +398,15 @@ void mode(uint8_t pin, uint8_t mode) {
}
}

} // namespace
} // namespace pin
} // namespace peripherals
} // namespace

namespace gpio {
namespace {

namespace settings {
namespace options {
namespace {

using espurna::settings::options::Enumeration;

Expand All @@ -433,7 +425,6 @@ static constexpr Enumeration<GpioType> GpioTypeOptions[] PROGMEM {
{GpioType::None, None},
};

} // namespace
} // namespace options
} // namespace settings

Expand Down Expand Up @@ -562,7 +553,6 @@ class Hardware : public GpioBase {

#if WEB_SUPPORT
namespace web {
namespace {

void onVisible(JsonObject& root) {
JsonObject& config = root.createNestedObject(F("gpioConfig"));
Expand Down Expand Up @@ -598,13 +588,35 @@ void setup() {
.onVisible(onVisible);
}

} // namespace
} // namespace web
#endif

namespace origin {
namespace internal {

std::forward_list<Origin> origins;

} // namespace internal

void add(Origin origin) {
internal::origins.emplace_front(origin);
}

} // namespace origin

#if TERMINAL_SUPPORT
namespace terminal {
namespace {

void gpio_list_origins(::terminal::CommandContext&& ctx) {
for (const auto& origin : origin::internal::origins) {
ctx.output.printf_P(PSTR("%c %s GPIO%hhu\t%d:%s:%s\n"),
origin.lock ? '*' : ' ',
origin.base, origin.pin,
origin.location.line,
origin.location.file,
origin.location.func);
}
}

void gpio_read_write(::terminal::CommandContext&& ctx) {
const int pin = (ctx.argv.size() >= 2)
Expand Down Expand Up @@ -712,15 +724,16 @@ void reg_write(::terminal::CommandContext&& ctx) {
}

void setup() {
terminalRegisterCommand(F("GPIO.LOCKS"), gpio_list_origins);
terminalRegisterCommand(F("GPIO"), gpio_read_write);
terminalRegisterCommand(F("REG.READ"), reg_read);
terminalRegisterCommand(F("REG.WRITE"), reg_write);
}

}
} // namespace terminal
#endif

} // namespace
} // namespace gpio

namespace settings {
Expand Down Expand Up @@ -811,6 +824,10 @@ void gpioSetup() {
#endif
}

void gpioLockOrigin(espurna::gpio::Origin origin) {
espurna::gpio::origin::add(origin);
}

extern "C" {

// All of these have __attribute__((weak)) in the Core files. While the original intent
Expand Down Expand Up @@ -867,4 +884,4 @@ void resetPins() {
}
}

}
} // extern "C"
53 changes: 41 additions & 12 deletions code/espurna/gpio.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,17 @@ enum class GpioType : int {
};

namespace espurna {
namespace gpio {

struct Origin {
const char* base;
uint8_t pin;
bool lock;
SourceLocation location;
};

} // namespace gpio

namespace settings {
namespace internal {

Expand All @@ -45,6 +56,7 @@ GpioBase* gpioBase(GpioType);
BasePinPtr gpioRegister(GpioBase& base, unsigned char gpio);
BasePinPtr gpioRegister(unsigned char gpio);

void gpioLockOrigin(espurna::gpio::Origin);
void gpioSetup();

inline size_t gpioPins(const GpioBase& base) {
Expand All @@ -63,30 +75,47 @@ inline bool gpioValid(unsigned char gpio) {
return gpioValid(hardwareGpio(), gpio);
}

inline bool gpioLock(GpioBase& base, unsigned char gpio, bool value) {
if (base.valid(gpio)) {
bool old = base.lock(gpio);
base.lock(gpio, value);
inline bool gpioLock(GpioBase& base, unsigned char pin, bool value,
espurna::SourceLocation source_location = espurna::make_source_location())
{
if (base.valid(pin)) {
gpioLockOrigin(espurna::gpio::Origin{
.base = base.id(),
.pin = pin,
.lock = value,
.location = source_location
});

bool old = base.lock(pin);
base.lock(pin, value);
return (value != old);
}

return false;
}

inline bool gpioLock(GpioBase& base, unsigned char gpio) {
return gpioLock(base, gpio, true);
inline bool gpioLock(GpioBase& base, unsigned char gpio,
espurna::SourceLocation source_location = espurna::make_source_location())
{
return gpioLock(base, gpio, true, source_location);
}

inline bool gpioLock(unsigned char gpio) {
return gpioLock(hardwareGpio(), gpio);
inline bool gpioLock(unsigned char gpio,
espurna::SourceLocation source_location = espurna::make_source_location())
{
return gpioLock(hardwareGpio(), gpio, source_location);
}

inline bool gpioUnlock(GpioBase& base, unsigned char gpio) {
return gpioLock(base, gpio, false);
inline bool gpioUnlock(GpioBase& base, unsigned char gpio,
espurna::SourceLocation source_location = espurna::make_source_location())
{
return gpioLock(base, gpio, false, source_location);
}

inline bool gpioUnlock(unsigned char gpio) {
return gpioUnlock(hardwareGpio(), gpio);
inline bool gpioUnlock(unsigned char gpio,
espurna::SourceLocation source_location = espurna::make_source_location())
{
return gpioUnlock(hardwareGpio(), gpio, source_location);
}

inline bool gpioLocked(const GpioBase& base, unsigned char gpio) {
Expand Down
3 changes: 3 additions & 0 deletions code/espurna/libs/BasePin.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ Copyright (C) 2020 by Maxim Prokhorov <prokhorov dot max at outlook dot com>
#include <cstdint>
#include <memory>

#if __cplusplus > 201103L
inline
#endif
constexpr unsigned char GPIO_NONE { 0x99 };

class BasePin {
Expand Down
19 changes: 19 additions & 0 deletions code/espurna/types.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,25 @@ extern "C" int memcmp_P(const void*, const void*, size_t);

namespace espurna {

// aka `std::source_location`
struct SourceLocation {
int line;
const char* file;
const char* func;
};

inline SourceLocation make_source_location(
int line = __builtin_LINE(),
const char* file = __builtin_FILE(),
const char* func = __builtin_FUNCTION())
{
return SourceLocation{
.line = line,
.file = file,
.func = func
};
}

// disallow re-locking, tracking external `bool`
struct ReentryLock {
ReentryLock() = delete;
Expand Down

0 comments on commit 5f6df82

Please sign in to comment.