1*61c4878aSAndroid Build Coastguard Worker.. _module-pw_persistent_ram: 2*61c4878aSAndroid Build Coastguard Worker 3*61c4878aSAndroid Build Coastguard Worker================= 4*61c4878aSAndroid Build Coastguard Workerpw_persistent_ram 5*61c4878aSAndroid Build Coastguard Worker================= 6*61c4878aSAndroid Build Coastguard WorkerThe ``pw_persistent_ram`` module contains utilities and containers for using 7*61c4878aSAndroid Build Coastguard Workerpersistent RAM. By persistent RAM we are referring to memory which is not 8*61c4878aSAndroid Build Coastguard Workerinitialized across reboots by the hardware nor bootloader(s). This memory may 9*61c4878aSAndroid Build Coastguard Workerdecay or bit rot between reboots including brownouts, ergo integrity checking is 10*61c4878aSAndroid Build Coastguard Workerhighly recommended. 11*61c4878aSAndroid Build Coastguard Worker 12*61c4878aSAndroid Build Coastguard Worker.. Note:: 13*61c4878aSAndroid Build Coastguard Worker This is something that not all architectures and applications built on them 14*61c4878aSAndroid Build Coastguard Worker support and requires hardware in the loop testing to verify it works as 15*61c4878aSAndroid Build Coastguard Worker intended. 16*61c4878aSAndroid Build Coastguard Worker 17*61c4878aSAndroid Build Coastguard Worker.. Warning:: 18*61c4878aSAndroid Build Coastguard Worker Do not treat the current containers provided in this module as stable storage 19*61c4878aSAndroid Build Coastguard Worker primitives. We are still evaluating lighterweight checksums from a code size 20*61c4878aSAndroid Build Coastguard Worker point of view. In other words, future updates to this module may result in a 21*61c4878aSAndroid Build Coastguard Worker loss of persistent data across software updates. 22*61c4878aSAndroid Build Coastguard Worker 23*61c4878aSAndroid Build Coastguard Worker------------------------ 24*61c4878aSAndroid Build Coastguard WorkerPersistent RAM Placement 25*61c4878aSAndroid Build Coastguard Worker------------------------ 26*61c4878aSAndroid Build Coastguard WorkerPersistent RAM is typically provided through specially carved out linker script 27*61c4878aSAndroid Build Coastguard Workersections and/or memory ranges which are located in such a way that any 28*61c4878aSAndroid Build Coastguard Workerbootloaders and the application boot code do not clobber it. 29*61c4878aSAndroid Build Coastguard Worker 30*61c4878aSAndroid Build Coastguard Worker1. If persistent linker sections are provided, use the ``PW_PLACE_IN_SECTION()`` 31*61c4878aSAndroid Build Coastguard Worker macro to assign variables to that memory region. For example, if the 32*61c4878aSAndroid Build Coastguard Worker persistent memory section name is ``.noinit``, then you could instantiate an 33*61c4878aSAndroid Build Coastguard Worker object as such: 34*61c4878aSAndroid Build Coastguard Worker 35*61c4878aSAndroid Build Coastguard Worker .. code-block:: cpp 36*61c4878aSAndroid Build Coastguard Worker 37*61c4878aSAndroid Build Coastguard Worker #include "pw_persistent_ram/persistent.h" 38*61c4878aSAndroid Build Coastguard Worker #include "pw_preprocessor/compiler.h" 39*61c4878aSAndroid Build Coastguard Worker 40*61c4878aSAndroid Build Coastguard Worker using pw::persistent_ram::Persistent; 41*61c4878aSAndroid Build Coastguard Worker 42*61c4878aSAndroid Build Coastguard Worker PW_PLACE_IN_SECTION(".noinit") Persistent<bool> persistent_bool; 43*61c4878aSAndroid Build Coastguard Worker 44*61c4878aSAndroid Build Coastguard Worker2. If persistent memory ranges are provided, you can use use a struct to wrap 45*61c4878aSAndroid Build Coastguard Worker the different persisted objects. This makes it possible to ensure that the 46*61c4878aSAndroid Build Coastguard Worker data fits in the provided memory range. This must be done via a runtime check 47*61c4878aSAndroid Build Coastguard Worker against variables provided through the linker script since the addresses 48*61c4878aSAndroid Build Coastguard Worker of linker script symbols aren't available at compile time. 49*61c4878aSAndroid Build Coastguard Worker 50*61c4878aSAndroid Build Coastguard Worker .. code-block:: cpp 51*61c4878aSAndroid Build Coastguard Worker 52*61c4878aSAndroid Build Coastguard Worker #include "pw_assert/check.h" 53*61c4878aSAndroid Build Coastguard Worker #include "pw_persistent_ram/persistent.h" 54*61c4878aSAndroid Build Coastguard Worker 55*61c4878aSAndroid Build Coastguard Worker // Provided for example through a linker script. 56*61c4878aSAndroid Build Coastguard Worker extern "C" uint8_t __noinit_begin; 57*61c4878aSAndroid Build Coastguard Worker extern "C" uint8_t __noinit_end; 58*61c4878aSAndroid Build Coastguard Worker 59*61c4878aSAndroid Build Coastguard Worker struct PersistentData { 60*61c4878aSAndroid Build Coastguard Worker Persistent<bool> persistent_bool; 61*61c4878aSAndroid Build Coastguard Worker }; 62*61c4878aSAndroid Build Coastguard Worker PersistentData& persistent_data = 63*61c4878aSAndroid Build Coastguard Worker *reinterpret_cast<NoinitData*>(&__noinit_begin); 64*61c4878aSAndroid Build Coastguard Worker 65*61c4878aSAndroid Build Coastguard Worker void CheckPersistentDataSize() { 66*61c4878aSAndroid Build Coastguard Worker PW_DCHECK_UINT_LE(sizeof(PersistentData), 67*61c4878aSAndroid Build Coastguard Worker __noinit_end - __noinit_begin, 68*61c4878aSAndroid Build Coastguard Worker "PersistentData overflowed the noinit memory range"); 69*61c4878aSAndroid Build Coastguard Worker } 70*61c4878aSAndroid Build Coastguard Worker 71*61c4878aSAndroid Build Coastguard Worker----------------------------------- 72*61c4878aSAndroid Build Coastguard WorkerPersistent RAM Lifecycle Management 73*61c4878aSAndroid Build Coastguard Worker----------------------------------- 74*61c4878aSAndroid Build Coastguard WorkerIn order for persistent RAM containers to be as useful as possible, any 75*61c4878aSAndroid Build Coastguard Workerinvalidation of persistent RAM and the containers therein should be executed 76*61c4878aSAndroid Build Coastguard Workerbefore the global static C++ constructors, but after the BSS and data sections 77*61c4878aSAndroid Build Coastguard Workerare initialized in RAM. 78*61c4878aSAndroid Build Coastguard Worker 79*61c4878aSAndroid Build Coastguard WorkerThe preferred way to clear Persistent RAM is to simply zero entire persistent 80*61c4878aSAndroid Build Coastguard WorkerRAM sections and/or memory regions. Pigweed's persistent containers have picked 81*61c4878aSAndroid Build Coastguard Workerintegrity checks which work with zeroed memory, meaning they do not hold a value 82*61c4878aSAndroid Build Coastguard Workerafter zeroing. Alternatively containers can be individually cleared. 83*61c4878aSAndroid Build Coastguard Worker 84*61c4878aSAndroid Build Coastguard WorkerThe boot sequence itself is tightly coupled to the number of persistent sections 85*61c4878aSAndroid Build Coastguard Workerand/or memory regions which exist in the final image, ergo this is something 86*61c4878aSAndroid Build Coastguard Workerwhich Pigweed cannot provide to the user directly. However, we do recommend 87*61c4878aSAndroid Build Coastguard Workerfollowing some guidelines: 88*61c4878aSAndroid Build Coastguard Worker 89*61c4878aSAndroid Build Coastguard Worker1. Do not instantiate regular types/objects in persistent RAM, ensure integrity 90*61c4878aSAndroid Build Coastguard Worker checking is always used! This is a major risk with this technique and can 91*61c4878aSAndroid Build Coastguard Worker lead to unexpected memory corruption. 92*61c4878aSAndroid Build Coastguard Worker2. Always instantiate persistent containers outside of the objects which depend 93*61c4878aSAndroid Build Coastguard Worker on them and use dependency injection. This permits unit testing and avoids 94*61c4878aSAndroid Build Coastguard Worker placement accidents of persistents and/or their users. 95*61c4878aSAndroid Build Coastguard Worker3. Always erase persistent RAM data after software updates unless the 96*61c4878aSAndroid Build Coastguard Worker persistent storage containers are explicitly stored at fixed address and 97*61c4878aSAndroid Build Coastguard Worker with a fixed layout. This prevents use of swapped objects or their members 98*61c4878aSAndroid Build Coastguard Worker where the same integrity checks are used. 99*61c4878aSAndroid Build Coastguard Worker4. Consider zeroing persistent RAM to recover from crashes which may be induced 100*61c4878aSAndroid Build Coastguard Worker by persistent RAM usage, for example by checking the reboot/crash reason. 101*61c4878aSAndroid Build Coastguard Worker5. Consider zeroing persistent RAM on cold boots to always start from a 102*61c4878aSAndroid Build Coastguard Worker consistent state if persistence is only desired across warm reboots. This can 103*61c4878aSAndroid Build Coastguard Worker create determinism from cold boots when using for example DRAM. 104*61c4878aSAndroid Build Coastguard Worker6. Consider an explicit persistent clear request which can be set before a warm 105*61c4878aSAndroid Build Coastguard Worker reboot as a signal to zero all persistent RAM on the next boot to emulate 106*61c4878aSAndroid Build Coastguard Worker persistent memory loss in a threadsafe manner. 107*61c4878aSAndroid Build Coastguard Worker 108*61c4878aSAndroid Build Coastguard Worker--------------------------------- 109*61c4878aSAndroid Build Coastguard Workerpw::persistent_ram::Persistent<T> 110*61c4878aSAndroid Build Coastguard Worker--------------------------------- 111*61c4878aSAndroid Build Coastguard WorkerThe Persistent is a simple container for holding its templated value ``T`` with 112*61c4878aSAndroid Build Coastguard WorkerCRC16 integrity checking. Note that a Persistent will be lost if a write/set 113*61c4878aSAndroid Build Coastguard Workeroperation is interrupted or otherwise not completed, as it is not double 114*61c4878aSAndroid Build Coastguard Workerbuffered. 115*61c4878aSAndroid Build Coastguard Worker 116*61c4878aSAndroid Build Coastguard WorkerThe default constructor does nothing, meaning it will result in either invalid 117*61c4878aSAndroid Build Coastguard Workerstate initially or a valid persisted value from a previous session. 118*61c4878aSAndroid Build Coastguard Worker 119*61c4878aSAndroid Build Coastguard WorkerThe destructor does nothing, ergo it is okay if it is not executed during 120*61c4878aSAndroid Build Coastguard Workershutdown. 121*61c4878aSAndroid Build Coastguard Worker 122*61c4878aSAndroid Build Coastguard WorkerExample: Storing an integer 123*61c4878aSAndroid Build Coastguard Worker--------------------------- 124*61c4878aSAndroid Build Coastguard WorkerA common use case of persistent data is to track boot counts, or effectively 125*61c4878aSAndroid Build Coastguard Workerhow often the device has rebooted. This can be useful for monitoring how many 126*61c4878aSAndroid Build Coastguard Workertimes the device rebooted and/or crashed. This can be easily accomplished using 127*61c4878aSAndroid Build Coastguard Workerthe Persistent container. 128*61c4878aSAndroid Build Coastguard Worker 129*61c4878aSAndroid Build Coastguard Worker.. code-block:: cpp 130*61c4878aSAndroid Build Coastguard Worker 131*61c4878aSAndroid Build Coastguard Worker #include "pw_persistent_ram/persistent.h" 132*61c4878aSAndroid Build Coastguard Worker #include "pw_preprocessor/compiler.h" 133*61c4878aSAndroid Build Coastguard Worker 134*61c4878aSAndroid Build Coastguard Worker using pw::persistent_ram::Persistent; 135*61c4878aSAndroid Build Coastguard Worker 136*61c4878aSAndroid Build Coastguard Worker class BootCount { 137*61c4878aSAndroid Build Coastguard Worker public: 138*61c4878aSAndroid Build Coastguard Worker explicit BootCount(Persistent<uint16_t>& persistent_boot_count) 139*61c4878aSAndroid Build Coastguard Worker : persistent_(persistent_boot_count) { 140*61c4878aSAndroid Build Coastguard Worker if (!persistent_.has_value()) { 141*61c4878aSAndroid Build Coastguard Worker persistent_ = 0; 142*61c4878aSAndroid Build Coastguard Worker } else { 143*61c4878aSAndroid Build Coastguard Worker persistent_ = persistent_.value() + 1; 144*61c4878aSAndroid Build Coastguard Worker } 145*61c4878aSAndroid Build Coastguard Worker boot_count_ = persistent_.value(); 146*61c4878aSAndroid Build Coastguard Worker } 147*61c4878aSAndroid Build Coastguard Worker 148*61c4878aSAndroid Build Coastguard Worker uint16_t GetBootCount() { return boot_count_; } 149*61c4878aSAndroid Build Coastguard Worker 150*61c4878aSAndroid Build Coastguard Worker private: 151*61c4878aSAndroid Build Coastguard Worker Persistent<uint16_t>& persistent_; 152*61c4878aSAndroid Build Coastguard Worker uint16_t boot_count_; 153*61c4878aSAndroid Build Coastguard Worker }; 154*61c4878aSAndroid Build Coastguard Worker 155*61c4878aSAndroid Build Coastguard Worker PW_PLACE_IN_SECTION(".noinit") Persistent<uint16_t> persistent_boot_count; 156*61c4878aSAndroid Build Coastguard Worker BootCount boot_count(persistent_boot_count); 157*61c4878aSAndroid Build Coastguard Worker 158*61c4878aSAndroid Build Coastguard Worker int main() { 159*61c4878aSAndroid Build Coastguard Worker const uint16_t boot_count = boot_count.GetBootCount(); 160*61c4878aSAndroid Build Coastguard Worker // ... rest of main 161*61c4878aSAndroid Build Coastguard Worker } 162*61c4878aSAndroid Build Coastguard Worker 163*61c4878aSAndroid Build Coastguard WorkerExample: Storing larger objects 164*61c4878aSAndroid Build Coastguard Worker------------------------------- 165*61c4878aSAndroid Build Coastguard WorkerLarger objects may be inefficient to copy back and forth due to the need for 166*61c4878aSAndroid Build Coastguard Workera working copy. To work around this, you can get a Mutator handle that provides 167*61c4878aSAndroid Build Coastguard Workerdirect access to the underlying object. As long as the Mutator is in scope, it 168*61c4878aSAndroid Build Coastguard Workeris invalid to access the underlying Persistent, but you'll be able to directly 169*61c4878aSAndroid Build Coastguard Workermodify the object in place. Once the Mutator goes out of scope, the Persistent 170*61c4878aSAndroid Build Coastguard Workerobject's checksum is updated to reflect the changes. 171*61c4878aSAndroid Build Coastguard Worker 172*61c4878aSAndroid Build Coastguard Worker.. code-block:: cpp 173*61c4878aSAndroid Build Coastguard Worker 174*61c4878aSAndroid Build Coastguard Worker #include "pw_persistent_ram/persistent.h" 175*61c4878aSAndroid Build Coastguard Worker #include "pw_preprocessor/compiler.h" 176*61c4878aSAndroid Build Coastguard Worker 177*61c4878aSAndroid Build Coastguard Worker using pw::persistent_ram::Persistent; 178*61c4878aSAndroid Build Coastguard Worker 179*61c4878aSAndroid Build Coastguard Worker contexpr size_t kMaxReasonLength = 256; 180*61c4878aSAndroid Build Coastguard Worker 181*61c4878aSAndroid Build Coastguard Worker struct LastCrashInfo { 182*61c4878aSAndroid Build Coastguard Worker uint32_t uptime_ms; 183*61c4878aSAndroid Build Coastguard Worker uint32_t boot_id; 184*61c4878aSAndroid Build Coastguard Worker char reason[kMaxReasonLength]; 185*61c4878aSAndroid Build Coastguard Worker } 186*61c4878aSAndroid Build Coastguard Worker 187*61c4878aSAndroid Build Coastguard Worker PW_PLACE_IN_SECTION(".noinit") Persistent<LastBootInfo> persistent_crash_info; 188*61c4878aSAndroid Build Coastguard Worker 189*61c4878aSAndroid Build Coastguard Worker void HandleCrash(const char* fmt, va_list args) { 190*61c4878aSAndroid Build Coastguard Worker // Once this scope ends, we know the persistent object has been updated 191*61c4878aSAndroid Build Coastguard Worker // to reflect changes. 192*61c4878aSAndroid Build Coastguard Worker { 193*61c4878aSAndroid Build Coastguard Worker auto& mutable_crash_info = 194*61c4878aSAndroid Build Coastguard Worker persistent_crash_info.mutator(GetterAction::kReset); 195*61c4878aSAndroid Build Coastguard Worker vsnprintf(mutable_crash_info->reason, 196*61c4878aSAndroid Build Coastguard Worker sizeof(mutable_crash_info->reason), 197*61c4878aSAndroid Build Coastguard Worker fmt, 198*61c4878aSAndroid Build Coastguard Worker args); 199*61c4878aSAndroid Build Coastguard Worker mutable_crash_info->uptime_ms = system::GetUptimeMs(); 200*61c4878aSAndroid Build Coastguard Worker mutable_crash_info->boot_id = system::GetBootId(); 201*61c4878aSAndroid Build Coastguard Worker } 202*61c4878aSAndroid Build Coastguard Worker // ... 203*61c4878aSAndroid Build Coastguard Worker } 204*61c4878aSAndroid Build Coastguard Worker 205*61c4878aSAndroid Build Coastguard Worker int main() { 206*61c4878aSAndroid Build Coastguard Worker if (persistent_crash_info.has_value()) { 207*61c4878aSAndroid Build Coastguard Worker LogLastCrashInfo(persistent_crash_info.value()); 208*61c4878aSAndroid Build Coastguard Worker // Clear crash info once it has been dumped. 209*61c4878aSAndroid Build Coastguard Worker persistent_crash_info.Invalidate(); 210*61c4878aSAndroid Build Coastguard Worker } 211*61c4878aSAndroid Build Coastguard Worker 212*61c4878aSAndroid Build Coastguard Worker // ... rest of main 213*61c4878aSAndroid Build Coastguard Worker } 214*61c4878aSAndroid Build Coastguard Worker 215*61c4878aSAndroid Build Coastguard Worker.. _module-pw_persistent_ram-persistent_buffer: 216*61c4878aSAndroid Build Coastguard Worker 217*61c4878aSAndroid Build Coastguard Worker------------------------------------ 218*61c4878aSAndroid Build Coastguard Workerpw::persistent_ram::PersistentBuffer 219*61c4878aSAndroid Build Coastguard Worker------------------------------------ 220*61c4878aSAndroid Build Coastguard WorkerThe PersistentBuffer is a persistent storage container for variable-length 221*61c4878aSAndroid Build Coastguard Workerserialized data. Rather than allowing direct access to the underlying buffer for 222*61c4878aSAndroid Build Coastguard Workerrandom-access mutations, the PersistentBuffer is mutable through a 223*61c4878aSAndroid Build Coastguard WorkerPersistentBufferWriter that implements the pw::stream::Writer interface. This 224*61c4878aSAndroid Build Coastguard Workerremoves the potential for logical errors due to RAII or open()/close() semantics 225*61c4878aSAndroid Build Coastguard Workeras both the PersistentBuffer and PersistentBufferWriter can be used validly as 226*61c4878aSAndroid Build Coastguard Workerlong as their access is serialized. 227*61c4878aSAndroid Build Coastguard Worker 228*61c4878aSAndroid Build Coastguard WorkerExample 229*61c4878aSAndroid Build Coastguard Worker------- 230*61c4878aSAndroid Build Coastguard WorkerAn example use case is emitting crash handler logs to a buffer for them to be 231*61c4878aSAndroid Build Coastguard Workeravailable after a the device reboots. Once the device reboots, the logs would be 232*61c4878aSAndroid Build Coastguard Workeremitted by the logging system. While this isn't always practical for plaintext 233*61c4878aSAndroid Build Coastguard Workerlogs, tokenized logs are small enough for this to be useful. 234*61c4878aSAndroid Build Coastguard Worker 235*61c4878aSAndroid Build Coastguard Worker.. code-block:: cpp 236*61c4878aSAndroid Build Coastguard Worker 237*61c4878aSAndroid Build Coastguard Worker #include "pw_persistent_ram/persistent_buffer.h" 238*61c4878aSAndroid Build Coastguard Worker #include "pw_preprocessor/compiler.h" 239*61c4878aSAndroid Build Coastguard Worker 240*61c4878aSAndroid Build Coastguard Worker using pw::persistent_ram::PersistentBuffer; 241*61c4878aSAndroid Build Coastguard Worker using pw::persistent_ram::PersistentBuffer::PersistentBufferWriter; 242*61c4878aSAndroid Build Coastguard Worker 243*61c4878aSAndroid Build Coastguard Worker PW_KEEP_IN_SECTION(".noinit") PersistentBuffer<2048> crash_logs; 244*61c4878aSAndroid Build Coastguard Worker void CheckForCrashLogs() { 245*61c4878aSAndroid Build Coastguard Worker if (crash_logs.has_value()) { 246*61c4878aSAndroid Build Coastguard Worker // A function that dumps sequentially serialized logs using pw_log. 247*61c4878aSAndroid Build Coastguard Worker DumpRawLogs(crash_logs.written_data()); 248*61c4878aSAndroid Build Coastguard Worker crash_logs.clear(); 249*61c4878aSAndroid Build Coastguard Worker } 250*61c4878aSAndroid Build Coastguard Worker } 251*61c4878aSAndroid Build Coastguard Worker 252*61c4878aSAndroid Build Coastguard Worker void HandleCrash(CrashInfo* crash_info) { 253*61c4878aSAndroid Build Coastguard Worker PersistentBufferWriter crash_log_writer = crash_logs.GetWriter(); 254*61c4878aSAndroid Build Coastguard Worker // Sets the pw::stream::Writer that pw_log should dump logs to. 255*61c4878aSAndroid Build Coastguard Worker crash_log_writer.clear(); 256*61c4878aSAndroid Build Coastguard Worker SetLogSink(crash_log_writer); 257*61c4878aSAndroid Build Coastguard Worker // Handle crash, calling PW_LOG to log useful info. 258*61c4878aSAndroid Build Coastguard Worker } 259*61c4878aSAndroid Build Coastguard Worker 260*61c4878aSAndroid Build Coastguard Worker int main() { 261*61c4878aSAndroid Build Coastguard Worker void CheckForCrashLogs(); 262*61c4878aSAndroid Build Coastguard Worker // ... rest of main 263*61c4878aSAndroid Build Coastguard Worker } 264*61c4878aSAndroid Build Coastguard Worker 265*61c4878aSAndroid Build Coastguard WorkerSize Report 266*61c4878aSAndroid Build Coastguard Worker----------- 267*61c4878aSAndroid Build Coastguard WorkerThe following size report showcases the overhead for using Persistent. Note that 268*61c4878aSAndroid Build Coastguard Workerthis is templating the Persistent only on a ``uint32_t``, ergo the cost without 269*61c4878aSAndroid Build Coastguard Workerpw_checksum's CRC16 is the approximate cost per type. 270*61c4878aSAndroid Build Coastguard Worker 271*61c4878aSAndroid Build Coastguard Worker.. include:: persistent_size 272*61c4878aSAndroid Build Coastguard Worker 273*61c4878aSAndroid Build Coastguard WorkerCompatibility 274*61c4878aSAndroid Build Coastguard Worker------------- 275*61c4878aSAndroid Build Coastguard Worker* C++17 276*61c4878aSAndroid Build Coastguard Worker 277*61c4878aSAndroid Build Coastguard WorkerDependencies 278*61c4878aSAndroid Build Coastguard Worker------------ 279*61c4878aSAndroid Build Coastguard Worker* ``pw_checksum`` 280