nrfcxx  0.1.0
C++-17 Framework for Nordic nRF5 Devices
utility.hpp
Go to the documentation of this file.
1 /* SPDX-License-Identifier: Apache-2.0 */
2 /* Copyright 2015-2019 Peter A. Bigot */
3 
6 #ifndef NRFCXX_UTILITY_HPP
7 #define NRFCXX_UTILITY_HPP
8 #pragma once
9 
10 #include <nrfcxx/core.hpp>
11 #include <type_traits>
12 #include <array>
13 #include <limits>
14 
16 extern "C" {
17  extern const uint32_t __PersistBase;
18  extern const uint32_t __PersistLimit;
19 }
22 namespace nrfcxx {
23 
25 namespace utility {
26 
43 template <unsigned int ALIGN_BITS = 2>
44 class memory_pool {
50  static constexpr size_t ignore_mask{(1U << ALIGN_BITS) - 1};
51 
53  static constexpr uintptr_t align_mask = ~static_cast<uintptr_t>(ignore_mask);
54 
55 public:
57 
60  static constexpr unsigned int align_bits = ALIGN_BITS;
61 
81  class scoped {
82  public:
85  {
86  pool_.clear();
87  }
88 
89  protected:
91  friend memory_pool;
92  scoped (pool_type& pool) :
93  pool_{pool}
94  { }
95 
96  scoped (const scoped&) = delete;
97  scoped& operator= (const scoped&) = delete;
98  scoped (scoped&&) = delete;
99  scoped& operator= (scoped&) = delete;
102  private:
103  pool_type& pool_;
104  };
105 
114  {
115  if (size()) {
116  failsafe(code_);
117  }
118  return {*this};
119  }
120 
126  constexpr memory_pool () :
127  begin_{},
128  end_{},
129  head_{},
130  code_{static_cast<unsigned int>(FailSafeCode::MEMORY_POOL)}
131  { }
132 
134  memory_pool (const memory_pool&) = delete;
135  memory_pool& operator= (const memory_pool&) = delete;
136  memory_pool (memory_pool&&) = delete;
137  memory_pool& operator= (memory_pool&&) = delete;
150  void configure (void* begin,
151  void* end,
152  unsigned int code = FailSafeCode::MEMORY_POOL)
153  {
154  if (begin_) {
155  failsafe(code_);
156  }
157  code_ = code;
158 
159  /* The region begins at the aligned address no less than the
160  * provided address. */
161  begin_ = reinterpret_cast<unsigned char*>(align_mask & (ignore_mask + reinterpret_cast<uintptr_t>(begin)));
162 
163  /* The region ends at the aligned address no greater than the
164  * provided address. */
165  end_ = reinterpret_cast<unsigned char*>(align_mask & reinterpret_cast<uintptr_t>(end));
166 
167  /* If somebody does something stupid, including configuring an
168  * empty region, failsafe. */
169  if (end_ <= begin_) {
170  failsafe(code_);
171  }
172  head_ = begin_;
173  }
174 
179  void clear ()
180  {
181  head_ = begin_;
182  }
183 
186  size_t capacity () const
187  {
188  return (end_ - begin_);
189  }
190 
192  size_t size () const
193  {
194  return (head_ - begin_);
195  }
196 
198  size_t available () const
199  {
200  return (end_ - head_);
201  }
202 
211  void* allocate (size_t span)
212  {
213  /* Increase the span so all pointers are aligned. */
214  span = align_mask & (span + ignore_mask);
215  if ((!head_) || ((head_ + span) > end_)) {
216  failsafe(code_);
217  }
218  void* rv = reinterpret_cast<void *>(head_);
219  head_ += span;
220  return rv;
221  }
222 
223 private:
224  /* Pointer to the aligned start of the configured region. */
225  unsigned char* begin_;
226 
227  /* Pointer to the aligned address just past the start of the
228  * unallocated portion of the configured region. */
229  unsigned char* end_;
230 
231  /* Pointer to the aligned start of the unallocated portion of the
232  * configured region. */
233  unsigned char* head_;
234 
235  /* The code to be used in the failsafe reset if allocation fails. */
236  unsigned int code_;
237 };
238 
240 namespace internal {
241 
242 /* Generic API underlying display_data */
243 template <typename T>
244 void display_data (const T* dp,
245  size_t count,
246  uintptr_t base);
247 
248 /* Known specialization for octets. ASCII values are displayed in
249  * right column. */
250 template <>
251 void display_data<uint8_t> (const uint8_t* dp,
252  size_t count,
253  uintptr_t base);
254 
255 /* Known specialization for words. */
256 template <>
257 void display_data<uint32_t> (const uint32_t* dp,
258  size_t count,
259  uintptr_t base);
260 
261 } // namespace internal
276 template <typename T>
277 inline void display_data (const T* dp,
278  size_t count,
279  uintptr_t base)
280 {
281  using base_type = typename std::remove_volatile<T>::type;
282  internal::display_data(const_cast<const base_type*>(dp), count, base);
283 }
284 
313 class Persist {
314 public:
315 
318  static constexpr uint16_t TAG_ERASED = 0;
319 
322  static constexpr uint16_t TAG_UNUSED = 0xFFFF;
323 
328  static constexpr const uint32_t* REGION_BEGIN = &__PersistBase;
329 
335  static constexpr const uint32_t* REGION_END = &__PersistLimit;
336 
338  struct header_type {
340  uint16_t span;
341 
343  uint16_t tag;
344 
346  uint8_t data[0];
347 
354  const header_type* next () const
355  {
356  /* By construction `span` cannot be zero. */
357  static_assert(sizeof(*this) == sizeof(uint32_t),
358  "header is too big");
359  return this + span;
360  }
361  };
362 
363 #if (51 == NRF_SERIES) || (NRFCXX_DOXYGEN - 0)
364 
368  static constexpr unsigned int PAGE_SIZE = 1024;
369 
374  static constexpr unsigned int BLOCK_SIZE = PAGE_SIZE;
375 #elif (52 == NRF_SERIES)
376  static constexpr unsigned int PAGE_SIZE = 4096;
377  static constexpr unsigned int BLOCK_SIZE = 512;
378 #endif
379 
386  code_{code},
387  begin_{},
388  end_{},
389  first_{},
390  unused_{},
391  erased_{}
392  { }
393 
395  constexpr Persist (unsigned int code) :
396  Persist(static_cast<FailSafeCode>(code))
397  { }
398 
400  Persist (const Persist&) = delete;
401  Persist& operator= (const Persist&) = delete;
402  Persist (Persist&& ) = delete;
403  Persist& operator= (Persist&) = delete;
417  int configure (const uint32_t* begin,
418  const uint32_t* end);
419 
426  const header_type* find (uint16_t tag)
427  {
428  return find_(tag);
429  }
430 
437  int erase (uint16_t tag)
438  {
439  int rv{-1};
440  const header_type* hp{find_(tag)};
441  if (hp) {
442  erase_(hp);
443  rv = 0;
444  }
445  return rv;
446  }
447 
463  const header_type* addReplace (uint16_t tag,
464  const void* data,
465  size_t count);
466 
481  ptrdiff_t extract (header_type* buffer = nullptr,
482  size_t length = 0) const;
483 
500  int restore (const header_type* buffer,
501  size_t length);
502 
508  int gc ();
509 
512  bool is_cleared () const
513  {
514  return begin_ && (TAG_UNUSED == begin_->tag);
515  }
516 
523  size_t available () const
524  {
525  size_t rv{};
526  if (unused_) {
527  rv = (end_ - unused_ - 1) * sizeof(*unused_);
528  }
529  return rv;
530  }
531 
535  size_t erased () const
536  {
537  return erased_ * sizeof(uint32_t);
538  }
539 
541  void clear ();
542 
543 protected:
545  void erase_ (const header_type* hp);
546 
548  const header_type* find_ (uint16_t tag);
549 
552 
555 
558 
565 
574 
577  unsigned int erased_;
578 };
579 
580 } // namespace utility
581 } // namespace nrfcxx
582 
583 #endif /* NRFCXX_UTILITY_HPP */
nrfcxx::utility::Persist
Class supporting persistence of tagged records to non-volatile memory.
Definition: utility.hpp:313
nrfcxx::utility::Persist::erase
int erase(uint16_t tag)
Remove the record with the given tag.
Definition: utility.hpp:437
nrfcxx::utility::Persist::erase_
void erase_(const header_type *hp)
Mark an existing record as erased.
nrfcxx::utility::Persist::BLOCK_SIZE
static constexpr unsigned int BLOCK_SIZE
Number of bytes in a flash block.
Definition: utility.hpp:374
nrfcxx::failsafe
void failsafe(FailSafeCode code)
Record a critical system failure and reset the system.
Definition: core.hpp:1692
nrfcxx::utility::Persist::TAG_UNUSED
static constexpr uint16_t TAG_UNUSED
header_type::tag value for the placeholder header of the next record to be written.
Definition: utility.hpp:322
nrfcxx::utility::Persist::REGION_END
static constexpr const uint32_t * REGION_END
pointer to the first word after the PERSIST memory region.
Definition: utility.hpp:335
nrfcxx::utility::memory_pool::available
size_t available() const
Return the number of unallocated bytes in the region.
Definition: utility.hpp:198
nrfcxx::utility::Persist::TAG_ERASED
static constexpr uint16_t TAG_ERASED
header_type::tag value for a record that has been erased.
Definition: utility.hpp:318
nrfcxx::utility::Persist::erased_
unsigned int erased_
Number of words in the region covered by erased records.
Definition: utility.hpp:577
nrfcxx::utility::Persist::Persist
constexpr Persist(unsigned int code)
Alternative constructor for uncast failsafe codes.
Definition: utility.hpp:395
nrfcxx::utility::memory_pool::scoped::~scoped
~scoped()
Contained pool is cleared on destruction.
Definition: utility.hpp:84
nrfcxx::utility::Persist::header_type::tag
uint16_t tag
Tag identifying the record content.
Definition: utility.hpp:343
nrfcxx::utility::memory_pool
Class supporting allocation from a fixed-size region.
Definition: utility.hpp:44
nrfcxx::utility::Persist::is_cleared
bool is_cleared() const
Return true iff the region is configured and starts with a used record.
Definition: utility.hpp:512
nrfcxx::utility::Persist::first_
const header_type * first_
Pointer to the first used and unerased record in the region.
Definition: utility.hpp:564
nrfcxx::FailSafeCode::PERSIST_VIOLATION
Default code for violation of a persisted memory region.
nrfcxx::utility::Persist::Persist
constexpr Persist(FailSafeCode code=FailSafeCode::PERSIST_VIOLATION)
Construct the wrapper class.
Definition: utility.hpp:385
nrfcxx::utility::Persist::begin_
const header_type * begin_
Inclusive lower bound of the persisted region.
Definition: utility.hpp:554
nrfcxx::utility::Persist::REGION_BEGIN
static constexpr const uint32_t * REGION_BEGIN
pointer to the first word of the PERSIST memory region.
Definition: utility.hpp:328
nrfcxx::utility::Persist::find_
const header_type * find_(uint16_t tag)
Locate a record by tag.
nrfcxx::utility::memory_pool::configure
void configure(void *begin, void *end, unsigned int code=FailSafeCode::MEMORY_POOL)
Provide the allocation region and failsafe code.
Definition: utility.hpp:150
nrfcxx::utility::Persist::header_type::data
uint8_t data[0]
The record content.
Definition: utility.hpp:346
nrfcxx::FailSafeCode::MEMORY_POOL
Exceeded allocated space of a memory pool.
nrfcxx::utility::memory_pool::capacity
size_t capacity() const
Return the total number of bytes in the region (allocated plus unallocated).
Definition: utility.hpp:186
nrfcxx::utility::Persist::end_
const header_type * end_
Exclusive upper bound of the persisted region.
Definition: utility.hpp:557
nrfcxx::utility::Persist::PAGE_SIZE
static constexpr unsigned int PAGE_SIZE
Number of bytes in a flash page.
Definition: utility.hpp:368
nrfcxx::utility::Persist::clear
void clear()
Clear all data from the persisted region.
nrfcxx::utility::display_data
void display_data(const T *dp, size_t count, uintptr_t base)
Display a block of data on the console.
Definition: utility.hpp:277
nrfcxx::utility::memory_pool::memory_pool
constexpr memory_pool()
Construct the instance.
Definition: utility.hpp:126
nrfcxx::utility::Persist::header_type::next
const header_type * next() const
Get a pointer to the following record.
Definition: utility.hpp:354
nrfcxx::utility::Persist::extract
ptrdiff_t extract(header_type *buffer=nullptr, size_t length=0) const
Extract the active records from the region.
nrfcxx::utility::memory_pool::make_scoped
scoped make_scoped()
Construct an RAII holder that maintains the instance as a scratch pool.
Definition: utility.hpp:113
nrfcxx::utility::Persist::unused_
const header_type * unused_
Pointer to the region's unused record.
Definition: utility.hpp:573
nrfcxx::utility::Persist::addReplace
const header_type * addReplace(uint16_t tag, const void *data, size_t count)
Add or replace the record with the given tag.
nrfcxx::utility::Persist::erased
size_t erased() const
Return the number of bytes that can be reclaimed if the region is extracted and restored.
Definition: utility.hpp:535
nrfcxx::utility::Persist::gc
int gc()
Extract, clear, and restore the page contents.
nrfcxx::utility::Persist::restore
int restore(const header_type *buffer, size_t length)
Replay extracted records into the persisted region.
nrfcxx::utility::Persist::header_type
Header identifying record content and its span.
Definition: utility.hpp:338
nrfcxx::utility::memory_pool::size
size_t size() const
Return the number of allocated bytes in the region.
Definition: utility.hpp:192
nrfcxx::utility::Persist::find
const header_type * find(uint16_t tag)
Find the record with the given tag, if it is present.
Definition: utility.hpp:426
core.hpp
Primary header for nrfcxx interface dependencies.
nrfcxx::utility::Persist::header_type::span
uint16_t span
Span of the record in words, including the header.
Definition: utility.hpp:340
nrfcxx::utility::memory_pool::align_bits
static constexpr unsigned int align_bits
The number of bits used for alignment of the return pointers.
Definition: utility.hpp:60
nrfcxx::utility::memory_pool::clear
void clear()
Release all allocations from the pool.
Definition: utility.hpp:179
nrfcxx::FailSafeCode
FailSafeCode
Enumerated constants used in failsafe() calls.
Definition: core.hpp:719
nrfcxx::utility::Persist::code_
const FailSafeCode code_
Code used in failsafe resets related to persistence failures.
Definition: utility.hpp:551
nrfcxx
Primary namespace for nrfcxx functionality.
Definition: clock.hpp:17
nrfcxx::utility::Persist::available
size_t available() const
Return the number of bytes available for payload in a new record.
Definition: utility.hpp:523
nrfcxx::utility::Persist::configure
int configure(const uint32_t *begin, const uint32_t *end)
Configure the instance to operate on a specific persisted region.
nrfcxx::utility::memory_pool::allocate
void * allocate(size_t span)
Allocate a block of at least span bytes.
Definition: utility.hpp:211
nrfcxx::utility::memory_pool::scoped
RAII class to maintain a shared memory pool within a block scope.
Definition: utility.hpp:81