Compare commits
34 Commits
main
...
FEAT/multi
Author | SHA1 | Date | |
---|---|---|---|
|
787fa94e91 | ||
|
e460a4f695 | ||
|
a183ad4858 | ||
|
dfd94b647c | ||
|
d0ff3defa1 | ||
|
7d228d67cc | ||
|
7838ed0448 | ||
|
6d42dd2ba1 | ||
|
0ec735adde | ||
|
618ddaaa1b | ||
aed65401f5 | |||
686eff6269 | |||
0d61cd598c | |||
|
55a6594646 | ||
|
3a3d27f93e | ||
|
afa1fb8aef | ||
|
b9c129e872 | ||
|
4fb09c690c | ||
|
62fd302d84 | ||
|
95e92e2564 | ||
980eb2b376 | |||
|
946e86025c | ||
|
36e4a07102 | ||
|
957860b2ff | ||
|
f64b8bdd9a | ||
|
34a57162ba | ||
|
031b98a0f7 | ||
|
ca33d26769 | ||
|
4c9a0e25a7 | ||
|
69bc8785a8 | ||
|
da79a18cd9 | ||
|
c4ff5361e9 | ||
|
7b5bcfc35e | ||
|
c92de22c09 |
2
.gitignore
vendored
2
.gitignore
vendored
@ -4,5 +4,5 @@ projectfiles
|
|||||||
*.py*
|
*.py*
|
||||||
BUILD
|
BUILD
|
||||||
mbed-os
|
mbed-os
|
||||||
DISCO_h747i
|
DISCO_H747I
|
||||||
advdembsof_library
|
advdembsof_library
|
||||||
|
@ -15,3 +15,4 @@ mbed-os/features/frameworks/mbed-client-cli/*
|
|||||||
mbed-os/features/frameworks/COMPONENT_FPGA_CI_TEST_SHIELD/*
|
mbed-os/features/frameworks/COMPONENT_FPGA_CI_TEST_SHIELD/*
|
||||||
mbed-os/platform/randlib/*
|
mbed-os/platform/randlib/*
|
||||||
mbed-os/storage/kvstore/*
|
mbed-os/storage/kvstore/*
|
||||||
|
mbed-os-bootloader/*
|
@ -1,4 +1,4 @@
|
|||||||
files: ^main.cpp|^static_scheduling|^static_scheduling_with_event|^TESTS
|
files: ^main.cpp|^static_scheduling|^static_scheduling_with_event|^TESTS|^multi_tasking|^common
|
||||||
repos:
|
repos:
|
||||||
- repo: https://github.com/pre-commit/pre-commit-hooks
|
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||||
rev: v4.3.0
|
rev: v4.3.0
|
||||||
|
31
README.md
31
README.md
@ -27,6 +27,7 @@ mbed test -m DISCO_H747I -t GCC_ARM -n advdembsof_library-tests-sensors-hdc1000
|
|||||||
On `.mbedignore` put at the end of the file
|
On `.mbedignore` put at the end of the file
|
||||||
```
|
```
|
||||||
static_scheduling_with_event/*
|
static_scheduling_with_event/*
|
||||||
|
multi_tasking/*
|
||||||
```
|
```
|
||||||
|
|
||||||
On main.cpp include `"static_scheduling/bike_system.hpp"` and use :
|
On main.cpp include `"static_scheduling/bike_system.hpp"` and use :
|
||||||
@ -39,6 +40,7 @@ bikeSystem.start();
|
|||||||
On `.mbedignore` put at the end of the file :
|
On `.mbedignore` put at the end of the file :
|
||||||
```
|
```
|
||||||
static_scheduling_with_event/*
|
static_scheduling_with_event/*
|
||||||
|
multi_tasking/*
|
||||||
```
|
```
|
||||||
|
|
||||||
On main.cpp include `"static_scheduling/bike_system.hpp"` and use :
|
On main.cpp include `"static_scheduling/bike_system.hpp"` and use :
|
||||||
@ -51,6 +53,20 @@ bikeSystem.startWithEventQueue();
|
|||||||
On `.mbedignore` put at the end of the file
|
On `.mbedignore` put at the end of the file
|
||||||
```
|
```
|
||||||
static_scheduling/*
|
static_scheduling/*
|
||||||
|
static_scheduling_with_event/*
|
||||||
|
```
|
||||||
|
|
||||||
|
On main.cpp include `"multi_tasking/bike_system.hpp"` and use :
|
||||||
|
```cpp
|
||||||
|
multi_tasking::BikeSystem bikeSystem;
|
||||||
|
bikeSystem.start();
|
||||||
|
```
|
||||||
|
|
||||||
|
## Run multi-tasking
|
||||||
|
On `.mbedignore` put at the end of the file
|
||||||
|
```
|
||||||
|
static_scheduling/*
|
||||||
|
multi_tasking/*
|
||||||
```
|
```
|
||||||
|
|
||||||
On main.cpp include `"static_scheduling_with_event/bike_system.hpp"` and use :
|
On main.cpp include `"static_scheduling_with_event/bike_system.hpp"` and use :
|
||||||
@ -84,6 +100,21 @@ We observe a light usage of 1% of CPU. The CPU is now sleeping all the time and
|
|||||||
|
|
||||||
We notice, that we miss such less event when is event driven (or not at all). But with a static scheduling the response time is still long because the reset task is call with a certain period.
|
We notice, that we miss such less event when is event driven (or not at all). But with a static scheduling the response time is still long because the reset task is call with a certain period.
|
||||||
|
|
||||||
|
# Multi-tasking
|
||||||
|
|
||||||
|
## Question 1
|
||||||
|
We have computed the elapsed time between the event is sent by the interruption until it is executed :
|
||||||
|
|
||||||
|
|Rtos priority |time |
|
||||||
|
|---|---|
|
||||||
|
|osPriorityBelowNormal |13 usecs |
|
||||||
|
|osPriorityNormal |13 usecs |
|
||||||
|
|osPriorityAboveNormal |13 usecs |
|
||||||
|
|
||||||
|
To abtain these values, we have to consider that there is a isr thread. He dispatchs all the events from the gear device and the reset device. The rest is processed by the main thread.
|
||||||
|
|
||||||
|
Main of the time, it meares these values. But sometimes, higher values can appear. These values doesn't change because there isn't often more than one event in the queue.
|
||||||
|
|
||||||
# Issues
|
# Issues
|
||||||
When compile with GCC, the full loop of static scheduling is 2 to 3 ms faster than expected.
|
When compile with GCC, the full loop of static scheduling is 2 to 3 ms faster than expected.
|
||||||
This problem doesn't occur if we compile with ARMC6.
|
This problem doesn't occur if we compile with ARMC6.
|
||||||
|
@ -23,15 +23,23 @@
|
|||||||
***************************************************************************/
|
***************************************************************************/
|
||||||
|
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
#include "gear_device.hpp"
|
||||||
#include "greentea-client/test_env.h"
|
#include "greentea-client/test_env.h"
|
||||||
#include "mbed.h"
|
#include "mbed.h"
|
||||||
|
#include "mbed_trace.h" // NOLINT
|
||||||
|
#include "multi_tasking/bike_system.hpp"
|
||||||
#include "static_scheduling/bike_system.hpp"
|
#include "static_scheduling/bike_system.hpp"
|
||||||
#include "static_scheduling_with_event/bike_system.hpp"
|
#include "static_scheduling_with_event/bike_system.hpp"
|
||||||
#include "task_logger.hpp"
|
#include "task_logger.hpp"
|
||||||
#include "unity/unity.h"
|
#include "unity/unity.h"
|
||||||
#include "utest/utest.h"
|
#include "utest/utest.h"
|
||||||
|
|
||||||
|
#if defined(MBED_CONF_MBED_TRACE_ENABLE)
|
||||||
|
#define TRACE_GROUP "TEST_BIKE_SYSTEM"
|
||||||
|
#endif // MBED_CONF_MBED_TRACE_ENAB
|
||||||
|
|
||||||
namespace utest {
|
namespace utest {
|
||||||
namespace v1 {
|
namespace v1 {
|
||||||
|
|
||||||
@ -140,6 +148,235 @@ static void test_bike_system_with_event() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// test_multi_tasking_bike_system handler function
|
||||||
|
static void test_multi_tasking_bike_system() {
|
||||||
|
tr_info("test multi tasking bike system");
|
||||||
|
|
||||||
|
// create the BikeSystem instance
|
||||||
|
multi_tasking::BikeSystem bikeSystem;
|
||||||
|
|
||||||
|
// run the bike system in a separate thread
|
||||||
|
Thread thread;
|
||||||
|
osStatus status =
|
||||||
|
thread.start(callback(&bikeSystem, &multi_tasking::BikeSystem::start));
|
||||||
|
|
||||||
|
if (status != osOK) {
|
||||||
|
tr_error("Thread bike system is not OK !");
|
||||||
|
}
|
||||||
|
|
||||||
|
tr_info("bike system has started");
|
||||||
|
|
||||||
|
// let the bike system run for 20 secs
|
||||||
|
ThisThread::sleep_for(20s);
|
||||||
|
|
||||||
|
// check whether scheduling was correct
|
||||||
|
// Order is kGearTaskIndex, kSpeedTaskIndex, kTemperatureTaskIndex,
|
||||||
|
// kResetTaskIndex, kDisplayTask1Index, kDisplayTask2Index
|
||||||
|
// When we use event handling, we do not check the computation time
|
||||||
|
constexpr std::chrono::microseconds taskPeriods[] = {
|
||||||
|
800000us, 400000us, 1600000us, 800000us, 1600000us, 1600000us};
|
||||||
|
|
||||||
|
// allow for 2 msecs offset (with EventQueue)
|
||||||
|
constexpr uint64_t kDeltaUs = 2000;
|
||||||
|
|
||||||
|
// stop the bike system
|
||||||
|
bikeSystem.stop();
|
||||||
|
thread.terminate();
|
||||||
|
|
||||||
|
tr_info("Threads have stopped");
|
||||||
|
|
||||||
|
TEST_ASSERT_UINT64_WITHIN(
|
||||||
|
kDeltaUs,
|
||||||
|
taskPeriods[advembsof::TaskLogger::kTemperatureTaskIndex].count(),
|
||||||
|
bikeSystem.getTaskLogger()
|
||||||
|
.getPeriod(advembsof::TaskLogger::kTemperatureTaskIndex)
|
||||||
|
.count());
|
||||||
|
TEST_ASSERT_UINT64_WITHIN(
|
||||||
|
kDeltaUs,
|
||||||
|
taskPeriods[advembsof::TaskLogger::kDisplayTask1Index].count(),
|
||||||
|
bikeSystem.getTaskLogger()
|
||||||
|
.getPeriod(advembsof::TaskLogger::kDisplayTask1Index)
|
||||||
|
.count());
|
||||||
|
}
|
||||||
|
|
||||||
|
// test_reset_multi_tasking_bike_system handler function
|
||||||
|
Timer timer;
|
||||||
|
static std::chrono::microseconds resetTime = std::chrono::microseconds::zero();
|
||||||
|
static EventFlags eventFlags;
|
||||||
|
static constexpr uint32_t kResetEventFlag = (1UL << 0);
|
||||||
|
static void resetCallback() {
|
||||||
|
resetTime = timer.elapsed_time();
|
||||||
|
eventFlags.set(kResetEventFlag);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_reset_multi_tasking_bike_system() {
|
||||||
|
tr_info("test reset multi tasking bike system");
|
||||||
|
// create the BikeSystem instance
|
||||||
|
multi_tasking::BikeSystem bikeSystem;
|
||||||
|
|
||||||
|
// run the bike system in a separate thread
|
||||||
|
Thread thread;
|
||||||
|
osStatus status =
|
||||||
|
thread.start(callback(&bikeSystem, &multi_tasking::BikeSystem::start));
|
||||||
|
|
||||||
|
if (status != osOK) {
|
||||||
|
tr_error("Thread bike system is not OK !");
|
||||||
|
}
|
||||||
|
|
||||||
|
tr_info("Bike system has started");
|
||||||
|
|
||||||
|
// let the bike system run for 2 secs
|
||||||
|
ThisThread::sleep_for(2s);
|
||||||
|
|
||||||
|
// test reset on BikeSystem
|
||||||
|
bikeSystem.getSpeedometer().setOnResetCallback(resetCallback);
|
||||||
|
|
||||||
|
// start the timer instance
|
||||||
|
timer.start();
|
||||||
|
|
||||||
|
// check for reset response time
|
||||||
|
constexpr uint8_t kNbrOfResets = 10;
|
||||||
|
std::chrono::microseconds lastResponseTime = std::chrono::microseconds::zero();
|
||||||
|
for (uint8_t i = 0; i < kNbrOfResets; i++) {
|
||||||
|
tr_info("Reset test N°%d", i);
|
||||||
|
// take time before reset
|
||||||
|
auto startTime = timer.elapsed_time();
|
||||||
|
|
||||||
|
// reset the BikeSystem
|
||||||
|
bikeSystem.onReset();
|
||||||
|
|
||||||
|
// wait for resetCallback to be called
|
||||||
|
eventFlags.wait_all(kResetEventFlag);
|
||||||
|
|
||||||
|
// get the response time and check it
|
||||||
|
auto responseTime = resetTime - startTime;
|
||||||
|
|
||||||
|
// cppcheck generates an internal error with 20us
|
||||||
|
constexpr std::chrono::microseconds kMaxExpectedResponseTime(20);
|
||||||
|
|
||||||
|
tr_info("Reset task: response time is %lld usecs\n, expected : %lld",
|
||||||
|
responseTime.count(),
|
||||||
|
kMaxExpectedResponseTime.count());
|
||||||
|
|
||||||
|
TEST_ASSERT_TRUE(responseTime.count() <= kMaxExpectedResponseTime.count());
|
||||||
|
|
||||||
|
// jitter of 20us is accepted
|
||||||
|
constexpr uint64_t kDeltaUs = 4;
|
||||||
|
constexpr std::chrono::microseconds kMaxExpectedJitter(3);
|
||||||
|
if (i > 0) {
|
||||||
|
auto jitter = responseTime - lastResponseTime;
|
||||||
|
tr_info("Reset task: jitter is %lld usecs\n", std::abs(jitter.count()));
|
||||||
|
TEST_ASSERT_UINT64_WITHIN(
|
||||||
|
kDeltaUs, kMaxExpectedJitter.count(), std::abs(jitter.count()));
|
||||||
|
}
|
||||||
|
lastResponseTime = responseTime;
|
||||||
|
|
||||||
|
// let the bike system run for 2 secs
|
||||||
|
ThisThread::sleep_for(2s);
|
||||||
|
}
|
||||||
|
|
||||||
|
// stop the bike system
|
||||||
|
bikeSystem.stop();
|
||||||
|
thread.terminate();
|
||||||
|
tr_info("Threads have stopped");
|
||||||
|
timer.stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
Timer timerGear;
|
||||||
|
static std::chrono::microseconds gearTime = std::chrono::microseconds::zero();
|
||||||
|
static EventFlags eventGearFlags;
|
||||||
|
static constexpr uint32_t kGearEventFlag = (1UL << 0);
|
||||||
|
constexpr uint8_t kNbrOfGear = 9;
|
||||||
|
static void onGearChange() {
|
||||||
|
gearTime = timerGear.elapsed_time();
|
||||||
|
eventGearFlags.set(kGearEventFlag);
|
||||||
|
tr_info("Gear changed");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void gearTest(Callback<void()> gearChange) {
|
||||||
|
// std::chrono::microseconds lastResponseTime = std::chrono::microseconds::zero();
|
||||||
|
|
||||||
|
for (uint8_t i = 1; i < kNbrOfGear; i++) {
|
||||||
|
tr_info("Gear test N°%d", i);
|
||||||
|
// take time before increase the gear
|
||||||
|
auto startTime = timerGear.elapsed_time();
|
||||||
|
|
||||||
|
// change the gear with the callback
|
||||||
|
tr_info("Change gear");
|
||||||
|
gearChange();
|
||||||
|
|
||||||
|
// wait flag
|
||||||
|
eventGearFlags.wait_all(kGearEventFlag);
|
||||||
|
|
||||||
|
// get the response time and check it
|
||||||
|
auto responseTime = gearTime - startTime;
|
||||||
|
constexpr std::chrono::microseconds kMaxExpectedResponseTime(100000);
|
||||||
|
|
||||||
|
tr_info("Change gear task: response time is %lld usecs\n, expected : %lld",
|
||||||
|
responseTime.count(),
|
||||||
|
kMaxExpectedResponseTime.count());
|
||||||
|
|
||||||
|
TEST_ASSERT_TRUE(responseTime.count() <= kMaxExpectedResponseTime.count());
|
||||||
|
|
||||||
|
// jitter of 20us is accepted
|
||||||
|
// constexpr uint64_t kDeltaUs = 2000;
|
||||||
|
// constexpr std::chrono::microseconds kMaxExpectedJitter(4000);
|
||||||
|
// if (i > 1) {
|
||||||
|
// auto jitter = responseTime - lastResponseTime;
|
||||||
|
// tr_info("Gear task: jitter is %lld usecs\n", std::abs(jitter.count()));
|
||||||
|
// TEST_ASSERT_UINT64_WITHIN(
|
||||||
|
// kDeltaUs, kMaxExpectedJitter.count(), std::abs(jitter.count()));
|
||||||
|
// }
|
||||||
|
// lastResponseTime = responseTime;
|
||||||
|
|
||||||
|
// let the bike system run for 2 secs
|
||||||
|
ThisThread::sleep_for(2s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_gear_multi_tasking_bike_system() {
|
||||||
|
tr_info("test reset multi tasking bike system");
|
||||||
|
// create the BikeSystem instance
|
||||||
|
multi_tasking::BikeSystem bikeSystem;
|
||||||
|
|
||||||
|
// run the bike system in a separate thread
|
||||||
|
Thread thread;
|
||||||
|
osStatus status =
|
||||||
|
thread.start(callback(&bikeSystem, &multi_tasking::BikeSystem::start));
|
||||||
|
|
||||||
|
if (status != osOK) {
|
||||||
|
tr_error("Thread bike system is not OK !");
|
||||||
|
}
|
||||||
|
|
||||||
|
tr_info("Bike system has started");
|
||||||
|
|
||||||
|
// let the bike system run for 2 secs
|
||||||
|
ThisThread::sleep_for(2s);
|
||||||
|
|
||||||
|
// get the gear device to call onUp and onDown functions
|
||||||
|
multi_tasking::GearDevice& gearDevice = bikeSystem.getGearDevice();
|
||||||
|
|
||||||
|
// set callback for response time measuring
|
||||||
|
bikeSystem.setCallbackGearChage(onGearChange);
|
||||||
|
|
||||||
|
// start the timer instance
|
||||||
|
timerGear.start();
|
||||||
|
|
||||||
|
// test timing incresing the gear
|
||||||
|
tr_info("Test incresing gear");
|
||||||
|
gearTest(callback(&gearDevice, &multi_tasking::GearDevice::onUp));
|
||||||
|
|
||||||
|
// test timing decreasing the gear
|
||||||
|
tr_info("Test decreasing gear");
|
||||||
|
gearTest(callback(&gearDevice, &multi_tasking::GearDevice::onDown));
|
||||||
|
|
||||||
|
// stop the bike system
|
||||||
|
bikeSystem.stop();
|
||||||
|
thread.terminate();
|
||||||
|
tr_info("Threads have stopped");
|
||||||
|
timerGear.stop();
|
||||||
|
}
|
||||||
|
|
||||||
static status_t greentea_setup(const size_t number_of_cases) {
|
static status_t greentea_setup(const size_t number_of_cases) {
|
||||||
// Here, we specify the timeout (60s) and the host test (a built-in host test
|
// Here, we specify the timeout (60s) and the host test (a built-in host test
|
||||||
// or the name of our Python file)
|
// or the name of our Python file)
|
||||||
@ -152,7 +389,10 @@ static status_t greentea_setup(const size_t number_of_cases) {
|
|||||||
static Case cases[] = {
|
static Case cases[] = {
|
||||||
Case("test bike system", test_bike_system),
|
Case("test bike system", test_bike_system),
|
||||||
Case("test bike system with event queue", test_bike_system_event_queue),
|
Case("test bike system with event queue", test_bike_system_event_queue),
|
||||||
Case("test bike system with event handling", test_bike_system_with_event),
|
Case("test bike system with event", test_bike_system_with_event),
|
||||||
|
Case("test multi-tasking bike system", test_multi_tasking_bike_system),
|
||||||
|
Case("test reset multi-tasking bike system", test_reset_multi_tasking_bike_system),
|
||||||
|
Case("test gear multi-tasking bike system", test_gear_multi_tasking_bike_system),
|
||||||
};
|
};
|
||||||
|
|
||||||
static Specification specification(greentea_setup, cases);
|
static Specification specification(greentea_setup, cases);
|
||||||
@ -160,4 +400,9 @@ static Specification specification(greentea_setup, cases);
|
|||||||
}; // namespace v1
|
}; // namespace v1
|
||||||
}; // namespace utest
|
}; // namespace utest
|
||||||
|
|
||||||
int main() { return !utest::v1::Harness::run(utest::v1::specification); }
|
int main() {
|
||||||
|
#if defined(MBED_CONF_MBED_TRACE_ENABLE)
|
||||||
|
mbed_trace_init();
|
||||||
|
#endif
|
||||||
|
return !utest::v1::Harness::run(utest::v1::specification);
|
||||||
|
}
|
||||||
|
@ -52,9 +52,8 @@ static constexpr std::chrono::milliseconds kMaxPedalRotationTime = 1500ms;
|
|||||||
static constexpr std::chrono::milliseconds kDeltaPedalRotationTime = 25ms;
|
static constexpr std::chrono::milliseconds kDeltaPedalRotationTime = 25ms;
|
||||||
|
|
||||||
static constexpr uint32_t kNbrOfSteps = static_cast<uint32_t>(
|
static constexpr uint32_t kNbrOfSteps = static_cast<uint32_t>(
|
||||||
(
|
(bike_computer::kMaxPedalRotationTime - bike_computer::kMinPedalRotationTime)
|
||||||
bike_computer::kMaxPedalRotationTime - bike_computer::kMinPedalRotationTime
|
.count() /
|
||||||
).count() / bike_computer::kDeltaPedalRotationTime.count()
|
bike_computer::kDeltaPedalRotationTime.count());
|
||||||
);
|
|
||||||
|
|
||||||
} // namespace bike_computer
|
} // namespace bike_computer
|
@ -1,21 +1,37 @@
|
|||||||
|
// Copyright 2022 Haute école d'ingénierie et d'architecture de Fribourg
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* @file speedometer_device.cpp
|
||||||
|
* @author Serge Ayer <serge.ayer@hefr.ch>
|
||||||
|
*
|
||||||
|
* @brief WheelCounterDevice implementation (static scheduling)
|
||||||
|
*
|
||||||
|
* @date 2023-08-20
|
||||||
|
* @version 1.0.0
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
#include "sensor_device.hpp"
|
#include "sensor_device.hpp"
|
||||||
|
|
||||||
namespace bike_computer {
|
namespace bike_computer {
|
||||||
|
|
||||||
SensorDevice::SensorDevice() : _hdc1000(I2C_SDA, I2C_SCL, STMOD_11)
|
SensorDevice::SensorDevice() : _hdc1000(I2C_SDA, I2C_SCL, STMOD_11) {}
|
||||||
{}
|
|
||||||
|
|
||||||
bool SensorDevice::init() {
|
bool SensorDevice::init() { return this->_hdc1000.probe(); }
|
||||||
return this->_hdc1000.probe();
|
|
||||||
}
|
|
||||||
|
|
||||||
float SensorDevice::readTemperature(void) {
|
float SensorDevice::readTemperature(void) { return this->_hdc1000.getTemperature(); }
|
||||||
return this->_hdc1000.getTemperature();
|
|
||||||
}
|
|
||||||
|
|
||||||
float SensorDevice::readHumidity(void) {
|
float SensorDevice::readHumidity(void) { return this->_hdc1000.getHumidity(); }
|
||||||
return this->_hdc1000.getHumidity();
|
|
||||||
}
|
|
||||||
|
|
||||||
} // bike_computer
|
|
||||||
|
|
||||||
|
} // namespace bike_computer
|
||||||
|
@ -24,9 +24,8 @@
|
|||||||
|
|
||||||
#include "speedometer.hpp"
|
#include "speedometer.hpp"
|
||||||
|
|
||||||
#include "static_scheduling/gear_device.hpp"
|
|
||||||
|
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
|
#include <cstddef>
|
||||||
#include <ratio>
|
#include <ratio>
|
||||||
|
|
||||||
// from disco_h747i/wrappers
|
// from disco_h747i/wrappers
|
||||||
@ -80,7 +79,12 @@ float Speedometer::getDistance() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Speedometer::reset() {
|
void Speedometer::reset() {
|
||||||
// TODO : done
|
#if defined(MBED_TEST_MODE)
|
||||||
|
if (_cbOnReset != NULL) {
|
||||||
|
_cbOnReset();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
this->_totalDistanceMutex.lock();
|
this->_totalDistanceMutex.lock();
|
||||||
this->_totalDistance = 0.0f;
|
this->_totalDistance = 0.0f;
|
||||||
this->_totalDistanceMutex.unlock();
|
this->_totalDistanceMutex.unlock();
|
||||||
@ -96,6 +100,7 @@ float Speedometer::getTraySize() const { return kTraySize; }
|
|||||||
std::chrono::milliseconds Speedometer::getCurrentPedalRotationTime() const {
|
std::chrono::milliseconds Speedometer::getCurrentPedalRotationTime() const {
|
||||||
return _pedalRotationTime;
|
return _pedalRotationTime;
|
||||||
}
|
}
|
||||||
|
void Speedometer::setOnResetCallback(mbed::Callback<void()> cb) { _cbOnReset = cb; }
|
||||||
|
|
||||||
#endif // defined(MBED_TEST_MODE)
|
#endif // defined(MBED_TEST_MODE)
|
||||||
|
|
||||||
@ -107,11 +112,14 @@ void Speedometer::computeSpeed() {
|
|||||||
// = 6.99m If you ride at 80 pedal turns / min, you run a distance of 6.99 * 80 / min
|
// = 6.99m If you ride at 80 pedal turns / min, you run a distance of 6.99 * 80 / min
|
||||||
// ~= 560 m / min = 33.6 km/h
|
// ~= 560 m / min = 33.6 km/h
|
||||||
|
|
||||||
// TODO : done
|
// Distance run with one pedal turn = tray size / rear gear size * circumference of
|
||||||
//Distance run with one pedal turn = tray size / rear gear size * circumference of the wheel
|
// the wheel
|
||||||
constexpr float ms_in_hour = static_cast<float>(3600 * 1000);
|
constexpr float ms_in_hour = static_cast<float>(3600 * 1000);
|
||||||
float pedal_rotation_per_hour = ms_in_hour / std::chrono::duration_cast<std::chrono::milliseconds>(_pedalRotationTime).count();
|
float pedal_rotation_per_hour =
|
||||||
float gear_ratio = static_cast<float>(kTraySize) / static_cast<float>(this->_gearSize);
|
ms_in_hour /
|
||||||
|
std::chrono::duration_cast<std::chrono::milliseconds>(_pedalRotationTime).count();
|
||||||
|
float gear_ratio =
|
||||||
|
static_cast<float>(kTraySize) / static_cast<float>(this->_gearSize);
|
||||||
float wheel_dist_km = static_cast<float>(this->kWheelCircumference) / 1000.0;
|
float wheel_dist_km = static_cast<float>(this->kWheelCircumference) / 1000.0;
|
||||||
this->_currentSpeed = gear_ratio * wheel_dist_km * pedal_rotation_per_hour;
|
this->_currentSpeed = gear_ratio * wheel_dist_km * pedal_rotation_per_hour;
|
||||||
}
|
}
|
||||||
@ -125,14 +133,13 @@ void Speedometer::computeDistance() {
|
|||||||
// ~= 560 m / min = 33.6 km/h. We then multiply the speed by the time for getting the
|
// ~= 560 m / min = 33.6 km/h. We then multiply the speed by the time for getting the
|
||||||
// distance traveled.
|
// distance traveled.
|
||||||
|
|
||||||
// TODO : done
|
|
||||||
Speedometer::computeSpeed();
|
Speedometer::computeSpeed();
|
||||||
// compute distance
|
// compute distance
|
||||||
|
|
||||||
const std::chrono::microseconds timeNow = _timer.elapsed_time();
|
const std::chrono::microseconds timeNow = _timer.elapsed_time();
|
||||||
const std::chrono::microseconds timeDiff = timeNow - _lastTime;
|
const std::chrono::microseconds timeDiff = timeNow - _lastTime;
|
||||||
constexpr float ms_in_hour = static_cast<float>(3600 * 1000);
|
constexpr float ms_in_hour = static_cast<float>(3600 * 1000);
|
||||||
float traveled_dist = _currentSpeed * timeDiff.count() / (ms_in_hour*1000.0/*μs*/);
|
float traveled_dist = _currentSpeed * timeDiff.count() / (ms_in_hour * 1000.0 /*μs*/);
|
||||||
|
|
||||||
this->_totalDistanceMutex.lock();
|
this->_totalDistanceMutex.lock();
|
||||||
this->_totalDistance += traveled_dist;
|
this->_totalDistance += traveled_dist;
|
||||||
|
@ -55,6 +55,7 @@ class Speedometer {
|
|||||||
float getTraySize() const;
|
float getTraySize() const;
|
||||||
std::chrono::milliseconds getCurrentPedalRotationTime() const;
|
std::chrono::milliseconds getCurrentPedalRotationTime() const;
|
||||||
void setOnResetCallback(mbed::Callback<void()> cb);
|
void setOnResetCallback(mbed::Callback<void()> cb);
|
||||||
|
mbed::Callback<void()> _cbOnReset = NULL;
|
||||||
#endif // defined(MBED_TEST_MODE)
|
#endif // defined(MBED_TEST_MODE)
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -79,9 +80,7 @@ class Speedometer {
|
|||||||
float _currentSpeed = 0.0f;
|
float _currentSpeed = 0.0f;
|
||||||
Mutex _totalDistanceMutex;
|
Mutex _totalDistanceMutex;
|
||||||
float _totalDistance = 0.0f;
|
float _totalDistance = 0.0f;
|
||||||
uint8_t _gearSize = 1;
|
uint8_t _gearSize = bike_computer::kMaxGearSize;
|
||||||
|
|
||||||
Thread _thread;
|
|
||||||
|
|
||||||
#if defined(MBED_TEST_MODE)
|
#if defined(MBED_TEST_MODE)
|
||||||
mbed::Callback<void()> _cb;
|
mbed::Callback<void()> _cb;
|
||||||
|
9
main.cpp
9
main.cpp
@ -5,10 +5,11 @@
|
|||||||
|
|
||||||
#if !MBED_TEST_MODE
|
#if !MBED_TEST_MODE
|
||||||
|
|
||||||
#include "mbed.h" // NOLINT
|
#include "mbed.h" // NOLINT
|
||||||
#include "mbed_trace.h"
|
#include "mbed_trace.h" // NOLINT
|
||||||
// #include "static_scheduling/bike_system.hpp"
|
// #include "static_scheduling/bike_system.hpp"
|
||||||
#include "static_scheduling_with_event/bike_system.hpp"
|
#include "static_scheduling_with_event/bike_system.hpp"
|
||||||
|
// #include "multi_tasking/bike_system.hpp"
|
||||||
|
|
||||||
#if defined(MBED_CONF_MBED_TRACE_ENABLE)
|
#if defined(MBED_CONF_MBED_TRACE_ENABLE)
|
||||||
#define TRACE_GROUP "MAIN"
|
#define TRACE_GROUP "MAIN"
|
||||||
@ -21,10 +22,12 @@ int main() {
|
|||||||
|
|
||||||
// static_scheduling::BikeSystem bikeSystem;
|
// static_scheduling::BikeSystem bikeSystem;
|
||||||
// bikeSystem.start();
|
// bikeSystem.start();
|
||||||
// bikeSystem.startWithEventQueue();
|
|
||||||
|
|
||||||
static_scheduling_with_event::BikeSystem bikeSystem;
|
static_scheduling_with_event::BikeSystem bikeSystem;
|
||||||
bikeSystem.start();
|
bikeSystem.start();
|
||||||
|
|
||||||
|
// multi_tasking::BikeSystem bikeSystem;
|
||||||
|
// bikeSystem.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // MBED_TEST_MODE
|
#endif // MBED_TEST_MODE
|
||||||
|
12
mbed-os-bootloader/.clang-format
Normal file
12
mbed-os-bootloader/.clang-format
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
---
|
||||||
|
BasedOnStyle: Google
|
||||||
|
IndentWidth: 4
|
||||||
|
---
|
||||||
|
Language: Cpp
|
||||||
|
ColumnLimit: 90
|
||||||
|
AlignConsecutiveAssignments: true
|
||||||
|
DerivePointerAlignment: false
|
||||||
|
PointerAlignment: Left
|
||||||
|
BinPackArguments: false
|
||||||
|
BinPackParameters: false
|
||||||
|
IndentAccessModifiers: false
|
8
mbed-os-bootloader/.gitignore
vendored
Normal file
8
mbed-os-bootloader/.gitignore
vendored
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
.build
|
||||||
|
.mbed
|
||||||
|
projectfiles
|
||||||
|
*.py*
|
||||||
|
mbed-os
|
||||||
|
BUILD
|
||||||
|
!BUILD/DISCO_H747I/GCC_ARM/mbed-os-bootloader.bin
|
||||||
|
|
17
mbed-os-bootloader/.mbedignore
Normal file
17
mbed-os-bootloader/.mbedignore
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
mbed-os/drivers/device_key/*
|
||||||
|
mbed-os/drivers/source/usb/USBMSD.cpp
|
||||||
|
mbed-os/drivers/source/SFDP.cpp
|
||||||
|
mbed-os/connectivity/cellular/*
|
||||||
|
mbed-os/connectivity/drivers/*
|
||||||
|
mbed-os/connectivity/FEATURE_BLE/*
|
||||||
|
mbed-os/connectivity/libraries/*
|
||||||
|
mbed-os/connectivity/lorawan/*
|
||||||
|
mbed-os/connectivity/lwipstack/*
|
||||||
|
mbed-os/connectivity/nanostack/*
|
||||||
|
mbed-os/connectivity/netsocket/*
|
||||||
|
mbed-os/connectivity/nfc/*
|
||||||
|
mbed-os/features/FEATURE_BOOTLOADER/*
|
||||||
|
mbed-os/features/frameworks/mbed-client-cli/*
|
||||||
|
mbed-os/features/frameworks/COMPONENT_FPGA_CI_TEST_SHIELD/*
|
||||||
|
mbed-os/platform/randlib/*
|
||||||
|
mbed-os/storage/kvstore/*
|
26
mbed-os-bootloader/.pre-commit-config.yaml
Normal file
26
mbed-os-bootloader/.pre-commit-config.yaml
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
files: ^main.cpp
|
||||||
|
repos:
|
||||||
|
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||||
|
rev: v4.3.0
|
||||||
|
hooks:
|
||||||
|
- id: check-yaml
|
||||||
|
args: [--allow-multiple-documents]
|
||||||
|
- id: end-of-file-fixer
|
||||||
|
- id: trailing-whitespace
|
||||||
|
- repo: https://github.com/pre-commit/mirrors-clang-format
|
||||||
|
rev: "v14.0.6"
|
||||||
|
hooks:
|
||||||
|
- id: clang-format
|
||||||
|
- repo: https://github.com/cpplint/cpplint
|
||||||
|
rev: "1.6.1"
|
||||||
|
hooks:
|
||||||
|
- id: cpplint
|
||||||
|
name: cpplint
|
||||||
|
entry: cpplint --linelength=90 --filter=-build/include_subdir,-whitespace/indent,-build/namespaces,-build/c++11
|
||||||
|
- repo: local
|
||||||
|
hooks:
|
||||||
|
- id: cppcheck
|
||||||
|
name: cppcheck
|
||||||
|
require_serial: true
|
||||||
|
entry: cppcheck --enable=all --suppress=missingInclude --inline-suppr -i mbed-os --std=c++14 --error-exitcode=1
|
||||||
|
language: system
|
Binary file not shown.
35
mbed-os-bootloader/main.cpp
Normal file
35
mbed-os-bootloader/main.cpp
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
#include "mbed.h"
|
||||||
|
|
||||||
|
#include "mbed_trace.h"
|
||||||
|
#if MBED_CONF_MBED_TRACE_ENABLE
|
||||||
|
#define TRACE_GROUP "bootloader"
|
||||||
|
#endif // MBED_CONF_MBED_TRACE_ENABLE
|
||||||
|
|
||||||
|
#if MBED_CONF_MBED_TRACE_ENABLE
|
||||||
|
static UnbufferedSerial g_uart(CONSOLE_TX, CONSOLE_RX);
|
||||||
|
|
||||||
|
// Function that directly outputs to an unbuffered serial port in blocking mode.
|
||||||
|
static void boot_debug(const char *s) {
|
||||||
|
size_t len = strlen(s);
|
||||||
|
g_uart.write(s, len);
|
||||||
|
g_uart.write("\r\n", 2);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
#if MBED_CONF_MBED_TRACE_ENABLE
|
||||||
|
mbed_trace_init();
|
||||||
|
mbed_trace_print_function_set(boot_debug);
|
||||||
|
#endif // MBED_CONF_MBED_TRACE_ENABLE
|
||||||
|
|
||||||
|
tr_debug("BikeComputer bootloader\r\n");
|
||||||
|
|
||||||
|
// at this stage we directly branch to the main application
|
||||||
|
void *sp = *((void **) POST_APPLICATION_ADDR + 0); // NOLINT(readability/casting)
|
||||||
|
void *pc = *((void **) POST_APPLICATION_ADDR + 1); // NOLINT(readability/casting)
|
||||||
|
tr_debug("Starting application at address 0x%08x (sp 0x%08x, pc 0x%08x)\r\n", POST_APPLICATION_ADDR, (uint32_t) sp, (uint32_t) pc);
|
||||||
|
|
||||||
|
mbed_start_application(POST_APPLICATION_ADDR);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
1
mbed-os-bootloader/mbed-os.lib
Normal file
1
mbed-os-bootloader/mbed-os.lib
Normal file
@ -0,0 +1 @@
|
|||||||
|
https://github.com/ARMmbed/mbed-os.git#17dc3dc2e6e2817a8bd3df62f38583319f0e4fed
|
28
mbed-os-bootloader/mbed_app.json
Normal file
28
mbed-os-bootloader/mbed_app.json
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
{
|
||||||
|
"macros": [
|
||||||
|
"MBED_CONF_MBED_TRACE_FEA_IPV6=0"
|
||||||
|
],
|
||||||
|
"config": {
|
||||||
|
"main-stack-size": {
|
||||||
|
"value": 4096
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"target_overrides": {
|
||||||
|
"*": {
|
||||||
|
"mbed-trace.enable": false,
|
||||||
|
"platform.stdio-convert-newlines": true,
|
||||||
|
"platform.stdio-baud-rate": 115200,
|
||||||
|
"platform.default-serial-baud-rate": 115200,
|
||||||
|
"platform.stdio-buffered-serial": true,
|
||||||
|
"platform.all-stats-enabled": true,
|
||||||
|
"target.printf_lib":"minimal-printf",
|
||||||
|
"platform.minimal-printf-enable-floating-point": true,
|
||||||
|
"platform.minimal-printf-set-floating-point-max-decimals": 2
|
||||||
|
},
|
||||||
|
"DISCO_H747I": {
|
||||||
|
"target.restrict_size": "0x20000",
|
||||||
|
"mbed-trace.enable": true,
|
||||||
|
"mbed-trace.max-level": "TRACE_LEVEL_DEBUG"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,27 +1,27 @@
|
|||||||
{
|
{
|
||||||
"macros": [
|
"macros": ["MBED_CONF_MBED_TRACE_FEA_IPV6=0"],
|
||||||
"MBED_CONF_MBED_TRACE_FEA_IPV6=0"
|
"config": {
|
||||||
],
|
"main-stack-size": {
|
||||||
"config": {
|
"value": 8192
|
||||||
"main-stack-size": {
|
}
|
||||||
"value": 4096
|
},
|
||||||
}
|
"target_overrides": {
|
||||||
|
"*": {
|
||||||
|
"mbed-trace.enable": false,
|
||||||
|
"platform.stdio-convert-newlines": true,
|
||||||
|
"platform.stdio-baud-rate": 115200,
|
||||||
|
"platform.default-serial-baud-rate": 115200,
|
||||||
|
"platform.stdio-buffered-serial": true,
|
||||||
|
"platform.all-stats-enabled": true,
|
||||||
|
"target.printf_lib": "minimal-printf",
|
||||||
|
"platform.minimal-printf-enable-floating-point": true,
|
||||||
|
"platform.minimal-printf-set-floating-point-max-decimals": 2
|
||||||
},
|
},
|
||||||
"target_overrides": {
|
"DISCO_H747I": {
|
||||||
"*": {
|
"mbed-trace.enable": true,
|
||||||
"mbed-trace.enable": false,
|
"mbed-trace.max-level": "TRACE_LEVEL_DEBUG",
|
||||||
"platform.stdio-convert-newlines": true,
|
"target.bootloader_img": "./mbed-os-bootloader/BUILD/DISCO_H747I/GCC_ARM/mbed-os-bootloader.bin",
|
||||||
"platform.stdio-baud-rate": 115200,
|
"target.app_offset": "0x20000"
|
||||||
"platform.default-serial-baud-rate": 115200,
|
|
||||||
"platform.stdio-buffered-serial": true,
|
|
||||||
"platform.all-stats-enabled": true,
|
|
||||||
"target.printf_lib":"minimal-printf",
|
|
||||||
"platform.minimal-printf-enable-floating-point": true,
|
|
||||||
"platform.minimal-printf-set-floating-point-max-decimals": 2
|
|
||||||
},
|
|
||||||
"DISCO_H747I": {
|
|
||||||
"mbed-trace.enable": true,
|
|
||||||
"mbed-trace.max-level": "TRACE_LEVEL_DEBUG"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
406
multi_tasking/bike_system.cpp
Normal file
406
multi_tasking/bike_system.cpp
Normal file
@ -0,0 +1,406 @@
|
|||||||
|
// Copyright 2022 Haute école d'ingénierie et d'architecture de Fribourg
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* @file bike_system.cpp
|
||||||
|
* @author Serge Ayer <serge.ayer@hefr.ch>
|
||||||
|
* @author Rémi Heredero <remi@heredero.ch>
|
||||||
|
* @author Yann Sierro <yannsierro.pro@gmail.com>
|
||||||
|
*
|
||||||
|
* @brief Bike System implementation (static scheduling)
|
||||||
|
*
|
||||||
|
* @date 2023-11-15
|
||||||
|
* @version 1.1.0
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
#include "bike_system.hpp"
|
||||||
|
|
||||||
|
#include <chrono>
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
#include "cmsis_os.h"
|
||||||
|
#include "common/constants.hpp"
|
||||||
|
#include "mbed_trace.h"
|
||||||
|
|
||||||
|
#if MBED_CONF_MBED_TRACE_ENABLE
|
||||||
|
#define TRACE_GROUP "BikeSystem"
|
||||||
|
#endif // MBED_CONF_MBED_TRACE_ENABLE
|
||||||
|
|
||||||
|
namespace multi_tasking {
|
||||||
|
|
||||||
|
static constexpr std::chrono::milliseconds kGearTaskComputationTime = 100ms;
|
||||||
|
static constexpr std::chrono::milliseconds kSpeedDistanceTaskComputationTime = 200ms;
|
||||||
|
static constexpr std::chrono::milliseconds kDisplayTask1Period = 1600ms;
|
||||||
|
static constexpr std::chrono::milliseconds kDisplayTask1Delay = 300ms;
|
||||||
|
static constexpr std::chrono::milliseconds kDisplayTask1ComputationTime = 200ms;
|
||||||
|
static constexpr std::chrono::milliseconds kTemperatureTaskPeriod = 1600ms;
|
||||||
|
static constexpr std::chrono::milliseconds kTemperatureTaskDelay = 1100ms;
|
||||||
|
static constexpr std::chrono::milliseconds kTemperatureTaskComputationTime = 100ms;
|
||||||
|
static constexpr std::chrono::milliseconds kCPUTaskPeriod = 1600ms;
|
||||||
|
static constexpr std::chrono::milliseconds kCPUTaskDelay = 0ms;
|
||||||
|
|
||||||
|
BikeSystem::BikeSystem()
|
||||||
|
: _timer(),
|
||||||
|
_isrEventQueue(),
|
||||||
|
_eventQueue(),
|
||||||
|
_mailPedalDevice(),
|
||||||
|
_mailGearDevice(),
|
||||||
|
_mutexGearSize(),
|
||||||
|
_mutexGear(),
|
||||||
|
_mutexSpeed(),
|
||||||
|
_mutexDistance(),
|
||||||
|
_mutexSpeedometer(),
|
||||||
|
_isrEventThread(osPriorityAboveNormal, OS_STACK_SIZE, nullptr, "ISR_Event"),
|
||||||
|
_speedDistanceThread(
|
||||||
|
osPriorityNormal, OS_STACK_SIZE, nullptr, "Speed_distance_Task"),
|
||||||
|
_gearTaskThread(osPriorityAboveNormal, OS_STACK_SIZE, nullptr, "Gear_Task"),
|
||||||
|
_gearDevice(&_mailGearDevice, _timer),
|
||||||
|
_pedalDevice(&_mailPedalDevice, _timer),
|
||||||
|
_resetDevice(callback(this, &BikeSystem::onReset)),
|
||||||
|
_displayDevice(),
|
||||||
|
_speedometer(_timer),
|
||||||
|
_sensorDevice(),
|
||||||
|
_taskLogger(),
|
||||||
|
_cpuLogger(_timer) {}
|
||||||
|
|
||||||
|
#if defined(MBED_TEST_MODE)
|
||||||
|
const advembsof::TaskLogger& BikeSystem::getTaskLogger() { return _taskLogger; }
|
||||||
|
|
||||||
|
bike_computer::Speedometer& BikeSystem::getSpeedometer() {
|
||||||
|
// ENTER CRITICAL SECTION
|
||||||
|
_mutexSpeedometer.lock();
|
||||||
|
bike_computer::Speedometer& speedometer = _speedometer;
|
||||||
|
_mutexSpeedometer.unlock();
|
||||||
|
// END CRITICAL SECTION
|
||||||
|
|
||||||
|
return speedometer;
|
||||||
|
}
|
||||||
|
|
||||||
|
GearDevice& BikeSystem::getGearDevice() { return _gearDevice; }
|
||||||
|
|
||||||
|
void BikeSystem::setCallbackGearChage(Callback<void()> cbGearChange) {
|
||||||
|
_cbGearChange = cbGearChange;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // defined(MBED_TEST_MODE)
|
||||||
|
|
||||||
|
void BikeSystem::init() {
|
||||||
|
// start the timer
|
||||||
|
_timer.start();
|
||||||
|
|
||||||
|
// initialize the lcd display
|
||||||
|
disco::ReturnCode rc = _displayDevice.init();
|
||||||
|
if (rc != disco::ReturnCode::Ok) {
|
||||||
|
tr_error("Ffalseailed to initialized the lcd display: %d", static_cast<int>(rc));
|
||||||
|
}
|
||||||
|
|
||||||
|
// initialize the sensor device
|
||||||
|
bool present = _sensorDevice.init();
|
||||||
|
if (!present) {
|
||||||
|
tr_error("Sensor not present or initialization failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
// enable/disable task logging
|
||||||
|
bool runTaskLogger = false;
|
||||||
|
|
||||||
|
#if defined(MBED_TEST_MODE)
|
||||||
|
runTaskLogger = true;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
_taskLogger.enable(runTaskLogger);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BikeSystem::start() {
|
||||||
|
init();
|
||||||
|
|
||||||
|
Event<void()> temperatureEvent(&_eventQueue,
|
||||||
|
callback(this, &BikeSystem::temperatureTask));
|
||||||
|
temperatureEvent.delay(kTemperatureTaskDelay);
|
||||||
|
temperatureEvent.period(kTemperatureTaskPeriod);
|
||||||
|
temperatureEvent.post();
|
||||||
|
|
||||||
|
Event<void()> displayEvent(&_eventQueue, callback(this, &BikeSystem::displayTask));
|
||||||
|
displayEvent.delay(kDisplayTask1Delay);
|
||||||
|
displayEvent.period(kDisplayTask1Period);
|
||||||
|
displayEvent.post();
|
||||||
|
|
||||||
|
osStatus status =
|
||||||
|
_isrEventThread.start(callback(this, &BikeSystem::dispatch_isr_events));
|
||||||
|
if (status != osOK) {
|
||||||
|
tr_error("Thread %s started with status %ld",
|
||||||
|
_isrEventThread.get_name(),
|
||||||
|
static_cast<int32_t>(status));
|
||||||
|
}
|
||||||
|
|
||||||
|
status =
|
||||||
|
_speedDistanceThread.start(callback(this, &BikeSystem::loop_speed_distance_task));
|
||||||
|
if (status != osOK) {
|
||||||
|
tr_error("Thread %s started with status %ld",
|
||||||
|
_isrEventThread.get_name(),
|
||||||
|
static_cast<int32_t>(status));
|
||||||
|
}
|
||||||
|
|
||||||
|
status = _gearTaskThread.start(callback(this, &BikeSystem::loop_gear_task));
|
||||||
|
if (status != osOK) {
|
||||||
|
tr_error("Thread %s started with status %ld",
|
||||||
|
_gearTaskThread.get_name(),
|
||||||
|
static_cast<int32_t>(status));
|
||||||
|
}
|
||||||
|
|
||||||
|
#if !defined(MBED_TEST_MODE)
|
||||||
|
Event<void()> cpuEvent(&_eventQueue, callback(this, &BikeSystem::cpuTask));
|
||||||
|
cpuEvent.delay(kCPUTaskDelay);
|
||||||
|
cpuEvent.period(kCPUTaskPeriod);
|
||||||
|
cpuEvent.post();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// dispatch the main queue in the main thread
|
||||||
|
dispatch_events();
|
||||||
|
}
|
||||||
|
|
||||||
|
void BikeSystem::stop() {
|
||||||
|
osStatus status = _isrEventThread.terminate();
|
||||||
|
status += _speedDistanceThread.terminate();
|
||||||
|
status += _gearTaskThread.terminate();
|
||||||
|
if (status != 0) {
|
||||||
|
tr_error("Stop thread error");
|
||||||
|
}
|
||||||
|
tr_info("Bike system has stopped !");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Callback from isr */
|
||||||
|
|
||||||
|
void BikeSystem::onReset() {
|
||||||
|
_resetTime = _timer.elapsed_time();
|
||||||
|
Event<void()> resetEvent(&_isrEventQueue, callback(this, &BikeSystem::resetTask));
|
||||||
|
resetEvent.post();
|
||||||
|
}
|
||||||
|
|
||||||
|
// ISR thread functions
|
||||||
|
|
||||||
|
void BikeSystem::resetTask() {
|
||||||
|
#if !defined(MBED_TEST_MODE)
|
||||||
|
auto taskStartTime = _timer.elapsed_time();
|
||||||
|
|
||||||
|
std::chrono::microseconds responseTime = _timer.elapsed_time() - _resetTime;
|
||||||
|
tr_info("Reset task: response time is %" PRIu64 " usecs", responseTime.count());
|
||||||
|
#endif
|
||||||
|
// ENTER CRITICAL SECTION
|
||||||
|
_mutexSpeedometer.lock();
|
||||||
|
_speedometer.reset();
|
||||||
|
_mutexSpeedometer.unlock();
|
||||||
|
// END CRITICAL SECTION
|
||||||
|
|
||||||
|
#if !defined(MBED_TEST_MODE)
|
||||||
|
_taskLogger.logPeriodAndExecutionTime(
|
||||||
|
_timer, advembsof::TaskLogger::kResetTaskIndex, taskStartTime);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
// Speed distance thread functions
|
||||||
|
|
||||||
|
void BikeSystem::speedDistanceTask() {
|
||||||
|
auto taskStartTime = _timer.elapsed_time();
|
||||||
|
|
||||||
|
pedalMail_t* currentStep = _mailPedalDevice.try_get();
|
||||||
|
|
||||||
|
if (currentStep != nullptr) {
|
||||||
|
const auto pedalRotationTime =
|
||||||
|
PedalDevice::getCurrentRotationTime(currentStep->step);
|
||||||
|
|
||||||
|
// ENTER CRITICAL SECTION
|
||||||
|
_mutexSpeedometer.lock();
|
||||||
|
_speedometer.setCurrentRotationTime(pedalRotationTime);
|
||||||
|
_mutexSpeedometer.unlock();
|
||||||
|
// END CRITICAL SECTION
|
||||||
|
|
||||||
|
std::chrono::microseconds responseTime =
|
||||||
|
_timer.elapsed_time() - currentStep->callTime;
|
||||||
|
tr_info("Speed distance task: response time is %" PRIu64 " usecs",
|
||||||
|
responseTime.count());
|
||||||
|
|
||||||
|
osStatus status = _mailPedalDevice.free(currentStep);
|
||||||
|
if (status != osOK) {
|
||||||
|
tr_error("free current step in the speed distance tasks doesn't work !");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ENTER CRITICAL SECTION
|
||||||
|
_mutexSpeedometer.lock();
|
||||||
|
_speedometer.setGearSize(getCurrentGearSize());
|
||||||
|
_mutexSpeed.lock();
|
||||||
|
_currentSpeed = _speedometer.getCurrentSpeed();
|
||||||
|
_mutexSpeed.unlock();
|
||||||
|
_mutexDistance.lock();
|
||||||
|
_traveledDistance = _speedometer.getDistance();
|
||||||
|
_mutexDistance.unlock();
|
||||||
|
_mutexSpeedometer.unlock();
|
||||||
|
// END CRITICAL SECTION
|
||||||
|
|
||||||
|
ThisThread::sleep_for(std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||||
|
kSpeedDistanceTaskComputationTime - (_timer.elapsed_time() - taskStartTime)));
|
||||||
|
|
||||||
|
_taskLogger.logPeriodAndExecutionTime(
|
||||||
|
_timer, advembsof::TaskLogger::kSpeedTaskIndex, taskStartTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Gear thread functions */
|
||||||
|
void BikeSystem::gearTask() {
|
||||||
|
auto taskStartTime = _timer.elapsed_time();
|
||||||
|
|
||||||
|
gearMail_t* currentGear = _mailGearDevice.try_get();
|
||||||
|
|
||||||
|
if (currentGear != nullptr) {
|
||||||
|
#if !defined(MBED_TEST_MODE)
|
||||||
|
std::chrono::microseconds responseTime =
|
||||||
|
_timer.elapsed_time() - currentGear->callTime;
|
||||||
|
tr_info("Gear task: response time is %" PRIu64 " usecs", responseTime.count());
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(MBED_TEST_MODE)
|
||||||
|
_cbGearChange();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// ENTER CRITICAL SECTION
|
||||||
|
_mutexGear.lock();
|
||||||
|
_currentGear = currentGear->gear;
|
||||||
|
_mutexGear.unlock();
|
||||||
|
_mutexGearSize.lock();
|
||||||
|
_currentGearSize = bike_computer::kMaxGearSize - currentGear->gear;
|
||||||
|
_mutexGearSize.unlock();
|
||||||
|
// END CRITICAL SECTION
|
||||||
|
|
||||||
|
osStatus status = _mailGearDevice.free(currentGear);
|
||||||
|
if (status != osOK) {
|
||||||
|
tr_error("free current gear in the gear tasks doesn't work !");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ThisThread::sleep_for(std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||||
|
kGearTaskComputationTime - (_timer.elapsed_time() - taskStartTime)));
|
||||||
|
|
||||||
|
_taskLogger.logPeriodAndExecutionTime(
|
||||||
|
_timer, advembsof::TaskLogger::kGearTaskIndex, taskStartTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Main thread functions */
|
||||||
|
|
||||||
|
void BikeSystem::temperatureTask() {
|
||||||
|
auto taskStartTime = _timer.elapsed_time();
|
||||||
|
|
||||||
|
// no need to protect access to data members (single threaded)
|
||||||
|
_currentTemperature = _sensorDevice.readTemperature();
|
||||||
|
|
||||||
|
ThisThread::sleep_for(std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||||
|
kTemperatureTaskComputationTime - (_timer.elapsed_time() - taskStartTime)));
|
||||||
|
|
||||||
|
_taskLogger.logPeriodAndExecutionTime(
|
||||||
|
_timer, advembsof::TaskLogger::kTemperatureTaskIndex, taskStartTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BikeSystem::displayTask() {
|
||||||
|
auto taskStartTime = _timer.elapsed_time();
|
||||||
|
|
||||||
|
// ENTER CRITICAL SECTION
|
||||||
|
_displayDevice.displayGear(getCurrentGear());
|
||||||
|
_displayDevice.displaySpeed(getCurrentSpeed());
|
||||||
|
_displayDevice.displayDistance(getCurrentDistance());
|
||||||
|
// END CRITICAL SECTION
|
||||||
|
|
||||||
|
_displayDevice.displayTemperature(_currentTemperature);
|
||||||
|
|
||||||
|
// ThisThread::sleep_for(std::chrono::duration_cast<std::chrono::milliseconds>(kDisplayTask1ComputationTime
|
||||||
|
// - (_timer.elapsed_time() - taskStartTime)));
|
||||||
|
|
||||||
|
_taskLogger.logPeriodAndExecutionTime(
|
||||||
|
_timer, advembsof::TaskLogger::kDisplayTask1Index, taskStartTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BikeSystem::cpuTask() { _cpuLogger.printStats(); }
|
||||||
|
|
||||||
|
void BikeSystem::dispatch_isr_events() {
|
||||||
|
tr_info("Start dispatching isr events");
|
||||||
|
_isrEventQueue.dispatch_forever();
|
||||||
|
tr_info("Stop dispatching isr events");
|
||||||
|
}
|
||||||
|
|
||||||
|
void BikeSystem::dispatch_events() {
|
||||||
|
tr_info("Start dispatching main events");
|
||||||
|
_eventQueue.dispatch_forever();
|
||||||
|
tr_info("Stop dispatching main events");
|
||||||
|
}
|
||||||
|
|
||||||
|
void BikeSystem::loop_speed_distance_task() {
|
||||||
|
tr_info("Start loop speed-distance calculation");
|
||||||
|
while (true) {
|
||||||
|
speedDistanceTask();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void BikeSystem::loop_gear_task() {
|
||||||
|
tr_info("Start loop gear calculation");
|
||||||
|
while (true) {
|
||||||
|
gearTask();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t BikeSystem::getCurrentGear() {
|
||||||
|
uint8_t currentGear;
|
||||||
|
|
||||||
|
// ENTER CRITICAL SECTION
|
||||||
|
_mutexGear.lock();
|
||||||
|
currentGear = _currentGear;
|
||||||
|
_mutexGear.unlock();
|
||||||
|
// END CRITICAL SECTION
|
||||||
|
|
||||||
|
return currentGear;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t BikeSystem::getCurrentGearSize() {
|
||||||
|
uint8_t currentGearSize;
|
||||||
|
|
||||||
|
// ENTER CRITICAL SECTION
|
||||||
|
_mutexGearSize.lock();
|
||||||
|
currentGearSize = _currentGearSize;
|
||||||
|
_mutexGearSize.unlock();
|
||||||
|
// END CRITICAL SECTION
|
||||||
|
|
||||||
|
return currentGearSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
float BikeSystem::getCurrentSpeed() {
|
||||||
|
float currentSpeed;
|
||||||
|
|
||||||
|
// ENTER CRITICAL SECTION
|
||||||
|
_mutexSpeed.lock();
|
||||||
|
currentSpeed = _currentSpeed;
|
||||||
|
_mutexSpeed.unlock();
|
||||||
|
// END CRITICAL SECTION
|
||||||
|
|
||||||
|
return currentSpeed;
|
||||||
|
}
|
||||||
|
|
||||||
|
float BikeSystem::getCurrentDistance() {
|
||||||
|
float currentDistance;
|
||||||
|
|
||||||
|
// ENTER CRITICAL SECTION
|
||||||
|
_mutexDistance.lock();
|
||||||
|
currentDistance = _traveledDistance;
|
||||||
|
_mutexDistance.unlock();
|
||||||
|
// END CRITICAL SECTION
|
||||||
|
|
||||||
|
return currentDistance;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace multi_tasking
|
171
multi_tasking/bike_system.hpp
Normal file
171
multi_tasking/bike_system.hpp
Normal file
@ -0,0 +1,171 @@
|
|||||||
|
// Copyright 2022 Haute école d'ingénierie et d'architecture de Fribourg
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* @file bike_system.hpp
|
||||||
|
* @author Serge Ayer <serge.ayer@hefr.ch>
|
||||||
|
*
|
||||||
|
* @brief Bike System header file (static scheduling)
|
||||||
|
*
|
||||||
|
* @date 2023-08-20
|
||||||
|
* @version 1.0.0
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
// from advembsof
|
||||||
|
#include "cpu_logger.hpp"
|
||||||
|
#include "display_device.hpp"
|
||||||
|
#include "mbed.h"
|
||||||
|
#include "task_logger.hpp"
|
||||||
|
|
||||||
|
// from common
|
||||||
|
#include "sensor_device.hpp"
|
||||||
|
#include "speedometer.hpp"
|
||||||
|
|
||||||
|
// local
|
||||||
|
#include "gear_device.hpp"
|
||||||
|
#include "pedal_device.hpp"
|
||||||
|
#include "reset_device.hpp"
|
||||||
|
|
||||||
|
namespace multi_tasking {
|
||||||
|
|
||||||
|
class BikeSystem {
|
||||||
|
public:
|
||||||
|
// constructor
|
||||||
|
BikeSystem();
|
||||||
|
|
||||||
|
// make the class non copyable
|
||||||
|
BikeSystem(BikeSystem&) = delete;
|
||||||
|
BikeSystem& operator=(BikeSystem&) = delete;
|
||||||
|
|
||||||
|
// method called in main() for starting the system
|
||||||
|
void start();
|
||||||
|
|
||||||
|
// method called for stopping the system
|
||||||
|
void stop();
|
||||||
|
|
||||||
|
#if defined(MBED_TEST_MODE)
|
||||||
|
const advembsof::TaskLogger& getTaskLogger();
|
||||||
|
bike_computer::Speedometer& getSpeedometer();
|
||||||
|
GearDevice& getGearDevice();
|
||||||
|
void setCallbackGearChage(Callback<void()> cbGearChange);
|
||||||
|
Callback<void()> _cbGearChange;
|
||||||
|
#endif // defined(MBED_TEST_MODE)
|
||||||
|
|
||||||
|
private:
|
||||||
|
// private methods
|
||||||
|
void init();
|
||||||
|
|
||||||
|
// Main Thread
|
||||||
|
void temperatureTask();
|
||||||
|
void displayTask();
|
||||||
|
void cpuTask();
|
||||||
|
|
||||||
|
// ISR Thread
|
||||||
|
#if defined(MBED_TEST_MODE)
|
||||||
|
|
||||||
|
public:
|
||||||
|
#endif
|
||||||
|
void onReset();
|
||||||
|
#if defined(MBED_TEST_MODE)
|
||||||
|
|
||||||
|
private:
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void resetTask();
|
||||||
|
|
||||||
|
// gear Thread
|
||||||
|
void gearTask();
|
||||||
|
|
||||||
|
// Speed / Distance Thread
|
||||||
|
void speedDistanceTask();
|
||||||
|
|
||||||
|
// GETTER - SETTER
|
||||||
|
uint8_t getCurrentGear();
|
||||||
|
uint8_t getCurrentGearSize();
|
||||||
|
float getCurrentSpeed();
|
||||||
|
float getCurrentDistance();
|
||||||
|
void setCurrentGear(uint8_t gear);
|
||||||
|
|
||||||
|
// Thread functions
|
||||||
|
void dispatch_isr_events();
|
||||||
|
void dispatch_events();
|
||||||
|
void loop_speed_distance_task();
|
||||||
|
void loop_gear_task();
|
||||||
|
|
||||||
|
// timer instance used for loggint task time and used by ResetDevice
|
||||||
|
std::chrono::microseconds _resetTime = std::chrono::microseconds::zero();
|
||||||
|
std::chrono::microseconds _onGearUpTime = std::chrono::microseconds::zero();
|
||||||
|
std::chrono::microseconds _onGearDownTime = std::chrono::microseconds::zero();
|
||||||
|
|
||||||
|
Timer _timer;
|
||||||
|
|
||||||
|
// Event queues
|
||||||
|
EventQueue _isrEventQueue;
|
||||||
|
EventQueue _eventQueue;
|
||||||
|
|
||||||
|
// Mail
|
||||||
|
Mail<pedalMail_t, 16> _mailPedalDevice;
|
||||||
|
Mail<gearMail_t, 16> _mailGearDevice;
|
||||||
|
|
||||||
|
// mutex for shared resource
|
||||||
|
Mutex _mutexGearSize;
|
||||||
|
Mutex _mutexGear;
|
||||||
|
Mutex _mutexSpeed;
|
||||||
|
Mutex _mutexDistance;
|
||||||
|
Mutex _mutexSpeedometer;
|
||||||
|
|
||||||
|
// Tread for isr events
|
||||||
|
Thread _isrEventThread;
|
||||||
|
Thread _speedDistanceThread;
|
||||||
|
Thread _gearTaskThread;
|
||||||
|
|
||||||
|
// data member that represents the device for manipulating the gear
|
||||||
|
GearDevice _gearDevice;
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////
|
||||||
|
// shared resources between the main thread and the isr thread
|
||||||
|
uint8_t _currentGear = bike_computer::kMinGear;
|
||||||
|
uint8_t _currentGearSize = bike_computer::kMaxGearSize;
|
||||||
|
//////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
// data member that represents the device for manipulating the pedal rotation
|
||||||
|
// speed/time
|
||||||
|
PedalDevice _pedalDevice;
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////
|
||||||
|
// shared resources between the main thread and the isr thread
|
||||||
|
float _currentSpeed = 0.0f;
|
||||||
|
float _traveledDistance = 0.0f;
|
||||||
|
//////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
// data member that represents the device used for resetting
|
||||||
|
ResetDevice _resetDevice;
|
||||||
|
// data member that represents the device display
|
||||||
|
advembsof::DisplayDevice _displayDevice;
|
||||||
|
// data member that represents the device for counting wheel rotations
|
||||||
|
bike_computer::Speedometer _speedometer;
|
||||||
|
// data member that represents the sensor device
|
||||||
|
bike_computer::SensorDevice _sensorDevice;
|
||||||
|
float _currentTemperature = 0.0f;
|
||||||
|
|
||||||
|
// used for logging task info
|
||||||
|
advembsof::TaskLogger _taskLogger;
|
||||||
|
|
||||||
|
// cpu logger to measure cpu usage
|
||||||
|
advembsof::CPULogger _cpuLogger;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace multi_tasking
|
74
multi_tasking/gear_device.cpp
Normal file
74
multi_tasking/gear_device.cpp
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
// Copyright 2022 Haute école d'ingénierie et d'architecture de Fribourg
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* @file gear_device.cpp
|
||||||
|
* @author Serge Ayer <serge.ayer@hefr.ch>
|
||||||
|
* @author Rémi Heredero <remi@heredero.ch>
|
||||||
|
* @author Yann Sierro <yannsierro.pro@gmail.com>
|
||||||
|
*
|
||||||
|
* @brief Gear Device implementation (static scheduling)
|
||||||
|
*
|
||||||
|
* @date 2023-11-17
|
||||||
|
* @version 1.1.0
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
#include "gear_device.hpp"
|
||||||
|
|
||||||
|
#include "bike_system.hpp"
|
||||||
|
|
||||||
|
// from disco_h747i/wrappers
|
||||||
|
|
||||||
|
#include "joystick.hpp"
|
||||||
|
#include "mbed_atomic.h"
|
||||||
|
#include "mbed_trace.h"
|
||||||
|
|
||||||
|
#if MBED_CONF_MBED_TRACE_ENABLE
|
||||||
|
#define TRACE_GROUP "GearDevice"
|
||||||
|
#endif // MBED_CONF_MBED_TRACE_ENABLE
|
||||||
|
|
||||||
|
namespace multi_tasking {
|
||||||
|
|
||||||
|
GearDevice::GearDevice(Mail<gearMail_t, 16>* mailBox, Timer& timer)
|
||||||
|
: _mailBox(mailBox), _timer(timer) {
|
||||||
|
disco::Joystick::getInstance().setUpCallback(callback(this, &GearDevice::onUp));
|
||||||
|
disco::Joystick::getInstance().setDownCallback(callback(this, &GearDevice::onDown));
|
||||||
|
}
|
||||||
|
|
||||||
|
void GearDevice::onUp() {
|
||||||
|
if (_currentGear < bike_computer::kMaxGear) {
|
||||||
|
core_util_atomic_incr_u8(&_currentGear, 1);
|
||||||
|
sendMail(core_util_atomic_load_u8(&_currentGear));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void GearDevice::onDown() {
|
||||||
|
if (_currentGear > bike_computer::kMinGear) {
|
||||||
|
core_util_atomic_decr_u8(&_currentGear, 1);
|
||||||
|
sendMail(core_util_atomic_load_u8(&_currentGear));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void GearDevice::sendMail(uint32_t data) {
|
||||||
|
if (_mailBox != nullptr) {
|
||||||
|
gearMail_t* currentGear = _mailBox->try_alloc();
|
||||||
|
if (currentGear != nullptr) {
|
||||||
|
currentGear->gear = data;
|
||||||
|
currentGear->callTime = _timer.elapsed_time();
|
||||||
|
_mailBox->put(currentGear);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace multi_tasking
|
61
multi_tasking/gear_device.hpp
Normal file
61
multi_tasking/gear_device.hpp
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
// Copyright 2022 Haute école d'ingénierie et d'architecture de Fribourg
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* @file gear_device.hpp
|
||||||
|
* @author Serge Ayer <serge.ayer@hefr.ch>
|
||||||
|
* @author Rémi Heredero <remi@heredero.ch>
|
||||||
|
* @author Yann Sierro <yannsierro.pro@gmail.com>
|
||||||
|
*
|
||||||
|
* @brief Gear Device header file (static scheduling)
|
||||||
|
*
|
||||||
|
* @date 2023-11-17
|
||||||
|
* @version 1.1.0
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "common/constants.hpp"
|
||||||
|
#include "mbed.h"
|
||||||
|
|
||||||
|
namespace multi_tasking {
|
||||||
|
|
||||||
|
typedef struct gearMail {
|
||||||
|
uint8_t gear;
|
||||||
|
std::chrono::microseconds callTime;
|
||||||
|
} gearMail_t;
|
||||||
|
|
||||||
|
class GearDevice {
|
||||||
|
public:
|
||||||
|
explicit GearDevice(Mail<gearMail_t, 16>* mailBox,
|
||||||
|
Timer& timer); // NOLINT(runtime/references)
|
||||||
|
|
||||||
|
// make the class non copyable
|
||||||
|
GearDevice(GearDevice&) = delete;
|
||||||
|
GearDevice& operator=(GearDevice&) = delete;
|
||||||
|
|
||||||
|
// method called for updating the bike system
|
||||||
|
void onUp();
|
||||||
|
void onDown();
|
||||||
|
|
||||||
|
void sendMail(uint32_t data);
|
||||||
|
|
||||||
|
private:
|
||||||
|
// data members
|
||||||
|
volatile uint8_t _currentGear = bike_computer::kMinGear;
|
||||||
|
Mail<gearMail_t, 16>* _mailBox;
|
||||||
|
Timer& _timer;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace multi_tasking
|
85
multi_tasking/pedal_device.cpp
Normal file
85
multi_tasking/pedal_device.cpp
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
// Copyright 2022 Haute école d'ingénierie et d'architecture de Fribourg
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* @file pedal_device.cpp
|
||||||
|
* @author Rémi Heredero <remi@heredero.ch>
|
||||||
|
* @author Yann Sierro <yannsierro.pro@gmail.com>
|
||||||
|
*
|
||||||
|
* @brief Pedal Device implementation (static scheduling)
|
||||||
|
* @date 2024-11-17
|
||||||
|
* @version 1.1.0
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#include "pedal_device.hpp"
|
||||||
|
|
||||||
|
// from disco_h747i/wrappers
|
||||||
|
#include <chrono>
|
||||||
|
|
||||||
|
#include "bike_system.hpp"
|
||||||
|
#include "joystick.hpp"
|
||||||
|
#include "mbed_trace.h"
|
||||||
|
|
||||||
|
#if MBED_CONF_MBED_TRACE_ENABLE
|
||||||
|
#define TRACE_GROUP "PedalDevice"
|
||||||
|
#endif // MBED_CONF_MBED_TRACE_ENABLE
|
||||||
|
|
||||||
|
namespace multi_tasking {
|
||||||
|
|
||||||
|
PedalDevice::PedalDevice(Mail<pedalMail_t, 16>* mailBox, Timer& timer)
|
||||||
|
: _mailBox(mailBox), _timer(timer) {
|
||||||
|
disco::Joystick::getInstance().setLeftCallback(callback(this, &PedalDevice::onLeft));
|
||||||
|
disco::Joystick::getInstance().setRightCallback(
|
||||||
|
callback(this, &PedalDevice::onRight));
|
||||||
|
}
|
||||||
|
|
||||||
|
void PedalDevice::increaseRotationSpeed() {
|
||||||
|
uint32_t currentStep = core_util_atomic_load_u32(&_currentStep);
|
||||||
|
if (currentStep > 0) {
|
||||||
|
core_util_atomic_decr_u32(&_currentStep, 1);
|
||||||
|
sendMail(core_util_atomic_load_u32(&_currentStep));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PedalDevice::decreaseRotationSpeed() {
|
||||||
|
uint32_t currentStep = core_util_atomic_load_u32(&_currentStep);
|
||||||
|
if (currentStep < bike_computer::kNbrOfSteps) {
|
||||||
|
core_util_atomic_incr_u32(&_currentStep, 1);
|
||||||
|
sendMail(core_util_atomic_load_u32(&_currentStep));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PedalDevice::onLeft() { decreaseRotationSpeed(); }
|
||||||
|
|
||||||
|
void PedalDevice::onRight() { increaseRotationSpeed(); }
|
||||||
|
|
||||||
|
void PedalDevice::sendMail(uint32_t data) {
|
||||||
|
if (_mailBox != nullptr) {
|
||||||
|
pedalMail_t* currentStep = _mailBox->try_alloc();
|
||||||
|
if (currentStep != nullptr) {
|
||||||
|
currentStep->step = data;
|
||||||
|
currentStep->callTime = _timer.elapsed_time();
|
||||||
|
_mailBox->put(currentStep);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// static methods
|
||||||
|
|
||||||
|
std::chrono::milliseconds PedalDevice::getCurrentRotationTime(uint32_t step) {
|
||||||
|
return bike_computer::kMinPedalRotationTime +
|
||||||
|
step * bike_computer::kDeltaPedalRotationTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace multi_tasking
|
69
multi_tasking/pedal_device.hpp
Normal file
69
multi_tasking/pedal_device.hpp
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
// Copyright 2022 Haute école d'ingénierie et d'architecture de Fribourg
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* @file pedal_device.hpp
|
||||||
|
* @author Serge Ayer <serge.ayer@hefr.ch>
|
||||||
|
* @author Rémi Heredero <remi@heredero.ch>
|
||||||
|
* @author Yann Sierro <yannsierro.pro@gmail.com>
|
||||||
|
*
|
||||||
|
* @brief Pedal System header file (static scheduling)
|
||||||
|
*
|
||||||
|
* @date 2023-11-17
|
||||||
|
* @version 1.1.0
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "constants.hpp"
|
||||||
|
#include "mbed.h"
|
||||||
|
|
||||||
|
namespace multi_tasking {
|
||||||
|
|
||||||
|
typedef struct pedalMail {
|
||||||
|
uint8_t step;
|
||||||
|
std::chrono::microseconds callTime;
|
||||||
|
} pedalMail_t;
|
||||||
|
|
||||||
|
class PedalDevice {
|
||||||
|
public:
|
||||||
|
explicit PedalDevice(Mail<pedalMail_t, 16>* mailBox, // NOLINT (runtime/references)
|
||||||
|
Timer& timer); // NOLINT (runtime/references)
|
||||||
|
|
||||||
|
// make the class non copyable
|
||||||
|
PedalDevice(PedalDevice&) = delete;
|
||||||
|
PedalDevice& operator=(PedalDevice&) = delete;
|
||||||
|
|
||||||
|
// method called for updating the bike system
|
||||||
|
static std::chrono::milliseconds getCurrentRotationTime(uint32_t step);
|
||||||
|
|
||||||
|
private:
|
||||||
|
// private methods
|
||||||
|
void onLeft();
|
||||||
|
void onRight();
|
||||||
|
void increaseRotationSpeed();
|
||||||
|
void decreaseRotationSpeed();
|
||||||
|
|
||||||
|
void sendMail(uint32_t data);
|
||||||
|
// data members
|
||||||
|
volatile uint32_t _currentStep = static_cast<uint32_t>(
|
||||||
|
(bike_computer::kInitialPedalRotationTime - bike_computer::kMinPedalRotationTime)
|
||||||
|
.count() /
|
||||||
|
bike_computer::kDeltaPedalRotationTime.count());
|
||||||
|
|
||||||
|
Mail<pedalMail_t, 16>* _mailBox;
|
||||||
|
Timer& _timer;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace multi_tasking
|
48
multi_tasking/reset_device.cpp
Normal file
48
multi_tasking/reset_device.cpp
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
// Copyright 2022 Haute école d'ingénierie et d'architecture de Fribourg
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* @file reset_device.cpp
|
||||||
|
* @author Rémi Heredero <remi@heredero.ch>
|
||||||
|
* @author Yann Sierro <yannsierro.pro@gmail.com>
|
||||||
|
*
|
||||||
|
* @brief Reset Device implementation (static scheduling with event)
|
||||||
|
* @date 2024-11-17
|
||||||
|
* @version 1.1.0
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#include "reset_device.hpp"
|
||||||
|
|
||||||
|
// from disco_h747i/wrappers
|
||||||
|
#include <chrono>
|
||||||
|
|
||||||
|
#include "joystick.hpp"
|
||||||
|
#include "mbed_trace.h"
|
||||||
|
|
||||||
|
#if defined(TARGET_DISCO_H747I)
|
||||||
|
#define PUSH_BUTTON BUTTON1
|
||||||
|
static constexpr uint8_t kPolarityPressed = 1;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if MBED_CONF_MBED_TRACE_ENABLE
|
||||||
|
#define TRACE_GROUP "ResetDevice"
|
||||||
|
#endif // MBED_CONF_MBED_TRACE_ENABLE
|
||||||
|
|
||||||
|
namespace multi_tasking {
|
||||||
|
|
||||||
|
ResetDevice::ResetDevice(Callback<void()> cb) : _resetButton(PUSH_BUTTON) {
|
||||||
|
_resetButton.fall(cb);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace multi_tasking
|
47
multi_tasking/reset_device.hpp
Normal file
47
multi_tasking/reset_device.hpp
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
// Copyright 2022 Haute école d'ingénierie et d'architecture de Fribourg
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* @file reset_device.hpp
|
||||||
|
* @author Serge Ayer <serge.ayer@hefr.ch>
|
||||||
|
* @author Rémi Heredero <remi@heredero.ch>
|
||||||
|
* @author Yann Sierro <yannsierro.pro@gmail.com>
|
||||||
|
*
|
||||||
|
* @brief ResetDevice header file (static scheduling with event)
|
||||||
|
*
|
||||||
|
* @date 2023-11-17
|
||||||
|
* @version 1.1.0
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "mbed.h"
|
||||||
|
|
||||||
|
namespace multi_tasking {
|
||||||
|
|
||||||
|
class ResetDevice {
|
||||||
|
public:
|
||||||
|
explicit ResetDevice(Callback<void()> cb); // NOLINT(runtime/references)
|
||||||
|
|
||||||
|
// make the class non copyable
|
||||||
|
ResetDevice(ResetDevice&) = delete;
|
||||||
|
ResetDevice& operator=(ResetDevice&) = delete;
|
||||||
|
|
||||||
|
private:
|
||||||
|
// data members
|
||||||
|
// instance representing the reset button
|
||||||
|
InterruptIn _resetButton;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace multi_tasking
|
@ -80,7 +80,7 @@ class BikeSystem {
|
|||||||
// data member that represents the device for manipulating the gear
|
// data member that represents the device for manipulating the gear
|
||||||
GearDevice _gearDevice;
|
GearDevice _gearDevice;
|
||||||
uint8_t _currentGear = bike_computer::kMinGear;
|
uint8_t _currentGear = bike_computer::kMinGear;
|
||||||
uint8_t _currentGearSize = bike_computer::kMinGearSize;
|
uint8_t _currentGearSize = bike_computer::kMaxGearSize;
|
||||||
// data member that represents the device for manipulating the pedal rotation
|
// data member that represents the device for manipulating the pedal rotation
|
||||||
// speed/time
|
// speed/time
|
||||||
PedalDevice _pedalDevice;
|
PedalDevice _pedalDevice;
|
||||||
|
@ -85,7 +85,7 @@ class BikeSystem {
|
|||||||
// data member that represents the device for manipulating the gear
|
// data member that represents the device for manipulating the gear
|
||||||
GearDevice _gearDevice;
|
GearDevice _gearDevice;
|
||||||
uint8_t _currentGear = bike_computer::kMinGear;
|
uint8_t _currentGear = bike_computer::kMinGear;
|
||||||
uint8_t _currentGearSize = bike_computer::kMinGearSize;
|
uint8_t _currentGearSize = bike_computer::kMaxGearSize;
|
||||||
// data member that represents the device for manipulating the pedal rotation
|
// data member that represents the device for manipulating the pedal rotation
|
||||||
// speed/time
|
// speed/time
|
||||||
PedalDevice _pedalDevice;
|
PedalDevice _pedalDevice;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user