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.
This file includes all the types the logdecoder script will decode.
Sensors information struct needed by the SensorManager.
Definition SensorInfo.h:42