amp-embedded-infra-lib
Introduction
amp-embedded-infra-lib is a set of C++ libraries and headers that provide heap-less, STL like, infrastructure for embedded software development. It includes, amongst others; a hardware abstraction layer (HAL), a remote procedure call (RPC) implementation for TCP/IP and Serial communication, a networking layer, a secure upgrade mechanism and several other re-usable utility classes.
amp-embedded-infra-lib is available as Philips Open Source under a MIT license.
infra
The infra
package contains the building blocks that all further code is built upon. There are basics concept like infra::MemoryRange
that provides an abstraction for a block of memory and several Containers that provide fixed-size alternatives for the well-known standard library containers like: std::vector
, std::list
, std::queue
, etc.
In the next few chapters the contents of the components within infra
will be described.
util
infra::BoundedString
infra::BoundedString
is similar to std::string
except that it can contain a maximum number of characters, and is not zero-terminated by default (see GitHub issue #37).
infra::BoundedString::WithStorage<5> string("abc");
EXPECT_EQ('a', string.front());
EXPECT_EQ('c', string.back());
EXPECT_FALSE(string.empty());
EXPECT_FALSE(string.full());
EXPECT_EQ(3, string.size());
EXPECT_EQ(5, string.max_size());
infra::CyclicBuffer
infra::CyclicBuffer
transforms a given chunk of memory into a cyclic buffer. Data can be pushed into this buffer, and popped out again. With ContiguousRange(), the largest block starting at the start can be obtained. This is useful when feeding large blocks to e.g. DMA. In practise, the typedef CyclicByteBuffer will most often be used.
infra::CyclicBuffer<uint8_t>::WithStorage<4> buffer;
buffer.Push(std::vector<uint8_t>{ 3, 7, 9 });
buffer.Pop(2);
buffer.Push(std::vector<uint8_t>{ 2, 4 });
EXPECT_EQ((std::vector<uint8_t>{ 9, 2 }), buffer.ContiguousRange());
EXPECT_EQ(3, buffer.Size());
EXPECT_EQ(1, buffer.Available());
infra::Function
infra::Function
is similar to std::function
. It is an object which can contain any callable function object, e.g. free function pointers and lambda expressions. A Function is declared by providing the function signature and optionally extra storage space for the function. For example, infra::Function<void()> f;
declares a function object f
that has a void return-type and no parameters. infra::Function<int(char x)> g;
declares a function object g
that has an int
return-type and one parameter of type char
.
Examples:
Function<void()> f = [this]() { Trigger(); };
if (f)
f(); // Call the lambda function which calls this->Trigger
f = nullptr; // Clear the function
Since no heap is used, all data used by the function object must be stored inside Function itself. The amount of data necessary is not known upfront, so the Function is parameterized with an ExtraSize parameter to reserve storage. For example, this lambda expression requires no storage: []() {}
while this expression requires 8 bytes of extra storage on a 32-bit platform: [this, &x]() { DoSomething(x); }
.
Function<void()> f = [this, &x]() { DoSomething(x); }; // Compile error, too much storage is needed
Function<void(), 2 * sizeof(void*)> g = [this, &x]() { DoSomething(x); }; // Ok.