Added io_port documentation

This commit is contained in:
John Wellbelove 2026-04-11 18:37:44 +02:00
parent 4aa3d945f9
commit 83db4f0366
3 changed files with 410 additions and 354 deletions

410
docs/IO/io_port.md Normal file
View File

@ -0,0 +1,410 @@
---
title: "io_port"
---
{{< callout type="info">}}
Header: `io_port.h`
Supported: `20.39.0`
{{< /callout >}}
A set of templates for building interface classes to memory mapped hardware ports.
They avoid the need to directly map carefully packed (and possibly non-portable) structures onto memory addresses.
>A read from a write-only, or write to a read-only port will result in a compile time error.
**Defines classes for the following IO types**
Read / Write.
Read only.
Write only.
Write only with shadow register.
With a shadow register the value written is stored locally and may be read back.
The port may either have an address fixed at compile time or set at runtime. The compile time versions require no extra overhead compared to a plain memory mapped structure.
Ports may be sent as parameters to algorithms that expect iterators, except the runtime address version of `io_port_wos`, which must use the built-in iterator if the shadow value is to be correctly updated for writes.
All classes define the following typedefs.
| Type name | Maps to |
| ----------------- | ------------------- |
| `value_type` | `T` |
| `pointer` | `volatile T*` |
| `const_pointer` | `volatile const T*` |
| `reference` | `volatile T&` |
| `const_reference` | `volatile const T&` |
## Read/write port
```cpp
io_port_rw<typename T, uintptr_t Address>
```
**Description**
Compile time port address.
---
**Types**
iterator
const_iterator
---
```cpp
operator T() const
```
**Description**
Read the value.
Conversion operator to T.
---
```cpp
iterator iter()
```
**Description**
Get an iterator to this port.
---
```cpp
const_iterator iter() const
const_iterator citer() const
```
**Description**
Get a const_iterator to this port.
---
```cpp
T read() const
```
**Description**
Read the value.
---
```cpp
void write(T value)
```
**Description**
Write the value.
---
```cpp
io_port_rw& operator =(T value)
```
**Description**
Write the value.
---
```cpp
pointer get_address()
const_pointer get_address() const
**Description**
Gets the address of the port.
---
```cpp
io_port_rw& operator |=(value_type value)
```
**Description**
Or-Equals operator.
---
```cpp
io_port_rw& operator &=(value_type value)
```
**Description**
And-Equals operator.
---
```cpp
io_port_rw& operator ^=(value_type value)
```
**Description**
Exclusive-Or-Equals operator.
---
```cpp
io_port_rw& operator <<=(int shift)
```
**Description**
Left-Shift-Equals operator.
---
```cpp
io_port_rw& operator >>=(int shift)
```
**Description**
Right-Shift-Equals operator.
---
```cpp
value_type operator ~() const
```
**Description**
Not operator.
## Read only port
```cpp
io_port_ro<typename T, uintptr_t Address>
```
---
**Types**
```cpp
const_iterator
```
---
```cpp
operator T() const
```
**Description**
Read the value. Conversion operator to T.
---
```cpp
const_iterator iter() const
const_iterator citer() const
```
**Description**
Get a const_iterator to this port.
---
```cpp
T read() const
```
**Description**
Read the value.
---
```cpp
const_pointer get_address() const
```
**Description**
Gets the address of the port.
## Write only port
```cpp
io_port_wo<typename T, uintptr_t Address>
```
---
**Types**
iterator
---
```cpp
iterator iter()
```
**Description**
Get an iterator to this port.
---
```cpp
void write(T value)
```
**Description**
Write the value.
---
```cpp
io_port_wo& operator =(T value)
```
**Description**
Write the value.
---
```cpp
pointer get_address()
```
**Description**
Gets the address of the port.
## Write only port, with shadow register
```cpp
io_port_wos<typename T, uintptr_t Address>
```
---
**Types**
```cpp
iterator
const_iterator
```
---
```cpp
operator T() const
```
**Description**
Read the value. Conversion operator to `T`.
---
```cpp
iterator iter()
```
**Description**
Get an iterator to this port.
---
```cpp
const_iterator iter() const
const_iterator citer() const
```
**Decsription**
Get a `const_iterator` to this port.
---
```cpp
T read() const
```
**Description**
Read the value.
---
```cpp
void write(T value)
```
**Description**
Write the value.
---
```cpp
io_port_rw& operator =(T value)
```
**Description**
Write the value.
---
```cpp
pointer get_address()
const_pointer get_address() const
```
**Description**
Gets the address of the port.
---
```cpp
io_port_rw& operator |=(value_type value)
```
**Description**
Or-Equals operator.
---
```cpp
io_port_rw& operator &=(value_type value)
```
**Description**
And-Equals operator.
---
```cpp
io_port_rw& operator ^=(value_type value)
```
**Description**
Exclusive-Or-Equals operator.
---
```cpp
io_port_rw& operator <<=(int shift)
```
**Description**
Left-Shift-Equals operator.
---
```cpp
io_port_rw& operator >>=(int shift)
```
**Description**
Right-Shift-Equals operator.
---
```cpp
value_type operator ~() const
```
**description**
Not operator.
## Example serial port
The example uses a port at a compile time address.
| Variable | Description |
| --------- | ---------------------------------------------------------- |
| `rxdata` | An 8 bit read only port |
| `txdata` | An 8 bit write only port |
| `control` | A 16 bit write only port, with shadow register |
| `status` | A 16 bit read only port. It shares an address with control |
| `option` | An 8 bit read/write port |
```cpp
template <uintptr_t Address>
struct serial_port
{
etl::io_port_ro<char, Address> rxdata; // Read only rx data register.
etl::io_port_wo<char, Address + 1> txdata; // Write only tx register.
etl::io_port_wos<uint16_t, Address + 2> control; // Write only, with shadow, control register.
etl::io_port_ro<uint16_t, Address + 2> status; // Read only status register.
etl::io_port_ro<char, Address> option; // Read/Write register.
};
serial_port<0x800> port; // A serial port at address 0x800
// Read Rx data
char data = port.rxdata;
// Write Tx data
port.txdata = 'A';
// Compile error! txdata is write only.
data = port.txdata;
// Write to the control register and read back what we wrote.
port.control = 0x1234;
uint16_t control = port.control;
// Flip bit 3 of the control register.
port.control ^= 0x0080;
// Read from the status register.
uint16_t status = port.status;
// Copy data from a buffer to the Tx data port.
std::copy(txBuffer.begin(), txBuffer.end(), serial_port.txdata.iter());
// Copy data from the Rx data port to a buffer.
std::copy_n(serial_port.rxdata, serial_port.status, std::back_inserter(rxBuffer));
```

View File

@ -1,148 +0,0 @@
debounce
A class to debounce signals.
Can detect signal hold and generate auto repeat.
etl::debounce<uint16_t VALID_COUNT = 0,
uint16_t HOLD_COUNT = 0,
uint16_t REPEAT_COUNT = 0>
There are four variants of the class which are selected at compile time according to the supplied template parameters.
All of the template parameters are optional.
If the first parameter is supplied then the debouncer acts as a simple signal debounce. The signal will become valid after VALID_COUNT identical samples have been added.
If the second parameter is supplied then the debouncer will detect the signal being held true for HOLD_COUNT samples after becoming valid.
If the third parameter is supplied then the debouncer will indicate that a change has occurred for the signal being held true for each REPEAT_COUNT that occurs after entering the hold state.
If no template parameters are supplied then the template variant using internal variables is used. This has similar parameters supplied to the constructor or the set member function.
The diagram below shows the effect of the various parameters.
Functions
debounce(bool initial_state = false)
Default constructor. The initial state defaults to false.
debounce(bool initial_state,
uint16_t valid_count = 1,
uint16_t hold_count = 0,
uint16_t repeat_count = 0)
The constructor available when no template parameters are supplied.
bool add(bool sample)
Adds a new signal sample. Returns true if the state of the debouncer becomes valid, held or repeating.
bool has_changed() const
Returns true if the state of the debouncer became valid, held or repeating after the last sample
bool is_set() const
Returns true if the debouncer is set, false if cleared.
bool is_held() const
Returns true if the debouncer signal is being held.
bool is_repeating() const
Returns true if the debouncer signal is repeating.
void set(uint16_t valid_count, uint16_t hold_count = 0, uint16_t repeat_count = 0)
Sets the debouncer parameters. Only available when no template parameters are supplied.
Examples
etl::debounce<20> debouncer;
Simple debounce.
Valid after 20 identical samples.
etl::debounce<20, 1000> debouncer;
Key debounce.
Valid after 20 identical samples.
Hold detection after 1000 'set' samples.
etl::debounce<20, 1000, 100> debouncer;
Key debounce with hold and auto repeat.
Valid after 20 identical samples.
Hold detection after 1000 'set' samples.
Repeat every 100 samples after hold.
etl::debounce<> debouncer;
debouncer.set(20, 1000, 100);
Key debounce with hold and auto repeat.
Runtime parameters.
The example below targets the Arduino hardware.
//***********************************************************************************
// A debounce demo that reads a key and toggles the LED.
// Set the pin to the correct one for your key.
//***********************************************************************************
#include <debounce.h>
// The sample time in ms.
const int SAMPLE_TIME = 1;
// The number of samples that must agree before a key state change is recognised.
// 50 = 50ms for 1ms sample time.
const int DEBOUNCE_COUNT = 50;
// The number of samples that must agree before a key held state is recognised.
// 1000 = 1s for 1ms sample time.
const int HOLD_COUNT = 1000;
// The number of samples that must agree before a key repeat state is recognised.
// 200 = 200ms for 1ms sample time.
const int REPEAT_COUNT = 200;
// The pin that the key is attached to.
const int KEY = XX;
void setup()
{
// Initialize LED pin as an output.
pinMode(LED_BUILTIN , OUTPUT);
digitalWrite(LED_BUILTIN, LOW);
// Initialize KEY pin as an input.
pinMode(KEY, INPUT);
}
void loop()
{
static int led_state = LOW;
static etl::debounce<DEBOUNCE_COUNT, HOLD_COUNT, REPEAT_COUNT> key_state;
// Assumes 'HIGH' is 'pressed' and 'LOW' is 'released'.
if (key_state.add(digitalRead(KEY) == HIGH))
{
if (key_state.is_set())
{
// Toggle the LED state on every validated press or repeat.
led_state = (led_state == LOW ? HIGH : LOW);
digitalWrite(LED_BUILTIN, led_state);
}
}
delay(1); // Wait 1ms
}

View File

@ -1,206 +0,0 @@
---
title: "Base64"
---
{{< callout type="info">}}
Header: `base64.h`
`base64_encoder.h`
`base64_decoder.h
Supported: `20.38.4`
{{< /callout >}}
Encodes and decodes data to and from Base64 format.
____________________________________________________________________________________________________
Encode
Input -> pointer/length : Output -> pointer/length
template <typename T>
ETL_CONSTEXPR14
static
size_t encode(const T* input, size_t input_length,
char* output, size_t output_length)
Transforms the input data described by input and input_length to Base64 format to be stored in output output_length.
Returns the length of the encoded data.
If output_length is not large enough to hold the encoded data then an etl::base64_overflow is raised.
Enabled if etl::is_integral<T> is true and etl::integral_limits<T>::bits == 8
____________________________________________________________________________________________________
Input -> pointer/length : Output -> string
template <typename T>
ETL_CONSTEXPR14
static
size_t encode(const T* input, size_t input_length,
etl::istring& output)
Transforms the input data described by input and input_length to Base64 format to be stored in output.
The output string must have capacity of at least etl::base64::encode_size(input).
Returns the length of the encoded data.
If output_length is not large enough to hold the encoded data then an etl::base64_overflow is raised.
Enabled if etl::is_integral<T> is true and etl::integral_limits<T>::bits == 8
____________________________________________________________________________________________________
Input -> pointer/pointer : Output -> pointer/pointer
template <typename T>
ETL_CONSTEXPR14
static
size_t encode(const T* input_begin, const T* input_end,
char* output_begin, char* output_end)
Transforms the input data described by input_begin and input_end to Base64 format to be stored in output_begin to output_end.
Returns the length of the encoded data.
If the output buffer is not large enough to hold the encoded data then an etl::base64_overflow is raised.
Enabled if etl::is_integral<T> is true and etl::integral_limits<T>::bits == 8
____________________________________________________________________________________________________
Input -> pointer/pointer : Output -> string
template <typename T>
ETL_CONSTEXPR14
static
size_t encode(const T* input_begin, const T* input_end,
etl::istring& output)
Transforms the input data described by input_begin and input_end to Base64 format to be stored in output.
The output string must have capacity of at least etl::base64::encode_size(input).
Returns the length of the encoded data.
If the output buffer is not large enough to hold the encoded data then an etl::base64_overflow is raised.
Enabled if etl::is_integral<T> is true and etl::integral_limits<T>::bits == 8
____________________________________________________________________________________________________
Input -> span : Output -> span
template <typename T, size_t Length1, size_t Length2>
ETL_CONSTEXPR14
static
size_t encode(const etl::span<const T, Length1>& input_span,
const etl::span<char, Length2>& output_span)
Transforms the input data described by input_span to Base64 format to be stored in output_span.
Returns the length of the encoded data.
If the output span is not large enough to hold the encoded data then an etl::base64_overflow is raised.
Enabled if etl::is_integral<T> is true and etl::integral_limits<T>::bits == 8
____________________________________________________________________________________________________
Input -> span : Output -> string
template <typename T, size_t Length>
ETL_CONSTEXPR14
static
size_t encode(const etl::span<const T, Length>& input_span,
etl::istring& output)
Transforms the input data described by input_span to Base64 format to be stored in output.
The output string must have capacity of at least etl::base64::encode_size(input).
Returns the length of the encoded data.
If the output span is not large enough to hold the encoded data then an etl::base64_overflow is raised.
Enabled if etl::is_integral<T> is true and etl::integral_limits<T>::bits == 8
____________________________________________________________________________________________________
ETL_NODISCARD
ETL_CONSTEXPR14
static
size_t encode_size(size_t input_length)
Returns the size of the output buffer required to encode the specified input data length.
____________________________________________________________________________________________________
Decode
Input -> pointer/length : Output -> pointer/length
template <typename T>
ETL_CONSTEXPR14
static
size_t decode(const char* input, size_t input_length,
T* output, size_t output_length)
Transforms the Base64 format input data described by input and input_length to by output and output_length.
Returns the length of the decoded data.
If output_length is not large enough to hold the decoded data then an etl::base64_overflow is raised.
Enabled if etl::is_integral<T> is true and etl::integral_limits<T>::bits == 8
____________________________________________________________________________________________________
Input -> pointer/pointer: Output -> pointer/pointer
template <typename T>
ETL_CONSTEXPR14
static
size_t decode(const char* input_begin, const char* input_end,
T* output_begin, T* output_end)
Transforms the Base64 format input data described by input_begin and input_end to output_begin and output_end.
Returns the length of the decoded data.
If the output buffer is not large enough to hold the decoded data then an etl::base64_overflow is raised.
Enabled if etl::is_integral<T> is true and etl::integral_limits<T>::bits == 8
____________________________________________________________________________________________________
Input -> span: Output -> span
template <typename T, size_t Length1, size_t Length2>
ETL_CONSTEXPR14
static
size_t decode(const etl::span<const char, Length1>& input_span,
const etl::span<T, Length2>& output_span)
Transforms the Base64 format input data described by input_span to output_span.
Returns the length of the decoded data.
If the output span is not large enough to hold the decoded data then an etl::base64_overflow is raised.
Enabled if etl::is_integral<T> is true and etl::integral_limits<T>::bits == 8
____________________________________________________________________________________________________
ETL_NODISCARD
ETL_CONSTEXPR14
static
size_t decode_size(const char* input, size_t input_length)
Returns the size of the output buffer required to decode the specified input Base64 data length.
____________________________________________________________________________________________________
ETL_NODISCARD
ETL_CONSTEXPR14
static
size_t decode_size(const char* input_begin, const char* input_end)
Returns the size of the output buffer required to decode the specified input Base64 data length.
____________________________________________________________________________________________________
ETL_NODISCARD
ETL_CONSTEXPR14
static
size_t decode_size(etl::span<const char> input)
Returns the size of the output buffer required to decode the specified input Base64 data length.
____________________________________________________________________________________________________
Examples
Encode
const etl::array<int8_t, 12> input =
{
0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x57, 0x6f, 0x72, 0x6c, 0x64, 0x21 // "Hello World!"
};
etl::string<20> encoded;
size_t encoded_size = etl::base64::encode(input.data(), input.size(),
encoded.data(), encoded.size());
encoded.resize(encoded_size);
// encoded == "OycDQy37KCphrg=="
____________________________________________________________________________________________________
Decode
const etl::string<16> encoded = "OycDQy37KCphrg==";
etl::vector<int8_t, 20> output;
size_t decoded_size = etl::base64::decode(encoded.data(), encoded.size(),
output.data(), output.size());
output.resize(decoded_size);
// output == { 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x57, 0x6f, 0x72, 0x6c, 0x64, 0x21____________________________________________________________________________________________________
Encode
For C++14 or above
const etl::array<int8_t, 12> input =
{
0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x57, 0x6f, 0x72, 0x6c, 0x64, 0x21 // "Hello World!"
};
constexpr size_t length = etl::base64::encode_size(input.size());
etl::string<length> output;
output.uninitialized_resize(output.capacity());
etl::base64::encode(input.data(), input.size(), output.data(), output.size());
// output == "OycDQy37KCphrg=="
____________________________________________________________________________________________________
Decode
For C++14 or above
// "OycDQy37KCphrg=="
constexpr const etl::array<char, 16> input =
{
0x4F, 0x79, 0x63, 0x44, 0x51, 0x79, 0x33, 0x37, 0x4B, 0x43, 0x70, 0x68, 0x72, 0x67, 0x3D, 0x3D
};
constexpr size_t length = etl::base64::decode_size(input.data(), input.size());
etl::vector<int8_t, length> output;
etl::base64::decode(input.data(), input.size(), output.data(), output.size());
// output == { 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x57, 0x6f, 0x72, 0x6c, 0x64, 0x21