Skyward boardcore
Loading...
Searching...
No Matches
SensorManager.cpp
Go to the documentation of this file.
1/* Copyright (c) 2020 Skyward Experimental Rocketry
2 * Author: Luca Conterio
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a copy
5 * of this software and associated documentation files (the "Software"), to deal
6 * in the Software without restriction, including without limitation the rights
7 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 * copies of the Software, and to permit persons to whom the Software is
9 * furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 * THE SOFTWARE.
21 */
22
23#include "SensorManager.h"
24
25#include <utils/Debug.h>
26
27namespace Boardcore
28{
29
31 : scheduler(new TaskScheduler()), customScheduler(true)
32{
33 if (!init(sensorsMap))
34 LOG_ERR(logger, "Initialization failed");
35}
36
38 TaskScheduler* scheduler)
39 : scheduler(scheduler), customScheduler(false)
40{
41 if (!init(sensorsMap))
42 LOG_ERR(logger, "Initialization failed");
43}
44
46{
47 for (auto sampler : samplers)
48 delete sampler;
49 if (customScheduler)
50 delete scheduler;
51}
52
54{
55 if (customScheduler)
56 scheduler->start();
57 return initResult;
58}
59
60void SensorManager::stop() { scheduler->stop(); }
61
63{
64 if (samplersMap.find(sensor) != samplersMap.end())
65 {
66 samplersMap[sensor]->toggleSensor(sensor, true);
67 }
68 else
69 {
70 LOG_ERR(logger, "Can't enable sensor {} it does not exist",
71 static_cast<void*>(sensor));
72 }
73}
74
76{
77 if (samplersMap.find(sensor) != samplersMap.end())
78 {
79 samplersMap[sensor]->toggleSensor(sensor, false);
80 }
81 else
82 {
83 LOG_ERR(logger, "Can't disable sensor {}, it does not exist",
84 static_cast<void*>(sensor));
85 }
86}
87
89{
90 for (auto sampler : samplers)
91 sampler->enableAllSensors();
92}
93
95{
96 for (auto sampler : samplers)
97 sampler->disableAllSensors();
98}
99
100bool SensorManager::areAllSensorsInitialized() { return initResult; }
101
103{
104 if (samplersMap.find(sensor) != samplersMap.end())
105 return samplersMap[sensor]->getSensorInfo(sensor);
106
107 LOG_ERR(logger, "Sensor {} not found, can't return SensorInfo",
108 static_cast<void*>(sensor));
109
110 return SensorInfo{};
111}
112
113const vector<TaskStatsResult> SensorManager::getSamplersStats()
114{
115 return scheduler->getTaskStats();
116}
117
118bool SensorManager::init(const SensorMap_t& sensorsMap)
119{
120 uint8_t currentSamplerId = getFirstTaskID();
121
122 if (currentSamplerId != 0)
123 {
124 LOG_DEBUG(logger, "Task scheduler not empty: starting from task ID {}",
125 currentSamplerId);
126 }
127
128 for (auto it : sensorsMap)
129 {
130 AbstractSensor* sensor = it.first;
131 SensorInfo sensorInfo = it.second;
132
133 LOG_DEBUG(logger, "Initializing sensor {}", sensorInfo.id);
134 // Try to initialize the sensors
135 if (!initSensor(sensor))
136 {
137 sensorInfo.isEnabled = false;
138
139 initResult = false;
140
141 LOG_ERR(
142 logger,
143 "Failed to initialize sensor {} -> Error: {} (period: {} ns)",
144 sensorInfo.id.c_str(), sensor->getLastError(),
145 sensorInfo.period.count());
146 }
147 else
148 {
149 sensorInfo.isInitialized = true;
150 }
151
152 // Add sensor even if not initialized correctly, its isInitialized info
153 // field will be false
154 LOG_DEBUG(logger, "Adding {} -> period: {} ns, enabled = {}",
155 sensorInfo.id.c_str(), sensorInfo.period.count(),
156 sensorInfo.isEnabled);
157
158 // Check if a sampler with the same sampling period exists
159 bool found = false;
160 for (auto sampler : samplers)
161 {
162 if (sensorInfo.period == sampler->getSamplingPeriod())
163 {
164 sampler->addSensor(sensor, sensorInfo);
165 samplersMap[sensor] = sampler;
166 found = true;
167 }
168 }
169
170 if (!found)
171 {
172 // A sampler with the required period does not exist yet
173 SensorSampler* newSampler =
174 createSampler(currentSamplerId, sensorInfo.period);
175
176 newSampler->addSensor(sensor, sensorInfo);
177
178 samplers.push_back(newSampler);
179 samplersMap[sensor] = newSampler;
180
181 if (currentSamplerId == MAX_TASK_ID)
182 {
183 LOG_WARN(logger,
184 "Max task ID (255) reached in task scheduler, IDs "
185 "will start again from 0");
186 }
187
188 currentSamplerId++;
189 }
190 }
191
192 initScheduler();
193
194 return initResult;
195}
196
197bool SensorManager::initSensor(AbstractSensor* sensor)
198{
199 return sensor->init() && sensor->selfTest();
200}
201
202void SensorManager::initScheduler()
203{
204 // Sort the vector to have lower period samplers (higher frequency) inserted
205 // before higher period ones into the TaskScheduler
206 std::stable_sort(samplers.begin(), samplers.end(),
208
209 // Add all the samplers to the scheduler
210 for (auto& sampler : samplers)
211 {
212 function_t samplerUpdateFunction([=]()
213 { sampler->sampleAndCallback(); });
214
215 scheduler->addTask(samplerUpdateFunction, sampler->getSamplingPeriod(),
217 }
218}
219
220uint8_t SensorManager::getFirstTaskID()
221{
222 std::vector<TaskStatsResult> tasksStats = scheduler->getTaskStats();
223
224 if (tasksStats.empty())
225 return 0;
226
227 auto max = std::max_element(
228 tasksStats.begin(), tasksStats.end(),
229 [](const TaskStatsResult& t1, const TaskStatsResult& t2)
230 { return t1.id < t2.id; });
231
232 return max->id + 1;
233}
234
235SensorSampler* SensorManager::createSampler(uint8_t id,
236 std::chrono::nanoseconds period)
237{
238 LOG_DEBUG(logger, "Creating Sampler {} with sampling period {} ns", id,
239 period.count());
240
241 return new SimpleSensorSampler(id, period);
242}
243
244} // namespace Boardcore
#define LOG_WARN(logger,...)
#define LOG_ERR(logger,...)
#define LOG_DEBUG(logger,...)
Base abstract class for sensor drivers.
Definition Sensor.h:52
std::map< AbstractSensor *, SensorInfo > SensorMap_t
bool start()
Starts the task scheduler.
void enableSensor(AbstractSensor *sensor)
Enable sampling for the specified sensor.
void stop()
Starts the task scheduler.
bool areAllSensorsInitialized()
Checks whether all the sensors have been initialized correctly.
std::function< void()> function_t
SensorManager(const SensorMap_t &sensorsMap)
~SensorManager()
Deallocates samplers (through the samplers vector).
void disableSensor(AbstractSensor *sensor)
Disable sampling for the specified sensor.
const SensorInfo getSensorInfo(AbstractSensor *sensor)
const vector< TaskStatsResult > getSamplersStats()
static bool compareByPeriod(SensorSampler *left, SensorSampler *right)
The Task Scheduler allow to manage simple tasks with a single thread. All the task added must not tak...
std::vector< TaskStatsResult > getTaskStats()
bool start() override
Start the thread associated with this active object.
@ RECOVER
Prioritize the number of executions over the period.
void stop() override
Signals the runner thread to terminate and joins the thread.
size_t addTask(function_t function, uint32_t periodMs, Policy policy=Policy::RECOVER, int64_t startTick=Kernel::getOldTick())
Add a millisecond-period task function to the scheduler with an auto generated ID.
Driver for the VN100S IMU.
Sensors information struct needed by the SensorManager.
Definition SensorInfo.h:42