Skip to content

Commit

Permalink
Make C standard library overhead configurable
Browse files Browse the repository at this point in the history
* assert may be implemented in a different way than libc.
* std::rand can lead to unnecessary overheads from libc.
* virtual destructors require an operator delete to be present
Signed-off-by: delphi <cpp.create@gmail.com>
  • Loading branch information
asmfreak committed Oct 13, 2021
1 parent ce141d0 commit f5aab3e
Show file tree
Hide file tree
Showing 4 changed files with 123 additions and 53 deletions.
62 changes: 61 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ The integration test application available under `/tests/integration/bootloader/

#### ROM interface

The ROM backend abstracts the specifics of reading and writing your ROM (usually this is the on-chip flash memory).
The ROM backend abstracts the specifics of reading and writing your ROM (usually this is the on-chip flash memory). Usually this memory should NOT be the same memory as the bootloader. Beware of that and design `WRITE_ROM` and `READ_ROM` functions accordingly.

```c++
class MyROMBackend final : public kocherga::IROMBackend
Expand Down Expand Up @@ -205,6 +205,66 @@ class MyCANDriver final : public kocherga::can::ICANDriver
};
```
#### Configuring Kochergá
##### Using random number generation
During normal operations through both serial and CAN interfaces, Kochergá needs a source of random numbers.
The following function specify this source, which you must configure yourself.
You can use this implementation, based on `std::rand` function from C standard library.
```c++
#include <cstdlib>
auto kocherga::getRandomByte() -> std::uint8_t {
return static_cast<std::uint8_t>(std::rand() * std::numeric_limits<std::uint8_t>::max() / RAND_MAX);
}
int main(){
std::srand(SOME_INITIALIZATION_FUNCTION());
// bootloader implementation below
return 0;
}
```

An alternative is to use a generator from C++ standard library:

```c++
#include <random>

auto kocherga::getRandomByte() -> std::uint8_t {
static std::mt19937 rd{SOME_INITIALIZATION_FUNCTION()};
return static_cast<std::uint8_t>(rd() * std::numeric_limits<std::uint8_t>::max() / std::mt19937::max());
}
```

In both cases beware that you need to initialize the psudorandom sequence with `SOME_INITIALIZATION_FUNCTION()`. This function should retrieve a true random or unique value (such as number of seconds since epoch). Look for more information in the respectful documentation of both `srand` and `std::mt19937`

##### Providing custom assert macros

Kochergá uses `assert` macro from stadard C library to check for it's invariants. If this is undesireable in your project, you can redefine the following macros. You can do this before including Kochergá or globally in your build system.

```c++
#define KOCHERGA_ASSERT(x) some_other_assert(x, ...);
#include <kocherga.hpp>
```
You can disable all internal assertions like this:
```c++
#define KOCHERGA_ASSERT(x) (void)(x);
#include <kocherga.hpp>
```

##### Using Kochergá without heap

If your implementation of buffers is stack-only and you don't want to use global heap from C standard library, implement `operator delete` in your code something like this:
```c++
void operator delete(void*) noexcept { std::abort(); }
```
This is needed as Kochergá uses virtual destructors, code generation for which includes an `operator delete` even if deleting an object through pointer to it's base class is not used in your entire application.

#### Passing arguments from the application

When the application is commanded to upgrade itself, it needs to store relevant context into a struct,
Expand Down
16 changes: 14 additions & 2 deletions kocherga/kocherga.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,11 @@
#define KOCHERGA_VERSION_MAJOR 0 // NOLINT
#define KOCHERGA_VERSION_MINOR 2 // NOLINT

#ifndef KOCHERGA_ASSERT
#include <cassert>
#define KOCHERGA_ASSERT(x) assert(x)
#endif

namespace kocherga
{
/// Semantic version number pair: major then minor.
Expand Down Expand Up @@ -226,6 +231,11 @@ class IROMBackend

// --------------------------------------------------------------------------------------------------------------------

/// This function is used in drivers to generate
auto getRandomByte() -> uint8_t;

// --------------------------------------------------------------------------------------------------------------------

/// This is used to verify integrity of the application and other data.
/// Note that the firmware CRC verification is a computationally expensive process that needs to be completed
/// in a limited time interval, which should be minimized. This class has been carefully manually optimized to
Expand Down Expand Up @@ -536,7 +546,7 @@ class Presenter final : public IReactor
system_info_(system_info), controller_(controller)
{}

[[nodiscard]] auto addNode(INode* const node) -> bool
[[nodiscard]] auto addNode(INode* node) -> bool
{
for (const auto* n : nodes_)
{
Expand Down Expand Up @@ -1021,9 +1031,11 @@ class Bootloader : public detail::IController
{}

/// Nodes shall be registered using this method after the instance is constructed.
/// Lifetime of the nodes is managed outside of the Bootloader class.
/// Bootloader does NOT manage lifetimes of nodes.
/// The return value is true on success, false if there are too many nodes already or this node is already
/// registered (no effect in this case).
[[nodiscard]] auto addNode(INode* const node) -> bool { return presentation_.addNode(node); }
[[nodiscard]] auto addNode(INode* node) -> bool { return presentation_.addNode(node); }

/// The number of nodes added with addNode(). Zero by default (obviously).
[[nodiscard]] auto getNumberOfNodes() const -> std::uint8_t { return presentation_.getNumberOfNodes(); }
Expand Down
Loading

0 comments on commit f5aab3e

Please sign in to comment.