Browse Source

gpio: source code locations of locks / unlocks

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
wiki-test
Maxim Prokhorov 1 year ago
parent
commit
5f6df82110
4 changed files with 99 additions and 31 deletions
  1. +36
    -19
      code/espurna/gpio.cpp
  2. +41
    -12
      code/espurna/gpio.h
  3. +3
    -0
      code/espurna/libs/BasePin.h
  4. +19
    -0
      code/espurna/types.h

+ 36
- 19
code/espurna/gpio.cpp View File

@ -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
@ -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
@ -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),
@ -108,7 +105,6 @@ inline Data data() {
}};
}
} // namespace
} // namespace efuse
namespace rtc {
@ -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;
@ -188,7 +182,6 @@ void gpio16_mode(int8_t mode) {
});
}
} // namespace
} // namespace rtc
namespace pin {
@ -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 :
@ -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;
@ -433,7 +425,6 @@ static constexpr Enumeration<GpioType> GpioTypeOptions[] PROGMEM {
{GpioType::None, None},
};
} // namespace
} // namespace options
} // namespace settings
@ -562,7 +553,6 @@ private:
#if WEB_SUPPORT
namespace web {
namespace {
void onVisible(JsonObject& root) {
JsonObject& config = root.createNestedObject(F("gpioConfig"));
@ -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)
@ -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 {
@ -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
@ -867,4 +884,4 @@ void resetPins() {
}
}
}
} // extern "C"

+ 41
- 12
code/espurna/gpio.h View File

@ -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 {
@ -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) {
@ -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) {


+ 3
- 0
code/espurna/libs/BasePin.h View File

@ -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 {


+ 19
- 0
code/espurna/types.h View File

@ -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;


Loading…
Cancel
Save