Migrate team and blob storage SPI gates

This commit is contained in:
liu weikai
2026-07-12 02:04:53 +08:00
parent d5a0be646e
commit a453bb372b
6 changed files with 270 additions and 94 deletions
@@ -0,0 +1,55 @@
#pragma once
#include "sys/bus_access_scope.h"
#include "sys/clock.h"
#include "sys/runtime_async.h"
#include <cstdint>
namespace platform::esp::arduino_common::storage
{
class PersistenceBusGate final
{
public:
PersistenceBusGate(sys::runtime::IBusArbiter& arbiter,
sys::runtime::BusAccessPolicy policy,
uint32_t wait_ms,
uint32_t resource,
uint32_t command_id,
uint32_t origin)
: scope_(arbiter, makeRequest(policy, wait_ms, resource, command_id, origin))
{
}
bool locked() const
{
return scope_.acquired();
}
sys::runtime::BusAcquireStatus status() const
{
return scope_.status();
}
private:
static sys::runtime::BusAcquireRequest makeRequest(
sys::runtime::BusAccessPolicy policy,
uint32_t wait_ms,
uint32_t resource,
uint32_t command_id,
uint32_t origin)
{
sys::runtime::BusAcquireRequest request{};
request.resource = resource;
request.policy = policy;
request.command_id = command_id;
request.origin = origin;
request.deadline_ms = sys::millis_now() + wait_ms;
return request;
}
sys::runtime::ScopedBusAccessToken scope_;
};
} // namespace platform::esp::arduino_common::storage
@@ -18,13 +18,14 @@
#include "platform/esp/arduino_common/device_identity.h"
#include "platform/esp/arduino_common/gps/gps_service.h"
#include "platform/esp/arduino_common/gps/track_recorder.h"
#include "platform/esp/arduino_common/storage/persistence_bus_gate.h"
#include "platform/esp/arduino_common/storage/sd_card_runtime.h"
#include "platform/esp/arduino_common/team/crypto/team_crypto.h"
#include "platform/esp/arduino_common/team/event/team_app_data_event_bus_bridge.h"
#include "platform/esp/arduino_common/team/event/team_event_bus_sink.h"
#include "platform/esp/arduino_common/team/event/team_pairing_event_bus_sink.h"
#include "platform/esp/arduino_common/team_platform_bundle.h"
#include "platform/esp/common/shared_spi_lock.h"
#include "platform/esp/common/shared_spi_bus_arbiter.h"
#include "platform/ui/team_ui_store_runtime.h"
#include "team/usecase/team_controller.h"
#include "team/usecase/team_track_sampler.h"
@@ -38,11 +39,31 @@
namespace
{
constexpr TickType_t kMeshPeerDirectorySdWait = pdMS_TO_TICKS(50);
constexpr uint32_t kMeshPeerDirectorySdWaitMs = 50;
constexpr const char* kMeshPeerDirectoryDir = "/mesh";
constexpr const char* kMeshPeerDirectoryPath = "/mesh/peers.bin";
constexpr const char* kMeshPeerDirectoryTempPath = "/mesh/peers.tmp";
constexpr std::size_t kMeshPeerDirectoryMaxBlobBytes = 768U * 1024U;
constexpr uint32_t kMeshPeerDirectoryBusResource = 5;
constexpr uint32_t kMeshPeerDirectoryBusOwnerId = 0x4D504452u; // 'MPDR'
::platform::esp::common::SharedSpiBusAdapter s_mesh_peer_directory_load_adapter(
"mesh_peer_dir_load",
kMeshPeerDirectoryBusOwnerId);
::platform::esp::common::SharedSpiBusAdapter s_mesh_peer_directory_save_adapter(
"mesh_peer_dir_save",
kMeshPeerDirectoryBusOwnerId);
::platform::esp::common::FixedSharedSpiBusPolicyStrategy s_mesh_peer_directory_bus_policy(
kMeshPeerDirectorySdWaitMs,
kMeshPeerDirectorySdWaitMs,
kMeshPeerDirectorySdWaitMs,
kMeshPeerDirectorySdWaitMs);
sys::runtime::StorageBusArbiter s_mesh_peer_directory_load_arbiter(
s_mesh_peer_directory_load_adapter,
s_mesh_peer_directory_bus_policy);
sys::runtime::StorageBusArbiter s_mesh_peer_directory_save_arbiter(
s_mesh_peer_directory_save_adapter,
s_mesh_peer_directory_bus_policy);
gps::GpsReceiverInitConfig make_receiver_init_config(const app::AppConfig& config)
{
@@ -166,10 +187,14 @@ class EspSdMeshPeerDirectoryBlobStore final
return chat::MeshPeerDirectoryBlobLoadResult::Missing;
}
::platform::esp::common::SharedSpiLockGuard spi_guard(
kMeshPeerDirectorySdWait,
"mesh_peer_dir_load");
if (!spi_guard.locked())
::platform::esp::arduino_common::storage::PersistenceBusGate bus_gate(
s_mesh_peer_directory_load_arbiter,
sys::runtime::BusAccessPolicy::BackgroundWorkerBounded,
kMeshPeerDirectorySdWaitMs,
kMeshPeerDirectoryBusResource,
kMeshPeerDirectoryBusOwnerId + 1,
kMeshPeerDirectoryBusOwnerId);
if (!bus_gate.locked())
{
return chat::MeshPeerDirectoryBlobLoadResult::Unavailable;
}
@@ -205,10 +230,14 @@ class EspSdMeshPeerDirectoryBlobStore final
return false;
}
::platform::esp::common::SharedSpiLockGuard spi_guard(
kMeshPeerDirectorySdWait,
"mesh_peer_dir_save");
if (!spi_guard.locked())
::platform::esp::arduino_common::storage::PersistenceBusGate bus_gate(
s_mesh_peer_directory_save_arbiter,
sys::runtime::BusAccessPolicy::DurableCommit,
kMeshPeerDirectorySdWaitMs,
kMeshPeerDirectoryBusResource,
kMeshPeerDirectoryBusOwnerId + 2,
kMeshPeerDirectoryBusOwnerId);
if (!bus_gate.locked())
{
return false;
}
@@ -5,8 +5,9 @@
#include "platform/esp/arduino_common/chat/infra/contact_store.h"
#include "../internal/blob_store_io.h"
#include "platform/esp/arduino_common/storage/persistence_bus_gate.h"
#include "platform/esp/arduino_common/storage/sd_card_runtime.h"
#include "platform/esp/common/shared_spi_lock.h"
#include "platform/esp/common/shared_spi_bus_arbiter.h"
#include <Arduino.h>
#include <esp_heap_caps.h>
@@ -48,8 +49,23 @@ void ContactStore::operator delete(void* ptr, std::size_t) noexcept
namespace
{
constexpr TickType_t kSdLoadWait = pdMS_TO_TICKS(250);
constexpr TickType_t kSdPersistWait = pdMS_TO_TICKS(100);
constexpr uint32_t kSdLoadWaitMs = 250;
constexpr uint32_t kSdPersistWaitMs = 100;
constexpr uint32_t kContactStoreBusResource = 5;
constexpr uint32_t kContactStoreBusOwnerId = 0x434F4E54u; // 'CONT'
constexpr const char* kContactStoreBusOwner = "contact_store_sd";
::platform::esp::common::SharedSpiBusAdapter s_contact_store_bus_adapter(
kContactStoreBusOwner,
kContactStoreBusOwnerId);
::platform::esp::common::FixedSharedSpiBusPolicyStrategy s_contact_store_bus_policy(
kSdLoadWaitMs,
kSdLoadWaitMs,
kSdLoadWaitMs,
kSdLoadWaitMs);
sys::runtime::StorageBusArbiter s_contact_store_bus_arbiter(
s_contact_store_bus_adapter,
s_contact_store_bus_policy);
} // namespace
ContactStore::ContactStore()
@@ -177,8 +193,14 @@ ContactStore::LoadResult ContactStore::loadFromSD(std::vector<uint8_t>& out) con
out.clear();
return LoadResult::MissingOrInvalid;
}
::platform::esp::common::SharedSpiLockGuard spi_guard(kSdLoadWait, "contact_store_sd");
if (!spi_guard.locked())
::platform::esp::arduino_common::storage::PersistenceBusGate bus_gate(
s_contact_store_bus_arbiter,
sys::runtime::BusAccessPolicy::BackgroundWorkerBounded,
kSdLoadWaitMs,
kContactStoreBusResource,
kContactStoreBusOwnerId + 1,
kContactStoreBusOwnerId);
if (!bus_gate.locked())
{
out.clear();
return LoadResult::Busy;
@@ -192,8 +214,14 @@ ContactStore::LoadResult ContactStore::loadFromSD(std::vector<uint8_t>& out) con
bool ContactStore::saveToSD(const uint8_t* data, size_t len) const
{
::platform::esp::common::SharedSpiLockGuard spi_guard(kSdPersistWait, "contact_store_sd");
if (!spi_guard.locked())
::platform::esp::arduino_common::storage::PersistenceBusGate bus_gate(
s_contact_store_bus_arbiter,
sys::runtime::BusAccessPolicy::DurableCommit,
kSdPersistWaitMs,
kContactStoreBusResource,
kContactStoreBusOwnerId + 2,
kContactStoreBusOwnerId);
if (!bus_gate.locked())
{
return false;
}
@@ -6,8 +6,9 @@
#include "platform/esp/arduino_common/chat/infra/meshtastic/node_store.h"
#include "../../internal/blob_store_io.h"
#include "chat/infra/node_store_blob_format.h"
#include "platform/esp/arduino_common/storage/persistence_bus_gate.h"
#include "platform/esp/arduino_common/storage/sd_card_runtime.h"
#include "platform/esp/common/shared_spi_lock.h"
#include "platform/esp/common/shared_spi_bus_arbiter.h"
#include <Arduino.h>
#include <algorithm>
@@ -57,11 +58,25 @@ namespace
constexpr TickType_t kAsyncSaveMutexWait = pdMS_TO_TICKS(20);
constexpr TickType_t kAsyncSavePollInterval = pdMS_TO_TICKS(10);
constexpr TickType_t kAsyncSaveRetryDelay = pdMS_TO_TICKS(500);
constexpr TickType_t kSdLoadWait = pdMS_TO_TICKS(250);
constexpr TickType_t kSdPersistWait = pdMS_TO_TICKS(100);
constexpr uint32_t kSdLoadWaitMs = 250;
constexpr uint32_t kSdPersistWaitMs = 100;
constexpr uint32_t kAsyncSaveTaskStackBytes = 4 * 1024;
constexpr UBaseType_t kAsyncSaveTaskPriority = 2;
constexpr size_t kSdReadChunkBytes = 256;
constexpr uint32_t kNodeStoreBusResource = 5;
constexpr uint32_t kNodeStoreBusOwnerId = 0x4E4F4445u; // 'NODE'
constexpr const char* kNodeStoreBusOwner = "node_store_sd";
::platform::esp::common::SharedSpiBusAdapter s_node_store_bus_adapter(
kNodeStoreBusOwner,
kNodeStoreBusOwnerId);
::platform::esp::common::FixedSharedSpiBusPolicyStrategy s_node_store_bus_policy(
kSdLoadWaitMs,
kSdLoadWaitMs,
kSdLoadWaitMs,
kSdLoadWaitMs);
sys::runtime::StorageBusArbiter s_node_store_bus_arbiter(s_node_store_bus_adapter,
s_node_store_bus_policy);
void logNvsStats(const char* tag, const char* ns)
{
@@ -258,8 +273,14 @@ void NodeStore::clearBlob()
if (::platform::esp::arduino_common::storage::sd_card_ready())
{
::platform::esp::common::SharedSpiLockGuard spi_guard(kSdPersistWait, "node_store_sd");
if (spi_guard.locked() &&
::platform::esp::arduino_common::storage::PersistenceBusGate bus_gate(
s_node_store_bus_arbiter,
sys::runtime::BusAccessPolicy::DurableCommit,
kSdPersistWaitMs,
kNodeStoreBusResource,
kNodeStoreBusOwnerId + 3,
kNodeStoreBusOwnerId);
if (bus_gate.locked() &&
::platform::esp::arduino_common::storage::sd_exists(kPersistNodesFile))
{
::platform::esp::arduino_common::storage::sd_remove(kPersistNodesFile);
@@ -366,8 +387,14 @@ NodeStore::LoadResult NodeStore::loadFromSd(std::vector<uint8_t>& out) const
return LoadResult::MissingOrInvalid;
}
::platform::esp::common::SharedSpiLockGuard spi_guard(kSdLoadWait, "node_store_sd");
if (!spi_guard.locked())
::platform::esp::arduino_common::storage::PersistenceBusGate bus_gate(
s_node_store_bus_arbiter,
sys::runtime::BusAccessPolicy::BackgroundWorkerBounded,
kSdLoadWaitMs,
kNodeStoreBusResource,
kNodeStoreBusOwnerId + 1,
kNodeStoreBusOwnerId);
if (!bus_gate.locked())
{
NODE_STORE_LOG("[NodeStore] load SD skipped: spi busy\n");
return LoadResult::Busy;
@@ -547,8 +574,14 @@ bool NodeStore::saveToSd(const uint8_t* data, size_t len) const
return false;
}
::platform::esp::common::SharedSpiLockGuard spi_guard(kSdPersistWait, "node_store_sd");
if (!spi_guard.locked())
::platform::esp::arduino_common::storage::PersistenceBusGate bus_gate(
s_node_store_bus_arbiter,
sys::runtime::BusAccessPolicy::DurableCommit,
kSdPersistWaitMs,
kNodeStoreBusResource,
kNodeStoreBusOwnerId + 2,
kNodeStoreBusOwnerId);
if (!bus_gate.locked())
{
NODE_STORE_LOG("[NodeStore] save SD skipped: spi busy len=%u\n",
static_cast<unsigned>(len));
@@ -6,8 +6,9 @@
#include "platform/ui/team_ui_store_runtime.h"
#include "ui/team_persistence/team_ui_snapshot_codec.h"
#include "platform/esp/arduino_common/storage/persistence_bus_gate.h"
#include "platform/esp/arduino_common/storage/sd_card_runtime.h"
#include "platform/esp/common/shared_spi_lock.h"
#include "platform/esp/common/shared_spi_bus_arbiter.h"
#include "sys/clock.h"
#include <algorithm>
#include <cctype>
@@ -68,13 +69,83 @@ constexpr uint32_t kPosHeaderSize = 24;
constexpr uint32_t kPosMinIntervalSec = 15;
constexpr uint32_t kPosMaxIntervalSec = 30;
constexpr float kPosMinDistanceM = 20.0f;
constexpr TickType_t kTeamStoreLoadWait = pdMS_TO_TICKS(60);
constexpr TickType_t kTeamStoreReadWait = pdMS_TO_TICKS(20);
constexpr TickType_t kTeamStoreWriteWait = pdMS_TO_TICKS(20);
constexpr uint32_t kTeamStoreLoadWaitMs = 60;
constexpr uint32_t kTeamStoreReadWaitMs = 20;
constexpr uint32_t kTeamStoreWriteWaitMs = 20;
constexpr uint32_t kTeamStoreBusResource = 4;
constexpr uint32_t kTeamStoreBusOwnerId = 0x5445414Du; // 'TEAM'
constexpr const char* kTeamStoreBusOwner = "team_store_sd";
constexpr size_t kChatlogMaxBytes = 256 * 1024;
constexpr uint32_t kMinValidEpoch = 1577836800U; // 2020-01-01
::platform::esp::common::SharedSpiBusAdapter s_team_store_bus_adapter(
kTeamStoreBusOwner,
kTeamStoreBusOwnerId);
::platform::esp::common::FixedSharedSpiBusPolicyStrategy s_team_store_bus_policy(
kTeamStoreLoadWaitMs,
kTeamStoreLoadWaitMs,
kTeamStoreLoadWaitMs,
kTeamStoreLoadWaitMs);
sys::runtime::StorageBusArbiter s_team_store_bus_arbiter(s_team_store_bus_adapter,
s_team_store_bus_policy);
enum class TeamStoreBusAccess : uint8_t
{
Load = 1,
Read,
Write,
};
class TeamStoreBusGate final
{
public:
explicit TeamStoreBusGate(TeamStoreBusAccess access)
: gate_(s_team_store_bus_arbiter,
policyFor(access),
waitMsFor(access),
kTeamStoreBusResource,
commandIdFor(access),
kTeamStoreBusOwnerId)
{
}
bool locked() const
{
return gate_.locked();
}
private:
static sys::runtime::BusAccessPolicy policyFor(TeamStoreBusAccess access)
{
return access == TeamStoreBusAccess::Write
? sys::runtime::BusAccessPolicy::DurableCommit
: sys::runtime::BusAccessPolicy::BackgroundWorkerBounded;
}
static uint32_t waitMsFor(TeamStoreBusAccess access)
{
switch (access)
{
case TeamStoreBusAccess::Load:
return kTeamStoreLoadWaitMs;
case TeamStoreBusAccess::Read:
return kTeamStoreReadWaitMs;
case TeamStoreBusAccess::Write:
return kTeamStoreWriteWaitMs;
default:
return 0;
}
}
static uint32_t commandIdFor(TeamStoreBusAccess access)
{
return kTeamStoreBusOwnerId + static_cast<uint32_t>(access);
}
::platform::esp::arduino_common::storage::PersistenceBusGate gate_;
};
uint32_t now_secs()
{
return sys::uptime_seconds_now();
@@ -914,8 +985,8 @@ class TeamUiSnapshotStorePersisted : public ITeamUiSnapshotStore
return false;
}
::platform::esp::common::SharedSpiLockGuard spi_guard(kTeamStoreLoadWait);
if (!spi_guard.locked())
TeamStoreBusGate bus_gate(TeamStoreBusAccess::Load);
if (!bus_gate.locked())
{
return false;
}
@@ -973,8 +1044,8 @@ class TeamUiSnapshotStorePersisted : public ITeamUiSnapshotStore
}
if (!in.has_team_id || !in.in_team)
{
::platform::esp::common::SharedSpiLockGuard spi_guard(kTeamStoreWriteWait);
if (spi_guard.locked())
TeamStoreBusGate bus_gate(TeamStoreBusAccess::Write);
if (bus_gate.locked())
{
clear_current_dir();
}
@@ -996,8 +1067,8 @@ class TeamUiSnapshotStorePersisted : public ITeamUiSnapshotStore
return;
}
::platform::esp::common::SharedSpiLockGuard spi_guard(kTeamStoreWriteWait);
if (!spi_guard.locked())
TeamStoreBusGate bus_gate(TeamStoreBusAccess::Write);
if (!bus_gate.locked())
{
return;
}
@@ -1025,8 +1096,8 @@ class TeamUiSnapshotStorePersisted : public ITeamUiSnapshotStore
void clear() override
{
s_has_cached_snapshot = false;
::platform::esp::common::SharedSpiLockGuard spi_guard(kTeamStoreWriteWait);
if (spi_guard.locked())
TeamStoreBusGate bus_gate(TeamStoreBusAccess::Write);
if (bus_gate.locked())
{
clear_current_dir();
}
@@ -1145,8 +1216,8 @@ bool team_ui_append_key_event(const TeamId& team_id,
const uint8_t* payload,
size_t len)
{
::platform::esp::common::SharedSpiLockGuard spi_guard(kTeamStoreWriteWait);
if (!spi_guard.locked())
TeamStoreBusGate bus_gate(TeamStoreBusAccess::Write);
if (!bus_gate.locked())
{
return false;
}
@@ -1166,8 +1237,8 @@ bool team_ui_posring_append(const TeamId& team_id,
return false;
}
::platform::esp::common::SharedSpiLockGuard spi_guard(kTeamStoreWriteWait);
if (!spi_guard.locked())
TeamStoreBusGate bus_gate(TeamStoreBusAccess::Write);
if (!bus_gate.locked())
{
return false;
}
@@ -1232,8 +1303,8 @@ bool team_ui_posring_load_latest(const TeamId& team_id,
{
return false;
}
::platform::esp::common::SharedSpiLockGuard spi_guard(kTeamStoreReadWait);
if (!spi_guard.locked())
TeamStoreBusGate bus_gate(TeamStoreBusAccess::Read);
if (!bus_gate.locked())
{
return false;
}
@@ -1346,8 +1417,8 @@ bool TeamUiSdChatLogStore::appendStructured(const TeamId& team_id,
team::proto::TeamChatType type,
const std::vector<uint8_t>& payload)
{
::platform::esp::common::SharedSpiLockGuard spi_guard(kTeamStoreWriteWait);
if (!spi_guard.locked())
TeamStoreBusGate bus_gate(TeamStoreBusAccess::Write);
if (!bus_gate.locked())
{
return false;
}
@@ -1429,8 +1500,8 @@ bool TeamUiSdChatLogStore::loadRecent(const TeamId& team_id,
{
return false;
}
::platform::esp::common::SharedSpiLockGuard spi_guard(kTeamStoreReadWait);
if (!spi_guard.locked())
TeamStoreBusGate bus_gate(TeamStoreBusAccess::Read);
if (!bus_gate.locked())
{
return false;
}
@@ -1571,8 +1642,8 @@ bool team_ui_save_keys_now(const TeamId& team_id,
{
return false;
}
::platform::esp::common::SharedSpiLockGuard spi_guard(kTeamStoreWriteWait);
if (!spi_guard.locked())
TeamStoreBusGate bus_gate(TeamStoreBusAccess::Write);
if (!bus_gate.locked())
{
return false;
}
@@ -1598,8 +1669,8 @@ bool team_ui_get_member_track_path(const TeamId& team_id,
{
return false;
}
::platform::esp::common::SharedSpiLockGuard spi_guard(kTeamStoreWriteWait);
if (!spi_guard.locked())
TeamStoreBusGate bus_gate(TeamStoreBusAccess::Write);
if (!bus_gate.locked())
{
return false;
}
@@ -1645,8 +1716,8 @@ bool team_ui_append_member_track(const TeamId& team_id,
return false;
}
::platform::esp::common::SharedSpiLockGuard spi_guard(kTeamStoreWriteWait);
if (!spi_guard.locked())
TeamStoreBusGate bus_gate(TeamStoreBusAccess::Write);
if (!bus_gate.locked())
{
return false;
}
-40
View File
@@ -220,31 +220,6 @@ LEGACY_TRANSITION_OCCURRENCES = {
"lilygo_display_spi_unlock",
"LilyGoDispArduinoSPI::unlock();",
): 18,
(
"platform/esp/arduino_common/src/app_context_platform_bindings.cpp",
"shared_spi_guard",
"::platform::esp::common::SharedSpiLockGuard spi_guard(",
): 2,
(
"platform/esp/arduino_common/src/chat/infra/contact_store.cpp",
"shared_spi_guard",
'::platform::esp::common::SharedSpiLockGuard spi_guard(kSdLoadWait, "contact_store_sd");',
): 1,
(
"platform/esp/arduino_common/src/chat/infra/contact_store.cpp",
"shared_spi_guard",
'::platform::esp::common::SharedSpiLockGuard spi_guard(kSdPersistWait, "contact_store_sd");',
): 1,
(
"platform/esp/arduino_common/src/chat/infra/meshtastic/node_store.cpp",
"shared_spi_guard",
'::platform::esp::common::SharedSpiLockGuard spi_guard(kSdLoadWait, "node_store_sd");',
): 1,
(
"platform/esp/arduino_common/src/chat/infra/meshtastic/node_store.cpp",
"shared_spi_guard",
'::platform::esp::common::SharedSpiLockGuard spi_guard(kSdPersistWait, "node_store_sd");',
): 2,
(
"platform/esp/arduino_common/src/platform_ui_usb_support_runtime.cpp",
"shared_spi_guard",
@@ -255,21 +230,6 @@ LEGACY_TRANSITION_OCCURRENCES = {
"shared_spi_guard",
"::platform::esp::common::SharedSpiLockGuard guard(pdMS_TO_TICKS(200));",
): 1,
(
"platform/esp/arduino_common/src/ui/screens/team/team_ui_store.cpp",
"shared_spi_guard",
"::platform::esp::common::SharedSpiLockGuard spi_guard(kTeamStoreLoadWait);",
): 1,
(
"platform/esp/arduino_common/src/ui/screens/team/team_ui_store.cpp",
"shared_spi_guard",
"::platform::esp::common::SharedSpiLockGuard spi_guard(kTeamStoreReadWait);",
): 2,
(
"platform/esp/arduino_common/src/ui/screens/team/team_ui_store.cpp",
"shared_spi_guard",
"::platform::esp::common::SharedSpiLockGuard spi_guard(kTeamStoreWriteWait);",
): 9,
}