... | ... | @@ -4,37 +4,51 @@ Sensors are periodically sampled and their corresponding callback is called, so |
|
|
|
|
|
## Main Elements
|
|
|
|
|
|
### Sensor Info
|
|
|
The `SensorInfo` strucutre defines an information set needed by the `SensorManager` along with the sensor itself
|
|
|
|
|
|
It contains:
|
|
|
* The sampling period for the given sensor.
|
|
|
* A callback function to be called after the sensor is sampled.
|
|
|
* A boolean value indicating whether the sensor uses DMA or not.
|
|
|
* A boolean value indicating whether the sensor is enabled or not (i.e. the sensor has to be sampled or not).
|
|
|
|
|
|
### Sensor Sampler
|
|
|
|
|
|
Sensors are grouped according to the required sampling frequency and to the fact that they use DMA or not.
|
|
|
Sensors are grouped according to the required sampling period and to the fact that they use DMA or not.
|
|
|
|
|
|
A `SensorSampler` is characterized by a type (`SIMPLE_SAMPLER` or `DMA_SAMPLER`), the sampling frequency and a set of sensors.
|
|
|
A `SensorSampler` is characterized by the sampling period and a set of sensors.
|
|
|
|
|
|
In particular, the `SensorSampler` class maintains a `map<Sensor*, function<void()>>` that maps each sensor to its corresponding callback function.
|
|
|
Every time the `sampleAndCallback()` method of the `SensorSampler` is called, the sampler cycles through all its sensors, samples them and calls their corresponding callback, where these samples can be processed and dispatched.
|
|
|
In particular, the `SensorSampler` class maintains a `vector<pair<AbstractSensor*, SensorInfo>>` that maps each sensor to its corresponding information.
|
|
|
Every time the `sampleAndCallback()` method of the `SensorSampler` is called, the sampler cycles through all its sensors, samples them (the enabled ones) and calls their corresponding callback, where these samples can be processed and dispatched.
|
|
|
|
|
|
Since `SensorSampler` is a virtual class, two sub-classes exist:
|
|
|
* **SimpleSensorSampler**: its type is `SIMPLE_SAMPLER`. In order to perform a sampling it calls the sensor's `onSimpleUpdate()` method.
|
|
|
* **DMASensorSampler**: its type is `DMA_SAMPLER`. It only manages sensors that use DMA. In order to perform a sampling it calls the sensor's `onDMAUpdate()` method.
|
|
|
* **SimpleSensorSampler**: for sensors that does not use DMA. In order to perform a sampling it calls the sensor's `sample()` method.
|
|
|
* **DMASensorSampler**: not implemented yet :no_entry_sign:
|
|
|
|
|
|
### Sensor Manager
|
|
|
In order to add a sensor to the `SensorManager`, the `addSensor()` method is provided: simply pass it the sensor, the required sampling frequency, the callback function and the sampler type (that has default value equal to `SIMPLE_SAMPLER`).
|
|
|
In order to add sensors to the `SensorManager` a map correlating each sensor to its `SensorInfo` object has to be passed to the constructor.
|
|
|
|
|
|
Every time a sensor is added, the `SensorManager` assigns it to a `SensorSampler`, according to the required sampling frequency and the sampling type.
|
|
|
If a `SensorSampler` for that frequency and type doesn't exist, the `SensorManager` manages its creation.
|
|
|
When the `SensorManager` is instantiated, each sensor is assigned to a `SensorSampler`, according to the required sampling period and the sampling type (DMA or not).
|
|
|
If a `SensorSampler` for that sampling period and type doesn't exist, the `SensorManager` manages its creation.
|
|
|
|
|
|
Note that when a sensor is added, it is also initialized (via `init()`) and `selfTest()` is performed.
|
|
|
The sensor will be added only if both the initialization and the test succeed.
|
|
|
|
|
|
When `start()` is called, the `SensorManager` initializes the `TaskScheduler`: for each `SensorSampler`, it adds to the scheduler the `sampleAndCallback()` method to be called periodically according to the sampler's frequency.
|
|
|
When `start()` is called, the `SensorManager` initializes the `TaskScheduler`: for each `SensorSampler`, it adds to the scheduler the `sampleAndCallback()` method to be called periodically according to the sampler's period.
|
|
|
Samplers with lower period are added to the `TaskScheduler` before the ones that have higher period (see `TaskScheduler`'s warning).
|
|
|
|
|
|
> :information_source: **The `SensorManager` also exposes method to enable/disable sensors at runtime, but the list of existing sensors in the `SensorManager` can not be changed after its creation.**
|
|
|
|
|
|
> :information_source: **An externally created `TaskScheduler` can be passed to the `SensorManager` constructor. In this case `SensorSampler` will be added to the existing scheduler, instead of creating a new one, starting from the higher task ID existing.**
|
|
|
|
|
|
## Component Behavior
|
|
|
It might seem tricky and complex, so in order to simplify the understanding we can schematize the component's behavior.
|
|
|
|
|
|
We outline three phases:
|
|
|
1. In the first phase sensors are added to the `SensorManager`, that assigns them to the correct `SensorSampler`, along with the corresponding callback.
|
|
|
2. When the `SensorManager` is started, for each sampler it schedules a periodic task, according to the required frequency.
|
|
|
3. From that point on, the `TaskScheduler` periodically calls the `SensorSampler` objects. When called, each sampler performs the sampling of all the sensors it manages and for each of them calls the associated callback.
|
|
|
1. In the first phase sensors are added to the `SensorManager`, that assigns them to the correct `SensorSampler`, along with the corresponding period, callback and booleans indicating if it is enabled or if it uses DMA.
|
|
|
2. When the `SensorManager` is started, for each sampler it schedules a periodic task, according to the required sampling period.
|
|
|
3. From that point on, the `TaskScheduler` periodically calls the `SensorSampler` objects. When called, each sampler performs the sampling of all the enabled sensors it manages and for each of them calls the associated callback.
|
|
|
|
|
|
<div align="center"><img src="images/sensor_manager/SensorManager_flowchart.png" height="500"/><br/><i></i></div><br>
|
|
|
|
... | ... | @@ -49,44 +63,52 @@ This example refers to the `TestSensor` class defined in [Sensor.h](Sensor). |
|
|
For more details see how to create a sensor, visit that page.
|
|
|
|
|
|
#### Step 2: Sampling the sensor
|
|
|
Include needed modules, define your sensor and the `SensorManager`.
|
|
|
```cpp
|
|
|
#include <miosix.h>
|
|
|
#include <sensors`SensorManager`.h>
|
|
|
#include "TestSensor.h"
|
|
|
SensorManager sensor_manager;
|
|
|
TestSensor* sensor;
|
|
|
```
|
|
|
Define the callback that will be passed to the `SensorSampler`, along with the sensor.
|
|
|
Define the callbacks that will be passed to the `SensorSampler`, along with the sensors.
|
|
|
Inside the callback you can get the sampled data from the sensor and perform operations on it.
|
|
|
```cpp
|
|
|
void testCallback() {
|
|
|
float data = sensor->getData();
|
|
|
printf("Test data : %f \n", data);
|
|
|
void testCallback1() {
|
|
|
float data = sensor1.getLastSample().value;
|
|
|
printf("Test data 1: %f \n", data);
|
|
|
}
|
|
|
|
|
|
void testCallback2() {
|
|
|
float data = sensor2.getLastSample().value;
|
|
|
printf("Test data 2: %f \n", data);
|
|
|
}
|
|
|
```
|
|
|
You can use `std::bind()` in order to bind your callback to an `std::function<void()>>` object.
|
|
|
Select the required frequency for the sampling and add the sensor and the callback to the `SensorManager`.
|
|
|
Select the required period for the sampling and create a map that associates each sensor to its `SensorInfo`.
|
|
|
|
|
|
You can now create and start the `SensorManager`.
|
|
|
|
|
|
You can now start the `SensorManager`.
|
|
|
```cpp
|
|
|
#include <miosix.h>
|
|
|
#include <sensors/SensorManager.h>
|
|
|
#include "TestSensor.h"
|
|
|
|
|
|
int main() {
|
|
|
|
|
|
uint32_t frequency = 10; // 10 Hz
|
|
|
std::function<void()> callback = std::bind(&testCallback);
|
|
|
sensor = new TestSensor();
|
|
|
TestSensor sensor1;
|
|
|
uint32_t period1 = 1000; // 1 Hz
|
|
|
std::function<void()> callback1 = std::bind(&testCallback1);
|
|
|
SensorInfo info1(/*Period=*/period1, /*Callback=*/callback1, /*DMA=*/false, /*Enabled=*/true);
|
|
|
|
|
|
TestSensor sensor2;
|
|
|
uint32_t period2 = 500; // 2 Hz
|
|
|
std::function<void()> callback2 = std::bind(&testCallback2);
|
|
|
SensorInfo info2(/*Period=*/period2, /*Callback=*/callback2, /*DMA=*/false, /*Enabled=*/true);
|
|
|
|
|
|
std::map<AbstractSensor*, SensorInfo> sensors_map = {
|
|
|
{ &sensor1, info1 },
|
|
|
{ &sensor2, info2 }
|
|
|
};
|
|
|
|
|
|
sensor_manager.addSensor(sensor, frequency, callback, SIMPLE_SAMPLER);
|
|
|
SensorManager SM(sensors_map);
|
|
|
|
|
|
sensor_manager.start();
|
|
|
|
|
|
// avoid the program to stop
|
|
|
for (;;)
|
|
|
{
|
|
|
miosix::ledOn();
|
|
|
miosix::Thread::sleep(1000);
|
|
|
miosix::ledOff();
|
|
|
miosix::Thread::sleep(1000);
|
|
|
}
|
|
|
}
|
|
|
``` |
|
|
\ No newline at end of file |