ADD mail box for pedal device

This commit is contained in:
fastium 2025-01-03 17:10:42 +01:00
parent 946e86025c
commit 95e92e2564
5 changed files with 227 additions and 125 deletions

View File

@ -22,5 +22,5 @@ repos:
- id: cppcheck - id: cppcheck
name: cppcheck name: cppcheck
require_serial: true require_serial: true
entry: cppcheck --enable=all --suppress=missingInclude --suppress=missingIncludeSystem --suppress=unusedFunction --inline-suppr -i mbed-os --std=c++14 --error-exitcode=1 entry: cppcheck --enable=all --suppress=missingInclude --suppress=missingIncludeSystem --suppress=unusedFunction --suppress=unusedStructMember --inline-suppr -i mbed-os --std=c++14 --error-exitcode=1
language: system language: system

View File

@ -28,9 +28,11 @@
#include <chrono> #include <chrono>
#include "Callback.h"
#include "cmsis_os2.h" #include "cmsis_os2.h"
#include "constants.hpp" #include "constants.hpp"
#include "mbed_trace.h" #include "mbed_trace.h"
#include "pedal_device.hpp"
#if MBED_CONF_MBED_TRACE_ENABLE #if MBED_CONF_MBED_TRACE_ENABLE
#define TRACE_GROUP "BikeSystem" #define TRACE_GROUP "BikeSystem"
#endif // MBED_CONF_MBED_TRACE_ENABLE #endif // MBED_CONF_MBED_TRACE_ENABLE
@ -62,11 +64,36 @@ static constexpr std::chrono::milliseconds kCPUTaskComputationTime = 0
BikeSystem::BikeSystem() BikeSystem::BikeSystem()
: _gearDevice(callback(this, &BikeSystem::onGearUp), : _gearDevice(callback(this, &BikeSystem::onGearUp),
callback(this, &BikeSystem::onGearDown)), callback(this, &BikeSystem::onGearDown)),
_pedalDevice(), _pedalDevice(&_mailPedalDevice),
_resetDevice(callback(this, &BikeSystem::onReset)), _resetDevice(callback(this, &BikeSystem::onReset)),
_speedometer(_timer), _speedometer(_timer),
_cpuLogger(_timer), _cpuLogger(_timer),
_isrEventThread(osPriorityAboveNormal, OS_STACK_SIZE, nullptr, "ISR_Event") {} _isrEventThread(osPriorityAboveNormal, OS_STACK_SIZE, nullptr, "ISR_Event"),
_speedDistanceThread(
osPriorityNormal, OS_STACK_SIZE, nullptr, "Speed_distance_Task") {}
#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("Ffalseailed to initialized the lcd display: %ld", 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(false);
}
void BikeSystem::start() { void BikeSystem::start() {
tr_info("Starting Super-Loop with event handling"); tr_info("Starting Super-Loop with event handling");
@ -101,9 +128,18 @@ void BikeSystem::start() {
tr_error("Thread %s started with status %d", _isrEventThread.get_name(), status); tr_error("Thread %s started with status %d", _isrEventThread.get_name(), status);
} }
status =
_speedDistanceThread.start(callback(this, &BikeSystem::loop_speed_distance_task));
if (status != osOK) {
tr_error("Thread %s started with status %d", _isrEventThread.get_name(), status);
}
// dispathc the main queue in the main thread
dispatch_events(); dispatch_events();
} }
/* Callback from isr */
void BikeSystem::onReset() { void BikeSystem::onReset() {
_resetTime = _timer.elapsed_time(); _resetTime = _timer.elapsed_time();
Event<void()> resetEvent(&_isrEventQueue, callback(this, &BikeSystem::resetTask)); Event<void()> resetEvent(&_isrEventQueue, callback(this, &BikeSystem::resetTask));
@ -123,100 +159,7 @@ void BikeSystem::onGearDown() {
gearDownEvent.post(); gearDownEvent.post();
} }
#if defined(MBED_TEST_MODE) // ISR thread functions
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("Ffalseailed to initialized the lcd display: %ld", 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(false);
}
void BikeSystem::gearUpTask() {
auto taskStartTime = _timer.elapsed_time();
std::chrono::microseconds responseTime = _timer.elapsed_time() - _onGearUpTime;
tr_info("Gear up task: response time is %" PRIu64 " usecs", responseTime.count());
// CRITICAL SECTION
mutexGear.lock();
if (_currentGear < bike_computer::kMaxGear) {
_currentGear++;
mutexGearSize.lock();
_currentGearSize = bike_computer::kMaxGearSize - _currentGear;
mutexGearSize.unlock();
}
mutexGear.unlock();
// END CRITICAL SECTION
_taskLogger.logPeriodAndExecutionTime(
_timer, advembsof::TaskLogger::kGearTaskIndex, taskStartTime);
}
void BikeSystem::gearDownTask() {
auto taskStartTime = _timer.elapsed_time();
std::chrono::microseconds responseTime = _timer.elapsed_time() - _onGearDownTime;
tr_info("Gear down task: response time is %" PRIu64 " usecs", responseTime.count());
// CRITICAL SECTION
mutexGear.lock();
if (_currentGear > bike_computer::kMinGear) {
_currentGear--;
mutexGearSize.lock();
_currentGearSize = bike_computer::kMaxGearSize - _currentGear;
mutexGearSize.unlock();
}
mutexGear.unlock();
// END CRITICAL SECTION
_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(getCurrentGearSize());
_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() { void BikeSystem::resetTask() {
auto taskStartTime = _timer.elapsed_time(); auto taskStartTime = _timer.elapsed_time();
@ -229,12 +172,106 @@ void BikeSystem::resetTask() {
_timer, advembsof::TaskLogger::kResetTaskIndex, taskStartTime); _timer, advembsof::TaskLogger::kResetTaskIndex, taskStartTime);
} }
// Speed distance thread functions
void BikeSystem::speedDistanceTask() {
auto taskStartTime = _timer.elapsed_time();
uint32_t* currentStep = _mailPedalDevice.try_get();
if (currentStep != nullptr) {
const auto pedalRotationTime = PedalDevice::getCurrentRotationTime(*currentStep);
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.setCurrentRotationTime(pedalRotationTime);
_mutexSpeedometer.unlock();
// END CRITICAL SECTION
}
// 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
_taskLogger.logPeriodAndExecutionTime(
_timer, advembsof::TaskLogger::kSpeedTaskIndex, taskStartTime);
}
/* Main thread functions */
void BikeSystem::gearUpTask() {
auto taskStartTime = _timer.elapsed_time();
std::chrono::microseconds responseTime = _timer.elapsed_time() - _onGearUpTime;
tr_info("Gear up task: response time is %" PRIu64 " usecs", responseTime.count());
// ENTER CRITICAL SECTION
_mutexGear.lock();
if (_currentGear < bike_computer::kMaxGear) {
_currentGear++;
_mutexGearSize.lock();
_currentGearSize = bike_computer::kMaxGearSize - _currentGear;
_mutexGearSize.unlock();
}
_mutexGear.unlock();
// END CRITICAL SECTION
_taskLogger.logPeriodAndExecutionTime(
_timer, advembsof::TaskLogger::kGearTaskIndex, taskStartTime);
}
void BikeSystem::gearDownTask() {
auto taskStartTime = _timer.elapsed_time();
std::chrono::microseconds responseTime = _timer.elapsed_time() - _onGearDownTime;
tr_info("Gear down task: response time is %" PRIu64 " usecs", responseTime.count());
// ENTER CRITICAL SECTION
_mutexGear.lock();
if (_currentGear > bike_computer::kMinGear) {
_currentGear--;
_mutexGearSize.lock();
_currentGearSize = bike_computer::kMaxGearSize - _currentGear;
_mutexGearSize.unlock();
}
_mutexGear.unlock();
// END CRITICAL SECTION
_taskLogger.logPeriodAndExecutionTime(
_timer, advembsof::TaskLogger::kGearTaskIndex, taskStartTime);
}
void BikeSystem::temperatureTask() {
auto taskStartTime = _timer.elapsed_time();
// no need to protect access to data members (single threaded)
_currentTemperature = _sensorDevice.readTemperature();
ThisThread::sleep_for(std::chrono::duration_cast<std::chrono::milliseconds>(
kTemperatureTaskComputationTime - (_timer.elapsed_time() - taskStartTime)));
_taskLogger.logPeriodAndExecutionTime(
_timer, advembsof::TaskLogger::kTemperatureTaskIndex, taskStartTime);
}
void BikeSystem::displayTask1() { void BikeSystem::displayTask1() {
auto taskStartTime = _timer.elapsed_time(); auto taskStartTime = _timer.elapsed_time();
// ENTER CRITICAL SECTION
_displayDevice.displayGear(getCurrentGear()); _displayDevice.displayGear(getCurrentGear());
_displayDevice.displaySpeed(_currentSpeed); _displayDevice.displaySpeed(getCurrentSpeed());
_displayDevice.displayDistance(_traveledDistance); _displayDevice.displayDistance(getCurrentDistance());
// END CRITICAL SECTION
ThisThread::sleep_for(std::chrono::duration_cast<std::chrono::milliseconds>( ThisThread::sleep_for(std::chrono::duration_cast<std::chrono::milliseconds>(
kDisplayTask1ComputationTime - (_timer.elapsed_time() - taskStartTime))); kDisplayTask1ComputationTime - (_timer.elapsed_time() - taskStartTime)));
@ -269,13 +306,20 @@ void BikeSystem::dispatch_events() {
tr_info("Stop dispatching main events"); tr_info("Stop dispatching main events");
} }
void BikeSystem::loop_speed_distance_task() {
tr_info("Start loop speed-distance calculation");
while (true) {
speedDistanceTask();
}
}
uint8_t BikeSystem::getCurrentGear() { uint8_t BikeSystem::getCurrentGear() {
uint8_t currentGear; uint8_t currentGear;
// CRITICAL SECTION // ENTER CRITICAL SECTION
mutexGear.lock(); _mutexGear.lock();
currentGear = _currentGear; currentGear = _currentGear;
mutexGear.unlock(); _mutexGear.unlock();
// END CRITICAL SECTION // END CRITICAL SECTION
return currentGear; return currentGear;
@ -284,13 +328,37 @@ uint8_t BikeSystem::getCurrentGear() {
uint8_t BikeSystem::getCurrentGearSize() { uint8_t BikeSystem::getCurrentGearSize() {
uint8_t currentGearSize; uint8_t currentGearSize;
// CRITICAL SECTION // ENTER CRITICAL SECTION
mutexGearSize.lock(); _mutexGearSize.lock();
currentGearSize = _currentGearSize; currentGearSize = _currentGearSize;
mutexGearSize.unlock(); _mutexGearSize.unlock();
// END CRITICAL SECTION // END CRITICAL SECTION
return currentGearSize; return currentGearSize;
} }
uint32_t BikeSystem::getCurrentSpeed() {
uint32_t currentSpeed;
// ENTER CRITICAL SECTION
_mutexSpeed.lock();
currentSpeed = _currentSpeed;
_mutexSpeed.unlock();
// END CRITICAL SECTION
return currentSpeed;
}
uint32_t BikeSystem::getCurrentDistance() {
uint32_t currentDistance;
// ENTER CRITICAL SECTION
_mutexDistance.lock();
currentDistance = _traveledDistance;
_mutexDistance.unlock();
// END CRITICAL SECTION
return currentDistance;
}
} // namespace multi_tasking } // namespace multi_tasking

View File

@ -53,9 +53,6 @@ class BikeSystem {
// method called in main() for starting the system // method called in main() for starting the system
void start(); void start();
// method called in main() for starting the sysytem with the event queue
void startWithEventQueue();
// method called for stopping the system // method called for stopping the system
void stop(); void stop();
@ -66,24 +63,32 @@ class BikeSystem {
private: private:
// private methods // private methods
void init(); void init();
// Main Thread
void temperatureTask();
void displayTask1();
void displayTask2();
void cpuTask();
// ISR Thread
void onReset(); void onReset();
void onGearUp(); void onGearUp();
void onGearDown(); void onGearDown();
void gearUpTask(); void gearUpTask();
void gearDownTask(); void gearDownTask();
void speedDistanceTask(); void speedDistanceTask();
void temperatureTask();
void resetTask(); void resetTask();
void displayTask1(); //
void displayTask2();
void cpuTask();
uint8_t getCurrentGear(); uint8_t getCurrentGear();
uint8_t getCurrentGearSize(); uint8_t getCurrentGearSize();
uint32_t getCurrentSpeed();
uint32_t getCurrentDistance();
void setCurrentGear(uint8_t gear); void setCurrentGear(uint8_t gear);
void dispatch_isr_events(); void dispatch_isr_events();
void dispatch_events(); void dispatch_events();
void loop_speed_distance_task();
// timer instance used for loggint task time and used by ResetDevice // timer instance used for loggint task time and used by ResetDevice
std::chrono::microseconds _resetTime = std::chrono::microseconds::zero(); std::chrono::microseconds _resetTime = std::chrono::microseconds::zero();
@ -130,12 +135,19 @@ class BikeSystem {
EventQueue _isrEventQueue; EventQueue _isrEventQueue;
EventQueue _eventQueue; EventQueue _eventQueue;
// Mail
Mail<uint32_t, 16> _mailPedalDevice;
// mutex for shared resource // mutex for shared resource
Mutex mutexGearSize; Mutex _mutexGearSize;
Mutex mutexGear; Mutex _mutexGear;
Mutex _mutexSpeed;
Mutex _mutexDistance;
Mutex _mutexSpeedometer;
// Tread for isr events // Tread for isr events
Thread _isrEventThread; Thread _isrEventThread;
Thread _speedDistanceThread;
}; };
} // namespace multi_tasking } // namespace multi_tasking

View File

@ -36,21 +36,19 @@
namespace multi_tasking { namespace multi_tasking {
PedalDevice::PedalDevice(Callback<void()> cbOnLeft, Callback<void()> cbOnRight) { PedalDevice::PedalDevice(Mail<uint32_t, 16>* mailBox) {
disco::Joystick::getInstance().setLeftCallback(callback(cbOnLeft)); disco::Joystick::getInstance().setLeftCallback(callback(this, &PedalDevice::onLeft));
disco::Joystick::getInstance().setRightCallback(callback(cbOnRight)); disco::Joystick::getInstance().setRightCallback(
} callback(this, &PedalDevice::onRight));
std::chrono::milliseconds PedalDevice::getCurrentRotationTime() { _mailBox = mailBox;
uint32_t currentStep = core_util_atomic_load_u32(&_currentStep);
return bike_computer::kMinPedalRotationTime +
currentStep * bike_computer::kDeltaPedalRotationTime;
} }
void PedalDevice::increaseRotationSpeed() { void PedalDevice::increaseRotationSpeed() {
uint32_t currentStep = core_util_atomic_load_u32(&_currentStep); uint32_t currentStep = core_util_atomic_load_u32(&_currentStep);
if (currentStep > 0) { if (currentStep > 0) {
core_util_atomic_decr_u32(&_currentStep, 1); core_util_atomic_decr_u32(&_currentStep, 1);
sendMail(--currentStep);
} }
} }
@ -58,6 +56,7 @@ void PedalDevice::decreaseRotationSpeed() {
uint32_t currentStep = core_util_atomic_load_u32(&_currentStep); uint32_t currentStep = core_util_atomic_load_u32(&_currentStep);
if (currentStep < bike_computer::kNbrOfSteps) { if (currentStep < bike_computer::kNbrOfSteps) {
core_util_atomic_incr_u32(&_currentStep, 1); core_util_atomic_incr_u32(&_currentStep, 1);
sendMail(++currentStep);
} }
} }
@ -65,4 +64,19 @@ void PedalDevice::onLeft() { decreaseRotationSpeed(); }
void PedalDevice::onRight() { increaseRotationSpeed(); } void PedalDevice::onRight() { increaseRotationSpeed(); }
void PedalDevice::sendMail(uint32_t data) {
uint32_t* currentStep = _mailBox->try_alloc();
if (currentStep != nullptr) {
*currentStep = data;
(*_mailBox).put(currentStep);
}
}
// mbed_build_and_runstatic methods
std::chrono::milliseconds PedalDevice::getCurrentRotationTime(uint32_t step) {
return bike_computer::kMinPedalRotationTime +
step * bike_computer::kDeltaPedalRotationTime;
}
} // namespace multi_tasking } // namespace multi_tasking

View File

@ -33,22 +33,30 @@ namespace multi_tasking {
class PedalDevice { class PedalDevice {
public: public:
PedalDevice(Callback<void()> cbOnLeft, explicit PedalDevice(Mail<uint32_t, 16>* mailBox); // NOLINT(runtime/references)
Callback<void()> cbOnRight); // NOLINT(runtime/references)
// make the class non copyable // make the class non copyable
PedalDevice(PedalDevice&) = delete; PedalDevice(PedalDevice&) = delete;
PedalDevice& operator=(PedalDevice&) = delete; PedalDevice& operator=(PedalDevice&) = delete;
// method called for updating the bike system // method called for updating the bike system
std::chrono::milliseconds getCurrentRotationTime(); static std::chrono::milliseconds getCurrentRotationTime(uint32_t step);
private: private:
// private methods
void onLeft();
void onRight();
void increaseRotationSpeed();
void decreaseRotationSpeed();
void sendMail(uint32_t data);
// data members // data members
volatile uint32_t _currentStep = static_cast<uint32_t>( volatile uint32_t _currentStep = static_cast<uint32_t>(
(bike_computer::kInitialPedalRotationTime - bike_computer::kMinPedalRotationTime) (bike_computer::kInitialPedalRotationTime - bike_computer::kMinPedalRotationTime)
.count() / .count() /
bike_computer::kDeltaPedalRotationTime.count()); bike_computer::kDeltaPedalRotationTime.count());
Mail<uint32_t, 16>* _mailBox;
}; };
} // namespace multi_tasking } // namespace multi_tasking