diff --git a/.gitignore b/.gitignore index ab749f6..41eff4a 100644 --- a/.gitignore +++ b/.gitignore @@ -4,5 +4,5 @@ projectfiles *.py* BUILD mbed-os -DISCO_h747i +DISCO_H747I advdembsof_library diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 0e8a5e3..f568f65 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,4 +1,4 @@ -files: ^main.cpp|^static_scheduling|^static_scheduling_with_event|^TESTS +files: ^main.cpp|^static_scheduling|^static_scheduling_with_event|^TESTS|^multi_tasking|^common repos: - repo: https://github.com/pre-commit/pre-commit-hooks rev: v4.3.0 diff --git a/README.md b/README.md index f919c9e..4d7a5f6 100644 --- a/README.md +++ b/README.md @@ -23,25 +23,27 @@ Test sensor libraries : mbed test -m DISCO_H747I -t GCC_ARM -n advdembsof_library-tests-sensors-hdc1000 --compile --run ``` -## Run static scheduling +## 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 : +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 : +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 : +On main.cpp include `"static_scheduling/bike_system.hpp"` and use : ```cpp static_scheduling::BikeSystem bikeSystem; bikeSystem.startWithEventQueue(); @@ -51,9 +53,23 @@ bikeSystem.startWithEventQueue(); On `.mbedignore` put at the end of the file ``` static_scheduling/* +static_scheduling_with_event/* ``` -On main.cpp include `"static_scheduling_with_event/bike_system.hpp"` and use : +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(); @@ -63,7 +79,7 @@ bikeSystem.start(); ## 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. +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?` @@ -73,7 +89,7 @@ We can observe only a usage of 75% because the CPU is more on Idle with Thread s ## 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. +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?` @@ -84,7 +100,22 @@ We observe a light usage of 1% of CPU. The CPU is now sleeping all the time and We notice, that we miss such less event when is event driven (or not at all). But with a static scheduling the response time is still long because the reset task is call with a certain period. +# 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 \ No newline at end of file +As the acceptable delta is 2ms and the teacher test is done with GCC, we modify the delta on the test to be 3ms diff --git a/TESTS/bike-computer/bike-system/main.cpp b/TESTS/bike-computer/bike-system/main.cpp index 605f74c..f1c819f 100644 --- a/TESTS/bike-computer/bike-system/main.cpp +++ b/TESTS/bike-computer/bike-system/main.cpp @@ -23,15 +23,23 @@ ***************************************************************************/ #include +#include +#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 { @@ -140,6 +148,235 @@ static void test_bike_system_with_event() { } } +// test_multi_tasking_bike_system handler function +static void test_multi_tasking_bike_system() { + tr_info("test multi tasking bike system"); + + // create the BikeSystem instance + multi_tasking::BikeSystem bikeSystem; + + // run the bike system in a separate thread + Thread thread; + osStatus status = + thread.start(callback(&bikeSystem, &multi_tasking::BikeSystem::start)); + + if (status != osOK) { + tr_error("Thread bike system is not OK !"); + } + + tr_info("bike system has started"); + + // let the bike system run for 20 secs + ThisThread::sleep_for(20s); + + // check whether scheduling was correct + // Order is kGearTaskIndex, kSpeedTaskIndex, kTemperatureTaskIndex, + // kResetTaskIndex, kDisplayTask1Index, kDisplayTask2Index + // When we use event handling, we do not check the computation time + constexpr std::chrono::microseconds taskPeriods[] = { + 800000us, 400000us, 1600000us, 800000us, 1600000us, 1600000us}; + + // allow for 2 msecs offset (with EventQueue) + constexpr uint64_t kDeltaUs = 2000; + + // stop the bike system + bikeSystem.stop(); + thread.terminate(); + + tr_info("Threads have stopped"); + + TEST_ASSERT_UINT64_WITHIN( + kDeltaUs, + taskPeriods[advembsof::TaskLogger::kTemperatureTaskIndex].count(), + bikeSystem.getTaskLogger() + .getPeriod(advembsof::TaskLogger::kTemperatureTaskIndex) + .count()); + TEST_ASSERT_UINT64_WITHIN( + kDeltaUs, + taskPeriods[advembsof::TaskLogger::kDisplayTask1Index].count(), + bikeSystem.getTaskLogger() + .getPeriod(advembsof::TaskLogger::kDisplayTask1Index) + .count()); +} + +// test_reset_multi_tasking_bike_system handler function +Timer timer; +static std::chrono::microseconds resetTime = std::chrono::microseconds::zero(); +static EventFlags eventFlags; +static constexpr uint32_t kResetEventFlag = (1UL << 0); +static void resetCallback() { + resetTime = timer.elapsed_time(); + eventFlags.set(kResetEventFlag); +} + +static void test_reset_multi_tasking_bike_system() { + tr_info("test reset multi tasking bike system"); + // create the BikeSystem instance + multi_tasking::BikeSystem bikeSystem; + + // run the bike system in a separate thread + Thread thread; + osStatus status = + thread.start(callback(&bikeSystem, &multi_tasking::BikeSystem::start)); + + if (status != osOK) { + tr_error("Thread bike system is not OK !"); + } + + tr_info("Bike system has started"); + + // let the bike system run for 2 secs + ThisThread::sleep_for(2s); + + // test reset on BikeSystem + bikeSystem.getSpeedometer().setOnResetCallback(resetCallback); + + // start the timer instance + timer.start(); + + // check for reset response time + constexpr uint8_t kNbrOfResets = 10; + std::chrono::microseconds lastResponseTime = std::chrono::microseconds::zero(); + for (uint8_t i = 0; i < kNbrOfResets; i++) { + tr_info("Reset test N°%d", i); + // take time before reset + auto startTime = timer.elapsed_time(); + + // reset the BikeSystem + bikeSystem.onReset(); + + // wait for resetCallback to be called + eventFlags.wait_all(kResetEventFlag); + + // get the response time and check it + auto responseTime = resetTime - startTime; + + // cppcheck generates an internal error with 20us + constexpr std::chrono::microseconds kMaxExpectedResponseTime(20); + + tr_info("Reset task: response time is %lld usecs\n, expected : %lld", + responseTime.count(), + kMaxExpectedResponseTime.count()); + + TEST_ASSERT_TRUE(responseTime.count() <= kMaxExpectedResponseTime.count()); + + // jitter of 20us is accepted + constexpr uint64_t kDeltaUs = 4; + constexpr std::chrono::microseconds kMaxExpectedJitter(3); + if (i > 0) { + auto jitter = responseTime - lastResponseTime; + tr_info("Reset task: jitter is %lld usecs\n", std::abs(jitter.count())); + TEST_ASSERT_UINT64_WITHIN( + kDeltaUs, kMaxExpectedJitter.count(), std::abs(jitter.count())); + } + lastResponseTime = responseTime; + + // let the bike system run for 2 secs + ThisThread::sleep_for(2s); + } + + // stop the bike system + bikeSystem.stop(); + thread.terminate(); + tr_info("Threads have stopped"); + timer.stop(); +} + +Timer timerGear; +static std::chrono::microseconds gearTime = std::chrono::microseconds::zero(); +static EventFlags eventGearFlags; +static constexpr uint32_t kGearEventFlag = (1UL << 0); +constexpr uint8_t kNbrOfGear = 9; +static void onGearChange() { + gearTime = timerGear.elapsed_time(); + eventGearFlags.set(kGearEventFlag); + tr_info("Gear changed"); +} + +static void gearTest(Callback 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) @@ -152,7 +389,10 @@ static status_t greentea_setup(const size_t number_of_cases) { 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), + 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); @@ -160,4 +400,9 @@ static Specification specification(greentea_setup, cases); }; // namespace v1 }; // namespace utest -int main() { return !utest::v1::Harness::run(utest::v1::specification); } +int main() { +#if defined(MBED_CONF_MBED_TRACE_ENABLE) + mbed_trace_init(); +#endif + return !utest::v1::Harness::run(utest::v1::specification); +} diff --git a/common/constants.hpp b/common/constants.hpp index 859a210..8ba92e1 100644 --- a/common/constants.hpp +++ b/common/constants.hpp @@ -52,9 +52,8 @@ static constexpr std::chrono::milliseconds kMaxPedalRotationTime = 1500ms; static constexpr std::chrono::milliseconds kDeltaPedalRotationTime = 25ms; static constexpr uint32_t kNbrOfSteps = static_cast( - ( - bike_computer::kMaxPedalRotationTime - bike_computer::kMinPedalRotationTime - ).count() / bike_computer::kDeltaPedalRotationTime.count() -); + (bike_computer::kMaxPedalRotationTime - bike_computer::kMinPedalRotationTime) + .count() / + bike_computer::kDeltaPedalRotationTime.count()); -} // namespace bike_computer \ No newline at end of file +} // namespace bike_computer diff --git a/common/sensor_device.cpp b/common/sensor_device.cpp index 4aa7ef2..69d3344 100644 --- a/common/sensor_device.cpp +++ b/common/sensor_device.cpp @@ -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 + * + * @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 diff --git a/common/sensor_device.hpp b/common/sensor_device.hpp index d6ead2c..37bc1f1 100644 --- a/common/sensor_device.hpp +++ b/common/sensor_device.hpp @@ -46,4 +46,4 @@ class SensorDevice { advembsof::HDC1000 _hdc1000; }; -} // namespace bike_computer \ No newline at end of file +} // namespace bike_computer diff --git a/common/speedometer.cpp b/common/speedometer.cpp index a24d685..2fbf212 100644 --- a/common/speedometer.cpp +++ b/common/speedometer.cpp @@ -24,9 +24,8 @@ #include "speedometer.hpp" -#include "static_scheduling/gear_device.hpp" - #include +#include #include // 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 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(3600 * 1000); - float pedal_rotation_per_hour = ms_in_hour / std::chrono::duration_cast(_pedalRotationTime).count(); - float gear_ratio = static_cast(kTraySize) / static_cast(this->_gearSize); + float pedal_rotation_per_hour = + ms_in_hour / + std::chrono::duration_cast(_pedalRotationTime).count(); + float gear_ratio = + static_cast(kTraySize) / static_cast(this->_gearSize); float wheel_dist_km = static_cast(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 timeNow = _timer.elapsed_time(); const std::chrono::microseconds timeDiff = timeNow - _lastTime; - constexpr float ms_in_hour = static_cast(3600 * 1000); - float traveled_dist = _currentSpeed * timeDiff.count() / (ms_in_hour*1000.0/*μs*/); + constexpr float ms_in_hour = static_cast(3600 * 1000); + float traveled_dist = _currentSpeed * timeDiff.count() / (ms_in_hour * 1000.0 /*μs*/); this->_totalDistanceMutex.lock(); this->_totalDistance += traveled_dist; diff --git a/common/speedometer.hpp b/common/speedometer.hpp index bbc1e6b..e831cb2 100644 --- a/common/speedometer.hpp +++ b/common/speedometer.hpp @@ -55,6 +55,7 @@ class Speedometer { float getTraySize() const; std::chrono::milliseconds getCurrentPedalRotationTime() const; void setOnResetCallback(mbed::Callback cb); + mbed::Callback _cbOnReset = NULL; #endif // defined(MBED_TEST_MODE) private: @@ -79,13 +80,11 @@ 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 _cb; #endif }; -} // namespace bike_computer \ No newline at end of file +} // namespace bike_computer diff --git a/main.cpp b/main.cpp index 222429a..45253da 100644 --- a/main.cpp +++ b/main.cpp @@ -5,10 +5,11 @@ #if !MBED_TEST_MODE -#include "mbed.h" // NOLINT -#include "mbed_trace.h" +#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" #if defined(MBED_CONF_MBED_TRACE_ENABLE) #define TRACE_GROUP "MAIN" @@ -21,10 +22,12 @@ int main() { // static_scheduling::BikeSystem bikeSystem; // bikeSystem.start(); - // bikeSystem.startWithEventQueue(); static_scheduling_with_event::BikeSystem bikeSystem; bikeSystem.start(); + + // multi_tasking::BikeSystem bikeSystem; + // bikeSystem.start(); } #endif // MBED_TEST_MODE diff --git a/mbed-bootloader-advembsof.bin b/mbed-bootloader-advembsof.bin deleted file mode 100644 index 5a505d0..0000000 Binary files a/mbed-bootloader-advembsof.bin and /dev/null differ diff --git a/mbed_app.json b/mbed_app.json index 89235e9..44c1335 100644 --- a/mbed_app.json +++ b/mbed_app.json @@ -1,29 +1,27 @@ { - "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": { - "mbed-trace.enable": true, - "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" - } + "macros": ["MBED_CONF_MBED_TRACE_FEA_IPV6=0"], + "config": { + "main-stack-size": { + "value": 8192 } - } \ No newline at end of file + }, + "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": { + "mbed-trace.enable": true, + "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" + } + } +} diff --git a/multi_tasking/bike_system.cpp b/multi_tasking/bike_system.cpp new file mode 100644 index 0000000..112455d --- /dev/null +++ b/multi_tasking/bike_system.cpp @@ -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 + * @author Rémi Heredero + * @author Yann Sierro + * + * @brief Bike System implementation (static scheduling) + * + * @date 2023-11-15 + * @version 1.1.0 + ***************************************************************************/ + +#include "bike_system.hpp" + +#include +#include + +#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 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(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 temperatureEvent(&_eventQueue, + callback(this, &BikeSystem::temperatureTask)); + temperatureEvent.delay(kTemperatureTaskDelay); + temperatureEvent.period(kTemperatureTaskPeriod); + temperatureEvent.post(); + + Event 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(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(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(status)); + } + +#if !defined(MBED_TEST_MODE) + Event 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 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( + 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( + 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( + 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(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 diff --git a/multi_tasking/bike_system.hpp b/multi_tasking/bike_system.hpp new file mode 100644 index 0000000..41a1935 --- /dev/null +++ b/multi_tasking/bike_system.hpp @@ -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 + * + * @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 cbGearChange); + Callback _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 _mailPedalDevice; + Mail _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 diff --git a/multi_tasking/gear_device.cpp b/multi_tasking/gear_device.cpp new file mode 100644 index 0000000..e45a69c --- /dev/null +++ b/multi_tasking/gear_device.cpp @@ -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 + * @author Rémi Heredero + * @author Yann Sierro + * + * @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* 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 diff --git a/multi_tasking/gear_device.hpp b/multi_tasking/gear_device.hpp new file mode 100644 index 0000000..5ec23c5 --- /dev/null +++ b/multi_tasking/gear_device.hpp @@ -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 + * @author Rémi Heredero + * @author Yann Sierro + * + * @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* 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* _mailBox; + Timer& _timer; +}; + +} // namespace multi_tasking diff --git a/multi_tasking/pedal_device.cpp b/multi_tasking/pedal_device.cpp new file mode 100644 index 0000000..29d600f --- /dev/null +++ b/multi_tasking/pedal_device.cpp @@ -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 + * @author Yann Sierro + * + * @brief Pedal Device implementation (static scheduling) + * @date 2024-11-17 + * @version 1.1.0 + ****************************************************************************/ + +#include "pedal_device.hpp" + +// from disco_h747i/wrappers +#include + +#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* 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 diff --git a/multi_tasking/pedal_device.hpp b/multi_tasking/pedal_device.hpp new file mode 100644 index 0000000..c6e014d --- /dev/null +++ b/multi_tasking/pedal_device.hpp @@ -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 + * @author Rémi Heredero + * @author Yann Sierro + * + * @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* 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( + (bike_computer::kInitialPedalRotationTime - bike_computer::kMinPedalRotationTime) + .count() / + bike_computer::kDeltaPedalRotationTime.count()); + + Mail* _mailBox; + Timer& _timer; +}; + +} // namespace multi_tasking diff --git a/multi_tasking/reset_device.cpp b/multi_tasking/reset_device.cpp new file mode 100644 index 0000000..f4a1fdb --- /dev/null +++ b/multi_tasking/reset_device.cpp @@ -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 + * @author Yann Sierro + * + * @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 + +#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 cb) : _resetButton(PUSH_BUTTON) { + _resetButton.fall(cb); +} + +} // namespace multi_tasking diff --git a/multi_tasking/reset_device.hpp b/multi_tasking/reset_device.hpp new file mode 100644 index 0000000..c0a57a5 --- /dev/null +++ b/multi_tasking/reset_device.hpp @@ -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 + * @author Rémi Heredero + * @author Yann Sierro + * + * @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 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 diff --git a/static_scheduling/bike_system.hpp b/static_scheduling/bike_system.hpp index 67fefd5..5e8ccf2 100644 --- a/static_scheduling/bike_system.hpp +++ b/static_scheduling/bike_system.hpp @@ -80,7 +80,7 @@ class BikeSystem { // data member that represents the device for manipulating the gear GearDevice _gearDevice; uint8_t _currentGear = bike_computer::kMinGear; - uint8_t _currentGearSize = bike_computer::kMinGearSize; + uint8_t _currentGearSize = bike_computer::kMaxGearSize; // data member that represents the device for manipulating the pedal rotation // speed/time PedalDevice _pedalDevice; diff --git a/static_scheduling_with_event/bike_system.cpp b/static_scheduling_with_event/bike_system.cpp index e9416d5..ce87c29 100644 --- a/static_scheduling_with_event/bike_system.cpp +++ b/static_scheduling_with_event/bike_system.cpp @@ -62,7 +62,7 @@ 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(), @@ -178,7 +178,7 @@ void BikeSystem::speedDistanceTask() { _taskLogger.logPeriodAndExecutionTime( _timer, advembsof::TaskLogger::kSpeedTaskIndex, taskStartTime); } - + void BikeSystem::displayTask1() { auto taskStartTime = _timer.elapsed_time(); diff --git a/static_scheduling_with_event/bike_system.hpp b/static_scheduling_with_event/bike_system.hpp index 8254f22..c51de14 100644 --- a/static_scheduling_with_event/bike_system.hpp +++ b/static_scheduling_with_event/bike_system.hpp @@ -85,7 +85,7 @@ class BikeSystem { // data member that represents the device for manipulating the gear GearDevice _gearDevice; uint8_t _currentGear = bike_computer::kMinGear; - uint8_t _currentGearSize = bike_computer::kMinGearSize; + uint8_t _currentGearSize = bike_computer::kMaxGearSize; // data member that represents the device for manipulating the pedal rotation // speed/time PedalDevice _pedalDevice;