1 Commits

Author SHA1 Message Date
f079714de5 ADD bike-system super-loop with while 2024-11-17 14:20:38 +01:00
28 changed files with 252 additions and 1188 deletions

View File

@ -1,6 +1,6 @@
name: Build test application
on:
push:
pull_request:
jobs:
build-cli-v1:
@ -14,9 +14,11 @@ 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-bike-system,
tests-bike-computer-speedometer
]

View File

@ -1,26 +1,24 @@
files: ^main.cpp|^static_scheduling|^static_scheduling_with_event|^TESTS
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 --suppress=missingIncludeSystem --inline-suppr -i mbed-os --std=c++14 --error-exitcode=1
language: system
- 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
- 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

View File

@ -22,69 +22,3 @@ 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/*
```
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/*
```
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/*
```
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.
# 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

View File

@ -24,16 +24,15 @@
#include <chrono>
#include "static_scheduling/bike_system.hpp"
#include "greentea-client/test_env.h"
#include "mbed.h"
#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"
namespace utest {
namespace v1 {
using namespace utest::v1;
// test_bike_system handler function
static void test_bike_system() {
@ -59,7 +58,7 @@ static void test_bike_system() {
800000us, 400000us, 1600000us, 800000us, 1600000us, 1600000us};
// allow for 2 msecs offset
uint64_t deltaUs = 3000;
uint64_t deltaUs = 2000;
for (uint8_t taskIndex = 0; taskIndex < advembsof::TaskLogger::kNbrOfTasks;
taskIndex++) {
TEST_ASSERT_UINT64_WITHIN(
@ -73,91 +72,17 @@ static void test_bike_system() {
}
}
// 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());
}
}
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)
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)
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 handling", test_bike_system_with_event),
};
static Case cases[] = {Case("test bike system", test_bike_system)};
static Specification specification(greentea_setup, cases);
}; // namespace v1
}; // namespace utest
int main() { return !utest::v1::Harness::run(utest::v1::specification); }
int main() { return !Harness::run(specification); }

View File

@ -29,8 +29,7 @@
#include "unity/unity.h"
#include "utest/utest.h"
namespace utest {
namespace v1 {
using namespace utest::v1;
// test_hdc1000 test handler function
static control_t test_sensor_device(const size_t call_count) {
@ -54,9 +53,9 @@ static control_t test_sensor_device(const size_t call_count) {
return CaseNext;
}
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)
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)
GREENTEA_SETUP(60, "default_auto");
return greentea_test_setup_handler(number_of_cases);
@ -66,7 +65,5 @@ static 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 !utest::v1::Harness::run(utest::v1::specification); }
int main() { return !Harness::run(specification); }

View File

@ -32,14 +32,13 @@
#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,
@ -76,8 +75,7 @@ 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;
}
@ -88,8 +86,7 @@ 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",
@ -337,9 +334,9 @@ static control_t test_reset(const size_t call_count) {
return CaseNext;
}
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)
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)
GREENTEA_SETUP(180, "default_auto");
return greentea_test_setup_handler(number_of_cases);
@ -353,7 +350,5 @@ static Case cases[] = {
Case("test speedometer reset", test_reset)};
static Specification specification(greentea_setup, cases);
}; // namespace v1
}; // namespace utest
int main() { return !utest::v1::Harness::run(utest::v1::specification); }
int main() { return !Harness::run(specification); }

View File

@ -27,8 +27,7 @@
#include "unity/unity.h"
#include "utest/utest.h"
namespace utest {
namespace v1 {
using namespace utest::v1;
// test handler function
static control_t always_succeed(const size_t call_count) {
@ -39,9 +38,9 @@ static control_t always_succeed(const size_t call_count) {
return CaseNext;
}
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)
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)
GREENTEA_SETUP(60, "default_auto");
return greentea_test_setup_handler(number_of_cases);
@ -52,7 +51,4 @@ static Case cases[] = {Case("always succeed test", always_succeed)};
static Specification specification(greentea_setup, cases);
}; // namespace v1
}; // namespace utest
int main() { return !utest::v1::Harness::run(utest::v1::specification); }
int main() { return !Harness::run(specification); }

View File

@ -24,14 +24,12 @@
* @version 0.2.0
***************************************************************************/
#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 {
#include "greentea-client/test_env.h"
#include "mbed.h"
#include "unity/unity.h"
#include "utest/utest.h"
using namespace utest::v1;
struct Test {
Test() {
_instanceCount++;
@ -50,8 +48,7 @@ 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
@ -69,8 +66,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);
@ -100,8 +97,8 @@ void test_instance_sharing() {
}
/**********************
* UNIQUE PTR EXERCISE *
**********************/
* UNIQUE PTR EXERCISE *
**********************/
/*
* Check normal lifetime on a unique_ptr
@ -117,7 +114,7 @@ void test_single_unique_ptr_lifetime() {
TEST_ASSERT_EQUAL(Test::kMagicNumber, p1->_value);
const uint32_t number = 42;
p1->_value = number;
p1->_value = number;
TEST_ASSERT_EQUAL(number, p1->_value);
p1.reset();
@ -135,12 +132,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);
@ -148,7 +145,7 @@ void test_unique_ptr_transfer() {
p2.reset();
TEST_ASSERT_EQUAL(0, Test::_instanceCount);
TEST_ASSERT(!p1); // cppcheck-suppress accessMoved
TEST_ASSERT(!p1);
TEST_ASSERT(!p2);
}
@ -163,13 +160,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);
@ -195,21 +192,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);
@ -226,13 +223,14 @@ 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
@ -244,12 +242,12 @@ 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);
const uint32_t number1 = 42;
p1->_value = number1;
p1->_value = number1;
TEST_ASSERT_EQUAL(number1, p1->_value);
TEST_ASSERT_EQUAL(number1, t1._value);
@ -262,9 +260,9 @@ void test_single_raw_ptr_lifetime() {
TEST_ASSERT_EQUAL(0, Test::_instanceCount);
}
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)
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)
GREENTEA_SETUP(60, "default_auto");
return greentea_test_setup_handler(number_of_cases);
}
@ -287,7 +285,4 @@ static Case cases[] = {
static Specification specification(greentea_setup, cases);
}; // namespace v1
}; // namespace utest
int main() { return !utest::v1::Harness::run(utest::v1::specification); }
int main() { return !Harness::run(specification); }

View File

@ -51,10 +51,4 @@ 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

View File

@ -110,7 +110,7 @@ void Speedometer::computeSpeed() {
// TODO : done
//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 / std::chrono::duration_cast<std::chrono::milliseconds>(_pedalRotationTime).count();
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 wheel_dist_km = static_cast<float>(this->kWheelCircumference) / 1000.0;
this->_currentSpeed = gear_ratio * wheel_dist_km * pedal_rotation_per_hour;
@ -141,4 +141,4 @@ void Speedometer::computeDistance() {
_lastTime = _timer.elapsed_time();
}
} // namespace bike_computer
} // namespace bike_computer

View File

@ -7,23 +7,26 @@
#include "mbed.h" // NOLINT
#include "mbed_trace.h"
// #include "static_scheduling/bike_system.hpp"
#include "static_scheduling_with_event/bike_system.hpp"
#include "static_scheduling/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() {
#if defined(MBED_CONF_MBED_TRACE_ENABLE)
// Initialise the digital pin LED1 as an output
mbed_trace_init();
#endif
// DigitalOut led(LED1);
// tr_debug("Hello world");
// static_scheduling::BikeSystem bikeSystem;
// bikeSystem.start();
// bikeSystem.startWithEventQueue();
static_scheduling_with_event::BikeSystem bikeSystem;
// while (true) {
// led = !led;
// ThisThread::sleep_for(BLINKING_RATE);
// tr_debug("blink");
// }
static_scheduling::BikeSystem bikeSystem;
bikeSystem.start();
}

View File

@ -14,7 +14,6 @@
"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

View File

@ -35,54 +35,61 @@
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 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;
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;
BikeSystem::BikeSystem()
: _gearDevice(_timer),
_pedalDevice(_timer),
_resetDevice(_timer),
_speedometer(_timer),
_cpuLogger(_timer) {}
// TODO: implement the constructor
BikeSystem::BikeSystem() :
_gearDevice(_timer),
_pedalDevice(_timer),
_resetDevice(_timer),
_speedometer(_timer)
{
}
void BikeSystem::start() {
tr_info("Starting Super-Loop without event handling");
init();
// TODO: implement the super-loop based for implementing the appropriate schedule
// Done
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
// TODO: implement calls to different tasks based on computed schedule
// Done
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
@ -91,67 +98,17 @@ void BikeSystem::start() {
std::chrono::duration_cast<std::chrono::milliseconds>(endTime - startTime);
tr_debug("Repeating cycle time is %" PRIu64 " milliseconds", cycle.count());
// TODO: implement loop exit when applicable
// Done
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)
@ -198,7 +155,7 @@ void BikeSystem::speedDistanceTask() {
_speedometer.setCurrentRotationTime(pedalRotationTime);
_speedometer.setGearSize(_currentGearSize);
// no need to protect access to data members (single threaded)
_currentSpeed = _speedometer.getCurrentSpeed();
_currentSpeed = _speedometer.getCurrentSpeed();
_traveledDistance = _speedometer.getDistance();
_taskLogger.logPeriodAndExecutionTime(
@ -215,16 +172,12 @@ void BikeSystem::temperatureTask() {
tr_warn("Tick2 %" PRIu64, _timer.elapsed_time().count());
ThisThread::sleep_for(std::chrono::duration_cast<std::chrono::milliseconds>(
kTemperatureTaskComputationTime - (_timer.elapsed_time() - taskStartTime)));
// simulate task computation by waiting for the required task computation time
// std::chrono::microseconds elapsedTime =
// std::chrono::microseconds::zero(); while (elapsedTime <
// kTemperatureTaskComputationTime) {
// elapsedTime = _timer.elapsed_time() - taskStartTime;
// }
std::chrono::microseconds elapsedTime = std::chrono::microseconds::zero();
while (elapsedTime < kTemperatureTaskComputationTime) {
elapsedTime = _timer.elapsed_time() - taskStartTime;
}
_taskLogger.logPeriodAndExecutionTime(
_timer, advembsof::TaskLogger::kTemperatureTaskIndex, taskStartTime);
@ -251,16 +204,12 @@ void BikeSystem::displayTask1() {
_displayDevice.displaySpeed(_currentSpeed);
_displayDevice.displayDistance(_traveledDistance);
ThisThread::sleep_for(std::chrono::duration_cast<std::chrono::milliseconds>(
kDisplayTask1ComputationTime - (_timer.elapsed_time() - taskStartTime)));
// simulate task computation by waiting for the required task computation time
// std::chrono::microseconds elapsedTime =
// std::chrono::microseconds::zero(); while (elapsedTime <
// kDisplayTask1ComputationTime) {
// elapsedTime = _timer.elapsed_time() - taskStartTime;
// }
std::chrono::microseconds elapsedTime = std::chrono::microseconds::zero();
while (elapsedTime < kDisplayTask1ComputationTime) {
elapsedTime = _timer.elapsed_time() - taskStartTime;
}
_taskLogger.logPeriodAndExecutionTime(
_timer, advembsof::TaskLogger::kDisplayTask1Index, taskStartTime);
@ -271,20 +220,14 @@ void BikeSystem::displayTask2() {
_displayDevice.displayTemperature(_currentTemperature);
ThisThread::sleep_for(std::chrono::duration_cast<std::chrono::milliseconds>(
kDisplayTask2ComputationTime - (_timer.elapsed_time() - taskStartTime)));
// simulate task computation by waiting for the required task computation time
// std::chrono::microseconds elapsedTime =
// std::chrono::microseconds::zero(); while (elapsedTime <
// kDisplayTask2ComputationTime) {
// elapsedTime = _timer.elapsed_time() - taskStartTime;
// }
std::chrono::microseconds elapsedTime = std::chrono::microseconds::zero();
while (elapsedTime < kDisplayTask2ComputationTime) {
elapsedTime = _timer.elapsed_time() - taskStartTime;
}
_taskLogger.logPeriodAndExecutionTime(
_timer, advembsof::TaskLogger::kDisplayTask2Index, taskStartTime);
}
void BikeSystem::cpuTask() { _cpuLogger.printStats(); }
} // namespace static_scheduling
} // namespace static_scheduling

View File

@ -25,7 +25,6 @@
#pragma once
// from advembsof
#include "cpu_logger.hpp"
#include "display_device.hpp"
#include "task_logger.hpp"
@ -52,9 +51,6 @@ class BikeSystem {
// 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();
@ -71,7 +67,6 @@ class BikeSystem {
void resetTask();
void displayTask1();
void displayTask2();
void cpuTask();
// stop flag, used for stopping the super-loop (set in stop())
bool _stopFlag = false;
@ -79,12 +74,12 @@ class BikeSystem {
Timer _timer;
// data member that represents the device for manipulating the gear
GearDevice _gearDevice;
uint8_t _currentGear = bike_computer::kMinGear;
uint8_t _currentGear = bike_computer::kMinGear;
uint8_t _currentGearSize = bike_computer::kMinGearSize;
// data member that represents the device for manipulating the pedal rotation
// speed/time
PedalDevice _pedalDevice;
float _currentSpeed = 0.0f;
float _currentSpeed = 0.0f;
float _traveledDistance = 0.0f;
// data member that represents the device used for resetting
ResetDevice _resetDevice;
@ -98,9 +93,6 @@ class BikeSystem {
// used for logging task info
advembsof::TaskLogger _taskLogger;
// cpu logger to measure cpu usage
advembsof::CPULogger _cpuLogger;
};
} // namespace static_scheduling
} // namespace static_scheduling

View File

@ -80,4 +80,4 @@ uint8_t GearDevice::getCurrentGearSize() const {
return bike_computer::kMaxGearSize - _currentGear;
}
} // namespace static_scheduling
} // namespace static_scheduling

View File

@ -47,4 +47,4 @@ class GearDevice {
Timer& _timer;
};
} // namespace static_scheduling
} // namespace static_scheduling

View File

@ -1,25 +1,12 @@
// 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"
@ -35,50 +22,51 @@
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) {}
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();
switch (joystickState) {
case disco::Joystick::State::LeftPressed:
if (_pedalRotationTime < bike_computer::kMaxPedalRotationTime) {
decreaseRotationSpeed();
hasChanged = true;
}
break;
std::chrono::milliseconds PedalDevice::getCurrentRotationTime() {
// TODO
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();
case disco::Joystick::State::DownPressed:
if (_pedalRotationTime > bike_computer::kMinPedalRotationTime) {
decreaseRotationSpeed();
hasChanged = true;
}
break;
switch (joystickState) {
case disco::Joystick::State::LeftPressed:
if (_pedalRotationTime < bike_computer::kMaxPedalRotationTime) {
decreaseRotationSpeed();
hasChanged = true;
}
break;
default:
break;
}
}
elapsedTime = _timer.elapsed_time() - initialTime;
case disco::Joystick::State::DownPressed:
if (_pedalRotationTime > bike_computer::kMinPedalRotationTime) {
decreaseRotationSpeed();
hasChanged = true;
}
break;
default:
break;
}
}
elapsedTime = _timer.elapsed_time() - initialTime;
}
return _pedalRotationTime;
}
return _pedalRotationTime;
}
void PedalDevice::increaseRotationSpeed() {
_pedalRotationTime -= bike_computer::kDeltaPedalRotationTime;
}
void PedalDevice::increaseRotationSpeed() {
_pedalRotationTime -= bike_computer::kDeltaPedalRotationTime;
}
void PedalDevice::decreaseRotationSpeed() {
_pedalRotationTime += bike_computer::kDeltaPedalRotationTime;
}
void PedalDevice::decreaseRotationSpeed() {
_pedalRotationTime += bike_computer::kDeltaPedalRotationTime;
}
} // namespace static_scheduling
}

View File

@ -51,4 +51,4 @@ class PedalDevice {
Timer& _timer;
};
} // namespace static_scheduling
} // namespace static_scheduling

View File

@ -1,26 +1,12 @@
// 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"
@ -35,35 +21,43 @@
static constexpr uint8_t kPolarityPressed = 1;
#endif
#if MBED_CONF_MBED_TRACE_ENABLE
#define TRACE_GROUP "ResetDevice"
#define TRACE_GROUP "PedalDevice"
#endif // MBED_CONF_MBED_TRACE_ENABLE
namespace static_scheduling {
static constexpr std::chrono::microseconds kTaskRunTime = 100000us;
static constexpr std::chrono::microseconds kTaskRunTime = 100000us;
ResetDevice::ResetDevice(Timer& timer) : _timer(timer), _resetButton(PUSH_BUTTON) {
_resetButton.rise(callback(this, &ResetDevice::onRise));
}
ResetDevice::ResetDevice(Timer& timer) : _timer(timer), _resetButton(PUSH_BUTTON) {
_resetButton.rise(callback(this, &ResetDevice::onRise));
}
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) {
isPressed = _resetButton.read() == kPolarityPressed;
}
elapsedTime = _timer.elapsed_time() - initialTime;
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) {
isPressed = _resetButton.read() == kPolarityPressed;
}
elapsedTime = _timer.elapsed_time() - initialTime;
}
return isPressed;
}
std::chrono::microseconds ResetDevice::getPressTime() {
return _pressTime;
}
return isPressed;
}
void ResetDevice::onRise() {
_pressTime = _timer.elapsed_time();
}
std::chrono::microseconds ResetDevice::getPressTime() { return _pressTime; }
void ResetDevice::onRise() { _pressTime = _timer.elapsed_time(); }
} // namespace static_scheduling
}

View File

@ -53,4 +53,4 @@ class ResetDevice {
std::chrono::microseconds _pressTime;
};
} // namespace static_scheduling
} // namespace static_scheduling

View File

@ -1,239 +0,0 @@
// 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)),
_speedometer(_timer),
_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::temperatureTask() {
auto taskStartTime = _timer.elapsed_time();
// tr_warn("Tick1 %" PRIu64, _timer.elapsed_time().count());
// no need to protect access to data members (single threaded)
_currentTemperature = _sensorDevice.readTemperature();
// tr_warn("Tick2 %" PRIu64, _timer.elapsed_time().count());
ThisThread::sleep_for(std::chrono::duration_cast<std::chrono::milliseconds>(
kTemperatureTaskComputationTime - (_timer.elapsed_time() - taskStartTime)));
_taskLogger.logPeriodAndExecutionTime(
_timer, advembsof::TaskLogger::kTemperatureTaskIndex, 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::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::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

View File

@ -1,111 +0,0 @@
// 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::kMinGearSize;
// 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

View File

@ -1,64 +0,0 @@
// 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

View File

@ -1,54 +0,0 @@
// 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

View File

@ -1,69 +0,0 @@
// 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

View File

@ -1,59 +0,0 @@
// 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

View File

@ -1,48 +0,0 @@
// 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

View File

@ -1,47 +0,0 @@
// 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