Compare commits
70 Commits
Author | SHA1 | Date | |
---|---|---|---|
fdab57142a | |||
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 | |||
5a85e1da8d | |||
9eb4f64b73
|
|||
031b98a0f7 | |||
ca33d26769 | |||
4c9a0e25a7 | |||
544df31a1b | |||
1f9e4ebd3c | |||
69bc8785a8 | |||
31e1f22c59 | |||
c0335b38a4 | |||
f8077db299 | |||
367c7178c0 | |||
394f4febff | |||
a887c91775 | |||
d176856326 | |||
7d7fb400ff | |||
db834de1fd | |||
84bd49be80 | |||
ebfcef2c57 | |||
e7a2a7da59 | |||
9aa656c7ac | |||
9c104fc3a2 | |||
da79a18cd9 | |||
c4ff5361e9 | |||
7b5bcfc35e | |||
c92de22c09 | |||
1ba466569e | |||
98f3a32a68 | |||
171c43b653 | |||
60baebd59b | |||
eeb88edba3 | |||
ac4067e5a4 | |||
86e033fe2f | |||
f6f3d59ef3 | |||
20406664c3 | |||
62d7d7b376 | |||
35d2d76bca | |||
0bd561b947 | |||
b52f476124 | |||
c66c8a0963 | |||
4c174ce444 | |||
15d1183bac | |||
df8edf3c34 |
8
.github/workflows/build-test.yml
vendored
8
.github/workflows/build-test.yml
vendored
@ -1,6 +1,6 @@
|
||||
name: Build test application
|
||||
on:
|
||||
pull_request:
|
||||
push:
|
||||
|
||||
jobs:
|
||||
build-cli-v1:
|
||||
@ -14,11 +14,9 @@ jobs:
|
||||
target: [DISCO_H747I]
|
||||
profile: [debug]
|
||||
tests: [
|
||||
tests-simple-test-always-succeed,
|
||||
tests-simple-test-test-ptr,
|
||||
advdembsof_library-tests-sensors-hdc1000,
|
||||
tests-bike-computer-sensor-device,
|
||||
tests-bike-computer-speedometer
|
||||
tests-bike-computer-speedometer,
|
||||
tests-bike-computer-bike-system,
|
||||
]
|
||||
|
||||
|
||||
|
2
.gitignore
vendored
2
.gitignore
vendored
@ -4,5 +4,5 @@ projectfiles
|
||||
*.py*
|
||||
BUILD
|
||||
mbed-os
|
||||
DISCO_h747i
|
||||
DISCO_H747I
|
||||
advdembsof_library
|
||||
|
@ -15,3 +15,4 @@ mbed-os/features/frameworks/mbed-client-cli/*
|
||||
mbed-os/features/frameworks/COMPONENT_FPGA_CI_TEST_SHIELD/*
|
||||
mbed-os/platform/randlib/*
|
||||
mbed-os/storage/kvstore/*
|
||||
mbed-os-bootloader/*
|
@ -1,24 +1,26 @@
|
||||
files: ^main.cpp
|
||||
files: ^main.cpp|^static_scheduling|^static_scheduling_with_event|^TESTS|^multi_tasking|^common
|
||||
repos:
|
||||
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||
- 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'
|
||||
- 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'
|
||||
- repo: https://github.com/cpplint/cpplint
|
||||
rev: "1.6.1"
|
||||
hooks:
|
||||
- id: cpplint
|
||||
- repo: local
|
||||
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
|
||||
entry: cppcheck --enable=all --suppress=missingInclude --suppress=missingIncludeSystem --inline-suppr -i mbed-os --std=c++14 --error-exitcode=1
|
||||
language: system
|
97
README.md
97
README.md
@ -22,3 +22,100 @@ Test sensor libraries :
|
||||
```terminal
|
||||
mbed test -m DISCO_H747I -t GCC_ARM -n advdembsof_library-tests-sensors-hdc1000 --compile --run
|
||||
```
|
||||
|
||||
## Run static scheduling
|
||||
On `.mbedignore` put at the end of the file
|
||||
```
|
||||
static_scheduling_with_event/*
|
||||
multi_tasking/*
|
||||
```
|
||||
|
||||
On main.cpp include `"static_scheduling/bike_system.hpp"` and use :
|
||||
```cpp
|
||||
static_scheduling::BikeSystem bikeSystem;
|
||||
bikeSystem.start();
|
||||
```
|
||||
|
||||
## Run static scheduling with event queue
|
||||
On `.mbedignore` put at the end of the file :
|
||||
```
|
||||
static_scheduling_with_event/*
|
||||
multi_tasking/*
|
||||
```
|
||||
|
||||
On main.cpp include `"static_scheduling/bike_system.hpp"` and use :
|
||||
```cpp
|
||||
static_scheduling::BikeSystem bikeSystem;
|
||||
bikeSystem.startWithEventQueue();
|
||||
```
|
||||
|
||||
## Run static scheduling with event scheduling
|
||||
On `.mbedignore` put at the end of the file
|
||||
```
|
||||
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 :
|
||||
```cpp
|
||||
static_scheduling_with_event::BikeSystem bikeSystem;
|
||||
bikeSystem.start();
|
||||
```
|
||||
|
||||
# Some questions
|
||||
## Question 1
|
||||
`If you print CPU statistics at the end of every major cycle (in the super-loop), what CPU usage do you observe? How can you explain the observed CPU uptime?`
|
||||
|
||||
We observe a 100% usage because on each CPU cycle it compare if time is done.
|
||||
|
||||
## Question 2
|
||||
`If you run the program after the change from busy wait to sleep calls, what CPU usage do you observe? How can you explain the observed CPU uptime?`
|
||||
|
||||
We can observe only a usage of 75% because the CPU is more on Idle with Thread sleep.
|
||||
|
||||
## Question 3
|
||||
`If you run the static_scheduling_with_event program, what CPU usage do you observe? How can you explain the observed CPU uptime?`
|
||||
|
||||
We observe a light usage of 1% of CPU. The CPU is now sleeping all the time and doing small task only on event.
|
||||
|
||||
## Question 4
|
||||
`When you run multiple tests for computing the response time of the reset event, what do you observe? Is there an improvement as compared to the static_scheduling::BikeSystem implementation?`
|
||||
|
||||
` - If you do not press long enough on the push button, the event may be missed and no reset happens.`
|
||||
|
||||
`Based on the program itself and on the task scheduling, explain these two behaviors. Explain also why such behaviors may be problematic.`
|
||||
|
||||
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
|
||||
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.
|
||||
As the acceptable delta is 2ms and the teacher test is done with GCC, we modify the delta on the test to be 3ms
|
||||
|
408
TESTS/bike-computer/bike-system/main.cpp
Normal file
408
TESTS/bike-computer/bike-system/main.cpp
Normal file
@ -0,0 +1,408 @@
|
||||
// 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 main.cpp
|
||||
* @author Serge Ayer <serge.ayer@hefr.ch>
|
||||
*
|
||||
* @brief Bike computer test suite: scheduling
|
||||
*
|
||||
* @date 2023-08-26
|
||||
* @version 0.1.0
|
||||
***************************************************************************/
|
||||
|
||||
#include <chrono>
|
||||
#include <cstdint>
|
||||
|
||||
#include "gear_device.hpp"
|
||||
#include "greentea-client/test_env.h"
|
||||
#include "mbed.h"
|
||||
#include "mbed_trace.h" // NOLINT
|
||||
#include "multi_tasking/bike_system.hpp"
|
||||
#include "static_scheduling/bike_system.hpp"
|
||||
#include "static_scheduling_with_event/bike_system.hpp"
|
||||
#include "task_logger.hpp"
|
||||
#include "unity/unity.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 v1 {
|
||||
|
||||
// test_bike_system handler function
|
||||
static void test_bike_system() {
|
||||
// create the BikeSystem instance
|
||||
static_scheduling::BikeSystem bikeSystem;
|
||||
|
||||
// run the bike system in a separate thread
|
||||
Thread thread;
|
||||
thread.start(callback(&bikeSystem, &static_scheduling::BikeSystem::start));
|
||||
|
||||
// let the bike system run for 20 secs
|
||||
ThisThread::sleep_for(20s);
|
||||
|
||||
// stop the bike system
|
||||
bikeSystem.stop();
|
||||
|
||||
// check whether scheduling was correct
|
||||
// Order is kGearTaskIndex, kSpeedTaskIndex, kTemperatureTaskIndex,
|
||||
// kResetTaskIndex, kDisplayTask1Index, kDisplayTask2Index
|
||||
constexpr std::chrono::microseconds taskComputationTimes[] = {
|
||||
100000us, 200000us, 100000us, 100000us, 200000us, 100000us};
|
||||
constexpr std::chrono::microseconds taskPeriods[] = {
|
||||
800000us, 400000us, 1600000us, 800000us, 1600000us, 1600000us};
|
||||
|
||||
// allow for 2 msecs offset
|
||||
uint64_t deltaUs = 3000;
|
||||
for (uint8_t taskIndex = 0; taskIndex < advembsof::TaskLogger::kNbrOfTasks;
|
||||
taskIndex++) {
|
||||
TEST_ASSERT_UINT64_WITHIN(
|
||||
deltaUs,
|
||||
taskPeriods[taskIndex].count(),
|
||||
bikeSystem.getTaskLogger().getPeriod(taskIndex).count());
|
||||
TEST_ASSERT_UINT64_WITHIN(
|
||||
deltaUs,
|
||||
taskComputationTimes[taskIndex].count(),
|
||||
bikeSystem.getTaskLogger().getComputationTime(taskIndex).count());
|
||||
}
|
||||
}
|
||||
|
||||
// test_bike_system_event_queue handler function
|
||||
static void test_bike_system_event_queue() {
|
||||
// create the BikeSystem instance
|
||||
static_scheduling::BikeSystem bikeSystem;
|
||||
|
||||
// run the bike system in a separate thread
|
||||
Thread thread;
|
||||
thread.start(
|
||||
callback(&bikeSystem, &static_scheduling::BikeSystem::startWithEventQueue));
|
||||
|
||||
// let the bike system run for 20 secs
|
||||
ThisThread::sleep_for(20s);
|
||||
|
||||
// stop the bike system
|
||||
bikeSystem.stop();
|
||||
|
||||
// check whether scheduling was correct
|
||||
// Order is kGearTaskIndex, kSpeedTaskIndex, kTemperatureTaskIndex,
|
||||
// kResetTaskIndex, kDisplayTask1Index, kDisplayTask2Index
|
||||
// When we use the event queue, 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)
|
||||
uint64_t deltaUs = 3000;
|
||||
for (uint8_t taskIndex = 0; taskIndex < advembsof::TaskLogger::kNbrOfTasks;
|
||||
taskIndex++) {
|
||||
TEST_ASSERT_UINT64_WITHIN(
|
||||
deltaUs,
|
||||
taskPeriods[taskIndex].count(),
|
||||
bikeSystem.getTaskLogger().getPeriod(taskIndex).count());
|
||||
}
|
||||
}
|
||||
|
||||
// test_bike_system_with_event handler function
|
||||
static void test_bike_system_with_event() {
|
||||
// create the BikeSystem instance
|
||||
static_scheduling_with_event::BikeSystem bikeSystem;
|
||||
|
||||
// run the bike system in a separate thread
|
||||
Thread thread;
|
||||
thread.start(callback(&bikeSystem, &static_scheduling_with_event::BikeSystem::start));
|
||||
|
||||
// let the bike system run for 20 secs
|
||||
ThisThread::sleep_for(20s);
|
||||
|
||||
// stop the bike system
|
||||
bikeSystem.stop();
|
||||
|
||||
// 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)
|
||||
uint64_t deltaUs = 3000;
|
||||
for (uint8_t taskIndex = 0; taskIndex < advembsof::TaskLogger::kNbrOfTasks;
|
||||
taskIndex++) {
|
||||
TEST_ASSERT_UINT64_WITHIN(
|
||||
deltaUs,
|
||||
taskPeriods[taskIndex].count(),
|
||||
bikeSystem.getTaskLogger().getPeriod(taskIndex).count());
|
||||
}
|
||||
}
|
||||
|
||||
// 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) {
|
||||
// Here, we specify the timeout (60s) and the host test (a built-in host test
|
||||
// or the name of our Python file)
|
||||
GREENTEA_SETUP(180, "default_auto");
|
||||
|
||||
return greentea_test_setup_handler(number_of_cases);
|
||||
}
|
||||
|
||||
// List of test cases in this file
|
||||
static Case cases[] = {
|
||||
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", 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);
|
||||
|
||||
}; // namespace v1
|
||||
}; // namespace utest
|
||||
|
||||
int main() {
|
||||
#if defined(MBED_CONF_MBED_TRACE_ENABLE)
|
||||
mbed_trace_init();
|
||||
#endif
|
||||
return !utest::v1::Harness::run(utest::v1::specification);
|
||||
}
|
@ -29,7 +29,8 @@
|
||||
#include "unity/unity.h"
|
||||
#include "utest/utest.h"
|
||||
|
||||
using namespace utest::v1;
|
||||
namespace utest {
|
||||
namespace v1 {
|
||||
|
||||
// test_hdc1000 test handler function
|
||||
static control_t test_sensor_device(const size_t call_count) {
|
||||
@ -53,9 +54,9 @@ static control_t test_sensor_device(const size_t call_count) {
|
||||
return CaseNext;
|
||||
}
|
||||
|
||||
static utest::v1::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 or the
|
||||
// name of our Python file)
|
||||
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
|
||||
// or the name of our Python file)
|
||||
GREENTEA_SETUP(60, "default_auto");
|
||||
|
||||
return greentea_test_setup_handler(number_of_cases);
|
||||
@ -65,5 +66,7 @@ static utest::v1::status_t greentea_setup(const size_t number_of_cases) {
|
||||
static Case cases[] = {Case("test sensor device", test_sensor_device)};
|
||||
|
||||
static Specification specification(greentea_setup, cases);
|
||||
}; // namespace v1
|
||||
}; // namespace utest
|
||||
|
||||
int main() { return !Harness::run(specification); }
|
||||
int main() { return !utest::v1::Harness::run(utest::v1::specification); }
|
||||
|
@ -32,13 +32,14 @@
|
||||
#include "unity/unity.h"
|
||||
#include "utest/utest.h"
|
||||
|
||||
using namespace utest::v1;
|
||||
|
||||
// allow for 0.1 km/h difference
|
||||
static constexpr float kAllowedSpeedDelta = 0.1f;
|
||||
// allow for 1m difference
|
||||
static constexpr float kAllowedDistanceDelta = 1.0f / 1000.0;
|
||||
|
||||
namespace utest {
|
||||
namespace v1 {
|
||||
|
||||
// function called by test handler functions for verifying the current speed
|
||||
void check_current_speed(const std::chrono::milliseconds& pedalRotationTime,
|
||||
uint8_t traySize,
|
||||
@ -75,7 +76,8 @@ float compute_distance(const std::chrono::milliseconds& pedalRotationTime,
|
||||
float trayGearRatio = static_cast<float>(traySize) / static_cast<float>(gearSize);
|
||||
float distancePerPedalTurn = trayGearRatio * wheelCircumference;
|
||||
|
||||
// distancePerPedalTurn is expressed in m, divide per 1000 for a distance in km
|
||||
// distancePerPedalTurn is expressed in m, divide per 1000 for a distance in
|
||||
// km
|
||||
return (distancePerPedalTurn * pedalRotations) / 1000.0;
|
||||
}
|
||||
|
||||
@ -86,7 +88,8 @@ void check_distance(const std::chrono::milliseconds& pedalRotationTime,
|
||||
float wheelCircumference,
|
||||
const std::chrono::milliseconds& travelTime,
|
||||
float distance) {
|
||||
// distancePerPedalTurn is expressed in m, divide per 1000 for a distance in km
|
||||
// distancePerPedalTurn is expressed in m, divide per 1000 for a distance in
|
||||
// km
|
||||
float expectedDistance = compute_distance(
|
||||
pedalRotationTime, traySize, gearSize, wheelCircumference, travelTime);
|
||||
printf(" Expected distance is %f, current distance is %f\n",
|
||||
@ -334,9 +337,9 @@ static control_t test_reset(const size_t call_count) {
|
||||
return CaseNext;
|
||||
}
|
||||
|
||||
static utest::v1::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 or the
|
||||
// name of our Python file)
|
||||
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
|
||||
// or the name of our Python file)
|
||||
GREENTEA_SETUP(180, "default_auto");
|
||||
|
||||
return greentea_test_setup_handler(number_of_cases);
|
||||
@ -350,5 +353,7 @@ static Case cases[] = {
|
||||
Case("test speedometer reset", test_reset)};
|
||||
|
||||
static Specification specification(greentea_setup, cases);
|
||||
}; // namespace v1
|
||||
}; // namespace utest
|
||||
|
||||
int main() { return !Harness::run(specification); }
|
||||
int main() { return !utest::v1::Harness::run(utest::v1::specification); }
|
||||
|
@ -27,7 +27,8 @@
|
||||
#include "unity/unity.h"
|
||||
#include "utest/utest.h"
|
||||
|
||||
using namespace utest::v1;
|
||||
namespace utest {
|
||||
namespace v1 {
|
||||
|
||||
// test handler function
|
||||
static control_t always_succeed(const size_t call_count) {
|
||||
@ -38,9 +39,9 @@ static control_t always_succeed(const size_t call_count) {
|
||||
return CaseNext;
|
||||
}
|
||||
|
||||
static utest::v1::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 or the
|
||||
// name of our Python file)
|
||||
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
|
||||
// or the name of our Python file)
|
||||
GREENTEA_SETUP(60, "default_auto");
|
||||
|
||||
return greentea_test_setup_handler(number_of_cases);
|
||||
@ -51,4 +52,7 @@ static Case cases[] = {Case("always succeed test", always_succeed)};
|
||||
|
||||
static Specification specification(greentea_setup, cases);
|
||||
|
||||
int main() { return !Harness::run(specification); }
|
||||
}; // namespace v1
|
||||
}; // namespace utest
|
||||
|
||||
int main() { return !utest::v1::Harness::run(utest::v1::specification); }
|
||||
|
@ -24,12 +24,14 @@
|
||||
* @version 0.2.0
|
||||
***************************************************************************/
|
||||
|
||||
#include "greentea-client/test_env.h"
|
||||
#include "mbed.h"
|
||||
#include "unity/unity.h"
|
||||
#include "utest/utest.h"
|
||||
#include "greentea-client/test_env.h" // NOLINT
|
||||
#include "mbed.h" // NOLINT
|
||||
#include "unity/unity.h" // NOLINT
|
||||
#include "utest/utest.h" // NOLINT
|
||||
|
||||
namespace utest {
|
||||
namespace v1 {
|
||||
|
||||
using namespace utest::v1;
|
||||
struct Test {
|
||||
Test() {
|
||||
_instanceCount++;
|
||||
@ -48,7 +50,8 @@ struct Test {
|
||||
uint32_t Test::_instanceCount = 0;
|
||||
|
||||
/**
|
||||
* Test that a shared pointer correctly manages the lifetime of the underlying raw pointer
|
||||
* Test that a shared pointer correctly manages the lifetime of the underlying
|
||||
* raw pointer
|
||||
*/
|
||||
void test_single_sharedptr_lifetime() {
|
||||
// Sanity-check value of counter
|
||||
@ -66,8 +69,8 @@ void test_single_sharedptr_lifetime() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that multiple instances of shared pointers correctly manage the reference count
|
||||
* to release the object at the correct point
|
||||
* Test that multiple instances of shared pointers correctly manage the
|
||||
* reference count to release the object at the correct point
|
||||
*/
|
||||
void test_instance_sharing() {
|
||||
std::shared_ptr<Test> shared_ptr1(nullptr);
|
||||
@ -97,8 +100,8 @@ void test_instance_sharing() {
|
||||
}
|
||||
|
||||
/**********************
|
||||
* UNIQUE PTR EXERCISE *
|
||||
**********************/
|
||||
* UNIQUE PTR EXERCISE *
|
||||
**********************/
|
||||
|
||||
/*
|
||||
* Check normal lifetime on a unique_ptr
|
||||
@ -132,12 +135,12 @@ void test_unique_ptr_transfer() {
|
||||
TEST_ASSERT_EQUAL(0, Test::_instanceCount);
|
||||
|
||||
{
|
||||
//create p1
|
||||
// create p1
|
||||
std::unique_ptr<Test> p1 = std::make_unique<Test>();
|
||||
TEST_ASSERT_EQUAL(Test::kMagicNumber, p1->_value);
|
||||
TEST_ASSERT_EQUAL(1, Test::_instanceCount);
|
||||
|
||||
//transfer p1 to p2
|
||||
// transfer p1 to p2
|
||||
std::unique_ptr<Test> p2 = std::move(p1);
|
||||
TEST_ASSERT_EQUAL(Test::kMagicNumber, p2->_value);
|
||||
TEST_ASSERT_EQUAL(1, Test::_instanceCount);
|
||||
@ -145,7 +148,7 @@ void test_unique_ptr_transfer() {
|
||||
p2.reset();
|
||||
|
||||
TEST_ASSERT_EQUAL(0, Test::_instanceCount);
|
||||
TEST_ASSERT(!p1);
|
||||
TEST_ASSERT(!p1); // cppcheck-suppress accessMoved
|
||||
TEST_ASSERT(!p2);
|
||||
}
|
||||
|
||||
@ -160,13 +163,13 @@ void test_unique_ptr_release() {
|
||||
TEST_ASSERT_EQUAL(0, Test::_instanceCount);
|
||||
|
||||
{
|
||||
//create p1
|
||||
// create p1
|
||||
std::unique_ptr<Test> p1 = std::make_unique<Test>();
|
||||
TEST_ASSERT_EQUAL(Test::kMagicNumber, p1->_value);
|
||||
TEST_ASSERT_EQUAL(1, Test::_instanceCount);
|
||||
|
||||
//transfer and release p1 to p2
|
||||
Test * p2 = p1.release();
|
||||
// transfer and release p1 to p2
|
||||
Test* p2 = p1.release();
|
||||
TEST_ASSERT_EQUAL(Test::kMagicNumber, p2->_value);
|
||||
TEST_ASSERT_EQUAL(1, Test::_instanceCount);
|
||||
|
||||
@ -192,21 +195,21 @@ void test_unique_ptr_swap() {
|
||||
const uint32_t number1 = 65;
|
||||
const uint32_t number2 = 42;
|
||||
|
||||
//create p1
|
||||
// create p1
|
||||
std::unique_ptr<Test> p1 = std::make_unique<Test>();
|
||||
TEST_ASSERT_EQUAL(Test::kMagicNumber, p1->_value);
|
||||
TEST_ASSERT_EQUAL(1, Test::_instanceCount);
|
||||
p1->_value = number1;
|
||||
TEST_ASSERT_EQUAL(number1, p1->_value);
|
||||
|
||||
//create p2
|
||||
// create p2
|
||||
std::unique_ptr<Test> p2 = std::make_unique<Test>();
|
||||
TEST_ASSERT_EQUAL(Test::kMagicNumber, p2->_value);
|
||||
TEST_ASSERT_EQUAL(2, Test::_instanceCount);
|
||||
p2->_value = number2;
|
||||
TEST_ASSERT_EQUAL(number2, p2->_value);
|
||||
|
||||
//swap
|
||||
// swap
|
||||
p1.swap(p2);
|
||||
|
||||
TEST_ASSERT_EQUAL(number1, p2->_value);
|
||||
@ -223,14 +226,13 @@ void test_unique_ptr_swap() {
|
||||
TEST_ASSERT_EQUAL(0, Test::_instanceCount);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************
|
||||
* RAW PTR EXERCISE *
|
||||
*******************/
|
||||
* RAW PTR EXERCISE *
|
||||
*******************/
|
||||
|
||||
/**
|
||||
* Test that a shared pointer correctly manages the lifetime of the underlying raw pointer
|
||||
* Test that a shared pointer correctly manages the lifetime of the underlying
|
||||
* raw pointer
|
||||
*/
|
||||
void test_single_raw_ptr_lifetime() {
|
||||
// Sanity-check value of counter
|
||||
@ -242,7 +244,7 @@ void test_single_raw_ptr_lifetime() {
|
||||
TEST_ASSERT_EQUAL(1, Test::_instanceCount);
|
||||
TEST_ASSERT_EQUAL(Test::kMagicNumber, t1._value);
|
||||
|
||||
Test * p1 = &t1;
|
||||
Test* p1 = &t1;
|
||||
TEST_ASSERT_EQUAL(1, Test::_instanceCount);
|
||||
TEST_ASSERT_EQUAL(Test::kMagicNumber, p1->_value);
|
||||
|
||||
@ -260,9 +262,9 @@ void test_single_raw_ptr_lifetime() {
|
||||
TEST_ASSERT_EQUAL(0, Test::_instanceCount);
|
||||
}
|
||||
|
||||
static utest::v1::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 or the
|
||||
// name of our Python file)
|
||||
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
|
||||
// or the name of our Python file)
|
||||
GREENTEA_SETUP(60, "default_auto");
|
||||
return greentea_test_setup_handler(number_of_cases);
|
||||
}
|
||||
@ -285,4 +287,7 @@ static Case cases[] = {
|
||||
|
||||
static Specification specification(greentea_setup, cases);
|
||||
|
||||
int main() { return !Harness::run(specification); }
|
||||
}; // namespace v1
|
||||
}; // namespace utest
|
||||
|
||||
int main() { return !utest::v1::Harness::run(utest::v1::specification); }
|
||||
|
@ -51,4 +51,9 @@ static constexpr std::chrono::milliseconds kMaxPedalRotationTime = 1500ms;
|
||||
// definition of pedal rotation time change upon acceleration/deceleration
|
||||
static constexpr std::chrono::milliseconds kDeltaPedalRotationTime = 25ms;
|
||||
|
||||
static constexpr uint32_t kNbrOfSteps = static_cast<uint32_t>(
|
||||
(bike_computer::kMaxPedalRotationTime - bike_computer::kMinPedalRotationTime)
|
||||
.count() /
|
||||
bike_computer::kDeltaPedalRotationTime.count());
|
||||
|
||||
} // 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"
|
||||
|
||||
namespace bike_computer {
|
||||
|
||||
SensorDevice::SensorDevice() : _hdc1000(I2C_SDA, I2C_SCL, STMOD_11)
|
||||
{}
|
||||
SensorDevice::SensorDevice() : _hdc1000(I2C_SDA, I2C_SCL, STMOD_11) {}
|
||||
|
||||
bool SensorDevice::init() {
|
||||
return this->_hdc1000.probe();
|
||||
}
|
||||
bool SensorDevice::init() { return this->_hdc1000.probe(); }
|
||||
|
||||
float SensorDevice::readTemperature(void) {
|
||||
return this->_hdc1000.getTemperature();
|
||||
}
|
||||
float SensorDevice::readTemperature(void) { return this->_hdc1000.getTemperature(); }
|
||||
|
||||
float SensorDevice::readHumidity(void) {
|
||||
return this->_hdc1000.getHumidity();
|
||||
}
|
||||
|
||||
} // bike_computer
|
||||
float SensorDevice::readHumidity(void) { return this->_hdc1000.getHumidity(); }
|
||||
|
||||
} // namespace bike_computer
|
||||
|
@ -24,9 +24,8 @@
|
||||
|
||||
#include "speedometer.hpp"
|
||||
|
||||
#include "static_scheduling/gear_device.hpp"
|
||||
|
||||
#include <chrono>
|
||||
#include <cstddef>
|
||||
#include <ratio>
|
||||
|
||||
// from disco_h747i/wrappers
|
||||
@ -80,7 +79,12 @@ float Speedometer::getDistance() {
|
||||
}
|
||||
|
||||
void Speedometer::reset() {
|
||||
// TODO : done
|
||||
#if defined(MBED_TEST_MODE)
|
||||
if (_cbOnReset != NULL) {
|
||||
_cbOnReset();
|
||||
}
|
||||
#endif
|
||||
|
||||
this->_totalDistanceMutex.lock();
|
||||
this->_totalDistance = 0.0f;
|
||||
this->_totalDistanceMutex.unlock();
|
||||
@ -96,6 +100,7 @@ float Speedometer::getTraySize() const { return kTraySize; }
|
||||
std::chrono::milliseconds Speedometer::getCurrentPedalRotationTime() const {
|
||||
return _pedalRotationTime;
|
||||
}
|
||||
void Speedometer::setOnResetCallback(mbed::Callback<void()> cb) { _cbOnReset = cb; }
|
||||
|
||||
#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
|
||||
// ~= 560 m / min = 33.6 km/h
|
||||
|
||||
// TODO : done
|
||||
//Distance run with one pedal turn = tray size / rear gear size * circumference of the wheel
|
||||
// Distance run with one pedal turn = tray size / rear gear size * circumference of
|
||||
// the wheel
|
||||
constexpr float ms_in_hour = static_cast<float>(3600 * 1000);
|
||||
float pedal_rotation_per_hour = ms_in_hour / static_cast<float>(_pedalRotationTime.count());
|
||||
float gear_ratio = static_cast<float>(kTraySize) / static_cast<float>(this->_gearSize);
|
||||
float pedal_rotation_per_hour =
|
||||
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;
|
||||
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
|
||||
// distance traveled.
|
||||
|
||||
// TODO : done
|
||||
Speedometer::computeSpeed();
|
||||
// compute distance
|
||||
|
||||
const std::chrono::microseconds timeNow = _timer.elapsed_time();
|
||||
const std::chrono::microseconds timeDiff = timeNow - _lastTime;
|
||||
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->_totalDistance += traveled_dist;
|
||||
|
@ -55,6 +55,7 @@ class Speedometer {
|
||||
float getTraySize() const;
|
||||
std::chrono::milliseconds getCurrentPedalRotationTime() const;
|
||||
void setOnResetCallback(mbed::Callback<void()> cb);
|
||||
mbed::Callback<void()> _cbOnReset = NULL;
|
||||
#endif // defined(MBED_TEST_MODE)
|
||||
|
||||
private:
|
||||
@ -79,9 +80,7 @@ class Speedometer {
|
||||
float _currentSpeed = 0.0f;
|
||||
Mutex _totalDistanceMutex;
|
||||
float _totalDistance = 0.0f;
|
||||
uint8_t _gearSize = 1;
|
||||
|
||||
Thread _thread;
|
||||
uint8_t _gearSize = bike_computer::kMaxGearSize;
|
||||
|
||||
#if defined(MBED_TEST_MODE)
|
||||
mbed::Callback<void()> _cb;
|
||||
|
25
main.cpp
25
main.cpp
@ -6,19 +6,28 @@
|
||||
#if !MBED_TEST_MODE
|
||||
|
||||
#include "mbed.h" // NOLINT
|
||||
#include "mbed_trace.h" // NOLINT
|
||||
// #include "static_scheduling/bike_system.hpp"
|
||||
#include "static_scheduling_with_event/bike_system.hpp"
|
||||
// #include "multi_tasking/bike_system.hpp"
|
||||
|
||||
// Blinking rate in milliseconds
|
||||
#define BLINKING_RATE 500ms
|
||||
#if defined(MBED_CONF_MBED_TRACE_ENABLE)
|
||||
#define TRACE_GROUP "MAIN"
|
||||
#endif // MBED_CONF_MBED_TRACE_ENAB
|
||||
|
||||
int main() {
|
||||
// Initialise the digital pin LED1 as an output
|
||||
#if defined(MBED_CONF_MBED_TRACE_ENABLE)
|
||||
mbed_trace_init();
|
||||
#endif
|
||||
|
||||
DigitalOut led(LED1);
|
||||
// static_scheduling::BikeSystem bikeSystem;
|
||||
// bikeSystem.start();
|
||||
|
||||
while (true) {
|
||||
led = !led;
|
||||
ThisThread::sleep_for(BLINKING_RATE);
|
||||
}
|
||||
static_scheduling_with_event::BikeSystem bikeSystem;
|
||||
bikeSystem.start();
|
||||
|
||||
// multi_tasking::BikeSystem bikeSystem;
|
||||
// bikeSystem.start();
|
||||
}
|
||||
|
||||
#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,10 +1,8 @@
|
||||
{
|
||||
"macros": [
|
||||
"MBED_CONF_MBED_TRACE_FEA_IPV6=0"
|
||||
],
|
||||
"macros": ["MBED_CONF_MBED_TRACE_FEA_IPV6=0"],
|
||||
"config": {
|
||||
"main-stack-size": {
|
||||
"value": 4096
|
||||
"value": 8192
|
||||
}
|
||||
},
|
||||
"target_overrides": {
|
||||
@ -14,13 +12,16 @@
|
||||
"platform.stdio-baud-rate": 115200,
|
||||
"platform.default-serial-baud-rate": 115200,
|
||||
"platform.stdio-buffered-serial": true,
|
||||
"target.printf_lib":"minimal-printf",
|
||||
"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"
|
||||
}
|
||||
"mbed-trace.max-level": "TRACE_LEVEL_DEBUG",
|
||||
"target.bootloader_img": "./mbed-os-bootloader/BUILD/DISCO_H747I/GCC_ARM/mbed-os-bootloader.bin",
|
||||
"target.app_offset": "0x20000"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
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
|
265
static_scheduling/bike_system.cpp
Normal file
265
static_scheduling/bike_system.cpp
Normal file
@ -0,0 +1,265 @@
|
||||
// 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 "mbed_trace.h"
|
||||
#if MBED_CONF_MBED_TRACE_ENABLE
|
||||
#define TRACE_GROUP "BikeSystem"
|
||||
#endif // MBED_CONF_MBED_TRACE_ENABLE
|
||||
|
||||
namespace static_scheduling {
|
||||
|
||||
static constexpr std::chrono::milliseconds kGearTaskPeriod = 800ms;
|
||||
static constexpr std::chrono::milliseconds kGearTaskDelay = 0ms;
|
||||
static constexpr std::chrono::milliseconds kGearTaskComputationTime = 100ms;
|
||||
static constexpr std::chrono::milliseconds kSpeedDistanceTaskPeriod = 400ms;
|
||||
static constexpr std::chrono::milliseconds kSpeedDistanceTaskDelay = 0ms; // 0 or 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 kResetTaskPeriod = 800ms;
|
||||
static constexpr std::chrono::milliseconds kResetTaskDelay = 700ms;
|
||||
static constexpr std::chrono::milliseconds kResetTaskComputationTime = 100ms;
|
||||
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 kDisplayTask2Period = 1600ms;
|
||||
static constexpr std::chrono::milliseconds kDisplayTask2Delay = 1200ms;
|
||||
static constexpr std::chrono::milliseconds kDisplayTask2ComputationTime = 100ms;
|
||||
static constexpr std::chrono::milliseconds kCPUTaskPeriod = 1600ms;
|
||||
static constexpr std::chrono::milliseconds kCPUTaskDelay = 0ms;
|
||||
static constexpr std::chrono::milliseconds kCPUTaskComputationTime = 0ms;
|
||||
|
||||
BikeSystem::BikeSystem()
|
||||
: _gearDevice(_timer),
|
||||
_pedalDevice(_timer),
|
||||
_resetDevice(_timer),
|
||||
_displayDevice(),
|
||||
_speedometer(_timer),
|
||||
_sensorDevice(),
|
||||
_taskLogger(),
|
||||
_cpuLogger(_timer) {}
|
||||
|
||||
void BikeSystem::start() {
|
||||
tr_info("Starting Super-Loop without event handling");
|
||||
|
||||
init();
|
||||
|
||||
while (true) {
|
||||
auto startTime = _timer.elapsed_time();
|
||||
|
||||
gearTask(); // 100ms : 0ms -> 100ms
|
||||
speedDistanceTask(); // 200ms : 100ms -> 300ms
|
||||
displayTask1(); // 200ms : 300ms -> 500ms
|
||||
speedDistanceTask(); // 200ms : 500ms -> 700ms
|
||||
resetTask(); // 100ms : 700ms -> 800ms
|
||||
gearTask(); // 100ms : 800ms -> 900ms
|
||||
speedDistanceTask(); // 200ms : 900ms -> 1100ms
|
||||
temperatureTask(); // 100ms : 1100ms -> 1200ms
|
||||
displayTask2(); // 100ms : 1200ms -> 1300ms
|
||||
speedDistanceTask(); // 200ms : 1300ms -> 1500ms
|
||||
resetTask(); // 100ms : 1500ms -> 1600ms
|
||||
|
||||
// register the time at the end of the cyclic schedule period and print the
|
||||
// elapsed time for the period
|
||||
std::chrono::microseconds endTime = _timer.elapsed_time();
|
||||
const auto cycle =
|
||||
std::chrono::duration_cast<std::chrono::milliseconds>(endTime - startTime);
|
||||
tr_debug("Repeating cycle time is %" PRIu64 " milliseconds", cycle.count());
|
||||
|
||||
bool fStop = false;
|
||||
core_util_atomic_load(&fStop);
|
||||
if (fStop) {
|
||||
break;
|
||||
}
|
||||
|
||||
#if !defined(MBED_TEST_MODE)
|
||||
_cpuLogger.printStats();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void BikeSystem::startWithEventQueue() {
|
||||
tr_info("Starting Super-Loop with event handling");
|
||||
|
||||
init();
|
||||
|
||||
EventQueue eventQueue;
|
||||
|
||||
Event<void()> gearEvent(&eventQueue, callback(this, &BikeSystem::gearTask));
|
||||
gearEvent.delay(kGearTaskDelay);
|
||||
gearEvent.period(kGearTaskPeriod);
|
||||
gearEvent.post();
|
||||
|
||||
Event<void()> speedDistanceEvent(&eventQueue,
|
||||
callback(this, &BikeSystem::speedDistanceTask));
|
||||
speedDistanceEvent.delay(kSpeedDistanceTaskDelay);
|
||||
speedDistanceEvent.period(kSpeedDistanceTaskPeriod);
|
||||
speedDistanceEvent.post();
|
||||
|
||||
Event<void()> display1Event(&eventQueue, callback(this, &BikeSystem::displayTask1));
|
||||
display1Event.delay(kDisplayTask1Delay);
|
||||
display1Event.period(kDisplayTask1Period);
|
||||
display1Event.post();
|
||||
|
||||
Event<void()> resetEvent(&eventQueue, callback(this, &BikeSystem::resetTask));
|
||||
resetEvent.delay(kResetTaskDelay);
|
||||
resetEvent.period(kResetTaskPeriod);
|
||||
resetEvent.post();
|
||||
|
||||
Event<void()> temperatureEvent(&eventQueue,
|
||||
callback(this, &BikeSystem::temperatureTask));
|
||||
temperatureEvent.delay(kTemperatureTaskDelay);
|
||||
temperatureEvent.period(kTemperatureTaskPeriod);
|
||||
temperatureEvent.post();
|
||||
|
||||
Event<void()> display2Event(&eventQueue, callback(this, &BikeSystem::displayTask2));
|
||||
display2Event.delay(kDisplayTask2Delay);
|
||||
display2Event.period(kDisplayTask2Period);
|
||||
display2Event.post();
|
||||
|
||||
#if !defined(MBED_TEST_MODE)
|
||||
Event<void()> cpuEvent(&eventQueue, callback(this, &BikeSystem::cpuTask));
|
||||
cpuEvent.delay(kCPUTaskDelay);
|
||||
cpuEvent.period(kCPUTaskPeriod);
|
||||
cpuEvent.post();
|
||||
#endif
|
||||
|
||||
eventQueue.dispatch_forever();
|
||||
}
|
||||
|
||||
void BikeSystem::stop() { core_util_atomic_store_bool(&_stopFlag, true); }
|
||||
|
||||
#if defined(MBED_TEST_MODE)
|
||||
const advembsof::TaskLogger& BikeSystem::getTaskLogger() { return _taskLogger; }
|
||||
#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("Failed 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
|
||||
_taskLogger.enable(true);
|
||||
}
|
||||
|
||||
void BikeSystem::gearTask() {
|
||||
// gear task
|
||||
auto taskStartTime = _timer.elapsed_time();
|
||||
|
||||
// no need to protect access to data members (single threaded)
|
||||
_currentGear = _gearDevice.getCurrentGear();
|
||||
_currentGearSize = _gearDevice.getCurrentGearSize();
|
||||
|
||||
_taskLogger.logPeriodAndExecutionTime(
|
||||
_timer, advembsof::TaskLogger::kGearTaskIndex, taskStartTime);
|
||||
}
|
||||
|
||||
void BikeSystem::speedDistanceTask() {
|
||||
// speed and distance task
|
||||
auto taskStartTime = _timer.elapsed_time();
|
||||
|
||||
const auto pedalRotationTime = _pedalDevice.getCurrentRotationTime();
|
||||
_speedometer.setCurrentRotationTime(pedalRotationTime);
|
||||
_speedometer.setGearSize(_currentGearSize);
|
||||
// no need to protect access to data members (single threaded)
|
||||
_currentSpeed = _speedometer.getCurrentSpeed();
|
||||
_traveledDistance = _speedometer.getDistance();
|
||||
|
||||
_taskLogger.logPeriodAndExecutionTime(
|
||||
_timer, advembsof::TaskLogger::kSpeedTaskIndex, taskStartTime);
|
||||
}
|
||||
|
||||
void BikeSystem::displayTask1() {
|
||||
auto taskStartTime = _timer.elapsed_time();
|
||||
|
||||
_displayDevice.displayGear(_currentGear);
|
||||
_displayDevice.displaySpeed(_currentSpeed);
|
||||
_displayDevice.displayDistance(_traveledDistance);
|
||||
|
||||
ThisThread::sleep_for(std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||
kDisplayTask1ComputationTime - (_timer.elapsed_time() - taskStartTime)));
|
||||
|
||||
_taskLogger.logPeriodAndExecutionTime(
|
||||
_timer, advembsof::TaskLogger::kDisplayTask1Index, taskStartTime);
|
||||
}
|
||||
|
||||
void BikeSystem::resetTask() {
|
||||
auto taskStartTime = _timer.elapsed_time();
|
||||
|
||||
if (_resetDevice.checkReset()) {
|
||||
std::chrono::microseconds responseTime =
|
||||
_timer.elapsed_time() - _resetDevice.getPressTime();
|
||||
tr_info("Reset task: response time is %" PRIu64 " usecs", responseTime.count());
|
||||
_speedometer.reset();
|
||||
}
|
||||
|
||||
_taskLogger.logPeriodAndExecutionTime(
|
||||
_timer, advembsof::TaskLogger::kResetTaskIndex, taskStartTime);
|
||||
}
|
||||
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::displayTask2() {
|
||||
auto taskStartTime = _timer.elapsed_time();
|
||||
|
||||
_displayDevice.displayTemperature(_currentTemperature);
|
||||
|
||||
ThisThread::sleep_for(std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||
kDisplayTask2ComputationTime - (_timer.elapsed_time() - taskStartTime)));
|
||||
|
||||
_taskLogger.logPeriodAndExecutionTime(
|
||||
_timer, advembsof::TaskLogger::kDisplayTask2Index, taskStartTime);
|
||||
}
|
||||
|
||||
void BikeSystem::cpuTask() { _cpuLogger.printStats(); }
|
||||
|
||||
} // namespace static_scheduling
|
106
static_scheduling/bike_system.hpp
Normal file
106
static_scheduling/bike_system.hpp
Normal file
@ -0,0 +1,106 @@
|
||||
// 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 "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 static_scheduling {
|
||||
|
||||
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 in main() for starting the sysytem with the event queue
|
||||
void startWithEventQueue();
|
||||
|
||||
// method called for stopping the system
|
||||
void stop();
|
||||
|
||||
#if defined(MBED_TEST_MODE)
|
||||
const advembsof::TaskLogger& getTaskLogger();
|
||||
#endif // defined(MBED_TEST_MODE)
|
||||
|
||||
private:
|
||||
// private methods
|
||||
void init();
|
||||
void gearTask();
|
||||
void speedDistanceTask();
|
||||
void temperatureTask();
|
||||
void resetTask();
|
||||
void displayTask1();
|
||||
void displayTask2();
|
||||
void cpuTask();
|
||||
|
||||
// stop flag, used for stopping the super-loop (set in stop())
|
||||
bool _stopFlag = false;
|
||||
// timer instance used for loggint task time and used by ResetDevice
|
||||
Timer _timer;
|
||||
// data member that represents the device for manipulating the gear
|
||||
GearDevice _gearDevice;
|
||||
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;
|
||||
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 static_scheduling
|
@ -1,12 +1,25 @@
|
||||
// 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-09
|
||||
* @version 0.1.0
|
||||
****************************************************************************/
|
||||
* @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-09
|
||||
* @version 0.1.0
|
||||
****************************************************************************/
|
||||
|
||||
#include "pedal_device.hpp"
|
||||
|
||||
@ -22,20 +35,19 @@
|
||||
|
||||
namespace static_scheduling {
|
||||
|
||||
static constexpr std::chrono::microseconds kTaskRunTime = 200000us;
|
||||
static constexpr std::chrono::microseconds kTaskRunTime = 200000us;
|
||||
|
||||
PedalDevice::PedalDevice(Timer& timer) : _timer(timer) {}
|
||||
PedalDevice::PedalDevice(Timer& timer) : _timer(timer), _pedalRotationTime(0) {}
|
||||
|
||||
|
||||
std::chrono::milliseconds PedalDevice::getCurrentRotationTime() {
|
||||
// TODO
|
||||
std::chrono::milliseconds PedalDevice::getCurrentRotationTime() {
|
||||
std::chrono::microseconds initialTime = _timer.elapsed_time();
|
||||
std::chrono::microseconds elapsedTime = std::chrono::microseconds::zero();
|
||||
// we bound the change to one increment/decrement per call
|
||||
bool hasChanged = false;
|
||||
while (elapsedTime < kTaskRunTime) {
|
||||
if (!hasChanged) {
|
||||
disco::Joystick::State joystickState = disco::Joystick::getInstance().getState();
|
||||
disco::Joystick::State joystickState =
|
||||
disco::Joystick::getInstance().getState();
|
||||
|
||||
switch (joystickState) {
|
||||
case disco::Joystick::State::LeftPressed:
|
||||
@ -59,14 +71,14 @@ namespace static_scheduling {
|
||||
elapsedTime = _timer.elapsed_time() - initialTime;
|
||||
}
|
||||
return _pedalRotationTime;
|
||||
}
|
||||
|
||||
void PedalDevice::increaseRotationSpeed() {
|
||||
_pedalRotationTime -= bike_computer::kDeltaPedalRotationTime;
|
||||
}
|
||||
|
||||
void PedalDevice::decreaseRotationSpeed() {
|
||||
_pedalRotationTime += bike_computer::kDeltaPedalRotationTime;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void PedalDevice::increaseRotationSpeed() {
|
||||
_pedalRotationTime -= bike_computer::kDeltaPedalRotationTime;
|
||||
}
|
||||
|
||||
void PedalDevice::decreaseRotationSpeed() {
|
||||
_pedalRotationTime += bike_computer::kDeltaPedalRotationTime;
|
||||
}
|
||||
|
||||
} // namespace static_scheduling
|
||||
|
@ -46,9 +46,9 @@ class PedalDevice {
|
||||
void decreaseRotationSpeed();
|
||||
|
||||
// data members
|
||||
Timer& _timer;
|
||||
std::chrono::milliseconds _pedalRotationTime =
|
||||
bike_computer::kInitialPedalRotationTime;
|
||||
Timer& _timer;
|
||||
};
|
||||
|
||||
} // namespace static_scheduling
|
@ -1,12 +1,26 @@
|
||||
// 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)
|
||||
* @date 2024-11-12
|
||||
* @version 0.1.0
|
||||
****************************************************************************/
|
||||
* @file reset_device.cpp
|
||||
* @author Rémi Heredero <remi@heredero.ch>
|
||||
* @author Yann Sierro <yannsierro.pro@gmail.com>
|
||||
*
|
||||
* @brief Reset Device implementation (static scheduling)
|
||||
* @date 2024-11-12
|
||||
* @version 0.1.0
|
||||
****************************************************************************/
|
||||
|
||||
#include "reset_device.hpp"
|
||||
|
||||
@ -21,43 +35,36 @@
|
||||
static constexpr uint8_t kPolarityPressed = 1;
|
||||
#endif
|
||||
|
||||
|
||||
#if MBED_CONF_MBED_TRACE_ENABLE
|
||||
#define TRACE_GROUP "PedalDevice"
|
||||
#define TRACE_GROUP "ResetDevice"
|
||||
#endif // MBED_CONF_MBED_TRACE_ENABLE
|
||||
|
||||
namespace static_scheduling {
|
||||
|
||||
static constexpr std::chrono::microseconds kTaskRunTime = 1000000us;
|
||||
static constexpr std::chrono::microseconds kTaskRunTime = 100000us;
|
||||
|
||||
ResetDevice::ResetDevice(Timer& timer) : _timer(timer), _resetButton(PUSH_BUTTON) {
|
||||
ResetDevice::ResetDevice(Timer& timer)
|
||||
: _resetButton(PUSH_BUTTON), _timer(timer), _pressTime(0) {
|
||||
_resetButton.rise(callback(this, &ResetDevice::onRise));
|
||||
}
|
||||
}
|
||||
|
||||
bool ResetDevice::checkReset() {
|
||||
bool ResetDevice::checkReset() {
|
||||
std::chrono::microseconds initialTime = _timer.elapsed_time();
|
||||
std::chrono::microseconds elapsedTime = std::chrono::microseconds::zero();
|
||||
// we bound the change to one increment/decrement per call
|
||||
bool isPressed = false;
|
||||
while (elapsedTime < kTaskRunTime) {
|
||||
if(!isPressed) {
|
||||
if (!isPressed) {
|
||||
isPressed = _resetButton.read() == kPolarityPressed;
|
||||
}
|
||||
elapsedTime = _timer.elapsed_time() - initialTime;
|
||||
}
|
||||
|
||||
return isPressed;
|
||||
|
||||
}
|
||||
|
||||
std::chrono::microseconds ResetDevice::getPressTime() {
|
||||
return _pressTime;
|
||||
}
|
||||
|
||||
void ResetDevice::onRise() {
|
||||
_pressTime = _timer.elapsed_time();
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
std::chrono::microseconds ResetDevice::getPressTime() { return _pressTime; }
|
||||
|
||||
void ResetDevice::onRise() { _pressTime = _timer.elapsed_time(); }
|
||||
|
||||
} // namespace static_scheduling
|
||||
|
238
static_scheduling_with_event/bike_system.cpp
Normal file
238
static_scheduling_with_event/bike_system.cpp
Normal file
@ -0,0 +1,238 @@
|
||||
// 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 "mbed_trace.h"
|
||||
#if MBED_CONF_MBED_TRACE_ENABLE
|
||||
#define TRACE_GROUP "BikeSystem"
|
||||
#endif // MBED_CONF_MBED_TRACE_ENABLE
|
||||
|
||||
namespace static_scheduling_with_event {
|
||||
|
||||
static constexpr std::chrono::milliseconds kGearTaskPeriod = 800ms;
|
||||
static constexpr std::chrono::milliseconds kGearTaskDelay = 0ms;
|
||||
static constexpr std::chrono::milliseconds kGearTaskComputationTime = 100ms;
|
||||
|
||||
static constexpr std::chrono::milliseconds kSpeedDistanceTaskPeriod = 400ms;
|
||||
static constexpr std::chrono::milliseconds kSpeedDistanceTaskDelay = 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 kResetTaskPeriod = 800ms;
|
||||
static constexpr std::chrono::milliseconds kResetTaskDelay = 700ms;
|
||||
static constexpr std::chrono::milliseconds kResetTaskComputationTime = 100ms;
|
||||
|
||||
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 kDisplayTask2Period = 1600ms;
|
||||
static constexpr std::chrono::milliseconds kDisplayTask2Delay = 1200ms;
|
||||
static constexpr std::chrono::milliseconds kDisplayTask2ComputationTime = 100ms;
|
||||
|
||||
static constexpr std::chrono::milliseconds kCPUTaskPeriod = 1600ms;
|
||||
static constexpr std::chrono::milliseconds kCPUTaskDelay = 1200ms;
|
||||
static constexpr std::chrono::milliseconds kCPUTaskComputationTime = 100ms;
|
||||
|
||||
BikeSystem::BikeSystem()
|
||||
: _gearDevice(),
|
||||
_pedalDevice(),
|
||||
_resetDevice(callback(this, &BikeSystem::onReset)),
|
||||
_displayDevice(),
|
||||
_speedometer(_timer),
|
||||
_sensorDevice(),
|
||||
_taskLogger(),
|
||||
_cpuLogger(_timer) {}
|
||||
|
||||
void BikeSystem::start() {
|
||||
tr_info("Starting Super-Loop with event handling");
|
||||
|
||||
init();
|
||||
|
||||
EventQueue eventQueue;
|
||||
|
||||
Event<void()> gearEvent(&eventQueue, callback(this, &BikeSystem::gearTask));
|
||||
gearEvent.delay(kGearTaskDelay);
|
||||
gearEvent.period(kGearTaskPeriod);
|
||||
gearEvent.post();
|
||||
|
||||
Event<void()> speedDistanceEvent(&eventQueue,
|
||||
callback(this, &BikeSystem::speedDistanceTask));
|
||||
speedDistanceEvent.delay(kSpeedDistanceTaskDelay);
|
||||
speedDistanceEvent.period(kSpeedDistanceTaskPeriod);
|
||||
speedDistanceEvent.post();
|
||||
|
||||
Event<void()> display1Event(&eventQueue, callback(this, &BikeSystem::displayTask1));
|
||||
display1Event.delay(kDisplayTask1Delay);
|
||||
display1Event.period(kDisplayTask1Period);
|
||||
display1Event.post();
|
||||
|
||||
Event<void()> resetEvent(&eventQueue, callback(this, &BikeSystem::resetTask));
|
||||
resetEvent.delay(kResetTaskDelay);
|
||||
resetEvent.period(kResetTaskPeriod);
|
||||
resetEvent.post();
|
||||
|
||||
Event<void()> temperatureEvent(&eventQueue,
|
||||
callback(this, &BikeSystem::temperatureTask));
|
||||
temperatureEvent.delay(kTemperatureTaskDelay);
|
||||
temperatureEvent.period(kTemperatureTaskPeriod);
|
||||
temperatureEvent.post();
|
||||
|
||||
Event<void()> display2Event(&eventQueue, callback(this, &BikeSystem::displayTask2));
|
||||
display2Event.delay(kDisplayTask2Delay);
|
||||
display2Event.period(kDisplayTask2Period);
|
||||
display2Event.post();
|
||||
|
||||
#if !defined(MBED_TEST_MODE)
|
||||
Event<void()> cpuEvent(&eventQueue, callback(this, &BikeSystem::cpuTask));
|
||||
cpuEvent.delay(kCPUTaskDelay);
|
||||
cpuEvent.period(kCPUTaskPeriod);
|
||||
cpuEvent.post();
|
||||
#endif
|
||||
|
||||
eventQueue.dispatch_forever();
|
||||
}
|
||||
|
||||
void BikeSystem::onReset() {
|
||||
_resetTime = _timer.elapsed_time();
|
||||
core_util_atomic_store_bool(&_resetFlag, true);
|
||||
}
|
||||
|
||||
void BikeSystem::stop() { core_util_atomic_store_bool(&_stopFlag, true); }
|
||||
|
||||
#if defined(MBED_TEST_MODE)
|
||||
const advembsof::TaskLogger& BikeSystem::getTaskLogger() { return _taskLogger; }
|
||||
#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("Failed 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
|
||||
_taskLogger.enable(true);
|
||||
}
|
||||
|
||||
void BikeSystem::gearTask() {
|
||||
// gear task
|
||||
auto taskStartTime = _timer.elapsed_time();
|
||||
|
||||
// no need to protect access to data members (single threaded)
|
||||
_currentGear = _gearDevice.getCurrentGear();
|
||||
_currentGearSize = _gearDevice.getCurrentGearSize();
|
||||
|
||||
_taskLogger.logPeriodAndExecutionTime(
|
||||
_timer, advembsof::TaskLogger::kGearTaskIndex, taskStartTime);
|
||||
}
|
||||
|
||||
void BikeSystem::speedDistanceTask() {
|
||||
auto taskStartTime = _timer.elapsed_time();
|
||||
|
||||
const auto pedalRotationTime = _pedalDevice.getCurrentRotationTime();
|
||||
_speedometer.setCurrentRotationTime(pedalRotationTime);
|
||||
_speedometer.setGearSize(_currentGearSize);
|
||||
|
||||
_currentSpeed = _speedometer.getCurrentSpeed();
|
||||
_traveledDistance = _speedometer.getDistance();
|
||||
|
||||
_taskLogger.logPeriodAndExecutionTime(
|
||||
_timer, advembsof::TaskLogger::kSpeedTaskIndex, taskStartTime);
|
||||
}
|
||||
|
||||
void BikeSystem::displayTask1() {
|
||||
auto taskStartTime = _timer.elapsed_time();
|
||||
|
||||
_displayDevice.displayGear(_currentGear);
|
||||
_displayDevice.displaySpeed(_currentSpeed);
|
||||
_displayDevice.displayDistance(_traveledDistance);
|
||||
|
||||
ThisThread::sleep_for(std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||
kDisplayTask1ComputationTime - (_timer.elapsed_time() - taskStartTime)));
|
||||
|
||||
_taskLogger.logPeriodAndExecutionTime(
|
||||
_timer, advembsof::TaskLogger::kDisplayTask1Index, taskStartTime);
|
||||
}
|
||||
|
||||
void BikeSystem::resetTask() {
|
||||
auto taskStartTime = _timer.elapsed_time();
|
||||
|
||||
if (core_util_atomic_load_bool(&_resetFlag)) {
|
||||
std::chrono::microseconds responseTime = _timer.elapsed_time() - _resetTime;
|
||||
tr_info("Reset task: response time is %" PRIu64 " usecs", responseTime.count());
|
||||
_speedometer.reset();
|
||||
|
||||
core_util_atomic_store_bool(&_resetFlag, false);
|
||||
}
|
||||
|
||||
_taskLogger.logPeriodAndExecutionTime(
|
||||
_timer, advembsof::TaskLogger::kResetTaskIndex, taskStartTime);
|
||||
}
|
||||
|
||||
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::displayTask2() {
|
||||
auto taskStartTime = _timer.elapsed_time();
|
||||
|
||||
_displayDevice.displayTemperature(_currentTemperature);
|
||||
|
||||
ThisThread::sleep_for(std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||
kDisplayTask2ComputationTime - (_timer.elapsed_time() - taskStartTime)));
|
||||
|
||||
_taskLogger.logPeriodAndExecutionTime(
|
||||
_timer, advembsof::TaskLogger::kDisplayTask2Index, taskStartTime);
|
||||
}
|
||||
|
||||
void BikeSystem::cpuTask() { _cpuLogger.printStats(); }
|
||||
|
||||
} // namespace static_scheduling_with_event
|
111
static_scheduling_with_event/bike_system.hpp
Normal file
111
static_scheduling_with_event/bike_system.hpp
Normal file
@ -0,0 +1,111 @@
|
||||
// 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 "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 static_scheduling_with_event {
|
||||
|
||||
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 in main() for starting the sysytem with the event queue
|
||||
void startWithEventQueue();
|
||||
|
||||
// method called for stopping the system
|
||||
void stop();
|
||||
|
||||
#if defined(MBED_TEST_MODE)
|
||||
const advembsof::TaskLogger& getTaskLogger();
|
||||
#endif // defined(MBED_TEST_MODE)
|
||||
|
||||
private:
|
||||
// private methods
|
||||
void init();
|
||||
void onReset();
|
||||
void gearTask();
|
||||
void speedDistanceTask();
|
||||
void temperatureTask();
|
||||
void resetTask();
|
||||
void displayTask1();
|
||||
void displayTask2();
|
||||
void cpuTask();
|
||||
|
||||
// stop flag, used for stopping the super-loop (set in stop())
|
||||
bool _stopFlag = false;
|
||||
|
||||
std::chrono::microseconds _resetTime = std::chrono::microseconds::zero();
|
||||
volatile bool _resetFlag = false;
|
||||
|
||||
// timer instance used for loggint task time and used by ResetDevice
|
||||
Timer _timer;
|
||||
// data member that represents the device for manipulating the gear
|
||||
GearDevice _gearDevice;
|
||||
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;
|
||||
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 static_scheduling_with_event
|
64
static_scheduling_with_event/gear_device.cpp
Normal file
64
static_scheduling_with_event/gear_device.cpp
Normal file
@ -0,0 +1,64 @@
|
||||
// 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"
|
||||
|
||||
// from disco_h747i/wrappers
|
||||
#include <chrono>
|
||||
|
||||
#include "joystick.hpp"
|
||||
#include "mbed_trace.h"
|
||||
|
||||
#if MBED_CONF_MBED_TRACE_ENABLE
|
||||
#define TRACE_GROUP "GearDevice"
|
||||
#endif // MBED_CONF_MBED_TRACE_ENABLE
|
||||
|
||||
namespace static_scheduling_with_event {
|
||||
|
||||
GearDevice::GearDevice() {
|
||||
disco::Joystick::getInstance().setUpCallback(callback(this, &GearDevice::onUp));
|
||||
disco::Joystick::getInstance().setDownCallback(callback(this, &GearDevice::onDown));
|
||||
}
|
||||
|
||||
uint8_t GearDevice::getCurrentGear() { return core_util_atomic_load_u8(&_currentGear); }
|
||||
|
||||
uint8_t GearDevice::getCurrentGearSize() const {
|
||||
return bike_computer::kMaxGearSize - core_util_atomic_load_u8(&_currentGear);
|
||||
}
|
||||
|
||||
void GearDevice::onUp() {
|
||||
if (_currentGear < bike_computer::kMaxGear) {
|
||||
core_util_atomic_incr_u8(&_currentGear, 1);
|
||||
}
|
||||
}
|
||||
|
||||
void GearDevice::onDown() {
|
||||
if (_currentGear > bike_computer::kMinGear) {
|
||||
core_util_atomic_decr_u8(&_currentGear, 1);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace static_scheduling_with_event
|
54
static_scheduling_with_event/gear_device.hpp
Normal file
54
static_scheduling_with_event/gear_device.hpp
Normal file
@ -0,0 +1,54 @@
|
||||
// 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 "constants.hpp"
|
||||
#include "mbed.h"
|
||||
|
||||
namespace static_scheduling_with_event {
|
||||
|
||||
class GearDevice {
|
||||
public:
|
||||
GearDevice(); // NOLINT(runtime/references)
|
||||
|
||||
// make the class non copyable
|
||||
GearDevice(GearDevice&) = delete;
|
||||
GearDevice& operator=(GearDevice&) = delete;
|
||||
|
||||
// method called for updating the bike system
|
||||
uint8_t getCurrentGear();
|
||||
uint8_t getCurrentGearSize() const;
|
||||
|
||||
void onUp();
|
||||
void onDown();
|
||||
|
||||
private:
|
||||
// data members
|
||||
volatile uint8_t _currentGear = bike_computer::kMinGear;
|
||||
};
|
||||
|
||||
} // namespace static_scheduling_with_event
|
69
static_scheduling_with_event/pedal_device.cpp
Normal file
69
static_scheduling_with_event/pedal_device.cpp
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.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 "joystick.hpp"
|
||||
#include "mbed_trace.h"
|
||||
|
||||
#if MBED_CONF_MBED_TRACE_ENABLE
|
||||
#define TRACE_GROUP "PedalDevice"
|
||||
#endif // MBED_CONF_MBED_TRACE_ENABLE
|
||||
|
||||
namespace static_scheduling_with_event {
|
||||
|
||||
PedalDevice::PedalDevice() {
|
||||
disco::Joystick::getInstance().setLeftCallback(callback(this, &PedalDevice::onLeft));
|
||||
disco::Joystick::getInstance().setRightCallback(
|
||||
callback(this, &PedalDevice::onRight));
|
||||
}
|
||||
|
||||
std::chrono::milliseconds PedalDevice::getCurrentRotationTime() {
|
||||
uint32_t currentStep = core_util_atomic_load_u32(&_currentStep);
|
||||
return bike_computer::kMinPedalRotationTime +
|
||||
currentStep * bike_computer::kDeltaPedalRotationTime;
|
||||
}
|
||||
|
||||
void PedalDevice::increaseRotationSpeed() {
|
||||
uint32_t currentStep = core_util_atomic_load_u32(&_currentStep);
|
||||
if (currentStep > 0) {
|
||||
core_util_atomic_decr_u32(&_currentStep, 1);
|
||||
}
|
||||
}
|
||||
|
||||
void PedalDevice::decreaseRotationSpeed() {
|
||||
uint32_t currentStep = core_util_atomic_load_u32(&_currentStep);
|
||||
if (currentStep < bike_computer::kNbrOfSteps) {
|
||||
core_util_atomic_incr_u32(&_currentStep, 1);
|
||||
}
|
||||
}
|
||||
|
||||
void PedalDevice::onLeft() { decreaseRotationSpeed(); }
|
||||
|
||||
void PedalDevice::onRight() { increaseRotationSpeed(); }
|
||||
|
||||
} // namespace static_scheduling_with_event
|
59
static_scheduling_with_event/pedal_device.hpp
Normal file
59
static_scheduling_with_event/pedal_device.hpp
Normal file
@ -0,0 +1,59 @@
|
||||
// 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 static_scheduling_with_event {
|
||||
|
||||
class PedalDevice {
|
||||
public:
|
||||
PedalDevice(); // NOLINT(runtime/references)
|
||||
|
||||
// make the class non copyable
|
||||
PedalDevice(PedalDevice&) = delete;
|
||||
PedalDevice& operator=(PedalDevice&) = delete;
|
||||
|
||||
// method called for updating the bike system
|
||||
std::chrono::milliseconds getCurrentRotationTime();
|
||||
|
||||
private:
|
||||
// private methods
|
||||
void onLeft();
|
||||
void onRight();
|
||||
void increaseRotationSpeed();
|
||||
void decreaseRotationSpeed();
|
||||
|
||||
// data members
|
||||
volatile uint32_t _currentStep = static_cast<uint32_t>(
|
||||
(bike_computer::kInitialPedalRotationTime - bike_computer::kMinPedalRotationTime)
|
||||
.count() /
|
||||
bike_computer::kDeltaPedalRotationTime.count());
|
||||
};
|
||||
|
||||
} // namespace static_scheduling_with_event
|
48
static_scheduling_with_event/reset_device.cpp
Normal file
48
static_scheduling_with_event/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 static_scheduling_with_event {
|
||||
|
||||
ResetDevice::ResetDevice(Callback<void()> cb) : _resetButton(PUSH_BUTTON) {
|
||||
_resetButton.fall(cb);
|
||||
}
|
||||
|
||||
} // namespace static_scheduling_with_event
|
47
static_scheduling_with_event/reset_device.hpp
Normal file
47
static_scheduling_with_event/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 static_scheduling_with_event {
|
||||
|
||||
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 static_scheduling_with_event
|
Reference in New Issue
Block a user