Skip to content
Merged
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
1 change: 1 addition & 0 deletions Docs/Commands.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ These are commands used to configure the system settings and can only be sent fr
| `F12` — OTA Check / Apply | `F12` or `F12:apply=1` | Trigger an OTA firmware check against the latest GitHub release. Without params (or `apply=0`) checks only and returns current status. With `apply=1` downloads and applies the update if one is available (or queues apply if a check is already in progress). Response params: `v=<current>` current firmware version, `av=<available>` available version tag (empty if none found yet), `s=<state>` OTA state string. **PCH only** — requires `OTA_AUTO_UPDATE`, ESP32 and WiFi in client mode. |
| `F13` — OTA Status | `F13` | Query current OTA state without triggering a check. Response params: `v=<current>` current firmware version, `av=<available>` available version tag, `s=<state>` OTA state string (`idle`, `checking`, `available`, `downloading`, `rebooting`, `failed`, `uptodate`), `auto=<0\|1>` whether auto-apply is enabled. **PCH only** — requires `OTA_AUTO_UPDATE`, ESP32 and WiFi in client mode. |
| `F14` — PinGuard Mode | `F14` or `F14:a=true` or `F14:a=false;b=false` | Read or write the persistent PinGuard mode flags stored in `SystemHeader::pinGuardFlags`. **Params:** `a=<bool>` — AllowAdvisory: when `true`, advisory (strapping/UART) pins are permitted. `b=<bool>` — Bypass: when `true`, all PinGuard checks are skipped (no validation at all). If both `a` and `b` are `true`, Bypass takes precedence and the system returns `Safe` immediately. Changes are persisted immediately via `saveHeader()` and take effect at runtime without reboot. **Response:** `a=<0\|1>` current AllowAdvisory state, `b=<0\|1>` current Bypass state. No params = read-only. |
| `F15` — Pin Usage | `F15` | Returns a list of all GPIO pins currently assigned in configuration. Pins set to `0xFF` (disabled / not fitted) are omitted. **Serial response:** `v=pin1,pin2,...` (single frame). **WiFi response:** JSON object with a `pins` array. No params. |


**OTA behaviour (F12 / F13):**
Expand Down
28 changes: 18 additions & 10 deletions PowerControlHub/PinGuard.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@

#include <stdint.h>
#include "SystemDefinitions.h"
#include "SystemFunctions.h"

// ─── Pin Use ─────────────────────────────────────────────────────────────────
// Describes the intended use of a pin. Input-only GPIO are fine for Input,
Expand All @@ -65,28 +66,29 @@ enum class PinUse : uint8_t
// ─── Pin Category ─────────────────────────────────────────────────────────────
enum class PinCategory : uint8_t
{
Safe = 0, // unrestricted
Safe = 0, // unrestricted
Advisory = 1, // risky; behaviour governed by PinGuardMode
Hard = 2, // always rejected for the given use
Hard = 2, // always rejected for the given use
};

// ─── Validation Result ────────────────────────────────────────────────────────
enum class PinGuardResult : uint8_t
{
Safe = 0, // pin is fine for the requested use
Safe = 0, // pin is fine for the requested use
AdvisoryBlocked = 1, // advisory pin blocked (mode does not permit advisory)
HardBlocked = 2, // hard-blocked — must not be used for this purpose
Disabled = 3, // pin == PinDisabled (0xFF) — treated as not fitted
HardBlocked = 2, // hard-blocked — must not be used for this purpose
Disabled = 3, // pin == PinDisabled (0xFF) — treated as not fitted
InUse = 4, // pin is already in use by another configured function
};

// ─── PinGuard Mode ────────────────────────────────────────────────────────────
// Persistent system setting stored in SystemHeader::pinGuardFlags.
// Configured via the F14 command.
namespace PinGuardMode
{
constexpr uint8_t None = 0x00; // strict — advisory pins are blocked
constexpr uint8_t None = 0x00; // strict — advisory pins are blocked
constexpr uint8_t AllowAdvisory = 0x01; // advisory pins are permitted
constexpr uint8_t Bypass = 0x02; // skip all checks — always returns Safe
constexpr uint8_t Bypass = 0x02; // skip all checks — always returns Safe
}

// ─── Internal helpers — not for direct use ───────────────────────────────────
Expand All @@ -113,8 +115,8 @@ namespace PinGuardInternal

struct PinTableEntry
{
uint8_t gpio;
PinCategory category;
uint8_t gpio;
PinCategory category;
};

#if defined(CONFIG_IDF_TARGET_ESP32S3)
Expand Down Expand Up @@ -224,7 +226,7 @@ class PinGuard
*/
static bool isBlocked(PinGuardResult result)
{
return result == PinGuardResult::HardBlocked || result == PinGuardResult::AdvisoryBlocked;
return result == PinGuardResult::HardBlocked || result == PinGuardResult::AdvisoryBlocked || result == PinGuardResult::InUse;
}

/**
Expand All @@ -244,6 +246,10 @@ class PinGuard
if (pin == PinDisabled)
return PinGuardResult::Disabled;

// Check whether this pin is already assigned elsewhere in the configuration
if (SystemFunctions::pinInUse(pin))
return PinGuardResult::InUse;

// Bypass: skip all checks
if (_mode & PinGuardMode::Bypass)
return PinGuardResult::Safe;
Expand Down Expand Up @@ -309,6 +315,8 @@ class PinGuard
return F("advisory (strapping/UART pin)");
case PinGuardResult::Disabled:
return F("disabled (255)");
case PinGuardResult::InUse:
return F("in use (already configured)");
default:
return F("safe");
}
Expand Down
Loading
Loading