From b1961e8a2944b4b3a917970ea410beb20d8366df Mon Sep 17 00:00:00 2001 From: Unknown Date: Mon, 24 Aug 2020 00:50:23 -0400 Subject: [PATCH 01/41] Add timers for sections --- Firmware/MotorControl/axis.cpp | 14 ++++++++++ Firmware/MotorControl/axis.hpp | 42 +++++++++++++++++++++++++++-- Firmware/MotorControl/low_level.cpp | 8 ++++++ Firmware/MotorControl/utils.cpp | 7 +++++ Firmware/MotorControl/utils.hpp | 1 + Firmware/odrive-interface.yaml | 19 +++++++++++++ 6 files changed, 89 insertions(+), 2 deletions(-) diff --git a/Firmware/MotorControl/axis.cpp b/Firmware/MotorControl/axis.cpp index 04a802c6..2f211a03 100644 --- a/Firmware/MotorControl/axis.cpp +++ b/Firmware/MotorControl/axis.cpp @@ -201,11 +201,23 @@ bool Axis::do_updates() { for (ThermistorCurrentLimiter* thermistor : thermistors_) { thermistor->update(); } + task_times_.thermistor_update = sample_TIM13(); + encoder_.update(); + task_times_.encoder_update = sample_TIM13(); + sensorless_estimator_.update(); + task_times_.sensorless_update = sample_TIM13(); + min_endstop_.update(); + task_times_.min_endstop_update = sample_TIM13(); + max_endstop_.update(); + task_times_.max_endstop_update = sample_TIM13(); + bool ret = check_for_errors(); + task_times_.axis_error_check = sample_TIM13(); + odCAN->send_heartbeat(this); return ret; } @@ -347,10 +359,12 @@ bool Axis::run_closed_loop_control_loop() { float torque_setpoint; if (!controller_.update(&torque_setpoint)) return error_ |= ERROR_CONTROLLER_FAILED, false; + task_times_.controller_update = sample_TIM13(); float phase_vel = (2*M_PI) * encoder_.vel_estimate_ * motor_.config_.pole_pairs; if (!motor_.update(torque_setpoint, encoder_.phase_, phase_vel)) return false; // set_error should update axis.error_ + task_times_.motor_update = sample_TIM13(); return true; }); diff --git a/Firmware/MotorControl/axis.hpp b/Firmware/MotorControl/axis.hpp index 446958d6..71610259 100644 --- a/Firmware/MotorControl/axis.hpp +++ b/Firmware/MotorControl/axis.hpp @@ -21,6 +21,25 @@ public: bool finish_on_enc_idx = false; }; + struct TaskTimes_t { + uint16_t thermistor_update = 0; + uint16_t encoder_update = 0; + uint16_t sensorless_update = 0; + uint16_t min_endstop_update = 0; + uint16_t max_endstop_update = 0; + uint16_t axis_update = 0; + uint16_t axis_error_check = 0; + + uint16_t controller_update = 0; + uint16_t motor_update = 0; + uint16_t update_handler = 0; + + uint16_t brake_update = 0; + uint16_t adc_cb = 0; + uint16_t control_loop = 0; + uint32_t total = 0; + }; + static LockinConfig_t default_calibration(); static LockinConfig_t default_sensorless(); static LockinConfig_t default_lockin(); @@ -140,14 +159,18 @@ public: // go to zero. // // @tparam T Must be a callable type that takes no arguments and returns a bool + uint16_t start = 0; template void run_control_loop(const T& update_handler) { while (requested_state_ == AXIS_STATE_UNDEFINED) { + start = sample_TIM13(); // look for errors at axis level and also all subcomponents bool checks_ok = do_checks(); + // Update all estimators // Note: updates run even if checks fail - bool updates_ok = do_updates(); + bool updates_ok = do_updates(); + task_times_.axis_update = sample_TIM13(); // make sure the watchdog is being fed. bool watchdog_ok = watchdog_check(); @@ -162,10 +185,24 @@ public: // Run main loop function, defer quitting for after wait // TODO: change arming logic to arm after waiting bool main_continue = update_handler(); - + task_times_.update_handler = sample_TIM13(); // Check we meet deadlines after queueing ++loop_counter_; + task_times_.control_loop = sample_TIM13() - task_times_.update_handler; + task_times_.update_handler -= task_times_.axis_update; + task_times_.axis_update -= start; + task_times_.motor_update -= task_times_.controller_update; + task_times_.controller_update -= task_times_.axis_error_check; + task_times_.axis_error_check -= task_times_.max_endstop_update; + task_times_.max_endstop_update -= task_times_.min_endstop_update; + task_times_.min_endstop_update -= task_times_.sensorless_update; + task_times_.sensorless_update -= task_times_.encoder_update; + task_times_.encoder_update -= task_times_.thermistor_update; + task_times_.thermistor_update -= start; + task_times_.total = sample_TIM13() - start; + + // Wait until the current measurement interrupt fires if (!wait_for_current_meas()) { // maybe the interrupt handler is dead, let's be @@ -206,6 +243,7 @@ public: TrapezoidalTrajectory& trap_traj_; Endstop& min_endstop_; Endstop& max_endstop_; + TaskTimes_t task_times_; // List of current_limiters and thermistors to // provide easy iteration. diff --git a/Firmware/MotorControl/low_level.cpp b/Firmware/MotorControl/low_level.cpp index d447539d..1402fbc7 100644 --- a/Firmware/MotorControl/low_level.cpp +++ b/Firmware/MotorControl/low_level.cpp @@ -492,6 +492,7 @@ static void decode_hall_samples(Encoder& enc, uint16_t GPIO_samples[num_GPIO]) { // This is the callback from the ADC that we expect after the PWM has triggered an ADC conversion. // TODO: Document how the phasing is done, link to timing diagram void pwm_trig_adc_cb(ADC_HandleTypeDef* hadc, bool injected) { + auto start = sample_TIM13(); #define calib_tau 0.2f //@TOTO make more easily configurable constexpr float calib_filter_k = CURRENT_MEAS_PERIOD / calib_tau; @@ -587,6 +588,9 @@ void pwm_trig_adc_cb(ADC_HandleTypeDef* hadc, bool injected) { axis.motor_.DC_calib_.phC += (current - axis.motor_.DC_calib_.phC) * calib_filter_k; } } + auto end = (sample_TIM13() - start); + axes[0]->task_times_.adc_cb = end; + axes[1]->task_times_.adc_cb = end; } void tim_update_cb(TIM_HandleTypeDef* htim) { @@ -620,6 +624,7 @@ void tim_update_cb(TIM_HandleTypeDef* htim) { // @brief Sums up the Ibus contribution of each motor and updates the // brake resistor PWM accordingly. void update_brake_current() { + auto start = sample_TIM13(); float Ibus_sum = 0.0f; for (size_t i = 0; i < AXIS_COUNT; ++i) { if (axes[i]->motor_.armed_state_ == Motor::ARMED_STATE_ARMED) { @@ -666,6 +671,9 @@ void update_brake_current() { int low_off = high_on - TIM_APB1_DEADTIME_CLOCKS; if (low_off < 0) low_off = 0; safety_critical_apply_brake_resistor_timings(low_off, high_on); + + auto end = sample_TIM13() - start; + axes[0]->task_times_.brake_update = end; } diff --git a/Firmware/MotorControl/utils.cpp b/Firmware/MotorControl/utils.cpp index 579a47a7..f089ba4e 100644 --- a/Firmware/MotorControl/utils.cpp +++ b/Firmware/MotorControl/utils.cpp @@ -5,6 +5,8 @@ #include #include +#include + int SVM(float alpha, float beta, float* tA, float* tB, float* tC) { int Sextant; @@ -203,3 +205,8 @@ void delay_us(uint32_t us) __ASM("nop"); } } + +uint16_t sample_TIM13(){ + constexpr uint16_t clocks_per_cnt = (uint16_t)((float)TIM_1_8_CLOCK_HZ / (float)TIM_APB1_CLOCK_HZ); + return clocks_per_cnt * htim13.Instance->CNT; // TODO: Use a hw_config +} \ No newline at end of file diff --git a/Firmware/MotorControl/utils.hpp b/Firmware/MotorControl/utils.hpp index 49f9434d..8dcf09aa 100644 --- a/Firmware/MotorControl/utils.hpp +++ b/Firmware/MotorControl/utils.hpp @@ -121,6 +121,7 @@ int is_in_the_future(uint32_t time_ms); uint32_t micros(void); void delay_us(uint32_t us); +uint16_t sample_TIM13(); float our_arm_sin_f32(float x); float our_arm_cos_f32(float x); diff --git a/Firmware/odrive-interface.yaml b/Firmware/odrive-interface.yaml index 2c9060eb..df4365d6 100644 --- a/Firmware/odrive-interface.yaml +++ b/Firmware/odrive-interface.yaml @@ -364,12 +364,31 @@ interfaces: trap_traj: TrapezoidalTrajectory min_endstop: Endstop max_endstop: Endstop + task_times: TaskTime functions: watchdog_feed: doc: Feed the watchdog to prevent watchdog timeouts. clear_errors: doc: Check the watchdog timer for expiration. Also sets the watchdog error bit if expired. + ODrive.Axis.TaskTime: + c_is_class: False + attributes: + thermistor_update: uint16 + encoder_update: uint16 + sensorless_update: uint16 + min_endstop_update: uint16 + max_endstop_update: uint16 + axis_update: uint16 + axis_error_check: uint16 + controller_update: uint16 + motor_update: uint16 + control_loop: uint16 + update_handler: uint16 + brake_update: uint16 + adc_cb: uint16 + total: uint32 + ODrive.Axis.LockinConfig: c_is_class: False attributes: From 05bf4da3f5549df814ebd9b44e0de8195559a435 Mon Sep 17 00:00:00 2001 From: Samuel Sadok Date: Mon, 24 Aug 2020 18:07:03 +0200 Subject: [PATCH 02/41] Revert "remove test artifact" This reverts commit dc47edf450e5f3ac39e0e2bf63a49bbd2ae345be. --- tools/odrive/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/odrive/utils.py b/tools/odrive/utils.py index 0add96dc..e1ba95c2 100755 --- a/tools/odrive/utils.py +++ b/tools/odrive/utils.py @@ -77,7 +77,7 @@ def dump_errors(odrv, clear=False): module_decode_map = [ (name, odrv, {k: v for k, v in odrive.enums.__dict__ .items() if k.startswith("AXIS_ERROR_")}), ('motor', axis, {k: v for k, v in odrive.enums.__dict__ .items() if k.startswith("MOTOR_ERROR_")}), - ('fet_thermistor', axis, {k: v for k, v in odrive.enums.__dict__ .items() if k.startswith("THERMISTOR_CURRENT_LIMITER_ERROR")}), + ('fet_thermistorr', axis, {k: v for k, v in odrive.enums.__dict__ .items() if k.startswith("THERMISTOR_CURRENT_LIMITER_ERROR")}), ('motor_thermistor', axis, {k: v for k, v in odrive.enums.__dict__ .items() if k.startswith("THERMISTOR_CURRENT_LIMITER_ERROR")}), ('encoder', axis, {k: v for k, v in odrive.enums.__dict__ .items() if k.startswith("ENCODER_ERROR_")}), ('controller', axis, {k: v for k, v in odrive.enums.__dict__ .items() if k.startswith("CONTROLLER_ERROR_")}), From 41597141525d1109647134abd206d59ceffe1b43 Mon Sep 17 00:00:00 2001 From: Samuel Sadok Date: Mon, 24 Aug 2020 13:58:22 +0200 Subject: [PATCH 03/41] Revert "improve compatibility of dump_errors()" This reverts commit 21357115126258b0afa7b3a5a77ecabb919c7da8. --- tools/odrive/utils.py | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/tools/odrive/utils.py b/tools/odrive/utils.py index e1ba95c2..04fa2d15 100755 --- a/tools/odrive/utils.py +++ b/tools/odrive/utils.py @@ -75,20 +75,18 @@ def dump_errors(odrv, clear=False): # Flatten axis and submodules # (name, remote_obj, errorcode) module_decode_map = [ - (name, odrv, {k: v for k, v in odrive.enums.__dict__ .items() if k.startswith("AXIS_ERROR_")}), - ('motor', axis, {k: v for k, v in odrive.enums.__dict__ .items() if k.startswith("MOTOR_ERROR_")}), - ('fet_thermistorr', axis, {k: v for k, v in odrive.enums.__dict__ .items() if k.startswith("THERMISTOR_CURRENT_LIMITER_ERROR")}), - ('motor_thermistor', axis, {k: v for k, v in odrive.enums.__dict__ .items() if k.startswith("THERMISTOR_CURRENT_LIMITER_ERROR")}), - ('encoder', axis, {k: v for k, v in odrive.enums.__dict__ .items() if k.startswith("ENCODER_ERROR_")}), - ('controller', axis, {k: v for k, v in odrive.enums.__dict__ .items() if k.startswith("CONTROLLER_ERROR_")}), + ('axis', axis, {k: v for k, v in odrive.enums.__dict__ .items() if k.startswith("AXIS_ERROR_")}), + ('motor', axis.motor, {k: v for k, v in odrive.enums.__dict__ .items() if k.startswith("MOTOR_ERROR_")}), + ('fet_thermistor', axis.fet_thermistor, {k: v for k, v in odrive.enums.__dict__ .items() if k.startswith("THERMISTOR_CURRENT_LIMITER_ERROR")}), + ('motor_thermistor', axis.motor_thermistor, {k: v for k, v in odrive.enums.__dict__ .items() if k.startswith("THERMISTOR_CURRENT_LIMITER_ERROR")}), + ('encoder', axis.encoder, {k: v for k, v in odrive.enums.__dict__ .items() if k.startswith("ENCODER_ERROR_")}), + ('controller', axis.controller, {k: v for k, v in odrive.enums.__dict__ .items() if k.startswith("CONTROLLER_ERROR_")}), ] # Module error decode for name, remote_obj, errorcodes in module_decode_map: - prefix = ' '*2 + name.strip('0123456789') + ": " - if not hasattr(remote_obj, name): - print(prefix + _VT100Colors['yellow'] + "not found" + _VT100Colors['default']) - elif getattr(remote_obj, name).error != 0: + prefix = ' '*2 + name + ": " + if (remote_obj.error != 0): foundError = False print(prefix + _VT100Colors['red'] + "Error(s):" + _VT100Colors['default']) errorcodes_dict = {val: name for name, val in errorcodes.items() if 'ERROR_' in name} From 2bb990937a533b2749edcdfdc019804e3d61981b Mon Sep 17 00:00:00 2001 From: Unknown Date: Tue, 25 Aug 2020 21:40:24 -0400 Subject: [PATCH 04/41] Add TaskTimer class --- Firmware/MotorControl/axis.cpp | 23 +++++++---- Firmware/MotorControl/axis.hpp | 62 ++++++++++++++-------------- Firmware/MotorControl/controller.cpp | 2 - Firmware/MotorControl/low_level.cpp | 16 +++---- Firmware/MotorControl/odrive_main.h | 3 +- Firmware/MotorControl/taskTimer.hpp | 27 ++++++++++++ Firmware/MotorControl/utils.cpp | 4 -- Firmware/MotorControl/utils.hpp | 1 - Firmware/odrive-interface.yaml | 40 +++++++++++------- 9 files changed, 106 insertions(+), 72 deletions(-) create mode 100644 Firmware/MotorControl/taskTimer.hpp diff --git a/Firmware/MotorControl/axis.cpp b/Firmware/MotorControl/axis.cpp index a69fc140..b44f0b8c 100644 --- a/Firmware/MotorControl/axis.cpp +++ b/Firmware/MotorControl/axis.cpp @@ -198,25 +198,29 @@ bool Axis::do_checks() { // @brief Update all esitmators bool Axis::do_updates() { // Sub-components should use set_error which will propegate to this error_ + task_times_.thermistor_update.beginTimer(); for (ThermistorCurrentLimiter* thermistor : thermistors_) { thermistor->update(); } - task_times_.thermistor_update = sample_TIM13(); + task_times_.thermistor_update.stopTimer(); + task_times_.encoder_update.beginTimer(); encoder_.update(); - task_times_.encoder_update = sample_TIM13(); + task_times_.encoder_update.stopTimer(); + task_times_.sensorless_update.beginTimer(); sensorless_estimator_.update(); - task_times_.sensorless_update = sample_TIM13(); + task_times_.sensorless_update.stopTimer(); + task_times_.min_endstop_update.beginTimer(); min_endstop_.update(); - task_times_.min_endstop_update = sample_TIM13(); + task_times_.min_endstop_update.stopTimer(); + task_times_.max_endstop_update.beginTimer(); max_endstop_.update(); - task_times_.max_endstop_update = sample_TIM13(); + task_times_.max_endstop_update.stopTimer(); bool ret = check_for_errors(); - task_times_.axis_error_check = sample_TIM13(); odCAN->send_heartbeat(this); return ret; @@ -356,15 +360,18 @@ bool Axis::run_closed_loop_control_loop() { set_step_dir_active(config_.enable_step_dir); run_control_loop([this](){ // Note that all estimators are updated in the loop prefix in run_control_loop + + task_times_.controller_update.beginTimer(); float torque_setpoint; if (!controller_.update(&torque_setpoint)) return error_ |= ERROR_CONTROLLER_FAILED, false; - task_times_.controller_update = sample_TIM13(); + task_times_.controller_update.stopTimer(); + task_times_.motor_update.beginTimer(); float phase_vel = (2*M_PI) * encoder_.vel_estimate_ * motor_.config_.pole_pairs; if (!motor_.update(torque_setpoint, encoder_.phase_, phase_vel)) return false; // set_error should update axis.error_ - task_times_.motor_update = sample_TIM13(); + task_times_.motor_update.stopTimer(); return true; }); diff --git a/Firmware/MotorControl/axis.hpp b/Firmware/MotorControl/axis.hpp index 3cf5dd91..13c631d8 100644 --- a/Firmware/MotorControl/axis.hpp +++ b/Firmware/MotorControl/axis.hpp @@ -11,6 +11,7 @@ class Axis; #include "low_level.h" #include "utils.hpp" #include "communication/interface_uart.h" // TODO: remove once uart_poll() is gone +#include "taskTimer.hpp" #include @@ -29,22 +30,24 @@ public: }; struct TaskTimes_t { - uint16_t thermistor_update = 0; - uint16_t encoder_update = 0; - uint16_t sensorless_update = 0; - uint16_t min_endstop_update = 0; - uint16_t max_endstop_update = 0; - uint16_t axis_update = 0; - uint16_t axis_error_check = 0; + TaskTimer thermistor_update; + TaskTimer encoder_update; + TaskTimer sensorless_update; + TaskTimer min_endstop_update; + TaskTimer max_endstop_update; + TaskTimer axis_update; + TaskTimer axis_error_check; - uint16_t controller_update = 0; - uint16_t motor_update = 0; - uint16_t update_handler = 0; + TaskTimer controller_update; + TaskTimer motor_update; + TaskTimer update_handler; - uint16_t brake_update = 0; - uint16_t adc_cb = 0; - uint16_t control_loop = 0; - uint32_t total = 0; + TaskTimer brake_update; + TaskTimer adc_cb; + TaskTimer control_loop; + TaskTimer total; + + TaskTimer uart_poll; }; static LockinConfig_t default_calibration(); @@ -166,18 +169,21 @@ public: // go to zero. // // @tparam T Must be a callable type that takes no arguments and returns a bool - uint16_t start = 0; template void run_control_loop(const T& update_handler) { while (requested_state_ == AXIS_STATE_UNDEFINED) { - start = sample_TIM13(); + task_times_.control_loop.beginTimer(); + // look for errors at axis level and also all subcomponents + task_times_.axis_error_check.beginTimer(); bool checks_ok = do_checks(); + task_times_.axis_error_check.stopTimer(); // Update all estimators // Note: updates run even if checks fail + task_times_.axis_update.beginTimer(); bool updates_ok = do_updates(); - task_times_.axis_update = sample_TIM13(); + task_times_.axis_update.stopTimer(); // make sure the watchdog is being fed. bool watchdog_ok = watchdog_check(); @@ -191,29 +197,21 @@ public: // Run main loop function, defer quitting for after wait // TODO: change arming logic to arm after waiting + task_times_.update_handler.beginTimer(); bool main_continue = update_handler(); - task_times_.update_handler = sample_TIM13(); + task_times_.update_handler.stopTimer(); if (axis_num_ == 0) { + task_times_.uart_poll.beginTimer(); uart_poll(); // TODO: move to board-level control loop once it exists + task_times_.uart_poll.stopTimer(); } // Check we meet deadlines after queueing ++loop_counter_; - task_times_.control_loop = sample_TIM13() - task_times_.update_handler; - task_times_.update_handler -= task_times_.axis_update; - task_times_.axis_update -= start; - task_times_.motor_update -= task_times_.controller_update; - task_times_.controller_update -= task_times_.axis_error_check; - task_times_.axis_error_check -= task_times_.max_endstop_update; - task_times_.max_endstop_update -= task_times_.min_endstop_update; - task_times_.min_endstop_update -= task_times_.sensorless_update; - task_times_.sensorless_update -= task_times_.encoder_update; - task_times_.encoder_update -= task_times_.thermistor_update; - task_times_.thermistor_update -= start; - task_times_.total = sample_TIM13() - start; - + task_times_.control_loop.stopTimer(); + task_times_.total.stopTimer(); // Wait until the current measurement interrupt fires if (!wait_for_current_meas()) { @@ -225,6 +223,8 @@ public: break; } + task_times_.total.beginTimer(); + if (!main_continue) break; } diff --git a/Firmware/MotorControl/controller.cpp b/Firmware/MotorControl/controller.cpp index 1524dce6..73e5fc00 100644 --- a/Firmware/MotorControl/controller.cpp +++ b/Firmware/MotorControl/controller.cpp @@ -2,8 +2,6 @@ #include "odrive_main.h" #include -#include - bool Controller::apply_config() { config_.parent = this; update_filter_gains(); diff --git a/Firmware/MotorControl/low_level.cpp b/Firmware/MotorControl/low_level.cpp index 0f9da174..c4495e5e 100644 --- a/Firmware/MotorControl/low_level.cpp +++ b/Firmware/MotorControl/low_level.cpp @@ -382,7 +382,8 @@ void vbus_sense_adc_cb(ADC_HandleTypeDef* hadc, bool injected) { // This is the callback from the ADC that we expect after the PWM has triggered an ADC conversion. // TODO: Document how the phasing is done, link to timing diagram void pwm_trig_adc_cb(ADC_HandleTypeDef* hadc, bool injected) { - auto start = sample_TIM13(); + axes[0].task_times_.adc_cb.beginTimer(); + axes[1].task_times_.adc_cb.beginTimer(); #define calib_tau 0.2f //@TOTO make more easily configurable constexpr float calib_filter_k = CURRENT_MEAS_PERIOD / calib_tau; @@ -478,15 +479,15 @@ void pwm_trig_adc_cb(ADC_HandleTypeDef* hadc, bool injected) { axis.motor_.DC_calib_.phC += (current - axis.motor_.DC_calib_.phC) * calib_filter_k; } } - auto end = (sample_TIM13() - start); - axes[0]->task_times_.adc_cb = end; - axes[1]->task_times_.adc_cb = end; + axes[0].task_times_.adc_cb.stopTimer(); + axes[1].task_times_.adc_cb.stopTimer(); } // @brief Sums up the Ibus contribution of each motor and updates the // brake resistor PWM accordingly. void update_brake_current() { - auto start = sample_TIM13(); + axes[0].task_times_.brake_update.beginTimer(); + axes[1].task_times_.brake_update.beginTimer(); float Ibus_sum = 0.0f; for (size_t i = 0; i < AXIS_COUNT; ++i) { if (axes[i].motor_.armed_state_ == Motor::ARMED_STATE_ARMED) { @@ -533,9 +534,8 @@ void update_brake_current() { int low_off = high_on - TIM_APB1_DEADTIME_CLOCKS; if (low_off < 0) low_off = 0; safety_critical_apply_brake_resistor_timings(low_off, high_on); - - auto end = sample_TIM13() - start; - axes[0]->task_times_.brake_update = end; + axes[0].task_times_.brake_update.stopTimer(); + axes[1].task_times_.brake_update.stopTimer(); } diff --git a/Firmware/MotorControl/odrive_main.h b/Firmware/MotorControl/odrive_main.h index 2a5c9f5c..41fecc58 100644 --- a/Firmware/MotorControl/odrive_main.h +++ b/Firmware/MotorControl/odrive_main.h @@ -128,9 +128,8 @@ inline ENUMTYPE &operator &= (ENUMTYPE &a, ENUMTYPE b) { return reinterpret_cast inline ENUMTYPE &operator ^= (ENUMTYPE &a, ENUMTYPE b) { return reinterpret_cast(reinterpret_cast&>(a) ^= static_cast>(b)); } \ inline ENUMTYPE operator ~ (ENUMTYPE a) { return static_cast(~static_cast>(a)); } - - #include "autogen/interfaces.hpp" +#include // ODrive specific includes #include diff --git a/Firmware/MotorControl/taskTimer.hpp b/Firmware/MotorControl/taskTimer.hpp new file mode 100644 index 00000000..b9363aa8 --- /dev/null +++ b/Firmware/MotorControl/taskTimer.hpp @@ -0,0 +1,27 @@ +#pragma once + +#include +#include +#include + +inline uint16_t sample_TIM13(){ + constexpr uint16_t clocks_per_cnt = (uint16_t)((float)TIM_1_8_CLOCK_HZ / (float)TIM_APB1_CLOCK_HZ); + return clocks_per_cnt * htim13.Instance->CNT; // TODO: Use a hw_config +} + +struct TaskTimer { + uint32_t startTime = 0; + uint32_t endTime = 0; + uint32_t length = 0; + uint32_t maxLength = 0; + + void beginTimer(){ + startTime = sample_TIM13(); + } + + void stopTimer(){ + endTime = sample_TIM13(); + length = endTime - startTime; + maxLength = std::max(maxLength, length); + } +}; \ No newline at end of file diff --git a/Firmware/MotorControl/utils.cpp b/Firmware/MotorControl/utils.cpp index 3dada0c8..a267aeea 100644 --- a/Firmware/MotorControl/utils.cpp +++ b/Firmware/MotorControl/utils.cpp @@ -206,7 +206,3 @@ void delay_us(uint32_t us) } } -uint16_t sample_TIM13(){ - constexpr uint16_t clocks_per_cnt = (uint16_t)((float)TIM_1_8_CLOCK_HZ / (float)TIM_APB1_CLOCK_HZ); - return clocks_per_cnt * htim13.Instance->CNT; // TODO: Use a hw_config -} \ No newline at end of file diff --git a/Firmware/MotorControl/utils.hpp b/Firmware/MotorControl/utils.hpp index 8dcf09aa..49f9434d 100644 --- a/Firmware/MotorControl/utils.hpp +++ b/Firmware/MotorControl/utils.hpp @@ -121,7 +121,6 @@ int is_in_the_future(uint32_t time_ms); uint32_t micros(void); void delay_us(uint32_t us); -uint16_t sample_TIM13(); float our_arm_sin_f32(float x); float our_arm_cos_f32(float x); diff --git a/Firmware/odrive-interface.yaml b/Firmware/odrive-interface.yaml index 3f991961..c1ff609b 100644 --- a/Firmware/odrive-interface.yaml +++ b/Firmware/odrive-interface.yaml @@ -454,30 +454,38 @@ interfaces: trap_traj: TrapezoidalTrajectory min_endstop: Endstop max_endstop: Endstop - task_times: TaskTime + task_times: TaskTimes functions: watchdog_feed: doc: Feed the watchdog to prevent watchdog timeouts. clear_errors: doc: Check the watchdog timer for expiration. Also sets the watchdog error bit if expired. - ODrive.Axis.TaskTime: + ODrive.Axis.TaskTimes: c_is_class: False attributes: - thermistor_update: uint16 - encoder_update: uint16 - sensorless_update: uint16 - min_endstop_update: uint16 - max_endstop_update: uint16 - axis_update: uint16 - axis_error_check: uint16 - controller_update: uint16 - motor_update: uint16 - control_loop: uint16 - update_handler: uint16 - brake_update: uint16 - adc_cb: uint16 - total: uint32 + thermistor_update: TaskTimer + encoder_update: TaskTimer + sensorless_update: TaskTimer + min_endstop_update: TaskTimer + max_endstop_update: TaskTimer + axis_update: TaskTimer + axis_error_check: TaskTimer + controller_update: TaskTimer + motor_update: TaskTimer + control_loop: TaskTimer + update_handler: TaskTimer + brake_update: TaskTimer + adc_cb: TaskTimer + total: TaskTimer + + ODrive.TaskTimer: + c_is_class: False + attributes: + startTime: readonly uint32 + endTime: readonly uint32 + length: readonly uint32 + maxLength: readonly uint32 ODrive.Axis.LockinConfig: c_is_class: False From 499dd64d87426e15814ba9ec7d837f21d78548b4 Mon Sep 17 00:00:00 2001 From: Unknown Date: Wed, 26 Aug 2020 01:42:03 -0400 Subject: [PATCH 05/41] Ensure sample trigger occurs at the right spot, and only once. --- Firmware/MotorControl/axis.hpp | 3 ++- Firmware/MotorControl/low_level.cpp | 26 ++++++++++++++++++++------ Firmware/MotorControl/low_level.h | 1 + Firmware/MotorControl/odrive_main.h | 1 + Firmware/MotorControl/taskTimer.cpp | 4 ++++ Firmware/MotorControl/taskTimer.hpp | 29 +++++++++++++++++++---------- Firmware/odrive-interface.yaml | 1 + Firmware/sampler.py | 11 ++++++++++- 8 files changed, 58 insertions(+), 18 deletions(-) create mode 100644 Firmware/MotorControl/taskTimer.cpp diff --git a/Firmware/MotorControl/axis.hpp b/Firmware/MotorControl/axis.hpp index 13c631d8..32f64dbd 100644 --- a/Firmware/MotorControl/axis.hpp +++ b/Firmware/MotorControl/axis.hpp @@ -212,6 +212,8 @@ public: task_times_.control_loop.stopTimer(); task_times_.total.stopTimer(); + if(axis_num_ == 1) + TaskTimer::sample_next = false; // Wait until the current measurement interrupt fires if (!wait_for_current_meas()) { @@ -222,7 +224,6 @@ public: error_ |= ERROR_CURRENT_MEASUREMENT_TIMEOUT; break; } - task_times_.total.beginTimer(); if (!main_continue) diff --git a/Firmware/MotorControl/low_level.cpp b/Firmware/MotorControl/low_level.cpp index c4495e5e..e248232d 100644 --- a/Firmware/MotorControl/low_level.cpp +++ b/Firmware/MotorControl/low_level.cpp @@ -31,6 +31,7 @@ constexpr float adc_ref_voltage = 3.3f; // Arbitrary non-zero inital value to avoid division by zero if ADC reading is late float vbus_voltage = 12.0f; float ibus_ = 0.0f; // exposed for monitoring only +bool task_timers_armed = false; bool brake_resistor_armed = false; bool brake_resistor_saturated = false; /* Private constant data -----------------------------------------------------*/ @@ -382,8 +383,8 @@ void vbus_sense_adc_cb(ADC_HandleTypeDef* hadc, bool injected) { // This is the callback from the ADC that we expect after the PWM has triggered an ADC conversion. // TODO: Document how the phasing is done, link to timing diagram void pwm_trig_adc_cb(ADC_HandleTypeDef* hadc, bool injected) { - axes[0].task_times_.adc_cb.beginTimer(); - axes[1].task_times_.adc_cb.beginTimer(); + + adc_timestamp = sample_TIM13(); #define calib_tau 0.2f //@TOTO make more easily configurable constexpr float calib_filter_k = CURRENT_MEAS_PERIOD / calib_tau; @@ -404,10 +405,12 @@ void pwm_trig_adc_cb(ADC_HandleTypeDef* hadc, bool injected) { bool current_meas_not_DC_CAL = !counting_down; // Check the timing of the sequencing - if (current_meas_not_DC_CAL) + if (current_meas_not_DC_CAL) { axis.motor_.log_timing(TIMING_LOG_ADC_CB_I); - else + } + else { axis.motor_.log_timing(TIMING_LOG_ADC_CB_DC); + } bool update_timings = false; if (hadc == &hadc2) { @@ -452,6 +455,19 @@ void pwm_trig_adc_cb(ADC_HandleTypeDef* hadc, bool injected) { } float current = axis.motor_.phase_current_from_adcval(ADCValue); + + if(current_meas_not_DC_CAL && axis_num == 0 && hadc == &hadc2){ + if (task_timers_armed) { + TaskTimer::sample_next = true; + task_timers_armed = false; + axes[0].task_times_.adc_cb.startTime = adc_timestamp; // Start of ADC2 + } + } + + if(current_meas_not_DC_CAL && axis_num == 0 && hadc == &hadc3){ + axes[0].task_times_.adc_cb.stopTimer(); // End of ADC3 + } + if (current_meas_not_DC_CAL) { // ADC2 and ADC3 record the phB and phC currents concurrently, // and their interrupts should arrive on the same clock cycle. @@ -479,8 +495,6 @@ void pwm_trig_adc_cb(ADC_HandleTypeDef* hadc, bool injected) { axis.motor_.DC_calib_.phC += (current - axis.motor_.DC_calib_.phC) * calib_filter_k; } } - axes[0].task_times_.adc_cb.stopTimer(); - axes[1].task_times_.adc_cb.stopTimer(); } // @brief Sums up the Ibus contribution of each motor and updates the diff --git a/Firmware/MotorControl/low_level.h b/Firmware/MotorControl/low_level.h index e02ef5c2..a1e5a470 100644 --- a/Firmware/MotorControl/low_level.h +++ b/Firmware/MotorControl/low_level.h @@ -19,6 +19,7 @@ extern const float adc_ref_voltage; /* Exported variables --------------------------------------------------------*/ extern float vbus_voltage; extern float ibus_; +extern bool task_timers_armed; extern bool brake_resistor_armed; extern bool brake_resistor_saturated; extern uint16_t adc_measurements_[ADC_CHANNEL_COUNT]; diff --git a/Firmware/MotorControl/odrive_main.h b/Firmware/MotorControl/odrive_main.h index 41fecc58..35b10dee 100644 --- a/Firmware/MotorControl/odrive_main.h +++ b/Firmware/MotorControl/odrive_main.h @@ -217,6 +217,7 @@ public: const uint8_t fw_version_revision_ = ::fw_version_revision_; const uint8_t fw_version_unreleased_ = ::fw_version_unreleased_; // 0 for official releases, 1 otherwise + bool& task_timers_armed_ = ::task_timers_armed; bool& brake_resistor_armed_ = ::brake_resistor_armed; // TODO: make this the actual variable bool& brake_resistor_saturated_ = ::brake_resistor_saturated; // TODO: make this the actual variable diff --git a/Firmware/MotorControl/taskTimer.cpp b/Firmware/MotorControl/taskTimer.cpp new file mode 100644 index 00000000..bc55573b --- /dev/null +++ b/Firmware/MotorControl/taskTimer.cpp @@ -0,0 +1,4 @@ +#include "taskTimer.hpp" + +bool TaskTimer::sample_next = false; +volatile uint32_t adc_timestamp = 0; diff --git a/Firmware/MotorControl/taskTimer.hpp b/Firmware/MotorControl/taskTimer.hpp index b9363aa8..8a2e17e4 100644 --- a/Firmware/MotorControl/taskTimer.hpp +++ b/Firmware/MotorControl/taskTimer.hpp @@ -1,12 +1,14 @@ #pragma once -#include #include +#include + #include -inline uint16_t sample_TIM13(){ + +inline uint16_t sample_TIM13() { constexpr uint16_t clocks_per_cnt = (uint16_t)((float)TIM_1_8_CLOCK_HZ / (float)TIM_APB1_CLOCK_HZ); - return clocks_per_cnt * htim13.Instance->CNT; // TODO: Use a hw_config + return clocks_per_cnt * htim13.Instance->CNT; // TODO: Use a hw_config } struct TaskTimer { @@ -15,13 +17,20 @@ struct TaskTimer { uint32_t length = 0; uint32_t maxLength = 0; - void beginTimer(){ - startTime = sample_TIM13(); + static bool sample_next; + + void beginTimer() { + if (sample_next) + startTime = sample_TIM13(); } - void stopTimer(){ - endTime = sample_TIM13(); - length = endTime - startTime; - maxLength = std::max(maxLength, length); + void stopTimer() { + if (sample_next) { + endTime = sample_TIM13(); + length = endTime - startTime; + maxLength = std::max(maxLength, length); + } } -}; \ No newline at end of file +}; + +extern volatile uint32_t adc_timestamp; \ No newline at end of file diff --git a/Firmware/odrive-interface.yaml b/Firmware/odrive-interface.yaml index c1ff609b..276a96ee 100644 --- a/Firmware/odrive-interface.yaml +++ b/Firmware/odrive-interface.yaml @@ -13,6 +13,7 @@ interfaces: The odrv0, odrv1, ... objects that appear in odrivetool implement this toplevel interface. attributes: + task_timers_armed: bool vbus_voltage: type: readonly float32 unit: V diff --git a/Firmware/sampler.py b/Firmware/sampler.py index 70a59115..c3f7c353 100644 --- a/Firmware/sampler.py +++ b/Firmware/sampler.py @@ -88,6 +88,7 @@ if __name__ == '__main__': total = 0 countmap = { } pcmap = { } + funcmap = { } start = time.time() try: @@ -101,6 +102,9 @@ if __name__ == '__main__': func, addr = sampler.func(pc) + if(func == 'ADC_IRQ_Dispatch'): + funcmap[pc] = 1 + if not addr: continue @@ -112,7 +116,12 @@ if __name__ == '__main__': total += 1 cur = time.time() - if cur - start > 1.0: + if cur - start > 5.0: + + # tmp = sorted(funcmap) + # for k in tmp: + # print(hex(k)) + tmp = sorted(countmap.items(), key=operator.itemgetter(1)) #, reverse=True) for k, v in tmp: print('{:05.2f}% {}'.format((v * 100.) / total, k)) From c834533be69dc83ab063b21c05222400b497af17 Mon Sep 17 00:00:00 2001 From: Unknown Date: Wed, 26 Aug 2020 02:23:57 -0400 Subject: [PATCH 06/41] Add missing taskTimer compile command --- Firmware/Tupfile.lua | 1 + 1 file changed, 1 insertion(+) diff --git a/Firmware/Tupfile.lua b/Firmware/Tupfile.lua index 040db512..9fb16b98 100644 --- a/Firmware/Tupfile.lua +++ b/Firmware/Tupfile.lua @@ -194,6 +194,7 @@ sources = { 'MotorControl/trapTraj.cpp', 'MotorControl/pwm_input.cpp', 'MotorControl/main.cpp', + 'MotorControl/taskTimer.cpp', 'Drivers/STM32/stm32_system.cpp', 'Drivers/STM32/stm32_gpio.cpp', 'Drivers/STM32/stm32_nvm.c', From ea03574ce3df68c74ccf617e32fc4dfd63583682 Mon Sep 17 00:00:00 2001 From: Unknown Date: Thu, 27 Aug 2020 18:09:44 -0400 Subject: [PATCH 07/41] Add FOC_Current timer --- Firmware/MotorControl/axis.hpp | 1 + Firmware/MotorControl/motor.cpp | 2 ++ Firmware/odrive-interface.yaml | 1 + 3 files changed, 4 insertions(+) diff --git a/Firmware/MotorControl/axis.hpp b/Firmware/MotorControl/axis.hpp index 32f64dbd..12904f09 100644 --- a/Firmware/MotorControl/axis.hpp +++ b/Firmware/MotorControl/axis.hpp @@ -48,6 +48,7 @@ public: TaskTimer total; TaskTimer uart_poll; + TaskTimer FOC_Current; }; static LockinConfig_t default_calibration(); diff --git a/Firmware/MotorControl/motor.cpp b/Firmware/MotorControl/motor.cpp index 9bdbaa75..5eff545c 100644 --- a/Firmware/MotorControl/motor.cpp +++ b/Firmware/MotorControl/motor.cpp @@ -292,6 +292,7 @@ bool Motor::FOC_voltage(float v_d, float v_q, float pwm_phase) { } bool Motor::FOC_current(float Id_des, float Iq_des, float I_phase, float pwm_phase, float phase_vel) { + axis_->task_times_.FOC_Current.beginTimer(); // Syntactic sugar CurrentControl_t& ictrl = current_control_; @@ -404,6 +405,7 @@ bool Motor::FOC_current(float Id_des, float Iq_des, float I_phase, float pwm_pha } } + axis_->task_times_.FOC_Current.stopTimer(); return true; } diff --git a/Firmware/odrive-interface.yaml b/Firmware/odrive-interface.yaml index 276a96ee..105b0d4c 100644 --- a/Firmware/odrive-interface.yaml +++ b/Firmware/odrive-interface.yaml @@ -479,6 +479,7 @@ interfaces: brake_update: TaskTimer adc_cb: TaskTimer total: TaskTimer + FOC_Current: TaskTimer ODrive.TaskTimer: c_is_class: False From 5c4e4374f02bc858051c57715188bcacf07da52f Mon Sep 17 00:00:00 2001 From: Unknown Date: Wed, 2 Sep 2020 22:22:09 -0400 Subject: [PATCH 08/41] Update to FreeRTOS v10 --- .../Third_Party/FreeRTOS/Source/croutine.c | 94 +- .../FreeRTOS/Source/event_groups.c | 205 +-- .../FreeRTOS/Source/include/FreeRTOS.h | 406 ++++- .../Source/include/FreeRTOSConfig_template.h | 173 -- .../FreeRTOS/Source/include/StackMacros.h | 96 +- .../FreeRTOS/Source/include/atomic.h | 414 +++++ .../FreeRTOS/Source/include/croutine.h | 94 +- .../Source/include/deprecated_definitions.h | 92 +- .../FreeRTOS/Source/include/event_groups.h | 122 +- .../FreeRTOS/Source/include/list.h | 117 +- .../FreeRTOS/Source/include/message_buffer.h | 803 ++++++++++ .../FreeRTOS/Source/include/mpu_prototypes.h | 297 ++-- .../FreeRTOS/Source/include/mpu_wrappers.h | 142 +- .../FreeRTOS/Source/include/portable.h | 150 +- .../FreeRTOS/Source/include/projdefs.h | 101 +- .../FreeRTOS/Source/include/queue.h | 283 +--- .../FreeRTOS/Source/include/semphr.h | 127 +- .../FreeRTOS/Source/include/stack_macros.h | 129 ++ .../FreeRTOS/Source/include/stdint.readme | 27 + .../FreeRTOS/Source/include/stream_buffer.h | 859 ++++++++++ .../FreeRTOS/Source/include/task.h | 610 +++++-- .../FreeRTOS/Source/include/timers.h | 165 +- .../Third_Party/FreeRTOS/Source/list.c | 122 +- .../Source/portable/GCC/ARM_CM4F/port.c | 250 +-- .../Source/portable/GCC/ARM_CM4F/portmacro.h | 105 +- .../Source/portable/MemMang/ReadMe.url | 5 + .../FreeRTOS/Source/portable/MemMang/heap_4.c | 152 +- .../Third_Party/FreeRTOS/Source/queue.c | 913 +++++++---- .../Third_Party/FreeRTOS/Source/readme.txt | 17 + .../FreeRTOS/Source/stream_buffer.c | 1263 +++++++++++++++ .../Third_Party/FreeRTOS/Source/tasks.c | 1411 +++++++++++------ .../Third_Party/FreeRTOS/Source/timers.c | 377 +++-- 32 files changed, 7162 insertions(+), 2959 deletions(-) delete mode 100644 Firmware/Board/v3/Middlewares/Third_Party/FreeRTOS/Source/include/FreeRTOSConfig_template.h create mode 100644 Firmware/Board/v3/Middlewares/Third_Party/FreeRTOS/Source/include/atomic.h create mode 100644 Firmware/Board/v3/Middlewares/Third_Party/FreeRTOS/Source/include/message_buffer.h create mode 100644 Firmware/Board/v3/Middlewares/Third_Party/FreeRTOS/Source/include/stack_macros.h create mode 100644 Firmware/Board/v3/Middlewares/Third_Party/FreeRTOS/Source/include/stdint.readme create mode 100644 Firmware/Board/v3/Middlewares/Third_Party/FreeRTOS/Source/include/stream_buffer.h create mode 100644 Firmware/Board/v3/Middlewares/Third_Party/FreeRTOS/Source/portable/MemMang/ReadMe.url create mode 100644 Firmware/Board/v3/Middlewares/Third_Party/FreeRTOS/Source/readme.txt create mode 100644 Firmware/Board/v3/Middlewares/Third_Party/FreeRTOS/Source/stream_buffer.c diff --git a/Firmware/Board/v3/Middlewares/Third_Party/FreeRTOS/Source/croutine.c b/Firmware/Board/v3/Middlewares/Third_Party/FreeRTOS/Source/croutine.c index 993e09b2..9ce50030 100644 --- a/Firmware/Board/v3/Middlewares/Third_Party/FreeRTOS/Source/croutine.c +++ b/Firmware/Board/v3/Middlewares/Third_Party/FreeRTOS/Source/croutine.c @@ -1,71 +1,29 @@ /* - FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. - All rights reserved - - VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. - - This file is part of the FreeRTOS distribution. - - FreeRTOS is free software; you can redistribute it and/or modify it under - the terms of the GNU General Public License (version 2) as published by the - Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception. - - *************************************************************************** - >>! NOTE: The modification to the GPL is included to allow you to !<< - >>! distribute a combined work that includes FreeRTOS without being !<< - >>! obliged to provide the source code for proprietary components !<< - >>! outside of the FreeRTOS kernel. !<< - *************************************************************************** - - FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - FOR A PARTICULAR PURPOSE. Full license text is available on the following - link: http://www.freertos.org/a00114.html - - *************************************************************************** - * * - * FreeRTOS provides completely free yet professionally developed, * - * robust, strictly quality controlled, supported, and cross * - * platform software that is more than just the market leader, it * - * is the industry's de facto standard. * - * * - * Help yourself get started quickly while simultaneously helping * - * to support the FreeRTOS project by purchasing a FreeRTOS * - * tutorial book, reference manual, or both: * - * http://www.FreeRTOS.org/Documentation * - * * - *************************************************************************** - - http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading - the FAQ page "My application does not run, what could be wrong?". Have you - defined configASSERT()? - - http://www.FreeRTOS.org/support - In return for receiving this top quality - embedded software for free we request you assist our global community by - participating in the support forum. - - http://www.FreeRTOS.org/training - Investing in training allows your team to - be as productive as possible as early as possible. Now you can receive - FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers - Ltd, and the world's leading authority on the world's leading RTOS. - - http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, - including FreeRTOS+Trace - an indispensable productivity tool, a DOS - compatible FAT file system, and our tiny thread aware UDP/IP stack. - - http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. - Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. - - http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High - Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS - licenses offer ticketed support, indemnification and commercial middleware. - - http://www.SafeRTOS.com - High Integrity Systems also provide a safety - engineered and independently SIL3 certified version for use in safety and - mission critical applications that require provable dependability. - - 1 tab == 4 spaces! -*/ + * FreeRTOS Kernel V10.3.1 + * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * http://www.FreeRTOS.org + * http://aws.amazon.com/freertos + * + * 1 tab == 4 spaces! + */ #include "FreeRTOS.h" #include "task.h" @@ -302,7 +260,7 @@ CRCB_t *pxCRCB; ( void ) uxListRemove( &( pxCRCB->xGenericListItem ) ); /* Is the co-routine waiting on an event also? */ - if( pxCRCB->xEventListItem.pvContainer ) + if( pxCRCB->xEventListItem.pxContainer ) { ( void ) uxListRemove( &( pxCRCB->xEventListItem ) ); } diff --git a/Firmware/Board/v3/Middlewares/Third_Party/FreeRTOS/Source/event_groups.c b/Firmware/Board/v3/Middlewares/Third_Party/FreeRTOS/Source/event_groups.c index b23ecb1c..bf4ec246 100644 --- a/Firmware/Board/v3/Middlewares/Third_Party/FreeRTOS/Source/event_groups.c +++ b/Firmware/Board/v3/Middlewares/Third_Party/FreeRTOS/Source/event_groups.c @@ -1,71 +1,29 @@ /* - FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. - All rights reserved - - VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. - - This file is part of the FreeRTOS distribution. - - FreeRTOS is free software; you can redistribute it and/or modify it under - the terms of the GNU General Public License (version 2) as published by the - Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception. - - *************************************************************************** - >>! NOTE: The modification to the GPL is included to allow you to !<< - >>! distribute a combined work that includes FreeRTOS without being !<< - >>! obliged to provide the source code for proprietary components !<< - >>! outside of the FreeRTOS kernel. !<< - *************************************************************************** - - FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - FOR A PARTICULAR PURPOSE. Full license text is available on the following - link: http://www.freertos.org/a00114.html - - *************************************************************************** - * * - * FreeRTOS provides completely free yet professionally developed, * - * robust, strictly quality controlled, supported, and cross * - * platform software that is more than just the market leader, it * - * is the industry's de facto standard. * - * * - * Help yourself get started quickly while simultaneously helping * - * to support the FreeRTOS project by purchasing a FreeRTOS * - * tutorial book, reference manual, or both: * - * http://www.FreeRTOS.org/Documentation * - * * - *************************************************************************** - - http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading - the FAQ page "My application does not run, what could be wrong?". Have you - defined configASSERT()? - - http://www.FreeRTOS.org/support - In return for receiving this top quality - embedded software for free we request you assist our global community by - participating in the support forum. - - http://www.FreeRTOS.org/training - Investing in training allows your team to - be as productive as possible as early as possible. Now you can receive - FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers - Ltd, and the world's leading authority on the world's leading RTOS. - - http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, - including FreeRTOS+Trace - an indispensable productivity tool, a DOS - compatible FAT file system, and our tiny thread aware UDP/IP stack. - - http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. - Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. - - http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High - Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS - licenses offer ticketed support, indemnification and commercial middleware. - - http://www.SafeRTOS.com - High Integrity Systems also provide a safety - engineered and independently SIL3 certified version for use in safety and - mission critical applications that require provable dependability. - - 1 tab == 4 spaces! -*/ + * FreeRTOS Kernel V10.3.1 + * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * http://www.FreeRTOS.org + * http://aws.amazon.com/freertos + * + * 1 tab == 4 spaces! + */ /* Standard includes. */ #include @@ -81,11 +39,11 @@ task.h is included from an application file. */ #include "timers.h" #include "event_groups.h" -/* Lint e961 and e750 are suppressed as a MISRA exception justified because the -MPU ports require MPU_WRAPPERS_INCLUDED_FROM_API_FILE to be defined for the -header files above, but not in this file, in order to generate the correct -privileged Vs unprivileged linkage and placement. */ -#undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE /*lint !e961 !e750. */ +/* Lint e961, e750 and e9021 are suppressed as a MISRA exception justified +because the MPU ports require MPU_WRAPPERS_INCLUDED_FROM_API_FILE to be defined +for the header files above, but not in this file, in order to generate the +correct privileged Vs unprivileged linkage and placement. */ +#undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE /*lint !e961 !e750 !e9021 See comment above. */ /* The following bit fields convey control information in a task's event list item value. It is important they don't clash with the @@ -102,7 +60,7 @@ taskEVENT_LIST_ITEM_VALUE_IN_USE definition. */ #define eventEVENT_BITS_CONTROL_BYTES 0xff000000UL #endif -typedef struct xEventGroupDefinition +typedef struct EventGroupDef_t { EventBits_t uxEventBits; List_t xTasksWaitingForBits; /*< List of tasks waiting for a bit to be set. */ @@ -126,7 +84,7 @@ typedef struct xEventGroupDefinition * wait condition is met if any of the bits set in uxBitsToWait for are also set * in uxCurrentEventBits. */ -PRIVILEGED_FUNCTION static BaseType_t prvTestWaitCondition( const EventBits_t uxCurrentEventBits, const EventBits_t uxBitsToWaitFor, const BaseType_t xWaitForAllBits ); +static BaseType_t prvTestWaitCondition( const EventBits_t uxCurrentEventBits, const EventBits_t uxBitsToWaitFor, const BaseType_t xWaitForAllBits ) PRIVILEGED_FUNCTION; /*-----------------------------------------------------------*/ @@ -139,8 +97,18 @@ PRIVILEGED_FUNCTION static BaseType_t prvTestWaitCondition( const EventBits_t ux /* A StaticEventGroup_t object must be provided. */ configASSERT( pxEventGroupBuffer ); + #if( configASSERT_DEFINED == 1 ) + { + /* Sanity check that the size of the structure used to declare a + variable of type StaticEventGroup_t equals the size of the real + event group structure. */ + volatile size_t xSize = sizeof( StaticEventGroup_t ); + configASSERT( xSize == sizeof( EventGroup_t ) ); + } /*lint !e529 xSize is referenced if configASSERT() is defined. */ + #endif /* configASSERT_DEFINED */ + /* The user has provided a statically allocated event group - use it. */ - pxEventBits = ( EventGroup_t * ) pxEventGroupBuffer; /*lint !e740 EventGroup_t and StaticEventGroup_t are guaranteed to have the same size and alignment requirement - checked by configASSERT(). */ + pxEventBits = ( EventGroup_t * ) pxEventGroupBuffer; /*lint !e740 !e9087 EventGroup_t and StaticEventGroup_t are deliberately aliased for data hiding purposes and guaranteed to have the same size and alignment requirement - checked by configASSERT(). */ if( pxEventBits != NULL ) { @@ -160,10 +128,13 @@ PRIVILEGED_FUNCTION static BaseType_t prvTestWaitCondition( const EventBits_t ux } else { + /* xEventGroupCreateStatic should only ever be called with + pxEventGroupBuffer pointing to a pre-allocated (compile time + allocated) StaticEventGroup_t variable. */ traceEVENT_GROUP_CREATE_FAILED(); } - return ( EventGroupHandle_t ) pxEventBits; + return pxEventBits; } #endif /* configSUPPORT_STATIC_ALLOCATION */ @@ -175,8 +146,20 @@ PRIVILEGED_FUNCTION static BaseType_t prvTestWaitCondition( const EventBits_t ux { EventGroup_t *pxEventBits; - /* Allocate the event group. */ - pxEventBits = ( EventGroup_t * ) pvPortMalloc( sizeof( EventGroup_t ) ); + /* Allocate the event group. Justification for MISRA deviation as + follows: pvPortMalloc() always ensures returned memory blocks are + aligned per the requirements of the MCU stack. In this case + pvPortMalloc() must return a pointer that is guaranteed to meet the + alignment requirements of the EventGroup_t structure - which (if you + follow it through) is the alignment requirements of the TickType_t type + (EventBits_t being of TickType_t itself). Therefore, whenever the + stack alignment requirements are greater than or equal to the + TickType_t alignment requirements the cast is safe. In other cases, + where the natural word size of the architecture is less than + sizeof( TickType_t ), the TickType_t variables will be accessed in two + or more reads operations, and the alignment requirements is only that + of each individual read. */ + pxEventBits = ( EventGroup_t * ) pvPortMalloc( sizeof( EventGroup_t ) ); /*lint !e9087 !e9079 see comment above. */ if( pxEventBits != NULL ) { @@ -196,10 +179,10 @@ PRIVILEGED_FUNCTION static BaseType_t prvTestWaitCondition( const EventBits_t ux } else { - traceEVENT_GROUP_CREATE_FAILED(); + traceEVENT_GROUP_CREATE_FAILED(); /*lint !e9063 Else branch only exists to allow tracing and does not generate code if trace macros are not defined. */ } - return ( EventGroupHandle_t ) pxEventBits; + return pxEventBits; } #endif /* configSUPPORT_DYNAMIC_ALLOCATION */ @@ -208,7 +191,7 @@ PRIVILEGED_FUNCTION static BaseType_t prvTestWaitCondition( const EventBits_t ux EventBits_t xEventGroupSync( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet, const EventBits_t uxBitsToWaitFor, TickType_t xTicksToWait ) { EventBits_t uxOriginalBitValue, uxReturn; -EventGroup_t *pxEventBits = ( EventGroup_t * ) xEventGroup; +EventGroup_t *pxEventBits = xEventGroup; BaseType_t xAlreadyYielded; BaseType_t xTimeoutOccurred = pdFALSE; @@ -259,6 +242,7 @@ BaseType_t xTimeoutOccurred = pdFALSE; /* The rendezvous bits were not set, but no block time was specified - just return the current event bit value. */ uxReturn = pxEventBits->uxEventBits; + xTimeoutOccurred = pdTRUE; } } } @@ -317,13 +301,16 @@ BaseType_t xTimeoutOccurred = pdFALSE; traceEVENT_GROUP_SYNC_END( xEventGroup, uxBitsToSet, uxBitsToWaitFor, xTimeoutOccurred ); + /* Prevent compiler warnings when trace macros are not used. */ + ( void ) xTimeoutOccurred; + return uxReturn; } /*-----------------------------------------------------------*/ EventBits_t xEventGroupWaitBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToWaitFor, const BaseType_t xClearOnExit, const BaseType_t xWaitForAllBits, TickType_t xTicksToWait ) { -EventGroup_t *pxEventBits = ( EventGroup_t * ) xEventGroup; +EventGroup_t *pxEventBits = xEventGroup; EventBits_t uxReturn, uxControlBits = 0; BaseType_t xWaitConditionMet, xAlreadyYielded; BaseType_t xTimeoutOccurred = pdFALSE; @@ -368,6 +355,7 @@ BaseType_t xTimeoutOccurred = pdFALSE; /* The wait condition has not been met, but no block time was specified, so just return the current value. */ uxReturn = uxCurrentEventBits; + xTimeoutOccurred = pdTRUE; } else { @@ -449,11 +437,9 @@ BaseType_t xTimeoutOccurred = pdFALSE; { mtCOVERAGE_TEST_MARKER(); } + xTimeoutOccurred = pdTRUE; } taskEXIT_CRITICAL(); - - /* Prevent compiler warnings when trace macros are not used. */ - xTimeoutOccurred = pdFALSE; } else { @@ -465,13 +451,16 @@ BaseType_t xTimeoutOccurred = pdFALSE; } traceEVENT_GROUP_WAIT_BITS_END( xEventGroup, uxBitsToWaitFor, xTimeoutOccurred ); + /* Prevent compiler warnings when trace macros are not used. */ + ( void ) xTimeoutOccurred; + return uxReturn; } /*-----------------------------------------------------------*/ EventBits_t xEventGroupClearBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToClear ) { -EventGroup_t *pxEventBits = ( EventGroup_t * ) xEventGroup; +EventGroup_t *pxEventBits = xEventGroup; EventBits_t uxReturn; /* Check the user is not attempting to clear the bits used by the kernel @@ -503,7 +492,7 @@ EventBits_t uxReturn; BaseType_t xReturn; traceEVENT_GROUP_CLEAR_BITS_FROM_ISR( xEventGroup, uxBitsToClear ); - xReturn = xTimerPendFunctionCallFromISR( vEventGroupClearBitsCallback, ( void * ) xEventGroup, ( uint32_t ) uxBitsToClear, NULL ); + xReturn = xTimerPendFunctionCallFromISR( vEventGroupClearBitsCallback, ( void * ) xEventGroup, ( uint32_t ) uxBitsToClear, NULL ); /*lint !e9087 Can't avoid cast to void* as a generic callback function not specific to this use case. Callback casts back to original type so safe. */ return xReturn; } @@ -514,7 +503,7 @@ EventBits_t uxReturn; EventBits_t xEventGroupGetBitsFromISR( EventGroupHandle_t xEventGroup ) { UBaseType_t uxSavedInterruptStatus; -EventGroup_t *pxEventBits = ( EventGroup_t * ) xEventGroup; +EventGroup_t const * const pxEventBits = xEventGroup; EventBits_t uxReturn; uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR(); @@ -524,16 +513,16 @@ EventBits_t uxReturn; portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus ); return uxReturn; -} +} /*lint !e818 EventGroupHandle_t is a typedef used in other functions to so can't be pointer to const. */ /*-----------------------------------------------------------*/ EventBits_t xEventGroupSetBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet ) { ListItem_t *pxListItem, *pxNext; ListItem_t const *pxListEnd; -List_t *pxList; +List_t const * pxList; EventBits_t uxBitsToClear = 0, uxBitsWaitedFor, uxControlBits; -EventGroup_t *pxEventBits = ( EventGroup_t * ) xEventGroup; +EventGroup_t *pxEventBits = xEventGroup; BaseType_t xMatchFound = pdFALSE; /* Check the user is not attempting to set the bits used by the kernel @@ -542,7 +531,7 @@ BaseType_t xMatchFound = pdFALSE; configASSERT( ( uxBitsToSet & eventEVENT_BITS_CONTROL_BYTES ) == 0 ); pxList = &( pxEventBits->xTasksWaitingForBits ); - pxListEnd = listGET_END_MARKER( pxList ); /*lint !e826 !e740 The mini list structure is used as the list end to save RAM. This is checked and valid. */ + pxListEnd = listGET_END_MARKER( pxList ); /*lint !e826 !e740 !e9087 The mini list structure is used as the list end to save RAM. This is checked and valid. */ vTaskSuspendAll(); { traceEVENT_GROUP_SET_BITS( xEventGroup, uxBitsToSet ); @@ -602,7 +591,7 @@ BaseType_t xMatchFound = pdFALSE; eventUNBLOCKED_DUE_TO_BIT_SET bit is set so the task knows that is was unblocked due to its required bits matching, rather than because it timed out. */ - ( void ) xTaskRemoveFromUnorderedEventList( pxListItem, pxEventBits->uxEventBits | eventUNBLOCKED_DUE_TO_BIT_SET ); + vTaskRemoveFromUnorderedEventList( pxListItem, pxEventBits->uxEventBits | eventUNBLOCKED_DUE_TO_BIT_SET ); } /* Move onto the next list item. Note pxListItem->pxNext is not @@ -623,7 +612,7 @@ BaseType_t xMatchFound = pdFALSE; void vEventGroupDelete( EventGroupHandle_t xEventGroup ) { -EventGroup_t *pxEventBits = ( EventGroup_t * ) xEventGroup; +EventGroup_t *pxEventBits = xEventGroup; const List_t *pxTasksWaitingForBits = &( pxEventBits->xTasksWaitingForBits ); vTaskSuspendAll(); @@ -633,9 +622,9 @@ const List_t *pxTasksWaitingForBits = &( pxEventBits->xTasksWaitingForBits ); while( listCURRENT_LIST_LENGTH( pxTasksWaitingForBits ) > ( UBaseType_t ) 0 ) { /* Unblock the task, returning 0 as the event list is being deleted - and cannot therefore have any bits set. */ - configASSERT( pxTasksWaitingForBits->xListEnd.pxNext != ( ListItem_t * ) &( pxTasksWaitingForBits->xListEnd ) ); - ( void ) xTaskRemoveFromUnorderedEventList( pxTasksWaitingForBits->xListEnd.pxNext, eventUNBLOCKED_DUE_TO_BIT_SET ); + and cannot therefore have any bits set. */ + configASSERT( pxTasksWaitingForBits->xListEnd.pxNext != ( const ListItem_t * ) &( pxTasksWaitingForBits->xListEnd ) ); + vTaskRemoveFromUnorderedEventList( pxTasksWaitingForBits->xListEnd.pxNext, eventUNBLOCKED_DUE_TO_BIT_SET ); } #if( ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) && ( configSUPPORT_STATIC_ALLOCATION == 0 ) ) @@ -667,7 +656,7 @@ const List_t *pxTasksWaitingForBits = &( pxEventBits->xTasksWaitingForBits ); an interrupt. */ void vEventGroupSetBitsCallback( void *pvEventGroup, const uint32_t ulBitsToSet ) { - ( void ) xEventGroupSetBits( pvEventGroup, ( EventBits_t ) ulBitsToSet ); + ( void ) xEventGroupSetBits( pvEventGroup, ( EventBits_t ) ulBitsToSet ); /*lint !e9079 Can't avoid cast to void* as a generic timer callback prototype. Callback casts back to original type so safe. */ } /*-----------------------------------------------------------*/ @@ -675,7 +664,7 @@ void vEventGroupSetBitsCallback( void *pvEventGroup, const uint32_t ulBitsToSet an interrupt. */ void vEventGroupClearBitsCallback( void *pvEventGroup, const uint32_t ulBitsToClear ) { - ( void ) xEventGroupClearBits( pvEventGroup, ( EventBits_t ) ulBitsToClear ); + ( void ) xEventGroupClearBits( pvEventGroup, ( EventBits_t ) ulBitsToClear ); /*lint !e9079 Can't avoid cast to void* as a generic timer callback prototype. Callback casts back to original type so safe. */ } /*-----------------------------------------------------------*/ @@ -721,7 +710,7 @@ BaseType_t xWaitConditionMet = pdFALSE; BaseType_t xReturn; traceEVENT_GROUP_SET_BITS_FROM_ISR( xEventGroup, uxBitsToSet ); - xReturn = xTimerPendFunctionCallFromISR( vEventGroupSetBitsCallback, ( void * ) xEventGroup, ( uint32_t ) uxBitsToSet, pxHigherPriorityTaskWoken ); + xReturn = xTimerPendFunctionCallFromISR( vEventGroupSetBitsCallback, ( void * ) xEventGroup, ( uint32_t ) uxBitsToSet, pxHigherPriorityTaskWoken ); /*lint !e9087 Can't avoid cast to void* as a generic callback function not specific to this use case. Callback casts back to original type so safe. */ return xReturn; } @@ -734,7 +723,7 @@ BaseType_t xWaitConditionMet = pdFALSE; UBaseType_t uxEventGroupGetNumber( void* xEventGroup ) { UBaseType_t xReturn; - EventGroup_t *pxEventBits = ( EventGroup_t * ) xEventGroup; + EventGroup_t const *pxEventBits = ( EventGroup_t * ) xEventGroup; /*lint !e9087 !e9079 EventGroupHandle_t is a pointer to an EventGroup_t, but EventGroupHandle_t is kept opaque outside of this file for data hiding purposes. */ if( xEventGroup == NULL ) { @@ -748,5 +737,17 @@ BaseType_t xWaitConditionMet = pdFALSE; return xReturn; } -#endif +#endif /* configUSE_TRACE_FACILITY */ +/*-----------------------------------------------------------*/ + +#if ( configUSE_TRACE_FACILITY == 1 ) + + void vEventGroupSetNumber( void * xEventGroup, UBaseType_t uxEventGroupNumber ) + { + ( ( EventGroup_t * ) xEventGroup )->uxEventGroupNumber = uxEventGroupNumber; /*lint !e9087 !e9079 EventGroupHandle_t is a pointer to an EventGroup_t, but EventGroupHandle_t is kept opaque outside of this file for data hiding purposes. */ + } + +#endif /* configUSE_TRACE_FACILITY */ +/*-----------------------------------------------------------*/ + diff --git a/Firmware/Board/v3/Middlewares/Third_Party/FreeRTOS/Source/include/FreeRTOS.h b/Firmware/Board/v3/Middlewares/Third_Party/FreeRTOS/Source/include/FreeRTOS.h index f81172db..ceb469a7 100644 --- a/Firmware/Board/v3/Middlewares/Third_Party/FreeRTOS/Source/include/FreeRTOS.h +++ b/Firmware/Board/v3/Middlewares/Third_Party/FreeRTOS/Source/include/FreeRTOS.h @@ -1,71 +1,29 @@ /* - FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. - All rights reserved - - VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. - - This file is part of the FreeRTOS distribution. - - FreeRTOS is free software; you can redistribute it and/or modify it under - the terms of the GNU General Public License (version 2) as published by the - Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception. - - *************************************************************************** - >>! NOTE: The modification to the GPL is included to allow you to !<< - >>! distribute a combined work that includes FreeRTOS without being !<< - >>! obliged to provide the source code for proprietary components !<< - >>! outside of the FreeRTOS kernel. !<< - *************************************************************************** - - FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - FOR A PARTICULAR PURPOSE. Full license text is available on the following - link: http://www.freertos.org/a00114.html - - *************************************************************************** - * * - * FreeRTOS provides completely free yet professionally developed, * - * robust, strictly quality controlled, supported, and cross * - * platform software that is more than just the market leader, it * - * is the industry's de facto standard. * - * * - * Help yourself get started quickly while simultaneously helping * - * to support the FreeRTOS project by purchasing a FreeRTOS * - * tutorial book, reference manual, or both: * - * http://www.FreeRTOS.org/Documentation * - * * - *************************************************************************** - - http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading - the FAQ page "My application does not run, what could be wrong?". Have you - defined configASSERT()? - - http://www.FreeRTOS.org/support - In return for receiving this top quality - embedded software for free we request you assist our global community by - participating in the support forum. - - http://www.FreeRTOS.org/training - Investing in training allows your team to - be as productive as possible as early as possible. Now you can receive - FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers - Ltd, and the world's leading authority on the world's leading RTOS. - - http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, - including FreeRTOS+Trace - an indispensable productivity tool, a DOS - compatible FAT file system, and our tiny thread aware UDP/IP stack. - - http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. - Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. - - http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High - Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS - licenses offer ticketed support, indemnification and commercial middleware. - - http://www.SafeRTOS.com - High Integrity Systems also provide a safety - engineered and independently SIL3 certified version for use in safety and - mission critical applications that require provable dependability. - - 1 tab == 4 spaces! -*/ + * FreeRTOS Kernel V10.3.1 + * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * http://www.FreeRTOS.org + * http://aws.amazon.com/freertos + * + * 1 tab == 4 spaces! + */ #ifndef INC_FREERTOS_H #define INC_FREERTOS_H @@ -126,6 +84,10 @@ extern "C" { #error Missing definition: configMAX_PRIORITIES must be defined in FreeRTOSConfig.h. See the Configuration section of the FreeRTOS API documentation for details. #endif +#if configMAX_PRIORITIES < 1 + #error configMAX_PRIORITIES must be defined to be greater than or equal to 1. +#endif + #ifndef configUSE_PREEMPTION #error Missing definition: configUSE_PREEMPTION must be defined in FreeRTOSConfig.h as either 1 or 0. See the Configuration section of the FreeRTOS API documentation for details. #endif @@ -142,10 +104,6 @@ extern "C" { #error Missing definition: configUSE_16_BIT_TICKS must be defined in FreeRTOSConfig.h as either 1 or 0. See the Configuration section of the FreeRTOS API documentation for details. #endif -#ifndef configMAX_PRIORITIES - #error configMAX_PRIORITIES must be defined to be greater than or equal to 1. -#endif - #ifndef configUSE_CO_ROUTINES #define configUSE_CO_ROUTINES 0 #endif @@ -198,6 +156,10 @@ extern "C" { #define INCLUDE_uxTaskGetStackHighWaterMark 0 #endif +#ifndef INCLUDE_uxTaskGetStackHighWaterMark2 + #define INCLUDE_uxTaskGetStackHighWaterMark2 0 +#endif + #ifndef INCLUDE_eTaskGetState #define INCLUDE_eTaskGetState 0 #endif @@ -279,6 +241,26 @@ extern "C" { #define configASSERT_DEFINED 1 #endif +/* configPRECONDITION should be defined as configASSERT. +The CBMC proofs need a way to track assumptions and assertions. +A configPRECONDITION statement should express an implicit invariant or +assumption made. A configASSERT statement should express an invariant that must +hold explicit before calling the code. */ +#ifndef configPRECONDITION + #define configPRECONDITION( X ) configASSERT(X) + #define configPRECONDITION_DEFINED 0 +#else + #define configPRECONDITION_DEFINED 1 +#endif + +#ifndef portMEMORY_BARRIER + #define portMEMORY_BARRIER() +#endif + +#ifndef portSOFTWARE_BARRIER + #define portSOFTWARE_BARRIER() +#endif + /* The timers module relies on xTaskGetSchedulerState(). */ #if configUSE_TIMERS == 1 @@ -396,6 +378,14 @@ extern "C" { #define traceBLOCKING_ON_QUEUE_RECEIVE( pxQueue ) #endif +#ifndef traceBLOCKING_ON_QUEUE_PEEK + /* Task is about to block because it cannot read from a + queue/mutex/semaphore. pxQueue is a pointer to the queue/mutex/semaphore + upon which the read was attempted. pxCurrentTCB points to the TCB of the + task that attempted the read. */ + #define traceBLOCKING_ON_QUEUE_PEEK( pxQueue ) +#endif + #ifndef traceBLOCKING_ON_QUEUE_SEND /* Task is about to block because it cannot write to a queue/mutex/semaphore. pxQueue is a pointer to the queue/mutex/semaphore @@ -408,6 +398,14 @@ extern "C" { #define configCHECK_FOR_STACK_OVERFLOW 0 #endif +#ifndef configRECORD_STACK_HIGH_ADDRESS + #define configRECORD_STACK_HIGH_ADDRESS 0 +#endif + +#ifndef configINCLUDE_FREERTOS_TASK_C_ADDITIONS_H + #define configINCLUDE_FREERTOS_TASK_C_ADDITIONS_H 0 +#endif + /* The following event macros are embedded in the kernel API calls. */ #ifndef traceMOVED_TASK_TO_READY_STATE @@ -474,6 +472,10 @@ extern "C" { #define traceQUEUE_PEEK( pxQueue ) #endif +#ifndef traceQUEUE_PEEK_FAILED + #define traceQUEUE_PEEK_FAILED( pxQueue ) +#endif + #ifndef traceQUEUE_PEEK_FROM_ISR #define traceQUEUE_PEEK_FROM_ISR( pxQueue ) #endif @@ -658,6 +660,58 @@ extern "C" { #define traceTASK_NOTIFY_GIVE_FROM_ISR() #endif +#ifndef traceSTREAM_BUFFER_CREATE_FAILED + #define traceSTREAM_BUFFER_CREATE_FAILED( xIsMessageBuffer ) +#endif + +#ifndef traceSTREAM_BUFFER_CREATE_STATIC_FAILED + #define traceSTREAM_BUFFER_CREATE_STATIC_FAILED( xReturn, xIsMessageBuffer ) +#endif + +#ifndef traceSTREAM_BUFFER_CREATE + #define traceSTREAM_BUFFER_CREATE( pxStreamBuffer, xIsMessageBuffer ) +#endif + +#ifndef traceSTREAM_BUFFER_DELETE + #define traceSTREAM_BUFFER_DELETE( xStreamBuffer ) +#endif + +#ifndef traceSTREAM_BUFFER_RESET + #define traceSTREAM_BUFFER_RESET( xStreamBuffer ) +#endif + +#ifndef traceBLOCKING_ON_STREAM_BUFFER_SEND + #define traceBLOCKING_ON_STREAM_BUFFER_SEND( xStreamBuffer ) +#endif + +#ifndef traceSTREAM_BUFFER_SEND + #define traceSTREAM_BUFFER_SEND( xStreamBuffer, xBytesSent ) +#endif + +#ifndef traceSTREAM_BUFFER_SEND_FAILED + #define traceSTREAM_BUFFER_SEND_FAILED( xStreamBuffer ) +#endif + +#ifndef traceSTREAM_BUFFER_SEND_FROM_ISR + #define traceSTREAM_BUFFER_SEND_FROM_ISR( xStreamBuffer, xBytesSent ) +#endif + +#ifndef traceBLOCKING_ON_STREAM_BUFFER_RECEIVE + #define traceBLOCKING_ON_STREAM_BUFFER_RECEIVE( xStreamBuffer ) +#endif + +#ifndef traceSTREAM_BUFFER_RECEIVE + #define traceSTREAM_BUFFER_RECEIVE( xStreamBuffer, xReceivedLength ) +#endif + +#ifndef traceSTREAM_BUFFER_RECEIVE_FAILED + #define traceSTREAM_BUFFER_RECEIVE_FAILED( xStreamBuffer ) +#endif + +#ifndef traceSTREAM_BUFFER_RECEIVE_FROM_ISR + #define traceSTREAM_BUFFER_RECEIVE_FROM_ISR( xStreamBuffer, xReceivedLength ) +#endif + #ifndef configGENERATE_RUN_TIME_STATS #define configGENERATE_RUN_TIME_STATS 0 #endif @@ -708,6 +762,10 @@ extern "C" { #define configUSE_TICKLESS_IDLE 0 #endif +#ifndef configPRE_SUPPRESS_TICKS_AND_SLEEP_PROCESSING + #define configPRE_SUPPRESS_TICKS_AND_SLEEP_PROCESSING( x ) +#endif + #ifndef configPRE_SLEEP_PROCESSING #define configPRE_SLEEP_PROCESSING( x ) #endif @@ -724,6 +782,14 @@ extern "C" { #define portTASK_USES_FLOATING_POINT() #endif +#ifndef portALLOCATE_SECURE_CONTEXT + #define portALLOCATE_SECURE_CONTEXT( ulSecureStackSize ) +#endif + +#ifndef portDONT_DISCARD + #define portDONT_DISCARD +#endif + #ifndef configUSE_TIME_SLICING #define configUSE_TIME_SLICING 1 #endif @@ -768,6 +834,10 @@ extern "C" { #define configUSE_TASK_NOTIFICATIONS 1 #endif +#ifndef configUSE_POSIX_ERRNO + #define configUSE_POSIX_ERRNO 0 +#endif + #ifndef portTICK_TYPE_IS_ATOMIC #define portTICK_TYPE_IS_ATOMIC 0 #endif @@ -782,6 +852,19 @@ extern "C" { #define configSUPPORT_DYNAMIC_ALLOCATION 1 #endif +#ifndef configSTACK_DEPTH_TYPE + /* Defaults to uint16_t for backward compatibility, but can be overridden + in FreeRTOSConfig.h if uint16_t is too restrictive. */ + #define configSTACK_DEPTH_TYPE uint16_t +#endif + +#ifndef configMESSAGE_BUFFER_LENGTH_TYPE + /* Defaults to size_t for backward compatibility, but can be overridden + in FreeRTOSConfig.h if lengths will always be less than the number of bytes + in a size_t. */ + #define configMESSAGE_BUFFER_LENGTH_TYPE size_t +#endif + /* Sanity check the configuration. */ #if( configUSE_TICKLESS_IDLE != 0 ) #if( INCLUDE_vTaskSuspend != 1 ) @@ -797,6 +880,10 @@ extern "C" { #error configUSE_MUTEXES must be set to 1 to use recursive mutexes #endif +#ifndef configINITIAL_TICK_COUNT + #define configINITIAL_TICK_COUNT 0 +#endif + #if( portTICK_TYPE_IS_ATOMIC == 0 ) /* Either variables of tick type cannot be read atomically, or portTICK_TYPE_IS_ATOMIC was not set - map the critical sections used when @@ -820,6 +907,32 @@ V8 if desired. */ #define configENABLE_BACKWARD_COMPATIBILITY 1 #endif +#ifndef configPRINTF + /* configPRINTF() was not defined, so define it away to nothing. To use + configPRINTF() then define it as follows (where MyPrintFunction() is + provided by the application writer): + + void MyPrintFunction(const char *pcFormat, ... ); + #define configPRINTF( X ) MyPrintFunction X + + Then call like a standard printf() function, but placing brackets around + all parameters so they are passed as a single parameter. For example: + configPRINTF( ("Value = %d", MyVariable) ); */ + #define configPRINTF( X ) +#endif + +#ifndef configMAX + /* The application writer has not provided their own MAX macro, so define + the following generic implementation. */ + #define configMAX( a, b ) ( ( ( a ) > ( b ) ) ? ( a ) : ( b ) ) +#endif + +#ifndef configMIN + /* The application writer has not provided their own MAX macro, so define + the following generic implementation. */ + #define configMIN( a, b ) ( ( ( a ) < ( b ) ) ? ( a ) : ( b ) ) +#endif + #if configENABLE_BACKWARD_COMPATIBILITY == 1 #define eTaskStateGet eTaskGetState #define portTickType TickType_t @@ -840,6 +953,7 @@ V8 if desired. */ #define pcTimerGetTimerName pcTimerGetName #define pcQueueGetQueueName pcQueueGetName #define vTaskGetTaskInfo vTaskGetInfo + #define xTaskGetIdleRunTimeCounter ulTaskGetIdleRunTimeCounter /* Backward compatibility within the scheduler code only - these definitions are not really required but are included for completeness. */ @@ -847,6 +961,10 @@ V8 if desired. */ #define pdTASK_CODE TaskFunction_t #define xListItem ListItem_t #define xList List_t + + /* For libraries that break the list data hiding, and access list structure + members directly (which is not supposed to be done). */ + #define pxContainer pvContainer #endif /* configENABLE_BACKWARD_COMPATIBILITY */ #if( configUSE_ALTERNATIVE_API != 0 ) @@ -861,6 +979,75 @@ point support. */ #define configUSE_TASK_FPU_SUPPORT 1 #endif +/* Set configENABLE_MPU to 1 to enable MPU support and 0 to disable it. This is +currently used in ARMv8M ports. */ +#ifndef configENABLE_MPU + #define configENABLE_MPU 0 +#endif + +/* Set configENABLE_FPU to 1 to enable FPU support and 0 to disable it. This is +currently used in ARMv8M ports. */ +#ifndef configENABLE_FPU + #define configENABLE_FPU 1 +#endif + +/* Set configENABLE_TRUSTZONE to 1 enable TrustZone support and 0 to disable it. +This is currently used in ARMv8M ports. */ +#ifndef configENABLE_TRUSTZONE + #define configENABLE_TRUSTZONE 1 +#endif + +/* Set configRUN_FREERTOS_SECURE_ONLY to 1 to run the FreeRTOS ARMv8M port on +the Secure Side only. */ +#ifndef configRUN_FREERTOS_SECURE_ONLY + #define configRUN_FREERTOS_SECURE_ONLY 0 +#endif + +/* Sometimes the FreeRTOSConfig.h settings only allow a task to be created using + * dynamically allocated RAM, in which case when any task is deleted it is known + * that both the task's stack and TCB need to be freed. Sometimes the + * FreeRTOSConfig.h settings only allow a task to be created using statically + * allocated RAM, in which case when any task is deleted it is known that neither + * the task's stack or TCB should be freed. Sometimes the FreeRTOSConfig.h + * settings allow a task to be created using either statically or dynamically + * allocated RAM, in which case a member of the TCB is used to record whether the + * stack and/or TCB were allocated statically or dynamically, so when a task is + * deleted the RAM that was allocated dynamically is freed again and no attempt is + * made to free the RAM that was allocated statically. + * tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE is only true if it is possible for a + * task to be created using either statically or dynamically allocated RAM. Note + * that if portUSING_MPU_WRAPPERS is 1 then a protected task can be created with + * a statically allocated stack and a dynamically allocated TCB. + * + * The following table lists various combinations of portUSING_MPU_WRAPPERS, + * configSUPPORT_DYNAMIC_ALLOCATION and configSUPPORT_STATIC_ALLOCATION and + * when it is possible to have both static and dynamic allocation: + * +-----+---------+--------+-----------------------------+-----------------------------------+------------------+-----------+ + * | MPU | Dynamic | Static | Available Functions | Possible Allocations | Both Dynamic and | Need Free | + * | | | | | | Static Possible | | + * +-----+---------+--------+-----------------------------+-----------------------------------+------------------+-----------+ + * | 0 | 0 | 1 | xTaskCreateStatic | TCB - Static, Stack - Static | No | No | + * +-----|---------|--------|-----------------------------|-----------------------------------|------------------|-----------| + * | 0 | 1 | 0 | xTaskCreate | TCB - Dynamic, Stack - Dynamic | No | Yes | + * +-----|---------|--------|-----------------------------|-----------------------------------|------------------|-----------| + * | 0 | 1 | 1 | xTaskCreate, | 1. TCB - Dynamic, Stack - Dynamic | Yes | Yes | + * | | | | xTaskCreateStatic | 2. TCB - Static, Stack - Static | | | + * +-----|---------|--------|-----------------------------|-----------------------------------|------------------|-----------| + * | 1 | 0 | 1 | xTaskCreateStatic, | TCB - Static, Stack - Static | No | No | + * | | | | xTaskCreateRestrictedStatic | | | | + * +-----|---------|--------|-----------------------------|-----------------------------------|------------------|-----------| + * | 1 | 1 | 0 | xTaskCreate, | 1. TCB - Dynamic, Stack - Dynamic | Yes | Yes | + * | | | | xTaskCreateRestricted | 2. TCB - Dynamic, Stack - Static | | | + * +-----|---------|--------|-----------------------------|-----------------------------------|------------------|-----------| + * | 1 | 1 | 1 | xTaskCreate, | 1. TCB - Dynamic, Stack - Dynamic | Yes | Yes | + * | | | | xTaskCreateStatic, | 2. TCB - Dynamic, Stack - Static | | | + * | | | | xTaskCreateRestricted, | 3. TCB - Static, Stack - Static | | | + * | | | | xTaskCreateRestrictedStatic | | | | + * +-----+---------+--------+-----------------------------+-----------------------------------+------------------+-----------+ + */ +#define tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE ( ( ( portUSING_MPU_WRAPPERS == 0 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) && ( configSUPPORT_STATIC_ALLOCATION == 1 ) ) || \ + ( ( portUSING_MPU_WRAPPERS == 1 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) ) ) + /* * In line with software engineering best practice, FreeRTOS implements a strict * data hiding policy, so the real structures used by FreeRTOS to maintain the @@ -873,25 +1060,40 @@ point support. */ */ struct xSTATIC_LIST_ITEM { - TickType_t xDummy1; - void *pvDummy2[ 4 ]; + #if( configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES == 1 ) + TickType_t xDummy1; + #endif + TickType_t xDummy2; + void *pvDummy3[ 4 ]; + #if( configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES == 1 ) + TickType_t xDummy4; + #endif }; typedef struct xSTATIC_LIST_ITEM StaticListItem_t; /* See the comments above the struct xSTATIC_LIST_ITEM definition. */ struct xSTATIC_MINI_LIST_ITEM { - TickType_t xDummy1; - void *pvDummy2[ 2 ]; + #if( configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES == 1 ) + TickType_t xDummy1; + #endif + TickType_t xDummy2; + void *pvDummy3[ 2 ]; }; typedef struct xSTATIC_MINI_LIST_ITEM StaticMiniListItem_t; /* See the comments above the struct xSTATIC_LIST_ITEM definition. */ typedef struct xSTATIC_LIST { - UBaseType_t uxDummy1; - void *pvDummy2; - StaticMiniListItem_t xDummy3; + #if( configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES == 1 ) + TickType_t xDummy1; + #endif + UBaseType_t uxDummy2; + void *pvDummy3; + StaticMiniListItem_t xDummy4; + #if( configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES == 1 ) + TickType_t xDummy5; + #endif } StaticList_t; /* @@ -917,7 +1119,7 @@ typedef struct xSTATIC_TCB UBaseType_t uxDummy5; void *pxDummy6; uint8_t ucDummy7[ configMAX_TASK_NAME_LEN ]; - #if ( portSTACK_GROWTH > 0 ) + #if ( ( portSTACK_GROWTH > 0 ) || ( configRECORD_STACK_HIGH_ADDRESS == 1 ) ) void *pxDummy8; #endif #if ( portCRITICAL_NESTING_IN_TCB == 1 ) @@ -945,10 +1147,16 @@ typedef struct xSTATIC_TCB uint32_t ulDummy18; uint8_t ucDummy19; #endif - #if( ( configSUPPORT_STATIC_ALLOCATION == 1 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) ) + #if ( tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE != 0 ) uint8_t uxDummy20; #endif + #if( INCLUDE_xTaskAbortDelay == 1 ) + uint8_t ucDummy21; + #endif + #if ( configUSE_POSIX_ERRNO == 1 ) + int iDummy22; + #endif } StaticTask_t; /* @@ -1043,18 +1251,42 @@ typedef struct xSTATIC_TIMER void *pvDummy1; StaticListItem_t xDummy2; TickType_t xDummy3; - UBaseType_t uxDummy4; - void *pvDummy5[ 2 ]; + void *pvDummy5; + TaskFunction_t pvDummy6; #if( configUSE_TRACE_FACILITY == 1 ) - UBaseType_t uxDummy6; - #endif - - #if( ( configSUPPORT_STATIC_ALLOCATION == 1 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) ) - uint8_t ucDummy7; + UBaseType_t uxDummy7; #endif + uint8_t ucDummy8; } StaticTimer_t; +/* +* In line with software engineering best practice, especially when supplying a +* library that is likely to change in future versions, FreeRTOS implements a +* strict data hiding policy. This means the stream buffer structure used +* internally by FreeRTOS is not accessible to application code. However, if +* the application writer wants to statically allocate the memory required to +* create a stream buffer then the size of the stream buffer object needs to be +* know. The StaticStreamBuffer_t structure below is provided for this purpose. +* Its size and alignment requirements are guaranteed to match those of the +* genuine structure, no matter which architecture is being used, and no matter +* how the values in FreeRTOSConfig.h are set. Its contents are somewhat +* obfuscated in the hope users will recognise that it would be unwise to make +* direct use of the structure members. +*/ +typedef struct xSTATIC_STREAM_BUFFER +{ + size_t uxDummy1[ 4 ]; + void * pvDummy2[ 3 ]; + uint8_t ucDummy3; + #if ( configUSE_TRACE_FACILITY == 1 ) + UBaseType_t uxDummy4; + #endif +} StaticStreamBuffer_t; + +/* Message buffers are built on stream buffers. */ +typedef StaticStreamBuffer_t StaticMessageBuffer_t; + #ifdef __cplusplus } #endif diff --git a/Firmware/Board/v3/Middlewares/Third_Party/FreeRTOS/Source/include/FreeRTOSConfig_template.h b/Firmware/Board/v3/Middlewares/Third_Party/FreeRTOS/Source/include/FreeRTOSConfig_template.h deleted file mode 100644 index 2662d227..00000000 --- a/Firmware/Board/v3/Middlewares/Third_Party/FreeRTOS/Source/include/FreeRTOSConfig_template.h +++ /dev/null @@ -1,173 +0,0 @@ -/* - FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. - All rights reserved - - VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. - - This file is part of the FreeRTOS distribution. - - FreeRTOS is free software; you can redistribute it and/or modify it under - the terms of the GNU General Public License (version 2) as published by the - Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception. - - *************************************************************************** - >>! NOTE: The modification to the GPL is included to allow you to !<< - >>! distribute a combined work that includes FreeRTOS without being !<< - >>! obliged to provide the source code for proprietary components !<< - >>! outside of the FreeRTOS kernel. !<< - *************************************************************************** - - FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - FOR A PARTICULAR PURPOSE. Full license text is available on the following - link: http://www.freertos.org/a00114.html - - *************************************************************************** - * * - * FreeRTOS provides completely free yet professionally developed, * - * robust, strictly quality controlled, supported, and cross * - * platform software that is more than just the market leader, it * - * is the industry's de facto standard. * - * * - * Help yourself get started quickly while simultaneously helping * - * to support the FreeRTOS project by purchasing a FreeRTOS * - * tutorial book, reference manual, or both: * - * http://www.FreeRTOS.org/Documentation * - * * - *************************************************************************** - - http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading - the FAQ page "My application does not run, what could be wrong?". Have you - defined configASSERT()? - - http://www.FreeRTOS.org/support - In return for receiving this top quality - embedded software for free we request you assist our global community by - participating in the support forum. - - http://www.FreeRTOS.org/training - Investing in training allows your team to - be as productive as possible as early as possible. Now you can receive - FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers - Ltd, and the world's leading authority on the world's leading RTOS. - - http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, - including FreeRTOS+Trace - an indispensable productivity tool, a DOS - compatible FAT file system, and our tiny thread aware UDP/IP stack. - - http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. - Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. - - http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High - Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS - licenses offer ticketed support, indemnification and commercial middleware. - - http://www.SafeRTOS.com - High Integrity Systems also provide a safety - engineered and independently SIL3 certified version for use in safety and - mission critical applications that require provable dependability. - - 1 tab == 4 spaces! -*/ - - -#ifndef FREERTOS_CONFIG_H -#define FREERTOS_CONFIG_H - -/*----------------------------------------------------------- - * Application specific definitions. - * - * These definitions should be adjusted for your particular hardware and - * application requirements. - * - * THESE PARAMETERS ARE DESCRIBED WITHIN THE 'CONFIGURATION' SECTION OF THE - * FreeRTOS API DOCUMENTATION AVAILABLE ON THE FreeRTOS.org WEB SITE. - * - * See http://www.freertos.org/a00110.html. - *----------------------------------------------------------*/ - -/* Ensure stdint is only used by the compiler, and not the assembler. */ -#if defined(__ICCARM__) || defined(__CC_ARM) || defined(__GNUC__) - #include - extern uint32_t SystemCoreClock; -#endif - -#define configUSE_PREEMPTION 1 -#define configUSE_IDLE_HOOK 0 -#define configUSE_TICK_HOOK 0 -#define configCPU_CLOCK_HZ (SystemCoreClock) -#define configTICK_RATE_HZ ((TickType_t)1000) -#define configMAX_PRIORITIES (7) -#define configMINIMAL_STACK_SIZE ((uint16_t)128) -#define configTOTAL_HEAP_SIZE ((size_t)(15 * 1024)) -#define configMAX_TASK_NAME_LEN (16) -#define configUSE_TRACE_FACILITY 1 -#define configUSE_16_BIT_TICKS 0 -#define configIDLE_SHOULD_YIELD 1 -#define configUSE_MUTEXES 1 -#define configQUEUE_REGISTRY_SIZE 8 -#define configCHECK_FOR_STACK_OVERFLOW 0 -#define configUSE_RECURSIVE_MUTEXES 1 -#define configUSE_MALLOC_FAILED_HOOK 0 -#define configUSE_APPLICATION_TASK_TAG 0 -#define configUSE_COUNTING_SEMAPHORES 1 -#define configGENERATE_RUN_TIME_STATS 0 - -/* Co-routine definitions. */ -#define configUSE_CO_ROUTINES 0 -#define configMAX_CO_ROUTINE_PRIORITIES (2) - -/* Software timer definitions. */ -#define configUSE_TIMERS 0 -#define configTIMER_TASK_PRIORITY (2) -#define configTIMER_QUEUE_LENGTH 10 -#define configTIMER_TASK_STACK_DEPTH (configMINIMAL_STACK_SIZE * 2) - -/* Set the following definitions to 1 to include the API function, or zero -to exclude the API function. */ -#define INCLUDE_vTaskPrioritySet 1 -#define INCLUDE_uxTaskPriorityGet 1 -#define INCLUDE_vTaskDelete 1 -#define INCLUDE_vTaskCleanUpResources 0 -#define INCLUDE_vTaskSuspend 1 -#define INCLUDE_vTaskDelayUntil 0 -#define INCLUDE_vTaskDelay 1 -#define INCLUDE_xTaskGetSchedulerState 1 - -/* Cortex-M specific definitions. */ -#ifdef __NVIC_PRIO_BITS - /* __BVIC_PRIO_BITS will be specified when CMSIS is being used. */ - #define configPRIO_BITS __NVIC_PRIO_BITS -#else - #define configPRIO_BITS 4 /* 15 priority levels */ -#endif - -/* The lowest interrupt priority that can be used in a call to a "set priority" -function. */ -#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY 0xf - -/* The highest interrupt priority that can be used by any interrupt service -routine that makes calls to interrupt safe FreeRTOS API functions. DO NOT CALL -INTERRUPT SAFE FREERTOS API FUNCTIONS FROM ANY INTERRUPT THAT HAS A HIGHER -PRIORITY THAN THIS! (higher priorities are lower numeric values. */ -#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 5 - -/* Interrupt priorities used by the kernel port layer itself. These are generic -to all Cortex-M ports, and do not rely on any particular library functions. */ -#define configKERNEL_INTERRUPT_PRIORITY ( configLIBRARY_LOWEST_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) ) -/* !!!! configMAX_SYSCALL_INTERRUPT_PRIORITY must not be set to zero !!!! -See http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html. */ -#define configMAX_SYSCALL_INTERRUPT_PRIORITY ( configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) ) - -/* Normal assert() semantics without relying on the provision of an assert.h -header file. */ -#define configASSERT( x ) if( ( x ) == 0 ) { taskDISABLE_INTERRUPTS(); for( ;; ); } - -/* Definitions that map the FreeRTOS port interrupt handlers to their CMSIS - standard names. */ -#define vPortSVCHandler SVC_Handler -#define xPortPendSVHandler PendSV_Handler - -/* IMPORTANT: This define MUST be commented when used with STM32Cube firmware, - to prevent overwriting SysTick_Handler defined within STM32Cube HAL */ -/* #define xPortSysTickHandler SysTick_Handler */ - -#endif /* FREERTOS_CONFIG_H */ - diff --git a/Firmware/Board/v3/Middlewares/Third_Party/FreeRTOS/Source/include/StackMacros.h b/Firmware/Board/v3/Middlewares/Third_Party/FreeRTOS/Source/include/StackMacros.h index 13c6b829..56439917 100644 --- a/Firmware/Board/v3/Middlewares/Third_Party/FreeRTOS/Source/include/StackMacros.h +++ b/Firmware/Board/v3/Middlewares/Third_Party/FreeRTOS/Source/include/StackMacros.h @@ -1,75 +1,37 @@ /* - FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. - All rights reserved - - VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. - - This file is part of the FreeRTOS distribution. - - FreeRTOS is free software; you can redistribute it and/or modify it under - the terms of the GNU General Public License (version 2) as published by the - Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception. - - *************************************************************************** - >>! NOTE: The modification to the GPL is included to allow you to !<< - >>! distribute a combined work that includes FreeRTOS without being !<< - >>! obliged to provide the source code for proprietary components !<< - >>! outside of the FreeRTOS kernel. !<< - *************************************************************************** - - FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - FOR A PARTICULAR PURPOSE. Full license text is available on the following - link: http://www.freertos.org/a00114.html - - *************************************************************************** - * * - * FreeRTOS provides completely free yet professionally developed, * - * robust, strictly quality controlled, supported, and cross * - * platform software that is more than just the market leader, it * - * is the industry's de facto standard. * - * * - * Help yourself get started quickly while simultaneously helping * - * to support the FreeRTOS project by purchasing a FreeRTOS * - * tutorial book, reference manual, or both: * - * http://www.FreeRTOS.org/Documentation * - * * - *************************************************************************** - - http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading - the FAQ page "My application does not run, what could be wrong?". Have you - defined configASSERT()? - - http://www.FreeRTOS.org/support - In return for receiving this top quality - embedded software for free we request you assist our global community by - participating in the support forum. - - http://www.FreeRTOS.org/training - Investing in training allows your team to - be as productive as possible as early as possible. Now you can receive - FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers - Ltd, and the world's leading authority on the world's leading RTOS. - - http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, - including FreeRTOS+Trace - an indispensable productivity tool, a DOS - compatible FAT file system, and our tiny thread aware UDP/IP stack. - - http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. - Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. - - http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High - Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS - licenses offer ticketed support, indemnification and commercial middleware. - - http://www.SafeRTOS.com - High Integrity Systems also provide a safety - engineered and independently SIL3 certified version for use in safety and - mission critical applications that require provable dependability. - - 1 tab == 4 spaces! -*/ + * FreeRTOS Kernel V10.3.1 + * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * http://www.FreeRTOS.org + * http://aws.amazon.com/freertos + * + * 1 tab == 4 spaces! + */ #ifndef STACK_MACROS_H #define STACK_MACROS_H +#ifndef _MSC_VER /* Visual Studio doesn't support #warning. */ + #warning The name of this file has changed to stack_macros.h. Please update your code accordingly. This source file (which has the original name) will be removed in future released. +#endif + /* * Call the stack overflow hook function if the stack of the task being swapped * out is currently overflowed, or looks like it might have overflowed in the diff --git a/Firmware/Board/v3/Middlewares/Third_Party/FreeRTOS/Source/include/atomic.h b/Firmware/Board/v3/Middlewares/Third_Party/FreeRTOS/Source/include/atomic.h new file mode 100644 index 00000000..ceca6960 --- /dev/null +++ b/Firmware/Board/v3/Middlewares/Third_Party/FreeRTOS/Source/include/atomic.h @@ -0,0 +1,414 @@ +/* + * FreeRTOS Kernel V10.3.1 + * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * http://www.FreeRTOS.org + * http://aws.amazon.com/freertos + * + * 1 tab == 4 spaces! + */ + +/** + * @file atomic.h + * @brief FreeRTOS atomic operation support. + * + * This file implements atomic functions by disabling interrupts globally. + * Implementations with architecture specific atomic instructions can be + * provided under each compiler directory. + */ + +#ifndef ATOMIC_H +#define ATOMIC_H + +#ifndef INC_FREERTOS_H + #error "include FreeRTOS.h must appear in source files before include atomic.h" +#endif + +/* Standard includes. */ +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Port specific definitions -- entering/exiting critical section. + * Refer template -- ./lib/FreeRTOS/portable/Compiler/Arch/portmacro.h + * + * Every call to ATOMIC_EXIT_CRITICAL() must be closely paired with + * ATOMIC_ENTER_CRITICAL(). + * + */ +#if defined( portSET_INTERRUPT_MASK_FROM_ISR ) + + /* Nested interrupt scheme is supported in this port. */ + #define ATOMIC_ENTER_CRITICAL() \ + UBaseType_t uxCriticalSectionType = portSET_INTERRUPT_MASK_FROM_ISR() + + #define ATOMIC_EXIT_CRITICAL() \ + portCLEAR_INTERRUPT_MASK_FROM_ISR( uxCriticalSectionType ) + +#else + + /* Nested interrupt scheme is NOT supported in this port. */ + #define ATOMIC_ENTER_CRITICAL() portENTER_CRITICAL() + #define ATOMIC_EXIT_CRITICAL() portEXIT_CRITICAL() + +#endif /* portSET_INTERRUPT_MASK_FROM_ISR() */ + +/* + * Port specific definition -- "always inline". + * Inline is compiler specific, and may not always get inlined depending on your + * optimization level. Also, inline is considered as performance optimization + * for atomic. Thus, if portFORCE_INLINE is not provided by portmacro.h, + * instead of resulting error, simply define it away. + */ +#ifndef portFORCE_INLINE + #define portFORCE_INLINE +#endif + +#define ATOMIC_COMPARE_AND_SWAP_SUCCESS 0x1U /**< Compare and swap succeeded, swapped. */ +#define ATOMIC_COMPARE_AND_SWAP_FAILURE 0x0U /**< Compare and swap failed, did not swap. */ + +/*----------------------------- Swap && CAS ------------------------------*/ + +/** + * Atomic compare-and-swap + * + * @brief Performs an atomic compare-and-swap operation on the specified values. + * + * @param[in, out] pulDestination Pointer to memory location from where value is + * to be loaded and checked. + * @param[in] ulExchange If condition meets, write this value to memory. + * @param[in] ulComparand Swap condition. + * + * @return Unsigned integer of value 1 or 0. 1 for swapped, 0 for not swapped. + * + * @note This function only swaps *pulDestination with ulExchange, if previous + * *pulDestination value equals ulComparand. + */ +static portFORCE_INLINE uint32_t Atomic_CompareAndSwap_u32( uint32_t volatile * pulDestination, + uint32_t ulExchange, + uint32_t ulComparand ) +{ +uint32_t ulReturnValue; + + ATOMIC_ENTER_CRITICAL(); + { + if( *pulDestination == ulComparand ) + { + *pulDestination = ulExchange; + ulReturnValue = ATOMIC_COMPARE_AND_SWAP_SUCCESS; + } + else + { + ulReturnValue = ATOMIC_COMPARE_AND_SWAP_FAILURE; + } + } + ATOMIC_EXIT_CRITICAL(); + + return ulReturnValue; +} +/*-----------------------------------------------------------*/ + +/** + * Atomic swap (pointers) + * + * @brief Atomically sets the address pointed to by *ppvDestination to the value + * of *pvExchange. + * + * @param[in, out] ppvDestination Pointer to memory location from where a pointer + * value is to be loaded and written back to. + * @param[in] pvExchange Pointer value to be written to *ppvDestination. + * + * @return The initial value of *ppvDestination. + */ +static portFORCE_INLINE void * Atomic_SwapPointers_p32( void * volatile * ppvDestination, + void * pvExchange ) +{ +void * pReturnValue; + + ATOMIC_ENTER_CRITICAL(); + { + pReturnValue = *ppvDestination; + *ppvDestination = pvExchange; + } + ATOMIC_EXIT_CRITICAL(); + + return pReturnValue; +} +/*-----------------------------------------------------------*/ + +/** + * Atomic compare-and-swap (pointers) + * + * @brief Performs an atomic compare-and-swap operation on the specified pointer + * values. + * + * @param[in, out] ppvDestination Pointer to memory location from where a pointer + * value is to be loaded and checked. + * @param[in] pvExchange If condition meets, write this value to memory. + * @param[in] pvComparand Swap condition. + * + * @return Unsigned integer of value 1 or 0. 1 for swapped, 0 for not swapped. + * + * @note This function only swaps *ppvDestination with pvExchange, if previous + * *ppvDestination value equals pvComparand. + */ +static portFORCE_INLINE uint32_t Atomic_CompareAndSwapPointers_p32( void * volatile * ppvDestination, + void * pvExchange, + void * pvComparand ) +{ +uint32_t ulReturnValue = ATOMIC_COMPARE_AND_SWAP_FAILURE; + + ATOMIC_ENTER_CRITICAL(); + { + if( *ppvDestination == pvComparand ) + { + *ppvDestination = pvExchange; + ulReturnValue = ATOMIC_COMPARE_AND_SWAP_SUCCESS; + } + } + ATOMIC_EXIT_CRITICAL(); + + return ulReturnValue; +} + + +/*----------------------------- Arithmetic ------------------------------*/ + +/** + * Atomic add + * + * @brief Atomically adds count to the value of the specified pointer points to. + * + * @param[in,out] pulAddend Pointer to memory location from where value is to be + * loaded and written back to. + * @param[in] ulCount Value to be added to *pulAddend. + * + * @return previous *pulAddend value. + */ +static portFORCE_INLINE uint32_t Atomic_Add_u32( uint32_t volatile * pulAddend, + uint32_t ulCount ) +{ + uint32_t ulCurrent; + + ATOMIC_ENTER_CRITICAL(); + { + ulCurrent = *pulAddend; + *pulAddend += ulCount; + } + ATOMIC_EXIT_CRITICAL(); + + return ulCurrent; +} +/*-----------------------------------------------------------*/ + +/** + * Atomic subtract + * + * @brief Atomically subtracts count from the value of the specified pointer + * pointers to. + * + * @param[in,out] pulAddend Pointer to memory location from where value is to be + * loaded and written back to. + * @param[in] ulCount Value to be subtract from *pulAddend. + * + * @return previous *pulAddend value. + */ +static portFORCE_INLINE uint32_t Atomic_Subtract_u32( uint32_t volatile * pulAddend, + uint32_t ulCount ) +{ + uint32_t ulCurrent; + + ATOMIC_ENTER_CRITICAL(); + { + ulCurrent = *pulAddend; + *pulAddend -= ulCount; + } + ATOMIC_EXIT_CRITICAL(); + + return ulCurrent; +} +/*-----------------------------------------------------------*/ + +/** + * Atomic increment + * + * @brief Atomically increments the value of the specified pointer points to. + * + * @param[in,out] pulAddend Pointer to memory location from where value is to be + * loaded and written back to. + * + * @return *pulAddend value before increment. + */ +static portFORCE_INLINE uint32_t Atomic_Increment_u32( uint32_t volatile * pulAddend ) +{ +uint32_t ulCurrent; + + ATOMIC_ENTER_CRITICAL(); + { + ulCurrent = *pulAddend; + *pulAddend += 1; + } + ATOMIC_EXIT_CRITICAL(); + + return ulCurrent; +} +/*-----------------------------------------------------------*/ + +/** + * Atomic decrement + * + * @brief Atomically decrements the value of the specified pointer points to + * + * @param[in,out] pulAddend Pointer to memory location from where value is to be + * loaded and written back to. + * + * @return *pulAddend value before decrement. + */ +static portFORCE_INLINE uint32_t Atomic_Decrement_u32( uint32_t volatile * pulAddend ) +{ +uint32_t ulCurrent; + + ATOMIC_ENTER_CRITICAL(); + { + ulCurrent = *pulAddend; + *pulAddend -= 1; + } + ATOMIC_EXIT_CRITICAL(); + + return ulCurrent; +} + +/*----------------------------- Bitwise Logical ------------------------------*/ + +/** + * Atomic OR + * + * @brief Performs an atomic OR operation on the specified values. + * + * @param [in, out] pulDestination Pointer to memory location from where value is + * to be loaded and written back to. + * @param [in] ulValue Value to be ORed with *pulDestination. + * + * @return The original value of *pulDestination. + */ +static portFORCE_INLINE uint32_t Atomic_OR_u32( uint32_t volatile * pulDestination, + uint32_t ulValue ) +{ +uint32_t ulCurrent; + + ATOMIC_ENTER_CRITICAL(); + { + ulCurrent = *pulDestination; + *pulDestination |= ulValue; + } + ATOMIC_EXIT_CRITICAL(); + + return ulCurrent; +} +/*-----------------------------------------------------------*/ + +/** + * Atomic AND + * + * @brief Performs an atomic AND operation on the specified values. + * + * @param [in, out] pulDestination Pointer to memory location from where value is + * to be loaded and written back to. + * @param [in] ulValue Value to be ANDed with *pulDestination. + * + * @return The original value of *pulDestination. + */ +static portFORCE_INLINE uint32_t Atomic_AND_u32( uint32_t volatile * pulDestination, + uint32_t ulValue ) +{ +uint32_t ulCurrent; + + ATOMIC_ENTER_CRITICAL(); + { + ulCurrent = *pulDestination; + *pulDestination &= ulValue; + } + ATOMIC_EXIT_CRITICAL(); + + return ulCurrent; +} +/*-----------------------------------------------------------*/ + +/** + * Atomic NAND + * + * @brief Performs an atomic NAND operation on the specified values. + * + * @param [in, out] pulDestination Pointer to memory location from where value is + * to be loaded and written back to. + * @param [in] ulValue Value to be NANDed with *pulDestination. + * + * @return The original value of *pulDestination. + */ +static portFORCE_INLINE uint32_t Atomic_NAND_u32( uint32_t volatile * pulDestination, + uint32_t ulValue ) +{ +uint32_t ulCurrent; + + ATOMIC_ENTER_CRITICAL(); + { + ulCurrent = *pulDestination; + *pulDestination = ~( ulCurrent & ulValue ); + } + ATOMIC_EXIT_CRITICAL(); + + return ulCurrent; +} +/*-----------------------------------------------------------*/ + +/** + * Atomic XOR + * + * @brief Performs an atomic XOR operation on the specified values. + * + * @param [in, out] pulDestination Pointer to memory location from where value is + * to be loaded and written back to. + * @param [in] ulValue Value to be XORed with *pulDestination. + * + * @return The original value of *pulDestination. + */ +static portFORCE_INLINE uint32_t Atomic_XOR_u32( uint32_t volatile * pulDestination, + uint32_t ulValue ) +{ +uint32_t ulCurrent; + + ATOMIC_ENTER_CRITICAL(); + { + ulCurrent = *pulDestination; + *pulDestination ^= ulValue; + } + ATOMIC_EXIT_CRITICAL(); + + return ulCurrent; +} + +#ifdef __cplusplus +} +#endif + +#endif /* ATOMIC_H */ diff --git a/Firmware/Board/v3/Middlewares/Third_Party/FreeRTOS/Source/include/croutine.h b/Firmware/Board/v3/Middlewares/Third_Party/FreeRTOS/Source/include/croutine.h index 4f003a0b..8d7069c0 100644 --- a/Firmware/Board/v3/Middlewares/Third_Party/FreeRTOS/Source/include/croutine.h +++ b/Firmware/Board/v3/Middlewares/Third_Party/FreeRTOS/Source/include/croutine.h @@ -1,71 +1,29 @@ /* - FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. - All rights reserved - - VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. - - This file is part of the FreeRTOS distribution. - - FreeRTOS is free software; you can redistribute it and/or modify it under - the terms of the GNU General Public License (version 2) as published by the - Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception. - - *************************************************************************** - >>! NOTE: The modification to the GPL is included to allow you to !<< - >>! distribute a combined work that includes FreeRTOS without being !<< - >>! obliged to provide the source code for proprietary components !<< - >>! outside of the FreeRTOS kernel. !<< - *************************************************************************** - - FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - FOR A PARTICULAR PURPOSE. Full license text is available on the following - link: http://www.freertos.org/a00114.html - - *************************************************************************** - * * - * FreeRTOS provides completely free yet professionally developed, * - * robust, strictly quality controlled, supported, and cross * - * platform software that is more than just the market leader, it * - * is the industry's de facto standard. * - * * - * Help yourself get started quickly while simultaneously helping * - * to support the FreeRTOS project by purchasing a FreeRTOS * - * tutorial book, reference manual, or both: * - * http://www.FreeRTOS.org/Documentation * - * * - *************************************************************************** - - http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading - the FAQ page "My application does not run, what could be wrong?". Have you - defined configASSERT()? - - http://www.FreeRTOS.org/support - In return for receiving this top quality - embedded software for free we request you assist our global community by - participating in the support forum. - - http://www.FreeRTOS.org/training - Investing in training allows your team to - be as productive as possible as early as possible. Now you can receive - FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers - Ltd, and the world's leading authority on the world's leading RTOS. - - http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, - including FreeRTOS+Trace - an indispensable productivity tool, a DOS - compatible FAT file system, and our tiny thread aware UDP/IP stack. - - http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. - Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. - - http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High - Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS - licenses offer ticketed support, indemnification and commercial middleware. - - http://www.SafeRTOS.com - High Integrity Systems also provide a safety - engineered and independently SIL3 certified version for use in safety and - mission critical applications that require provable dependability. - - 1 tab == 4 spaces! -*/ + * FreeRTOS Kernel V10.3.1 + * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * http://www.FreeRTOS.org + * http://aws.amazon.com/freertos + * + * 1 tab == 4 spaces! + */ #ifndef CO_ROUTINE_H #define CO_ROUTINE_H @@ -199,7 +157,7 @@ BaseType_t xCoRoutineCreate( crCOROUTINE_CODE pxCoRoutineCode, UBaseType_t uxPri } // Alternatively, if you do not require any other part of the idle task to - // execute, the idle task hook can call vCoRoutineScheduler() within an + // execute, the idle task hook can call vCoRoutineSchedule() within an // infinite loop. void vApplicationIdleHook( void ) { diff --git a/Firmware/Board/v3/Middlewares/Third_Party/FreeRTOS/Source/include/deprecated_definitions.h b/Firmware/Board/v3/Middlewares/Third_Party/FreeRTOS/Source/include/deprecated_definitions.h index 4ea816cc..21657b9d 100644 --- a/Firmware/Board/v3/Middlewares/Third_Party/FreeRTOS/Source/include/deprecated_definitions.h +++ b/Firmware/Board/v3/Middlewares/Third_Party/FreeRTOS/Source/include/deprecated_definitions.h @@ -1,71 +1,29 @@ /* - FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. - All rights reserved - - VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. - - This file is part of the FreeRTOS distribution. - - FreeRTOS is free software; you can redistribute it and/or modify it under - the terms of the GNU General Public License (version 2) as published by the - Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception. - - *************************************************************************** - >>! NOTE: The modification to the GPL is included to allow you to !<< - >>! distribute a combined work that includes FreeRTOS without being !<< - >>! obliged to provide the source code for proprietary components !<< - >>! outside of the FreeRTOS kernel. !<< - *************************************************************************** - - FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - FOR A PARTICULAR PURPOSE. Full license text is available on the following - link: http://www.freertos.org/a00114.html - - *************************************************************************** - * * - * FreeRTOS provides completely free yet professionally developed, * - * robust, strictly quality controlled, supported, and cross * - * platform software that is more than just the market leader, it * - * is the industry's de facto standard. * - * * - * Help yourself get started quickly while simultaneously helping * - * to support the FreeRTOS project by purchasing a FreeRTOS * - * tutorial book, reference manual, or both: * - * http://www.FreeRTOS.org/Documentation * - * * - *************************************************************************** - - http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading - the FAQ page "My application does not run, what could be wrong?". Have you - defined configASSERT()? - - http://www.FreeRTOS.org/support - In return for receiving this top quality - embedded software for free we request you assist our global community by - participating in the support forum. - - http://www.FreeRTOS.org/training - Investing in training allows your team to - be as productive as possible as early as possible. Now you can receive - FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers - Ltd, and the world's leading authority on the world's leading RTOS. - - http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, - including FreeRTOS+Trace - an indispensable productivity tool, a DOS - compatible FAT file system, and our tiny thread aware UDP/IP stack. - - http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. - Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. - - http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High - Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS - licenses offer ticketed support, indemnification and commercial middleware. - - http://www.SafeRTOS.com - High Integrity Systems also provide a safety - engineered and independently SIL3 certified version for use in safety and - mission critical applications that require provable dependability. - - 1 tab == 4 spaces! -*/ + * FreeRTOS Kernel V10.3.1 + * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * http://www.FreeRTOS.org + * http://aws.amazon.com/freertos + * + * 1 tab == 4 spaces! + */ #ifndef DEPRECATED_DEFINITIONS_H #define DEPRECATED_DEFINITIONS_H diff --git a/Firmware/Board/v3/Middlewares/Third_Party/FreeRTOS/Source/include/event_groups.h b/Firmware/Board/v3/Middlewares/Third_Party/FreeRTOS/Source/include/event_groups.h index cab9d59e..a87fdf37 100644 --- a/Firmware/Board/v3/Middlewares/Third_Party/FreeRTOS/Source/include/event_groups.h +++ b/Firmware/Board/v3/Middlewares/Third_Party/FreeRTOS/Source/include/event_groups.h @@ -1,71 +1,29 @@ /* - FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. - All rights reserved - - VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. - - This file is part of the FreeRTOS distribution. - - FreeRTOS is free software; you can redistribute it and/or modify it under - the terms of the GNU General Public License (version 2) as published by the - Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception. - - *************************************************************************** - >>! NOTE: The modification to the GPL is included to allow you to !<< - >>! distribute a combined work that includes FreeRTOS without being !<< - >>! obliged to provide the source code for proprietary components !<< - >>! outside of the FreeRTOS kernel. !<< - *************************************************************************** - - FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - FOR A PARTICULAR PURPOSE. Full license text is available on the following - link: http://www.freertos.org/a00114.html - - *************************************************************************** - * * - * FreeRTOS provides completely free yet professionally developed, * - * robust, strictly quality controlled, supported, and cross * - * platform software that is more than just the market leader, it * - * is the industry's de facto standard. * - * * - * Help yourself get started quickly while simultaneously helping * - * to support the FreeRTOS project by purchasing a FreeRTOS * - * tutorial book, reference manual, or both: * - * http://www.FreeRTOS.org/Documentation * - * * - *************************************************************************** - - http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading - the FAQ page "My application does not run, what could be wrong?". Have you - defined configASSERT()? - - http://www.FreeRTOS.org/support - In return for receiving this top quality - embedded software for free we request you assist our global community by - participating in the support forum. - - http://www.FreeRTOS.org/training - Investing in training allows your team to - be as productive as possible as early as possible. Now you can receive - FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers - Ltd, and the world's leading authority on the world's leading RTOS. - - http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, - including FreeRTOS+Trace - an indispensable productivity tool, a DOS - compatible FAT file system, and our tiny thread aware UDP/IP stack. - - http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. - Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. - - http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High - Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS - licenses offer ticketed support, indemnification and commercial middleware. - - http://www.SafeRTOS.com - High Integrity Systems also provide a safety - engineered and independently SIL3 certified version for use in safety and - mission critical applications that require provable dependability. - - 1 tab == 4 spaces! -*/ + * FreeRTOS Kernel V10.3.1 + * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * http://www.FreeRTOS.org + * http://aws.amazon.com/freertos + * + * 1 tab == 4 spaces! + */ #ifndef EVENT_GROUPS_H #define EVENT_GROUPS_H @@ -120,7 +78,8 @@ extern "C" { * \defgroup EventGroupHandle_t EventGroupHandle_t * \ingroup EventGroup */ -typedef void * EventGroupHandle_t; +struct EventGroupDef_t; +typedef struct EventGroupDef_t * EventGroupHandle_t; /* * The type that holds event bits always matches TickType_t - therefore the @@ -185,7 +144,7 @@ typedef TickType_t EventBits_t; * \ingroup EventGroup */ #if( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) -PRIVILEGED_FUNCTION EventGroupHandle_t xEventGroupCreate( void ) ; + EventGroupHandle_t xEventGroupCreate( void ) PRIVILEGED_FUNCTION; #endif /** @@ -238,7 +197,7 @@ PRIVILEGED_FUNCTION EventGroupHandle_t xEventGroupCreate( void ) ; */ #if( configSUPPORT_STATIC_ALLOCATION == 1 ) -PRIVILEGED_FUNCTION EventGroupHandle_t xEventGroupCreateStatic( StaticEventGroup_t *pxEventGroupBuffer ); + EventGroupHandle_t xEventGroupCreateStatic( StaticEventGroup_t *pxEventGroupBuffer ) PRIVILEGED_FUNCTION; #endif /** @@ -333,7 +292,7 @@ PRIVILEGED_FUNCTION EventGroupHandle_t xEventGroupCreateStatic( StaticEventGroup * \defgroup xEventGroupWaitBits xEventGroupWaitBits * \ingroup EventGroup */ -PRIVILEGED_FUNCTION EventBits_t xEventGroupWaitBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToWaitFor, const BaseType_t xClearOnExit, const BaseType_t xWaitForAllBits, TickType_t xTicksToWait ); +EventBits_t xEventGroupWaitBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToWaitFor, const BaseType_t xClearOnExit, const BaseType_t xWaitForAllBits, TickType_t xTicksToWait ) PRIVILEGED_FUNCTION; /** * event_groups.h @@ -390,7 +349,7 @@ PRIVILEGED_FUNCTION EventBits_t xEventGroupWaitBits( EventGroupHandle_t xEventGr * \defgroup xEventGroupClearBits xEventGroupClearBits * \ingroup EventGroup */ -PRIVILEGED_FUNCTION EventBits_t xEventGroupClearBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToClear ); +EventBits_t xEventGroupClearBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToClear ) PRIVILEGED_FUNCTION; /** * event_groups.h @@ -446,7 +405,7 @@ PRIVILEGED_FUNCTION EventBits_t xEventGroupClearBits( EventGroupHandle_t xEventG * \ingroup EventGroup */ #if( configUSE_TRACE_FACILITY == 1 ) - PRIVILEGED_FUNCTION BaseType_t xEventGroupClearBitsFromISR( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet ); + BaseType_t xEventGroupClearBitsFromISR( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToClear ) PRIVILEGED_FUNCTION; #else #define xEventGroupClearBitsFromISR( xEventGroup, uxBitsToClear ) xTimerPendFunctionCallFromISR( vEventGroupClearBitsCallback, ( void * ) xEventGroup, ( uint32_t ) uxBitsToClear, NULL ) #endif @@ -523,7 +482,7 @@ PRIVILEGED_FUNCTION EventBits_t xEventGroupClearBits( EventGroupHandle_t xEventG * \defgroup xEventGroupSetBits xEventGroupSetBits * \ingroup EventGroup */ -PRIVILEGED_FUNCTION EventBits_t xEventGroupSetBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet ); +EventBits_t xEventGroupSetBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet ) PRIVILEGED_FUNCTION; /** * event_groups.h @@ -598,7 +557,7 @@ PRIVILEGED_FUNCTION EventBits_t xEventGroupSetBits( EventGroupHandle_t xEventGro * \ingroup EventGroup */ #if( configUSE_TRACE_FACILITY == 1 ) - PRIVILEGED_FUNCTION BaseType_t xEventGroupSetBitsFromISR( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet, BaseType_t *pxHigherPriorityTaskWoken ); + BaseType_t xEventGroupSetBitsFromISR( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet, BaseType_t *pxHigherPriorityTaskWoken ) PRIVILEGED_FUNCTION; #else #define xEventGroupSetBitsFromISR( xEventGroup, uxBitsToSet, pxHigherPriorityTaskWoken ) xTimerPendFunctionCallFromISR( vEventGroupSetBitsCallback, ( void * ) xEventGroup, ( uint32_t ) uxBitsToSet, pxHigherPriorityTaskWoken ) #endif @@ -727,7 +686,7 @@ PRIVILEGED_FUNCTION EventBits_t xEventGroupSetBits( EventGroupHandle_t xEventGro * \defgroup xEventGroupSync xEventGroupSync * \ingroup EventGroup */ -PRIVILEGED_FUNCTION EventBits_t xEventGroupSync( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet, const EventBits_t uxBitsToWaitFor, TickType_t xTicksToWait ); +EventBits_t xEventGroupSync( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet, const EventBits_t uxBitsToWaitFor, TickType_t xTicksToWait ) PRIVILEGED_FUNCTION; /** @@ -763,7 +722,7 @@ PRIVILEGED_FUNCTION EventBits_t xEventGroupSync( EventGroupHandle_t xEventGroup, * \defgroup xEventGroupGetBitsFromISR xEventGroupGetBitsFromISR * \ingroup EventGroup */ -PRIVILEGED_FUNCTION EventBits_t xEventGroupGetBitsFromISR( EventGroupHandle_t xEventGroup ); +EventBits_t xEventGroupGetBitsFromISR( EventGroupHandle_t xEventGroup ) PRIVILEGED_FUNCTION; /** * event_groups.h @@ -777,15 +736,16 @@ PRIVILEGED_FUNCTION EventBits_t xEventGroupGetBitsFromISR( EventGroupHandle_t xE * * @param xEventGroup The event group being deleted. */ -PRIVILEGED_FUNCTION void vEventGroupDelete( EventGroupHandle_t xEventGroup ); +void vEventGroupDelete( EventGroupHandle_t xEventGroup ) PRIVILEGED_FUNCTION; /* For internal use only. */ -PRIVILEGED_FUNCTION void vEventGroupSetBitsCallback( void *pvEventGroup, const uint32_t ulBitsToSet ); -PRIVILEGED_FUNCTION void vEventGroupClearBitsCallback( void *pvEventGroup, const uint32_t ulBitsToClear ); +void vEventGroupSetBitsCallback( void *pvEventGroup, const uint32_t ulBitsToSet ) PRIVILEGED_FUNCTION; +void vEventGroupClearBitsCallback( void *pvEventGroup, const uint32_t ulBitsToClear ) PRIVILEGED_FUNCTION; #if (configUSE_TRACE_FACILITY == 1) - PRIVILEGED_FUNCTION UBaseType_t uxEventGroupGetNumber( void* xEventGroup ); + UBaseType_t uxEventGroupGetNumber( void* xEventGroup ) PRIVILEGED_FUNCTION; + void vEventGroupSetNumber( void* xEventGroup, UBaseType_t uxEventGroupNumber ) PRIVILEGED_FUNCTION; #endif #ifdef __cplusplus diff --git a/Firmware/Board/v3/Middlewares/Third_Party/FreeRTOS/Source/include/list.h b/Firmware/Board/v3/Middlewares/Third_Party/FreeRTOS/Source/include/list.h index e552625e..a3e30249 100644 --- a/Firmware/Board/v3/Middlewares/Third_Party/FreeRTOS/Source/include/list.h +++ b/Firmware/Board/v3/Middlewares/Third_Party/FreeRTOS/Source/include/list.h @@ -1,71 +1,29 @@ /* - FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. - All rights reserved - - VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. - - This file is part of the FreeRTOS distribution. - - FreeRTOS is free software; you can redistribute it and/or modify it under - the terms of the GNU General Public License (version 2) as published by the - Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception. - - *************************************************************************** - >>! NOTE: The modification to the GPL is included to allow you to !<< - >>! distribute a combined work that includes FreeRTOS without being !<< - >>! obliged to provide the source code for proprietary components !<< - >>! outside of the FreeRTOS kernel. !<< - *************************************************************************** - - FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - FOR A PARTICULAR PURPOSE. Full license text is available on the following - link: http://www.freertos.org/a00114.html - - *************************************************************************** - * * - * FreeRTOS provides completely free yet professionally developed, * - * robust, strictly quality controlled, supported, and cross * - * platform software that is more than just the market leader, it * - * is the industry's de facto standard. * - * * - * Help yourself get started quickly while simultaneously helping * - * to support the FreeRTOS project by purchasing a FreeRTOS * - * tutorial book, reference manual, or both: * - * http://www.FreeRTOS.org/Documentation * - * * - *************************************************************************** - - http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading - the FAQ page "My application does not run, what could be wrong?". Have you - defined configASSERT()? - - http://www.FreeRTOS.org/support - In return for receiving this top quality - embedded software for free we request you assist our global community by - participating in the support forum. - - http://www.FreeRTOS.org/training - Investing in training allows your team to - be as productive as possible as early as possible. Now you can receive - FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers - Ltd, and the world's leading authority on the world's leading RTOS. - - http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, - including FreeRTOS+Trace - an indispensable productivity tool, a DOS - compatible FAT file system, and our tiny thread aware UDP/IP stack. - - http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. - Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. - - http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High - Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS - licenses offer ticketed support, indemnification and commercial middleware. - - http://www.SafeRTOS.com - High Integrity Systems also provide a safety - engineered and independently SIL3 certified version for use in safety and - mission critical applications that require provable dependability. - - 1 tab == 4 spaces! -*/ + * FreeRTOS Kernel V10.3.1 + * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * http://www.FreeRTOS.org + * http://aws.amazon.com/freertos + * + * 1 tab == 4 spaces! + */ /* * This is the list implementation used by the scheduler. While it is tailored @@ -178,6 +136,7 @@ use of FreeRTOS.*/ /* * Definition of the only type of object that a list can contain. */ +struct xLIST; struct xLIST_ITEM { listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE /*< Set to a known value if configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */ @@ -185,7 +144,7 @@ struct xLIST_ITEM struct xLIST_ITEM * configLIST_VOLATILE pxNext; /*< Pointer to the next ListItem_t in the list. */ struct xLIST_ITEM * configLIST_VOLATILE pxPrevious; /*< Pointer to the previous ListItem_t in the list. */ void * pvOwner; /*< Pointer to the object (normally a TCB) that contains the list item. There is therefore a two way link between the object containing the list item and the list item itself. */ - void * configLIST_VOLATILE pvContainer; /*< Pointer to the list in which this list item is placed (if any). */ + struct xLIST * configLIST_VOLATILE pxContainer; /*< Pointer to the list in which this list item is placed (if any). */ listSECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE /*< Set to a known value if configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */ }; typedef struct xLIST_ITEM ListItem_t; /* For some reason lint wants this as two separate definitions. */ @@ -205,7 +164,7 @@ typedef struct xMINI_LIST_ITEM MiniListItem_t; typedef struct xLIST { listFIRST_LIST_INTEGRITY_CHECK_VALUE /*< Set to a known value if configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */ - configLIST_VOLATILE UBaseType_t uxNumberOfItems; + volatile UBaseType_t uxNumberOfItems; ListItem_t * configLIST_VOLATILE pxIndex; /*< Used to walk through the list. Points to the last item returned by a call to listGET_OWNER_OF_NEXT_ENTRY (). */ MiniListItem_t xListEnd; /*< List item that contains the maximum possible item value meaning it is always at the end of the list and is therefore used as a marker. */ listSECOND_LIST_INTEGRITY_CHECK_VALUE /*< Set to a known value if configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */ @@ -224,7 +183,7 @@ typedef struct xLIST * Access macro to get the owner of a list item. The owner of a list item * is the object (usually a TCB) that contains the list item. * - * \page listSET_LIST_ITEM_OWNER listSET_LIST_ITEM_OWNER + * \page listGET_LIST_ITEM_OWNER listSET_LIST_ITEM_OWNER * \ingroup LinkedList */ #define listGET_LIST_ITEM_OWNER( pxListItem ) ( ( pxListItem )->pvOwner ) @@ -266,7 +225,7 @@ typedef struct xLIST #define listGET_HEAD_ENTRY( pxList ) ( ( ( pxList )->xListEnd ).pxNext ) /* - * Return the list item at the head of the list. + * Return the next list item. * * \page listGET_NEXT listGET_NEXT * \ingroup LinkedList @@ -288,7 +247,7 @@ typedef struct xLIST * \page listLIST_IS_EMPTY listLIST_IS_EMPTY * \ingroup LinkedList */ -#define listLIST_IS_EMPTY( pxList ) ( ( BaseType_t ) ( ( pxList )->uxNumberOfItems == ( UBaseType_t ) 0 ) ) +#define listLIST_IS_EMPTY( pxList ) ( ( ( pxList )->uxNumberOfItems == ( UBaseType_t ) 0 ) ? pdTRUE : pdFALSE ) /* * Access macro to return the number of items in the list. @@ -356,7 +315,7 @@ List_t * const pxConstList = ( pxList ); \ * @param pxListItem The list item we want to know if is in the list. * @return pdTRUE if the list item is in the list, otherwise pdFALSE. */ -#define listIS_CONTAINED_WITHIN( pxList, pxListItem ) ( ( BaseType_t ) ( ( pxListItem )->pvContainer == ( void * ) ( pxList ) ) ) +#define listIS_CONTAINED_WITHIN( pxList, pxListItem ) ( ( ( pxListItem )->pxContainer == ( pxList ) ) ? ( pdTRUE ) : ( pdFALSE ) ) /* * Return the list a list item is contained within (referenced from). @@ -364,7 +323,7 @@ List_t * const pxConstList = ( pxList ); \ * @param pxListItem The list item being queried. * @return A pointer to the List_t object that references the pxListItem */ -#define listLIST_ITEM_CONTAINER( pxListItem ) ( ( pxListItem )->pvContainer ) +#define listLIST_ITEM_CONTAINER( pxListItem ) ( ( pxListItem )->pxContainer ) /* * This provides a crude means of knowing if a list has been initialised, as @@ -383,7 +342,7 @@ List_t * const pxConstList = ( pxList ); \ * \page vListInitialise vListInitialise * \ingroup LinkedList */ -PRIVILEGED_FUNCTION void vListInitialise( List_t * const pxList ); +void vListInitialise( List_t * const pxList ) PRIVILEGED_FUNCTION; /* * Must be called before a list item is used. This sets the list container to @@ -394,7 +353,7 @@ PRIVILEGED_FUNCTION void vListInitialise( List_t * const pxList ); * \page vListInitialiseItem vListInitialiseItem * \ingroup LinkedList */ -PRIVILEGED_FUNCTION void vListInitialiseItem( ListItem_t * const pxItem ); +void vListInitialiseItem( ListItem_t * const pxItem ) PRIVILEGED_FUNCTION; /* * Insert a list item into a list. The item will be inserted into the list in @@ -407,7 +366,7 @@ PRIVILEGED_FUNCTION void vListInitialiseItem( ListItem_t * const pxItem ); * \page vListInsert vListInsert * \ingroup LinkedList */ -PRIVILEGED_FUNCTION void vListInsert( List_t * const pxList, ListItem_t * const pxNewListItem ); +void vListInsert( List_t * const pxList, ListItem_t * const pxNewListItem ) PRIVILEGED_FUNCTION; /* * Insert a list item into a list. The item will be inserted in a position @@ -428,7 +387,7 @@ PRIVILEGED_FUNCTION void vListInsert( List_t * const pxList, ListItem_t * const * \page vListInsertEnd vListInsertEnd * \ingroup LinkedList */ -PRIVILEGED_FUNCTION void vListInsertEnd( List_t * const pxList, ListItem_t * const pxNewListItem ); +void vListInsertEnd( List_t * const pxList, ListItem_t * const pxNewListItem ) PRIVILEGED_FUNCTION; /* * Remove an item from a list. The list item has a pointer to the list that @@ -443,7 +402,7 @@ PRIVILEGED_FUNCTION void vListInsertEnd( List_t * const pxList, ListItem_t * con * \page uxListRemove uxListRemove * \ingroup LinkedList */ -PRIVILEGED_FUNCTION UBaseType_t uxListRemove( ListItem_t * const pxItemToRemove ); +UBaseType_t uxListRemove( ListItem_t * const pxItemToRemove ) PRIVILEGED_FUNCTION; #ifdef __cplusplus } diff --git a/Firmware/Board/v3/Middlewares/Third_Party/FreeRTOS/Source/include/message_buffer.h b/Firmware/Board/v3/Middlewares/Third_Party/FreeRTOS/Source/include/message_buffer.h new file mode 100644 index 00000000..0c3edb9c --- /dev/null +++ b/Firmware/Board/v3/Middlewares/Third_Party/FreeRTOS/Source/include/message_buffer.h @@ -0,0 +1,803 @@ +/* + * FreeRTOS Kernel V10.3.1 + * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * http://www.FreeRTOS.org + * http://aws.amazon.com/freertos + * + * 1 tab == 4 spaces! + */ + + +/* + * Message buffers build functionality on top of FreeRTOS stream buffers. + * Whereas stream buffers are used to send a continuous stream of data from one + * task or interrupt to another, message buffers are used to send variable + * length discrete messages from one task or interrupt to another. Their + * implementation is light weight, making them particularly suited for interrupt + * to task and core to core communication scenarios. + * + * ***NOTE***: Uniquely among FreeRTOS objects, the stream buffer + * implementation (so also the message buffer implementation, as message buffers + * are built on top of stream buffers) assumes there is only one task or + * interrupt that will write to the buffer (the writer), and only one task or + * interrupt that will read from the buffer (the reader). It is safe for the + * writer and reader to be different tasks or interrupts, but, unlike other + * FreeRTOS objects, it is not safe to have multiple different writers or + * multiple different readers. If there are to be multiple different writers + * then the application writer must place each call to a writing API function + * (such as xMessageBufferSend()) inside a critical section and set the send + * block time to 0. Likewise, if there are to be multiple different readers + * then the application writer must place each call to a reading API function + * (such as xMessageBufferRead()) inside a critical section and set the receive + * timeout to 0. + * + * Message buffers hold variable length messages. To enable that, when a + * message is written to the message buffer an additional sizeof( size_t ) bytes + * are also written to store the message's length (that happens internally, with + * the API function). sizeof( size_t ) is typically 4 bytes on a 32-bit + * architecture, so writing a 10 byte message to a message buffer on a 32-bit + * architecture will actually reduce the available space in the message buffer + * by 14 bytes (10 byte are used by the message, and 4 bytes to hold the length + * of the message). + */ + +#ifndef FREERTOS_MESSAGE_BUFFER_H +#define FREERTOS_MESSAGE_BUFFER_H + +#ifndef INC_FREERTOS_H + #error "include FreeRTOS.h must appear in source files before include message_buffer.h" +#endif + +/* Message buffers are built onto of stream buffers. */ +#include "stream_buffer.h" + +#if defined( __cplusplus ) +extern "C" { +#endif + +/** + * Type by which message buffers are referenced. For example, a call to + * xMessageBufferCreate() returns an MessageBufferHandle_t variable that can + * then be used as a parameter to xMessageBufferSend(), xMessageBufferReceive(), + * etc. + */ +typedef void * MessageBufferHandle_t; + +/*-----------------------------------------------------------*/ + +/** + * message_buffer.h + * +
+MessageBufferHandle_t xMessageBufferCreate( size_t xBufferSizeBytes );
+
+ * + * Creates a new message buffer using dynamically allocated memory. See + * xMessageBufferCreateStatic() for a version that uses statically allocated + * memory (memory that is allocated at compile time). + * + * configSUPPORT_DYNAMIC_ALLOCATION must be set to 1 or left undefined in + * FreeRTOSConfig.h for xMessageBufferCreate() to be available. + * + * @param xBufferSizeBytes The total number of bytes (not messages) the message + * buffer will be able to hold at any one time. When a message is written to + * the message buffer an additional sizeof( size_t ) bytes are also written to + * store the message's length. sizeof( size_t ) is typically 4 bytes on a + * 32-bit architecture, so on most 32-bit architectures a 10 byte message will + * take up 14 bytes of message buffer space. + * + * @return If NULL is returned, then the message buffer cannot be created + * because there is insufficient heap memory available for FreeRTOS to allocate + * the message buffer data structures and storage area. A non-NULL value being + * returned indicates that the message buffer has been created successfully - + * the returned value should be stored as the handle to the created message + * buffer. + * + * Example use: +
+
+void vAFunction( void )
+{
+MessageBufferHandle_t xMessageBuffer;
+const size_t xMessageBufferSizeBytes = 100;
+
+    // Create a message buffer that can hold 100 bytes.  The memory used to hold
+    // both the message buffer structure and the messages themselves is allocated
+    // dynamically.  Each message added to the buffer consumes an additional 4
+    // bytes which are used to hold the lengh of the message.
+    xMessageBuffer = xMessageBufferCreate( xMessageBufferSizeBytes );
+
+    if( xMessageBuffer == NULL )
+    {
+        // There was not enough heap memory space available to create the
+        // message buffer.
+    }
+    else
+    {
+        // The message buffer was created successfully and can now be used.
+    }
+
+
+ * \defgroup xMessageBufferCreate xMessageBufferCreate + * \ingroup MessageBufferManagement + */ +#define xMessageBufferCreate( xBufferSizeBytes ) ( MessageBufferHandle_t ) xStreamBufferGenericCreate( xBufferSizeBytes, ( size_t ) 0, pdTRUE ) + +/** + * message_buffer.h + * +
+MessageBufferHandle_t xMessageBufferCreateStatic( size_t xBufferSizeBytes,
+                                                  uint8_t *pucMessageBufferStorageArea,
+                                                  StaticMessageBuffer_t *pxStaticMessageBuffer );
+
+ * Creates a new message buffer using statically allocated memory. See + * xMessageBufferCreate() for a version that uses dynamically allocated memory. + * + * @param xBufferSizeBytes The size, in bytes, of the buffer pointed to by the + * pucMessageBufferStorageArea parameter. When a message is written to the + * message buffer an additional sizeof( size_t ) bytes are also written to store + * the message's length. sizeof( size_t ) is typically 4 bytes on a 32-bit + * architecture, so on most 32-bit architecture a 10 byte message will take up + * 14 bytes of message buffer space. The maximum number of bytes that can be + * stored in the message buffer is actually (xBufferSizeBytes - 1). + * + * @param pucMessageBufferStorageArea Must point to a uint8_t array that is at + * least xBufferSizeBytes + 1 big. This is the array to which messages are + * copied when they are written to the message buffer. + * + * @param pxStaticMessageBuffer Must point to a variable of type + * StaticMessageBuffer_t, which will be used to hold the message buffer's data + * structure. + * + * @return If the message buffer is created successfully then a handle to the + * created message buffer is returned. If either pucMessageBufferStorageArea or + * pxStaticmessageBuffer are NULL then NULL is returned. + * + * Example use: +
+
+// Used to dimension the array used to hold the messages.  The available space
+// will actually be one less than this, so 999.
+#define STORAGE_SIZE_BYTES 1000
+
+// Defines the memory that will actually hold the messages within the message
+// buffer.
+static uint8_t ucStorageBuffer[ STORAGE_SIZE_BYTES ];
+
+// The variable used to hold the message buffer structure.
+StaticMessageBuffer_t xMessageBufferStruct;
+
+void MyFunction( void )
+{
+MessageBufferHandle_t xMessageBuffer;
+
+    xMessageBuffer = xMessageBufferCreateStatic( sizeof( ucBufferStorage ),
+                                                 ucBufferStorage,
+                                                 &xMessageBufferStruct );
+
+    // As neither the pucMessageBufferStorageArea or pxStaticMessageBuffer
+    // parameters were NULL, xMessageBuffer will not be NULL, and can be used to
+    // reference the created message buffer in other message buffer API calls.
+
+    // Other code that uses the message buffer can go here.
+}
+
+
+ * \defgroup xMessageBufferCreateStatic xMessageBufferCreateStatic + * \ingroup MessageBufferManagement + */ +#define xMessageBufferCreateStatic( xBufferSizeBytes, pucMessageBufferStorageArea, pxStaticMessageBuffer ) ( MessageBufferHandle_t ) xStreamBufferGenericCreateStatic( xBufferSizeBytes, 0, pdTRUE, pucMessageBufferStorageArea, pxStaticMessageBuffer ) + +/** + * message_buffer.h + * +
+size_t xMessageBufferSend( MessageBufferHandle_t xMessageBuffer,
+                           const void *pvTxData,
+                           size_t xDataLengthBytes,
+                           TickType_t xTicksToWait );
+
+ *
+ * Sends a discrete message to the message buffer.  The message can be any
+ * length that fits within the buffer's free space, and is copied into the
+ * buffer.
+ *
+ * ***NOTE***:  Uniquely among FreeRTOS objects, the stream buffer
+ * implementation (so also the message buffer implementation, as message buffers
+ * are built on top of stream buffers) assumes there is only one task or
+ * interrupt that will write to the buffer (the writer), and only one task or
+ * interrupt that will read from the buffer (the reader).  It is safe for the
+ * writer and reader to be different tasks or interrupts, but, unlike other
+ * FreeRTOS objects, it is not safe to have multiple different writers or
+ * multiple different readers.  If there are to be multiple different writers
+ * then the application writer must place each call to a writing API function
+ * (such as xMessageBufferSend()) inside a critical section and set the send
+ * block time to 0.  Likewise, if there are to be multiple different readers
+ * then the application writer must place each call to a reading API function
+ * (such as xMessageBufferRead()) inside a critical section and set the receive
+ * block time to 0.
+ *
+ * Use xMessageBufferSend() to write to a message buffer from a task.  Use
+ * xMessageBufferSendFromISR() to write to a message buffer from an interrupt
+ * service routine (ISR).
+ *
+ * @param xMessageBuffer The handle of the message buffer to which a message is
+ * being sent.
+ *
+ * @param pvTxData A pointer to the message that is to be copied into the
+ * message buffer.
+ *
+ * @param xDataLengthBytes The length of the message.  That is, the number of
+ * bytes to copy from pvTxData into the message buffer.  When a message is
+ * written to the message buffer an additional sizeof( size_t ) bytes are also
+ * written to store the message's length.  sizeof( size_t ) is typically 4 bytes
+ * on a 32-bit architecture, so on most 32-bit architecture setting
+ * xDataLengthBytes to 20 will reduce the free space in the message buffer by 24
+ * bytes (20 bytes of message data and 4 bytes to hold the message length).
+ *
+ * @param xTicksToWait The maximum amount of time the calling task should remain
+ * in the Blocked state to wait for enough space to become available in the
+ * message buffer, should the message buffer have insufficient space when
+ * xMessageBufferSend() is called.  The calling task will never block if
+ * xTicksToWait is zero.  The block time is specified in tick periods, so the
+ * absolute time it represents is dependent on the tick frequency.  The macro
+ * pdMS_TO_TICKS() can be used to convert a time specified in milliseconds into
+ * a time specified in ticks.  Setting xTicksToWait to portMAX_DELAY will cause
+ * the task to wait indefinitely (without timing out), provided
+ * INCLUDE_vTaskSuspend is set to 1 in FreeRTOSConfig.h.  Tasks do not use any
+ * CPU time when they are in the Blocked state.
+ *
+ * @return The number of bytes written to the message buffer.  If the call to
+ * xMessageBufferSend() times out before there was enough space to write the
+ * message into the message buffer then zero is returned.  If the call did not
+ * time out then xDataLengthBytes is returned.
+ *
+ * Example use:
+
+void vAFunction( MessageBufferHandle_t xMessageBuffer )
+{
+size_t xBytesSent;
+uint8_t ucArrayToSend[] = { 0, 1, 2, 3 };
+char *pcStringToSend = "String to send";
+const TickType_t x100ms = pdMS_TO_TICKS( 100 );
+
+    // Send an array to the message buffer, blocking for a maximum of 100ms to
+    // wait for enough space to be available in the message buffer.
+    xBytesSent = xMessageBufferSend( xMessageBuffer, ( void * ) ucArrayToSend, sizeof( ucArrayToSend ), x100ms );
+
+    if( xBytesSent != sizeof( ucArrayToSend ) )
+    {
+        // The call to xMessageBufferSend() times out before there was enough
+        // space in the buffer for the data to be written.
+    }
+
+    // Send the string to the message buffer.  Return immediately if there is
+    // not enough space in the buffer.
+    xBytesSent = xMessageBufferSend( xMessageBuffer, ( void * ) pcStringToSend, strlen( pcStringToSend ), 0 );
+
+    if( xBytesSent != strlen( pcStringToSend ) )
+    {
+        // The string could not be added to the message buffer because there was
+        // not enough free space in the buffer.
+    }
+}
+
+ * \defgroup xMessageBufferSend xMessageBufferSend + * \ingroup MessageBufferManagement + */ +#define xMessageBufferSend( xMessageBuffer, pvTxData, xDataLengthBytes, xTicksToWait ) xStreamBufferSend( ( StreamBufferHandle_t ) xMessageBuffer, pvTxData, xDataLengthBytes, xTicksToWait ) + +/** + * message_buffer.h + * +
+size_t xMessageBufferSendFromISR( MessageBufferHandle_t xMessageBuffer,
+                                  const void *pvTxData,
+                                  size_t xDataLengthBytes,
+                                  BaseType_t *pxHigherPriorityTaskWoken );
+
+ *
+ * Interrupt safe version of the API function that sends a discrete message to
+ * the message buffer.  The message can be any length that fits within the
+ * buffer's free space, and is copied into the buffer.
+ *
+ * ***NOTE***:  Uniquely among FreeRTOS objects, the stream buffer
+ * implementation (so also the message buffer implementation, as message buffers
+ * are built on top of stream buffers) assumes there is only one task or
+ * interrupt that will write to the buffer (the writer), and only one task or
+ * interrupt that will read from the buffer (the reader).  It is safe for the
+ * writer and reader to be different tasks or interrupts, but, unlike other
+ * FreeRTOS objects, it is not safe to have multiple different writers or
+ * multiple different readers.  If there are to be multiple different writers
+ * then the application writer must place each call to a writing API function
+ * (such as xMessageBufferSend()) inside a critical section and set the send
+ * block time to 0.  Likewise, if there are to be multiple different readers
+ * then the application writer must place each call to a reading API function
+ * (such as xMessageBufferRead()) inside a critical section and set the receive
+ * block time to 0.
+ *
+ * Use xMessageBufferSend() to write to a message buffer from a task.  Use
+ * xMessageBufferSendFromISR() to write to a message buffer from an interrupt
+ * service routine (ISR).
+ *
+ * @param xMessageBuffer The handle of the message buffer to which a message is
+ * being sent.
+ *
+ * @param pvTxData A pointer to the message that is to be copied into the
+ * message buffer.
+ *
+ * @param xDataLengthBytes The length of the message.  That is, the number of
+ * bytes to copy from pvTxData into the message buffer.  When a message is
+ * written to the message buffer an additional sizeof( size_t ) bytes are also
+ * written to store the message's length.  sizeof( size_t ) is typically 4 bytes
+ * on a 32-bit architecture, so on most 32-bit architecture setting
+ * xDataLengthBytes to 20 will reduce the free space in the message buffer by 24
+ * bytes (20 bytes of message data and 4 bytes to hold the message length).
+ *
+ * @param pxHigherPriorityTaskWoken  It is possible that a message buffer will
+ * have a task blocked on it waiting for data.  Calling
+ * xMessageBufferSendFromISR() can make data available, and so cause a task that
+ * was waiting for data to leave the Blocked state.  If calling
+ * xMessageBufferSendFromISR() causes a task to leave the Blocked state, and the
+ * unblocked task has a priority higher than the currently executing task (the
+ * task that was interrupted), then, internally, xMessageBufferSendFromISR()
+ * will set *pxHigherPriorityTaskWoken to pdTRUE.  If
+ * xMessageBufferSendFromISR() sets this value to pdTRUE, then normally a
+ * context switch should be performed before the interrupt is exited.  This will
+ * ensure that the interrupt returns directly to the highest priority Ready
+ * state task.  *pxHigherPriorityTaskWoken should be set to pdFALSE before it
+ * is passed into the function.  See the code example below for an example.
+ *
+ * @return The number of bytes actually written to the message buffer.  If the
+ * message buffer didn't have enough free space for the message to be stored
+ * then 0 is returned, otherwise xDataLengthBytes is returned.
+ *
+ * Example use:
+
+// A message buffer that has already been created.
+MessageBufferHandle_t xMessageBuffer;
+
+void vAnInterruptServiceRoutine( void )
+{
+size_t xBytesSent;
+char *pcStringToSend = "String to send";
+BaseType_t xHigherPriorityTaskWoken = pdFALSE; // Initialised to pdFALSE.
+
+    // Attempt to send the string to the message buffer.
+    xBytesSent = xMessageBufferSendFromISR( xMessageBuffer,
+                                            ( void * ) pcStringToSend,
+                                            strlen( pcStringToSend ),
+                                            &xHigherPriorityTaskWoken );
+
+    if( xBytesSent != strlen( pcStringToSend ) )
+    {
+        // The string could not be added to the message buffer because there was
+        // not enough free space in the buffer.
+    }
+
+    // If xHigherPriorityTaskWoken was set to pdTRUE inside
+    // xMessageBufferSendFromISR() then a task that has a priority above the
+    // priority of the currently executing task was unblocked and a context
+    // switch should be performed to ensure the ISR returns to the unblocked
+    // task.  In most FreeRTOS ports this is done by simply passing
+    // xHigherPriorityTaskWoken into portYIELD_FROM_ISR(), which will test the
+    // variables value, and perform the context switch if necessary.  Check the
+    // documentation for the port in use for port specific instructions.
+    portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
+}
+
+ * \defgroup xMessageBufferSendFromISR xMessageBufferSendFromISR + * \ingroup MessageBufferManagement + */ +#define xMessageBufferSendFromISR( xMessageBuffer, pvTxData, xDataLengthBytes, pxHigherPriorityTaskWoken ) xStreamBufferSendFromISR( ( StreamBufferHandle_t ) xMessageBuffer, pvTxData, xDataLengthBytes, pxHigherPriorityTaskWoken ) + +/** + * message_buffer.h + * +
+size_t xMessageBufferReceive( MessageBufferHandle_t xMessageBuffer,
+                              void *pvRxData,
+                              size_t xBufferLengthBytes,
+                              TickType_t xTicksToWait );
+
+ * + * Receives a discrete message from a message buffer. Messages can be of + * variable length and are copied out of the buffer. + * + * ***NOTE***: Uniquely among FreeRTOS objects, the stream buffer + * implementation (so also the message buffer implementation, as message buffers + * are built on top of stream buffers) assumes there is only one task or + * interrupt that will write to the buffer (the writer), and only one task or + * interrupt that will read from the buffer (the reader). It is safe for the + * writer and reader to be different tasks or interrupts, but, unlike other + * FreeRTOS objects, it is not safe to have multiple different writers or + * multiple different readers. If there are to be multiple different writers + * then the application writer must place each call to a writing API function + * (such as xMessageBufferSend()) inside a critical section and set the send + * block time to 0. Likewise, if there are to be multiple different readers + * then the application writer must place each call to a reading API function + * (such as xMessageBufferRead()) inside a critical section and set the receive + * block time to 0. + * + * Use xMessageBufferReceive() to read from a message buffer from a task. Use + * xMessageBufferReceiveFromISR() to read from a message buffer from an + * interrupt service routine (ISR). + * + * @param xMessageBuffer The handle of the message buffer from which a message + * is being received. + * + * @param pvRxData A pointer to the buffer into which the received message is + * to be copied. + * + * @param xBufferLengthBytes The length of the buffer pointed to by the pvRxData + * parameter. This sets the maximum length of the message that can be received. + * If xBufferLengthBytes is too small to hold the next message then the message + * will be left in the message buffer and 0 will be returned. + * + * @param xTicksToWait The maximum amount of time the task should remain in the + * Blocked state to wait for a message, should the message buffer be empty. + * xMessageBufferReceive() will return immediately if xTicksToWait is zero and + * the message buffer is empty. The block time is specified in tick periods, so + * the absolute time it represents is dependent on the tick frequency. The + * macro pdMS_TO_TICKS() can be used to convert a time specified in milliseconds + * into a time specified in ticks. Setting xTicksToWait to portMAX_DELAY will + * cause the task to wait indefinitely (without timing out), provided + * INCLUDE_vTaskSuspend is set to 1 in FreeRTOSConfig.h. Tasks do not use any + * CPU time when they are in the Blocked state. + * + * @return The length, in bytes, of the message read from the message buffer, if + * any. If xMessageBufferReceive() times out before a message became available + * then zero is returned. If the length of the message is greater than + * xBufferLengthBytes then the message will be left in the message buffer and + * zero is returned. + * + * Example use: +
+void vAFunction( MessageBuffer_t xMessageBuffer )
+{
+uint8_t ucRxData[ 20 ];
+size_t xReceivedBytes;
+const TickType_t xBlockTime = pdMS_TO_TICKS( 20 );
+
+    // Receive the next message from the message buffer.  Wait in the Blocked
+    // state (so not using any CPU processing time) for a maximum of 100ms for
+    // a message to become available.
+    xReceivedBytes = xMessageBufferReceive( xMessageBuffer,
+                                            ( void * ) ucRxData,
+                                            sizeof( ucRxData ),
+                                            xBlockTime );
+
+    if( xReceivedBytes > 0 )
+    {
+        // A ucRxData contains a message that is xReceivedBytes long.  Process
+        // the message here....
+    }
+}
+
+ * \defgroup xMessageBufferReceive xMessageBufferReceive + * \ingroup MessageBufferManagement + */ +#define xMessageBufferReceive( xMessageBuffer, pvRxData, xBufferLengthBytes, xTicksToWait ) xStreamBufferReceive( ( StreamBufferHandle_t ) xMessageBuffer, pvRxData, xBufferLengthBytes, xTicksToWait ) + + +/** + * message_buffer.h + * +
+size_t xMessageBufferReceiveFromISR( MessageBufferHandle_t xMessageBuffer,
+                                     void *pvRxData,
+                                     size_t xBufferLengthBytes,
+                                     BaseType_t *pxHigherPriorityTaskWoken );
+
+ * + * An interrupt safe version of the API function that receives a discrete + * message from a message buffer. Messages can be of variable length and are + * copied out of the buffer. + * + * ***NOTE***: Uniquely among FreeRTOS objects, the stream buffer + * implementation (so also the message buffer implementation, as message buffers + * are built on top of stream buffers) assumes there is only one task or + * interrupt that will write to the buffer (the writer), and only one task or + * interrupt that will read from the buffer (the reader). It is safe for the + * writer and reader to be different tasks or interrupts, but, unlike other + * FreeRTOS objects, it is not safe to have multiple different writers or + * multiple different readers. If there are to be multiple different writers + * then the application writer must place each call to a writing API function + * (such as xMessageBufferSend()) inside a critical section and set the send + * block time to 0. Likewise, if there are to be multiple different readers + * then the application writer must place each call to a reading API function + * (such as xMessageBufferRead()) inside a critical section and set the receive + * block time to 0. + * + * Use xMessageBufferReceive() to read from a message buffer from a task. Use + * xMessageBufferReceiveFromISR() to read from a message buffer from an + * interrupt service routine (ISR). + * + * @param xMessageBuffer The handle of the message buffer from which a message + * is being received. + * + * @param pvRxData A pointer to the buffer into which the received message is + * to be copied. + * + * @param xBufferLengthBytes The length of the buffer pointed to by the pvRxData + * parameter. This sets the maximum length of the message that can be received. + * If xBufferLengthBytes is too small to hold the next message then the message + * will be left in the message buffer and 0 will be returned. + * + * @param pxHigherPriorityTaskWoken It is possible that a message buffer will + * have a task blocked on it waiting for space to become available. Calling + * xMessageBufferReceiveFromISR() can make space available, and so cause a task + * that is waiting for space to leave the Blocked state. If calling + * xMessageBufferReceiveFromISR() causes a task to leave the Blocked state, and + * the unblocked task has a priority higher than the currently executing task + * (the task that was interrupted), then, internally, + * xMessageBufferReceiveFromISR() will set *pxHigherPriorityTaskWoken to pdTRUE. + * If xMessageBufferReceiveFromISR() sets this value to pdTRUE, then normally a + * context switch should be performed before the interrupt is exited. That will + * ensure the interrupt returns directly to the highest priority Ready state + * task. *pxHigherPriorityTaskWoken should be set to pdFALSE before it is + * passed into the function. See the code example below for an example. + * + * @return The length, in bytes, of the message read from the message buffer, if + * any. + * + * Example use: +
+// A message buffer that has already been created.
+MessageBuffer_t xMessageBuffer;
+
+void vAnInterruptServiceRoutine( void )
+{
+uint8_t ucRxData[ 20 ];
+size_t xReceivedBytes;
+BaseType_t xHigherPriorityTaskWoken = pdFALSE;  // Initialised to pdFALSE.
+
+    // Receive the next message from the message buffer.
+    xReceivedBytes = xMessageBufferReceiveFromISR( xMessageBuffer,
+                                                  ( void * ) ucRxData,
+                                                  sizeof( ucRxData ),
+                                                  &xHigherPriorityTaskWoken );
+
+    if( xReceivedBytes > 0 )
+    {
+        // A ucRxData contains a message that is xReceivedBytes long.  Process
+        // the message here....
+    }
+
+    // If xHigherPriorityTaskWoken was set to pdTRUE inside
+    // xMessageBufferReceiveFromISR() then a task that has a priority above the
+    // priority of the currently executing task was unblocked and a context
+    // switch should be performed to ensure the ISR returns to the unblocked
+    // task.  In most FreeRTOS ports this is done by simply passing
+    // xHigherPriorityTaskWoken into portYIELD_FROM_ISR(), which will test the
+    // variables value, and perform the context switch if necessary.  Check the
+    // documentation for the port in use for port specific instructions.
+    portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
+}
+
+ * \defgroup xMessageBufferReceiveFromISR xMessageBufferReceiveFromISR + * \ingroup MessageBufferManagement + */ +#define xMessageBufferReceiveFromISR( xMessageBuffer, pvRxData, xBufferLengthBytes, pxHigherPriorityTaskWoken ) xStreamBufferReceiveFromISR( ( StreamBufferHandle_t ) xMessageBuffer, pvRxData, xBufferLengthBytes, pxHigherPriorityTaskWoken ) + +/** + * message_buffer.h + * +
+void vMessageBufferDelete( MessageBufferHandle_t xMessageBuffer );
+
+ * + * Deletes a message buffer that was previously created using a call to + * xMessageBufferCreate() or xMessageBufferCreateStatic(). If the message + * buffer was created using dynamic memory (that is, by xMessageBufferCreate()), + * then the allocated memory is freed. + * + * A message buffer handle must not be used after the message buffer has been + * deleted. + * + * @param xMessageBuffer The handle of the message buffer to be deleted. + * + */ +#define vMessageBufferDelete( xMessageBuffer ) vStreamBufferDelete( ( StreamBufferHandle_t ) xMessageBuffer ) + +/** + * message_buffer.h +
+BaseType_t xMessageBufferIsFull( MessageBufferHandle_t xMessageBuffer ) );
+
+ * + * Tests to see if a message buffer is full. A message buffer is full if it + * cannot accept any more messages, of any size, until space is made available + * by a message being removed from the message buffer. + * + * @param xMessageBuffer The handle of the message buffer being queried. + * + * @return If the message buffer referenced by xMessageBuffer is full then + * pdTRUE is returned. Otherwise pdFALSE is returned. + */ +#define xMessageBufferIsFull( xMessageBuffer ) xStreamBufferIsFull( ( StreamBufferHandle_t ) xMessageBuffer ) + +/** + * message_buffer.h +
+BaseType_t xMessageBufferIsEmpty( MessageBufferHandle_t xMessageBuffer ) );
+
+ * + * Tests to see if a message buffer is empty (does not contain any messages). + * + * @param xMessageBuffer The handle of the message buffer being queried. + * + * @return If the message buffer referenced by xMessageBuffer is empty then + * pdTRUE is returned. Otherwise pdFALSE is returned. + * + */ +#define xMessageBufferIsEmpty( xMessageBuffer ) xStreamBufferIsEmpty( ( StreamBufferHandle_t ) xMessageBuffer ) + +/** + * message_buffer.h +
+BaseType_t xMessageBufferReset( MessageBufferHandle_t xMessageBuffer );
+
+ * + * Resets a message buffer to its initial empty state, discarding any message it + * contained. + * + * A message buffer can only be reset if there are no tasks blocked on it. + * + * @param xMessageBuffer The handle of the message buffer being reset. + * + * @return If the message buffer was reset then pdPASS is returned. If the + * message buffer could not be reset because either there was a task blocked on + * the message queue to wait for space to become available, or to wait for a + * a message to be available, then pdFAIL is returned. + * + * \defgroup xMessageBufferReset xMessageBufferReset + * \ingroup MessageBufferManagement + */ +#define xMessageBufferReset( xMessageBuffer ) xStreamBufferReset( ( StreamBufferHandle_t ) xMessageBuffer ) + + +/** + * message_buffer.h +
+size_t xMessageBufferSpaceAvailable( MessageBufferHandle_t xMessageBuffer ) );
+
+ * Returns the number of bytes of free space in the message buffer. + * + * @param xMessageBuffer The handle of the message buffer being queried. + * + * @return The number of bytes that can be written to the message buffer before + * the message buffer would be full. When a message is written to the message + * buffer an additional sizeof( size_t ) bytes are also written to store the + * message's length. sizeof( size_t ) is typically 4 bytes on a 32-bit + * architecture, so if xMessageBufferSpacesAvailable() returns 10, then the size + * of the largest message that can be written to the message buffer is 6 bytes. + * + * \defgroup xMessageBufferSpaceAvailable xMessageBufferSpaceAvailable + * \ingroup MessageBufferManagement + */ +#define xMessageBufferSpaceAvailable( xMessageBuffer ) xStreamBufferSpacesAvailable( ( StreamBufferHandle_t ) xMessageBuffer ) +#define xMessageBufferSpacesAvailable( xMessageBuffer ) xStreamBufferSpacesAvailable( ( StreamBufferHandle_t ) xMessageBuffer ) /* Corrects typo in original macro name. */ + +/** + * message_buffer.h +
+ size_t xMessageBufferNextLengthBytes( MessageBufferHandle_t xMessageBuffer ) );
+ 
+ * Returns the length (in bytes) of the next message in a message buffer. + * Useful if xMessageBufferReceive() returned 0 because the size of the buffer + * passed into xMessageBufferReceive() was too small to hold the next message. + * + * @param xMessageBuffer The handle of the message buffer being queried. + * + * @return The length (in bytes) of the next message in the message buffer, or 0 + * if the message buffer is empty. + * + * \defgroup xMessageBufferNextLengthBytes xMessageBufferNextLengthBytes + * \ingroup MessageBufferManagement + */ +#define xMessageBufferNextLengthBytes( xMessageBuffer ) xStreamBufferNextMessageLengthBytes( ( StreamBufferHandle_t ) xMessageBuffer ) PRIVILEGED_FUNCTION; + +/** + * message_buffer.h + * +
+BaseType_t xMessageBufferSendCompletedFromISR( MessageBufferHandle_t xStreamBuffer, BaseType_t *pxHigherPriorityTaskWoken );
+
+ * + * For advanced users only. + * + * The sbSEND_COMPLETED() macro is called from within the FreeRTOS APIs when + * data is sent to a message buffer or stream buffer. If there was a task that + * was blocked on the message or stream buffer waiting for data to arrive then + * the sbSEND_COMPLETED() macro sends a notification to the task to remove it + * from the Blocked state. xMessageBufferSendCompletedFromISR() does the same + * thing. It is provided to enable application writers to implement their own + * version of sbSEND_COMPLETED(), and MUST NOT BE USED AT ANY OTHER TIME. + * + * See the example implemented in FreeRTOS/Demo/Minimal/MessageBufferAMP.c for + * additional information. + * + * @param xStreamBuffer The handle of the stream buffer to which data was + * written. + * + * @param pxHigherPriorityTaskWoken *pxHigherPriorityTaskWoken should be + * initialised to pdFALSE before it is passed into + * xMessageBufferSendCompletedFromISR(). If calling + * xMessageBufferSendCompletedFromISR() removes a task from the Blocked state, + * and the task has a priority above the priority of the currently running task, + * then *pxHigherPriorityTaskWoken will get set to pdTRUE indicating that a + * context switch should be performed before exiting the ISR. + * + * @return If a task was removed from the Blocked state then pdTRUE is returned. + * Otherwise pdFALSE is returned. + * + * \defgroup xMessageBufferSendCompletedFromISR xMessageBufferSendCompletedFromISR + * \ingroup StreamBufferManagement + */ +#define xMessageBufferSendCompletedFromISR( xMessageBuffer, pxHigherPriorityTaskWoken ) xStreamBufferSendCompletedFromISR( ( StreamBufferHandle_t ) xMessageBuffer, pxHigherPriorityTaskWoken ) + +/** + * message_buffer.h + * +
+BaseType_t xMessageBufferReceiveCompletedFromISR( MessageBufferHandle_t xStreamBuffer, BaseType_t *pxHigherPriorityTaskWoken );
+
+ * + * For advanced users only. + * + * The sbRECEIVE_COMPLETED() macro is called from within the FreeRTOS APIs when + * data is read out of a message buffer or stream buffer. If there was a task + * that was blocked on the message or stream buffer waiting for data to arrive + * then the sbRECEIVE_COMPLETED() macro sends a notification to the task to + * remove it from the Blocked state. xMessageBufferReceiveCompletedFromISR() + * does the same thing. It is provided to enable application writers to + * implement their own version of sbRECEIVE_COMPLETED(), and MUST NOT BE USED AT + * ANY OTHER TIME. + * + * See the example implemented in FreeRTOS/Demo/Minimal/MessageBufferAMP.c for + * additional information. + * + * @param xStreamBuffer The handle of the stream buffer from which data was + * read. + * + * @param pxHigherPriorityTaskWoken *pxHigherPriorityTaskWoken should be + * initialised to pdFALSE before it is passed into + * xMessageBufferReceiveCompletedFromISR(). If calling + * xMessageBufferReceiveCompletedFromISR() removes a task from the Blocked state, + * and the task has a priority above the priority of the currently running task, + * then *pxHigherPriorityTaskWoken will get set to pdTRUE indicating that a + * context switch should be performed before exiting the ISR. + * + * @return If a task was removed from the Blocked state then pdTRUE is returned. + * Otherwise pdFALSE is returned. + * + * \defgroup xMessageBufferReceiveCompletedFromISR xMessageBufferReceiveCompletedFromISR + * \ingroup StreamBufferManagement + */ +#define xMessageBufferReceiveCompletedFromISR( xMessageBuffer, pxHigherPriorityTaskWoken ) xStreamBufferReceiveCompletedFromISR( ( StreamBufferHandle_t ) xMessageBuffer, pxHigherPriorityTaskWoken ) + +#if defined( __cplusplus ) +} /* extern "C" */ +#endif + +#endif /* !defined( FREERTOS_MESSAGE_BUFFER_H ) */ diff --git a/Firmware/Board/v3/Middlewares/Third_Party/FreeRTOS/Source/include/mpu_prototypes.h b/Firmware/Board/v3/Middlewares/Third_Party/FreeRTOS/Source/include/mpu_prototypes.h index 8f7500b0..a21b7a66 100644 --- a/Firmware/Board/v3/Middlewares/Third_Party/FreeRTOS/Source/include/mpu_prototypes.h +++ b/Firmware/Board/v3/Middlewares/Third_Party/FreeRTOS/Source/include/mpu_prototypes.h @@ -1,71 +1,29 @@ /* - FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. - All rights reserved - - VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. - - This file is part of the FreeRTOS distribution. - - FreeRTOS is free software; you can redistribute it and/or modify it under - the terms of the GNU General Public License (version 2) as published by the - Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception. - - *************************************************************************** - >>! NOTE: The modification to the GPL is included to allow you to !<< - >>! distribute a combined work that includes FreeRTOS without being !<< - >>! obliged to provide the source code for proprietary components !<< - >>! outside of the FreeRTOS kernel. !<< - *************************************************************************** - - FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - FOR A PARTICULAR PURPOSE. Full license text is available on the following - link: http://www.freertos.org/a00114.html - - *************************************************************************** - * * - * FreeRTOS provides completely free yet professionally developed, * - * robust, strictly quality controlled, supported, and cross * - * platform software that is more than just the market leader, it * - * is the industry's de facto standard. * - * * - * Help yourself get started quickly while simultaneously helping * - * to support the FreeRTOS project by purchasing a FreeRTOS * - * tutorial book, reference manual, or both: * - * http://www.FreeRTOS.org/Documentation * - * * - *************************************************************************** - - http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading - the FAQ page "My application does not run, what could be wrong?". Have you - defined configASSERT()? - - http://www.FreeRTOS.org/support - In return for receiving this top quality - embedded software for free we request you assist our global community by - participating in the support forum. - - http://www.FreeRTOS.org/training - Investing in training allows your team to - be as productive as possible as early as possible. Now you can receive - FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers - Ltd, and the world's leading authority on the world's leading RTOS. - - http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, - including FreeRTOS+Trace - an indispensable productivity tool, a DOS - compatible FAT file system, and our tiny thread aware UDP/IP stack. - - http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. - Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. - - http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High - Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS - licenses offer ticketed support, indemnification and commercial middleware. - - http://www.SafeRTOS.com - High Integrity Systems also provide a safety - engineered and independently SIL3 certified version for use in safety and - mission critical applications that require provable dependability. - - 1 tab == 4 spaces! -*/ + * FreeRTOS Kernel V10.3.1 + * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * http://www.FreeRTOS.org + * http://aws.amazon.com/freertos + * + * 1 tab == 4 spaces! + */ /* * When the MPU is used the standard (non MPU) API functions are mapped to @@ -79,99 +37,124 @@ #ifndef MPU_PROTOTYPES_H #define MPU_PROTOTYPES_H -/* MPU versions of tasks.h API function. */ -BaseType_t MPU_xTaskCreate( TaskFunction_t pxTaskCode, const char * const pcName, const uint16_t usStackDepth, void * const pvParameters, UBaseType_t uxPriority, TaskHandle_t * const pxCreatedTask ); -TaskHandle_t MPU_xTaskCreateStatic( TaskFunction_t pxTaskCode, const char * const pcName, const uint32_t ulStackDepth, void * const pvParameters, UBaseType_t uxPriority, StackType_t * const puxStackBuffer, StaticTask_t * const pxTaskBuffer ); -BaseType_t MPU_xTaskCreateRestricted( const TaskParameters_t * const pxTaskDefinition, TaskHandle_t *pxCreatedTask ); -void MPU_vTaskAllocateMPURegions( TaskHandle_t xTask, const MemoryRegion_t * const pxRegions ); -void MPU_vTaskDelete( TaskHandle_t xTaskToDelete ); -void MPU_vTaskDelay( const TickType_t xTicksToDelay ); -void MPU_vTaskDelayUntil( TickType_t * const pxPreviousWakeTime, const TickType_t xTimeIncrement ); -BaseType_t MPU_xTaskAbortDelay( TaskHandle_t xTask ); -UBaseType_t MPU_uxTaskPriorityGet( TaskHandle_t xTask ); -eTaskState MPU_eTaskGetState( TaskHandle_t xTask ); -void MPU_vTaskGetInfo( TaskHandle_t xTask, TaskStatus_t *pxTaskStatus, BaseType_t xGetFreeStackSpace, eTaskState eState ); -void MPU_vTaskPrioritySet( TaskHandle_t xTask, UBaseType_t uxNewPriority ); -void MPU_vTaskSuspend( TaskHandle_t xTaskToSuspend ); -void MPU_vTaskResume( TaskHandle_t xTaskToResume ); -void MPU_vTaskStartScheduler( void ); -void MPU_vTaskSuspendAll( void ); -BaseType_t MPU_xTaskResumeAll( void ); -TickType_t MPU_xTaskGetTickCount( void ); -UBaseType_t MPU_uxTaskGetNumberOfTasks( void ); -char * MPU_pcTaskGetName( TaskHandle_t xTaskToQuery ); -TaskHandle_t MPU_xTaskGetHandle( const char *pcNameToQuery ); -UBaseType_t MPU_uxTaskGetStackHighWaterMark( TaskHandle_t xTask ); -void MPU_vTaskSetApplicationTaskTag( TaskHandle_t xTask, TaskHookFunction_t pxHookFunction ); -TaskHookFunction_t MPU_xTaskGetApplicationTaskTag( TaskHandle_t xTask ); -void MPU_vTaskSetThreadLocalStoragePointer( TaskHandle_t xTaskToSet, BaseType_t xIndex, void *pvValue ); -void * MPU_pvTaskGetThreadLocalStoragePointer( TaskHandle_t xTaskToQuery, BaseType_t xIndex ); -BaseType_t MPU_xTaskCallApplicationTaskHook( TaskHandle_t xTask, void *pvParameter ); -TaskHandle_t MPU_xTaskGetIdleTaskHandle( void ); -UBaseType_t MPU_uxTaskGetSystemState( TaskStatus_t * const pxTaskStatusArray, const UBaseType_t uxArraySize, uint32_t * const pulTotalRunTime ); -void MPU_vTaskList( char * pcWriteBuffer ); -void MPU_vTaskGetRunTimeStats( char *pcWriteBuffer ); -BaseType_t MPU_xTaskGenericNotify( TaskHandle_t xTaskToNotify, uint32_t ulValue, eNotifyAction eAction, uint32_t *pulPreviousNotificationValue ); -BaseType_t MPU_xTaskNotifyWait( uint32_t ulBitsToClearOnEntry, uint32_t ulBitsToClearOnExit, uint32_t *pulNotificationValue, TickType_t xTicksToWait ); -uint32_t MPU_ulTaskNotifyTake( BaseType_t xClearCountOnExit, TickType_t xTicksToWait ); -BaseType_t MPU_xTaskNotifyStateClear( TaskHandle_t xTask ); -BaseType_t MPU_xTaskIncrementTick( void ); -TaskHandle_t MPU_xTaskGetCurrentTaskHandle( void ); -void MPU_vTaskSetTimeOutState( TimeOut_t * const pxTimeOut ); -BaseType_t MPU_xTaskCheckForTimeOut( TimeOut_t * const pxTimeOut, TickType_t * const pxTicksToWait ); -void MPU_vTaskMissedYield( void ); -BaseType_t MPU_xTaskGetSchedulerState( void ); +/* MPU versions of tasks.h API functions. */ +BaseType_t MPU_xTaskCreate( TaskFunction_t pxTaskCode, const char * const pcName, const uint16_t usStackDepth, void * const pvParameters, UBaseType_t uxPriority, TaskHandle_t * const pxCreatedTask ) FREERTOS_SYSTEM_CALL; +TaskHandle_t MPU_xTaskCreateStatic( TaskFunction_t pxTaskCode, const char * const pcName, const uint32_t ulStackDepth, void * const pvParameters, UBaseType_t uxPriority, StackType_t * const puxStackBuffer, StaticTask_t * const pxTaskBuffer ) FREERTOS_SYSTEM_CALL; +BaseType_t MPU_xTaskCreateRestricted( const TaskParameters_t * const pxTaskDefinition, TaskHandle_t *pxCreatedTask ) FREERTOS_SYSTEM_CALL; +BaseType_t MPU_xTaskCreateRestrictedStatic( const TaskParameters_t * const pxTaskDefinition, TaskHandle_t *pxCreatedTask ) FREERTOS_SYSTEM_CALL; +void MPU_vTaskAllocateMPURegions( TaskHandle_t xTask, const MemoryRegion_t * const pxRegions ) FREERTOS_SYSTEM_CALL; +void MPU_vTaskDelete( TaskHandle_t xTaskToDelete ) FREERTOS_SYSTEM_CALL; +void MPU_vTaskDelay( const TickType_t xTicksToDelay ) FREERTOS_SYSTEM_CALL; +void MPU_vTaskDelayUntil( TickType_t * const pxPreviousWakeTime, const TickType_t xTimeIncrement ) FREERTOS_SYSTEM_CALL; +BaseType_t MPU_xTaskAbortDelay( TaskHandle_t xTask ) FREERTOS_SYSTEM_CALL; +UBaseType_t MPU_uxTaskPriorityGet( const TaskHandle_t xTask ) FREERTOS_SYSTEM_CALL; +eTaskState MPU_eTaskGetState( TaskHandle_t xTask ) FREERTOS_SYSTEM_CALL; +void MPU_vTaskGetInfo( TaskHandle_t xTask, TaskStatus_t *pxTaskStatus, BaseType_t xGetFreeStackSpace, eTaskState eState ) FREERTOS_SYSTEM_CALL; +void MPU_vTaskPrioritySet( TaskHandle_t xTask, UBaseType_t uxNewPriority ) FREERTOS_SYSTEM_CALL; +void MPU_vTaskSuspend( TaskHandle_t xTaskToSuspend ) FREERTOS_SYSTEM_CALL; +void MPU_vTaskResume( TaskHandle_t xTaskToResume ) FREERTOS_SYSTEM_CALL; +void MPU_vTaskStartScheduler( void ) FREERTOS_SYSTEM_CALL; +void MPU_vTaskSuspendAll( void ) FREERTOS_SYSTEM_CALL; +BaseType_t MPU_xTaskResumeAll( void ) FREERTOS_SYSTEM_CALL; +TickType_t MPU_xTaskGetTickCount( void ) FREERTOS_SYSTEM_CALL; +UBaseType_t MPU_uxTaskGetNumberOfTasks( void ) FREERTOS_SYSTEM_CALL; +char * MPU_pcTaskGetName( TaskHandle_t xTaskToQuery ) FREERTOS_SYSTEM_CALL; +TaskHandle_t MPU_xTaskGetHandle( const char *pcNameToQuery ) FREERTOS_SYSTEM_CALL; +UBaseType_t MPU_uxTaskGetStackHighWaterMark( TaskHandle_t xTask ) FREERTOS_SYSTEM_CALL; +configSTACK_DEPTH_TYPE MPU_uxTaskGetStackHighWaterMark2( TaskHandle_t xTask ) FREERTOS_SYSTEM_CALL; +void MPU_vTaskSetApplicationTaskTag( TaskHandle_t xTask, TaskHookFunction_t pxHookFunction ) FREERTOS_SYSTEM_CALL; +TaskHookFunction_t MPU_xTaskGetApplicationTaskTag( TaskHandle_t xTask ) FREERTOS_SYSTEM_CALL; +void MPU_vTaskSetThreadLocalStoragePointer( TaskHandle_t xTaskToSet, BaseType_t xIndex, void *pvValue ) FREERTOS_SYSTEM_CALL; +void * MPU_pvTaskGetThreadLocalStoragePointer( TaskHandle_t xTaskToQuery, BaseType_t xIndex ) FREERTOS_SYSTEM_CALL; +BaseType_t MPU_xTaskCallApplicationTaskHook( TaskHandle_t xTask, void *pvParameter ) FREERTOS_SYSTEM_CALL; +TaskHandle_t MPU_xTaskGetIdleTaskHandle( void ) FREERTOS_SYSTEM_CALL; +UBaseType_t MPU_uxTaskGetSystemState( TaskStatus_t * const pxTaskStatusArray, const UBaseType_t uxArraySize, uint32_t * const pulTotalRunTime ) FREERTOS_SYSTEM_CALL; +uint32_t MPU_ulTaskGetIdleRunTimeCounter( void ) FREERTOS_SYSTEM_CALL; +void MPU_vTaskList( char * pcWriteBuffer ) FREERTOS_SYSTEM_CALL; +void MPU_vTaskGetRunTimeStats( char *pcWriteBuffer ) FREERTOS_SYSTEM_CALL; +BaseType_t MPU_xTaskGenericNotify( TaskHandle_t xTaskToNotify, uint32_t ulValue, eNotifyAction eAction, uint32_t *pulPreviousNotificationValue ) FREERTOS_SYSTEM_CALL; +BaseType_t MPU_xTaskNotifyWait( uint32_t ulBitsToClearOnEntry, uint32_t ulBitsToClearOnExit, uint32_t *pulNotificationValue, TickType_t xTicksToWait ) FREERTOS_SYSTEM_CALL; +uint32_t MPU_ulTaskNotifyTake( BaseType_t xClearCountOnExit, TickType_t xTicksToWait ) FREERTOS_SYSTEM_CALL; +BaseType_t MPU_xTaskNotifyStateClear( TaskHandle_t xTask ) FREERTOS_SYSTEM_CALL; +uint32_t MPU_ulTaskNotifyValueClear( TaskHandle_t xTask, uint32_t ulBitsToClear ) FREERTOS_SYSTEM_CALL; +BaseType_t MPU_xTaskIncrementTick( void ) FREERTOS_SYSTEM_CALL; +TaskHandle_t MPU_xTaskGetCurrentTaskHandle( void ) FREERTOS_SYSTEM_CALL; +void MPU_vTaskSetTimeOutState( TimeOut_t * const pxTimeOut ) FREERTOS_SYSTEM_CALL; +BaseType_t MPU_xTaskCheckForTimeOut( TimeOut_t * const pxTimeOut, TickType_t * const pxTicksToWait ) FREERTOS_SYSTEM_CALL; +void MPU_vTaskMissedYield( void ) FREERTOS_SYSTEM_CALL; +BaseType_t MPU_xTaskGetSchedulerState( void ) FREERTOS_SYSTEM_CALL; +BaseType_t MPU_xTaskCatchUpTicks( TickType_t xTicksToCatchUp ) FREERTOS_SYSTEM_CALL; -/* MPU versions of queue.h API function. */ -BaseType_t MPU_xQueueGenericSend( QueueHandle_t xQueue, const void * const pvItemToQueue, TickType_t xTicksToWait, const BaseType_t xCopyPosition ); -BaseType_t MPU_xQueueGenericReceive( QueueHandle_t xQueue, void * const pvBuffer, TickType_t xTicksToWait, const BaseType_t xJustPeek ); -UBaseType_t MPU_uxQueueMessagesWaiting( const QueueHandle_t xQueue ); -UBaseType_t MPU_uxQueueSpacesAvailable( const QueueHandle_t xQueue ); -void MPU_vQueueDelete( QueueHandle_t xQueue ); -QueueHandle_t MPU_xQueueCreateMutex( const uint8_t ucQueueType ); -QueueHandle_t MPU_xQueueCreateMutexStatic( const uint8_t ucQueueType, StaticQueue_t *pxStaticQueue ); -QueueHandle_t MPU_xQueueCreateCountingSemaphore( const UBaseType_t uxMaxCount, const UBaseType_t uxInitialCount ); -QueueHandle_t MPU_xQueueCreateCountingSemaphoreStatic( const UBaseType_t uxMaxCount, const UBaseType_t uxInitialCount, StaticQueue_t *pxStaticQueue ); -void* MPU_xQueueGetMutexHolder( QueueHandle_t xSemaphore ); -BaseType_t MPU_xQueueTakeMutexRecursive( QueueHandle_t xMutex, TickType_t xTicksToWait ); -BaseType_t MPU_xQueueGiveMutexRecursive( QueueHandle_t pxMutex ); -void MPU_vQueueAddToRegistry( QueueHandle_t xQueue, const char *pcName ); -void MPU_vQueueUnregisterQueue( QueueHandle_t xQueue ); -const char * MPU_pcQueueGetName( QueueHandle_t xQueue ); -QueueHandle_t MPU_xQueueGenericCreate( const UBaseType_t uxQueueLength, const UBaseType_t uxItemSize, const uint8_t ucQueueType ); -QueueHandle_t MPU_xQueueGenericCreateStatic( const UBaseType_t uxQueueLength, const UBaseType_t uxItemSize, uint8_t *pucQueueStorage, StaticQueue_t *pxStaticQueue, const uint8_t ucQueueType ); -QueueSetHandle_t MPU_xQueueCreateSet( const UBaseType_t uxEventQueueLength ); -BaseType_t MPU_xQueueAddToSet( QueueSetMemberHandle_t xQueueOrSemaphore, QueueSetHandle_t xQueueSet ); -BaseType_t MPU_xQueueRemoveFromSet( QueueSetMemberHandle_t xQueueOrSemaphore, QueueSetHandle_t xQueueSet ); -QueueSetMemberHandle_t MPU_xQueueSelectFromSet( QueueSetHandle_t xQueueSet, const TickType_t xTicksToWait ); -BaseType_t MPU_xQueueGenericReset( QueueHandle_t xQueue, BaseType_t xNewQueue ); -void MPU_vQueueSetQueueNumber( QueueHandle_t xQueue, UBaseType_t uxQueueNumber ); -UBaseType_t MPU_uxQueueGetQueueNumber( QueueHandle_t xQueue ); -uint8_t MPU_ucQueueGetQueueType( QueueHandle_t xQueue ); +/* MPU versions of queue.h API functions. */ +BaseType_t MPU_xQueueGenericSend( QueueHandle_t xQueue, const void * const pvItemToQueue, TickType_t xTicksToWait, const BaseType_t xCopyPosition ) FREERTOS_SYSTEM_CALL; +BaseType_t MPU_xQueueReceive( QueueHandle_t xQueue, void * const pvBuffer, TickType_t xTicksToWait ) FREERTOS_SYSTEM_CALL; +BaseType_t MPU_xQueuePeek( QueueHandle_t xQueue, void * const pvBuffer, TickType_t xTicksToWait ) FREERTOS_SYSTEM_CALL; +BaseType_t MPU_xQueueSemaphoreTake( QueueHandle_t xQueue, TickType_t xTicksToWait ) FREERTOS_SYSTEM_CALL; +UBaseType_t MPU_uxQueueMessagesWaiting( const QueueHandle_t xQueue ) FREERTOS_SYSTEM_CALL; +UBaseType_t MPU_uxQueueSpacesAvailable( const QueueHandle_t xQueue ) FREERTOS_SYSTEM_CALL; +void MPU_vQueueDelete( QueueHandle_t xQueue ) FREERTOS_SYSTEM_CALL; +QueueHandle_t MPU_xQueueCreateMutex( const uint8_t ucQueueType ) FREERTOS_SYSTEM_CALL; +QueueHandle_t MPU_xQueueCreateMutexStatic( const uint8_t ucQueueType, StaticQueue_t *pxStaticQueue ) FREERTOS_SYSTEM_CALL; +QueueHandle_t MPU_xQueueCreateCountingSemaphore( const UBaseType_t uxMaxCount, const UBaseType_t uxInitialCount ) FREERTOS_SYSTEM_CALL; +QueueHandle_t MPU_xQueueCreateCountingSemaphoreStatic( const UBaseType_t uxMaxCount, const UBaseType_t uxInitialCount, StaticQueue_t *pxStaticQueue ) FREERTOS_SYSTEM_CALL; +TaskHandle_t MPU_xQueueGetMutexHolder( QueueHandle_t xSemaphore ) FREERTOS_SYSTEM_CALL; +BaseType_t MPU_xQueueTakeMutexRecursive( QueueHandle_t xMutex, TickType_t xTicksToWait ) FREERTOS_SYSTEM_CALL; +BaseType_t MPU_xQueueGiveMutexRecursive( QueueHandle_t pxMutex ) FREERTOS_SYSTEM_CALL; +void MPU_vQueueAddToRegistry( QueueHandle_t xQueue, const char *pcName ) FREERTOS_SYSTEM_CALL; +void MPU_vQueueUnregisterQueue( QueueHandle_t xQueue ) FREERTOS_SYSTEM_CALL; +const char * MPU_pcQueueGetName( QueueHandle_t xQueue ) FREERTOS_SYSTEM_CALL; +QueueHandle_t MPU_xQueueGenericCreate( const UBaseType_t uxQueueLength, const UBaseType_t uxItemSize, const uint8_t ucQueueType ) FREERTOS_SYSTEM_CALL; +QueueHandle_t MPU_xQueueGenericCreateStatic( const UBaseType_t uxQueueLength, const UBaseType_t uxItemSize, uint8_t *pucQueueStorage, StaticQueue_t *pxStaticQueue, const uint8_t ucQueueType ) FREERTOS_SYSTEM_CALL; +QueueSetHandle_t MPU_xQueueCreateSet( const UBaseType_t uxEventQueueLength ) FREERTOS_SYSTEM_CALL; +BaseType_t MPU_xQueueAddToSet( QueueSetMemberHandle_t xQueueOrSemaphore, QueueSetHandle_t xQueueSet ) FREERTOS_SYSTEM_CALL; +BaseType_t MPU_xQueueRemoveFromSet( QueueSetMemberHandle_t xQueueOrSemaphore, QueueSetHandle_t xQueueSet ) FREERTOS_SYSTEM_CALL; +QueueSetMemberHandle_t MPU_xQueueSelectFromSet( QueueSetHandle_t xQueueSet, const TickType_t xTicksToWait ) FREERTOS_SYSTEM_CALL; +BaseType_t MPU_xQueueGenericReset( QueueHandle_t xQueue, BaseType_t xNewQueue ) FREERTOS_SYSTEM_CALL; +void MPU_vQueueSetQueueNumber( QueueHandle_t xQueue, UBaseType_t uxQueueNumber ) FREERTOS_SYSTEM_CALL; +UBaseType_t MPU_uxQueueGetQueueNumber( QueueHandle_t xQueue ) FREERTOS_SYSTEM_CALL; +uint8_t MPU_ucQueueGetQueueType( QueueHandle_t xQueue ) FREERTOS_SYSTEM_CALL; + +/* MPU versions of timers.h API functions. */ +TimerHandle_t MPU_xTimerCreate( const char * const pcTimerName, const TickType_t xTimerPeriodInTicks, const UBaseType_t uxAutoReload, void * const pvTimerID, TimerCallbackFunction_t pxCallbackFunction ) FREERTOS_SYSTEM_CALL; +TimerHandle_t MPU_xTimerCreateStatic( const char * const pcTimerName, const TickType_t xTimerPeriodInTicks, const UBaseType_t uxAutoReload, void * const pvTimerID, TimerCallbackFunction_t pxCallbackFunction, StaticTimer_t *pxTimerBuffer ) FREERTOS_SYSTEM_CALL; +void * MPU_pvTimerGetTimerID( const TimerHandle_t xTimer ) FREERTOS_SYSTEM_CALL; +void MPU_vTimerSetTimerID( TimerHandle_t xTimer, void *pvNewID ) FREERTOS_SYSTEM_CALL; +BaseType_t MPU_xTimerIsTimerActive( TimerHandle_t xTimer ) FREERTOS_SYSTEM_CALL; +TaskHandle_t MPU_xTimerGetTimerDaemonTaskHandle( void ) FREERTOS_SYSTEM_CALL; +BaseType_t MPU_xTimerPendFunctionCall( PendedFunction_t xFunctionToPend, void *pvParameter1, uint32_t ulParameter2, TickType_t xTicksToWait ) FREERTOS_SYSTEM_CALL; +const char * MPU_pcTimerGetName( TimerHandle_t xTimer ) FREERTOS_SYSTEM_CALL; +void MPU_vTimerSetReloadMode( TimerHandle_t xTimer, const UBaseType_t uxAutoReload ) FREERTOS_SYSTEM_CALL; +UBaseType_t MPU_uxTimerGetReloadMode( TimerHandle_t xTimer ) FREERTOS_SYSTEM_CALL; +TickType_t MPU_xTimerGetPeriod( TimerHandle_t xTimer ) FREERTOS_SYSTEM_CALL; +TickType_t MPU_xTimerGetExpiryTime( TimerHandle_t xTimer ) FREERTOS_SYSTEM_CALL; +BaseType_t MPU_xTimerCreateTimerTask( void ) FREERTOS_SYSTEM_CALL; +BaseType_t MPU_xTimerGenericCommand( TimerHandle_t xTimer, const BaseType_t xCommandID, const TickType_t xOptionalValue, BaseType_t * const pxHigherPriorityTaskWoken, const TickType_t xTicksToWait ) FREERTOS_SYSTEM_CALL; + +/* MPU versions of event_group.h API functions. */ +EventGroupHandle_t MPU_xEventGroupCreate( void ) FREERTOS_SYSTEM_CALL; +EventGroupHandle_t MPU_xEventGroupCreateStatic( StaticEventGroup_t *pxEventGroupBuffer ) FREERTOS_SYSTEM_CALL; +EventBits_t MPU_xEventGroupWaitBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToWaitFor, const BaseType_t xClearOnExit, const BaseType_t xWaitForAllBits, TickType_t xTicksToWait ) FREERTOS_SYSTEM_CALL; +EventBits_t MPU_xEventGroupClearBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToClear ) FREERTOS_SYSTEM_CALL; +EventBits_t MPU_xEventGroupSetBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet ) FREERTOS_SYSTEM_CALL; +EventBits_t MPU_xEventGroupSync( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet, const EventBits_t uxBitsToWaitFor, TickType_t xTicksToWait ) FREERTOS_SYSTEM_CALL; +void MPU_vEventGroupDelete( EventGroupHandle_t xEventGroup ) FREERTOS_SYSTEM_CALL; +UBaseType_t MPU_uxEventGroupGetNumber( void* xEventGroup ) FREERTOS_SYSTEM_CALL; + +/* MPU versions of message/stream_buffer.h API functions. */ +size_t MPU_xStreamBufferSend( StreamBufferHandle_t xStreamBuffer, const void *pvTxData, size_t xDataLengthBytes, TickType_t xTicksToWait ) FREERTOS_SYSTEM_CALL; +size_t MPU_xStreamBufferReceive( StreamBufferHandle_t xStreamBuffer, void *pvRxData, size_t xBufferLengthBytes, TickType_t xTicksToWait ) FREERTOS_SYSTEM_CALL; +size_t MPU_xStreamBufferNextMessageLengthBytes( StreamBufferHandle_t xStreamBuffer ) FREERTOS_SYSTEM_CALL; +void MPU_vStreamBufferDelete( StreamBufferHandle_t xStreamBuffer ) FREERTOS_SYSTEM_CALL; +BaseType_t MPU_xStreamBufferIsFull( StreamBufferHandle_t xStreamBuffer ) FREERTOS_SYSTEM_CALL; +BaseType_t MPU_xStreamBufferIsEmpty( StreamBufferHandle_t xStreamBuffer ) FREERTOS_SYSTEM_CALL; +BaseType_t MPU_xStreamBufferReset( StreamBufferHandle_t xStreamBuffer ) FREERTOS_SYSTEM_CALL; +size_t MPU_xStreamBufferSpacesAvailable( StreamBufferHandle_t xStreamBuffer ) FREERTOS_SYSTEM_CALL; +size_t MPU_xStreamBufferBytesAvailable( StreamBufferHandle_t xStreamBuffer ) FREERTOS_SYSTEM_CALL; +BaseType_t MPU_xStreamBufferSetTriggerLevel( StreamBufferHandle_t xStreamBuffer, size_t xTriggerLevel ) FREERTOS_SYSTEM_CALL; +StreamBufferHandle_t MPU_xStreamBufferGenericCreate( size_t xBufferSizeBytes, size_t xTriggerLevelBytes, BaseType_t xIsMessageBuffer ) FREERTOS_SYSTEM_CALL; +StreamBufferHandle_t MPU_xStreamBufferGenericCreateStatic( size_t xBufferSizeBytes, size_t xTriggerLevelBytes, BaseType_t xIsMessageBuffer, uint8_t * const pucStreamBufferStorageArea, StaticStreamBuffer_t * const pxStaticStreamBuffer ) FREERTOS_SYSTEM_CALL; -/* MPU versions of timers.h API function. */ -TimerHandle_t MPU_xTimerCreate( const char * const pcTimerName, const TickType_t xTimerPeriodInTicks, const UBaseType_t uxAutoReload, void * const pvTimerID, TimerCallbackFunction_t pxCallbackFunction ); -TimerHandle_t MPU_xTimerCreateStatic( const char * const pcTimerName, const TickType_t xTimerPeriodInTicks, const UBaseType_t uxAutoReload, void * const pvTimerID, TimerCallbackFunction_t pxCallbackFunction, StaticTimer_t *pxTimerBuffer ); -void * MPU_pvTimerGetTimerID( const TimerHandle_t xTimer ); -void MPU_vTimerSetTimerID( TimerHandle_t xTimer, void *pvNewID ); -BaseType_t MPU_xTimerIsTimerActive( TimerHandle_t xTimer ); -TaskHandle_t MPU_xTimerGetTimerDaemonTaskHandle( void ); -BaseType_t MPU_xTimerPendFunctionCall( PendedFunction_t xFunctionToPend, void *pvParameter1, uint32_t ulParameter2, TickType_t xTicksToWait ); -const char * MPU_pcTimerGetName( TimerHandle_t xTimer ); -TickType_t MPU_xTimerGetPeriod( TimerHandle_t xTimer ); -TickType_t MPU_xTimerGetExpiryTime( TimerHandle_t xTimer ); -BaseType_t MPU_xTimerCreateTimerTask( void ); -BaseType_t MPU_xTimerGenericCommand( TimerHandle_t xTimer, const BaseType_t xCommandID, const TickType_t xOptionalValue, BaseType_t * const pxHigherPriorityTaskWoken, const TickType_t xTicksToWait ); -/* MPU versions of event_group.h API function. */ -EventGroupHandle_t MPU_xEventGroupCreate( void ); -EventGroupHandle_t MPU_xEventGroupCreateStatic( StaticEventGroup_t *pxEventGroupBuffer ); -EventBits_t MPU_xEventGroupWaitBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToWaitFor, const BaseType_t xClearOnExit, const BaseType_t xWaitForAllBits, TickType_t xTicksToWait ); -EventBits_t MPU_xEventGroupClearBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToClear ); -EventBits_t MPU_xEventGroupSetBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet ); -EventBits_t MPU_xEventGroupSync( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet, const EventBits_t uxBitsToWaitFor, TickType_t xTicksToWait ); -void MPU_vEventGroupDelete( EventGroupHandle_t xEventGroup ); -UBaseType_t MPU_uxEventGroupGetNumber( void* xEventGroup ); #endif /* MPU_PROTOTYPES_H */ diff --git a/Firmware/Board/v3/Middlewares/Third_Party/FreeRTOS/Source/include/mpu_wrappers.h b/Firmware/Board/v3/Middlewares/Third_Party/FreeRTOS/Source/include/mpu_wrappers.h index 1a05c9fd..5f63d4f2 100644 --- a/Firmware/Board/v3/Middlewares/Third_Party/FreeRTOS/Source/include/mpu_wrappers.h +++ b/Firmware/Board/v3/Middlewares/Third_Party/FreeRTOS/Source/include/mpu_wrappers.h @@ -1,71 +1,29 @@ /* - FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. - All rights reserved - - VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. - - This file is part of the FreeRTOS distribution. - - FreeRTOS is free software; you can redistribute it and/or modify it under - the terms of the GNU General Public License (version 2) as published by the - Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception. - - *************************************************************************** - >>! NOTE: The modification to the GPL is included to allow you to !<< - >>! distribute a combined work that includes FreeRTOS without being !<< - >>! obliged to provide the source code for proprietary components !<< - >>! outside of the FreeRTOS kernel. !<< - *************************************************************************** - - FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - FOR A PARTICULAR PURPOSE. Full license text is available on the following - link: http://www.freertos.org/a00114.html - - *************************************************************************** - * * - * FreeRTOS provides completely free yet professionally developed, * - * robust, strictly quality controlled, supported, and cross * - * platform software that is more than just the market leader, it * - * is the industry's de facto standard. * - * * - * Help yourself get started quickly while simultaneously helping * - * to support the FreeRTOS project by purchasing a FreeRTOS * - * tutorial book, reference manual, or both: * - * http://www.FreeRTOS.org/Documentation * - * * - *************************************************************************** - - http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading - the FAQ page "My application does not run, what could be wrong?". Have you - defined configASSERT()? - - http://www.FreeRTOS.org/support - In return for receiving this top quality - embedded software for free we request you assist our global community by - participating in the support forum. - - http://www.FreeRTOS.org/training - Investing in training allows your team to - be as productive as possible as early as possible. Now you can receive - FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers - Ltd, and the world's leading authority on the world's leading RTOS. - - http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, - including FreeRTOS+Trace - an indispensable productivity tool, a DOS - compatible FAT file system, and our tiny thread aware UDP/IP stack. - - http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. - Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. - - http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High - Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS - licenses offer ticketed support, indemnification and commercial middleware. - - http://www.SafeRTOS.com - High Integrity Systems also provide a safety - engineered and independently SIL3 certified version for use in safety and - mission critical applications that require provable dependability. - - 1 tab == 4 spaces! -*/ + * FreeRTOS Kernel V10.3.1 + * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * http://www.FreeRTOS.org + * http://aws.amazon.com/freertos + * + * 1 tab == 4 spaces! + */ #ifndef MPU_WRAPPERS_H #define MPU_WRAPPERS_H @@ -109,6 +67,7 @@ only for ports that are using the MPU. */ #define pcTaskGetName MPU_pcTaskGetName #define xTaskGetHandle MPU_xTaskGetHandle #define uxTaskGetStackHighWaterMark MPU_uxTaskGetStackHighWaterMark + #define uxTaskGetStackHighWaterMark2 MPU_uxTaskGetStackHighWaterMark2 #define vTaskSetApplicationTaskTag MPU_vTaskSetApplicationTaskTag #define xTaskGetApplicationTaskTag MPU_xTaskGetApplicationTaskTag #define vTaskSetThreadLocalStoragePointer MPU_vTaskSetThreadLocalStoragePointer @@ -118,10 +77,13 @@ only for ports that are using the MPU. */ #define uxTaskGetSystemState MPU_uxTaskGetSystemState #define vTaskList MPU_vTaskList #define vTaskGetRunTimeStats MPU_vTaskGetRunTimeStats + #define ulTaskGetIdleRunTimeCounter MPU_ulTaskGetIdleRunTimeCounter #define xTaskGenericNotify MPU_xTaskGenericNotify #define xTaskNotifyWait MPU_xTaskNotifyWait #define ulTaskNotifyTake MPU_ulTaskNotifyTake #define xTaskNotifyStateClear MPU_xTaskNotifyStateClear + #define ulTaskNotifyValueClear MPU_ulTaskNotifyValueClear + #define xTaskCatchUpTicks MPU_xTaskCatchUpTicks #define xTaskGetCurrentTaskHandle MPU_xTaskGetCurrentTaskHandle #define vTaskSetTimeOutState MPU_vTaskSetTimeOutState @@ -130,7 +92,9 @@ only for ports that are using the MPU. */ /* Map standard queue.h API functions to the MPU equivalents. */ #define xQueueGenericSend MPU_xQueueGenericSend - #define xQueueGenericReceive MPU_xQueueGenericReceive + #define xQueueReceive MPU_xQueueReceive + #define xQueuePeek MPU_xQueuePeek + #define xQueueSemaphoreTake MPU_xQueueSemaphoreTake #define uxQueueMessagesWaiting MPU_uxQueueMessagesWaiting #define uxQueueSpacesAvailable MPU_uxQueueSpacesAvailable #define vQueueDelete MPU_vQueueDelete @@ -164,6 +128,8 @@ only for ports that are using the MPU. */ #define xTimerGetTimerDaemonTaskHandle MPU_xTimerGetTimerDaemonTaskHandle #define xTimerPendFunctionCall MPU_xTimerPendFunctionCall #define pcTimerGetName MPU_pcTimerGetName + #define vTimerSetReloadMode MPU_vTimerSetReloadMode + #define uxTimerGetReloadMode MPU_uxTimerGetReloadMode #define xTimerGetPeriod MPU_xTimerGetPeriod #define xTimerGetExpiryTime MPU_xTimerGetExpiryTime #define xTimerGenericCommand MPU_xTimerGenericCommand @@ -177,25 +143,35 @@ only for ports that are using the MPU. */ #define xEventGroupSync MPU_xEventGroupSync #define vEventGroupDelete MPU_vEventGroupDelete - /* Remove the privileged function macro. */ + /* Map standard message/stream_buffer.h API functions to the MPU + equivalents. */ + #define xStreamBufferSend MPU_xStreamBufferSend + #define xStreamBufferReceive MPU_xStreamBufferReceive + #define xStreamBufferNextMessageLengthBytes MPU_xStreamBufferNextMessageLengthBytes + #define vStreamBufferDelete MPU_vStreamBufferDelete + #define xStreamBufferIsFull MPU_xStreamBufferIsFull + #define xStreamBufferIsEmpty MPU_xStreamBufferIsEmpty + #define xStreamBufferReset MPU_xStreamBufferReset + #define xStreamBufferSpacesAvailable MPU_xStreamBufferSpacesAvailable + #define xStreamBufferBytesAvailable MPU_xStreamBufferBytesAvailable + #define xStreamBufferSetTriggerLevel MPU_xStreamBufferSetTriggerLevel + #define xStreamBufferGenericCreate MPU_xStreamBufferGenericCreate + #define xStreamBufferGenericCreateStatic MPU_xStreamBufferGenericCreateStatic + + + /* Remove the privileged function macro, but keep the PRIVILEGED_DATA + macro so applications can place data in privileged access sections + (useful when using statically allocated objects). */ #define PRIVILEGED_FUNCTION + #define PRIVILEGED_DATA __attribute__((section("privileged_data"))) + #define FREERTOS_SYSTEM_CALL #else /* MPU_WRAPPERS_INCLUDED_FROM_API_FILE */ /* Ensure API functions go in the privileged execution section. */ -#if defined(__ICCARM__) - -#define PRIVILEGED_FUNCTION _Pragma("location= \"privileged_functions\"") -#define PRIVILEGED_DATA _Pragma("location= \"privileged_data\"") -#define PRIVILEGED_INITIALIZED_DATA _Pragma("location= \"privileged_initialized_data\"") - -#else - -#define PRIVILEGED_FUNCTION __attribute__((section("privileged_functions"))) -#define PRIVILEGED_DATA __attribute__((section("privileged_data"))) -#define PRIVILEGED_INITIALIZED_DATA PRIVILEGED_DATA - -#endif + #define PRIVILEGED_FUNCTION __attribute__((section("privileged_functions"))) + #define PRIVILEGED_DATA __attribute__((section("privileged_data"))) + #define FREERTOS_SYSTEM_CALL __attribute__((section( "freertos_system_calls"))) #endif /* MPU_WRAPPERS_INCLUDED_FROM_API_FILE */ @@ -203,7 +179,7 @@ only for ports that are using the MPU. */ #define PRIVILEGED_FUNCTION #define PRIVILEGED_DATA - #define PRIVILEGED_INITIALIZED_DATA + #define FREERTOS_SYSTEM_CALL #define portUSING_MPU_WRAPPERS 0 #endif /* portUSING_MPU_WRAPPERS */ diff --git a/Firmware/Board/v3/Middlewares/Third_Party/FreeRTOS/Source/include/portable.h b/Firmware/Board/v3/Middlewares/Third_Party/FreeRTOS/Source/include/portable.h index 00a22086..a2099c33 100644 --- a/Firmware/Board/v3/Middlewares/Third_Party/FreeRTOS/Source/include/portable.h +++ b/Firmware/Board/v3/Middlewares/Third_Party/FreeRTOS/Source/include/portable.h @@ -1,71 +1,29 @@ /* - FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. - All rights reserved - - VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. - - This file is part of the FreeRTOS distribution. - - FreeRTOS is free software; you can redistribute it and/or modify it under - the terms of the GNU General Public License (version 2) as published by the - Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception. - - *************************************************************************** - >>! NOTE: The modification to the GPL is included to allow you to !<< - >>! distribute a combined work that includes FreeRTOS without being !<< - >>! obliged to provide the source code for proprietary components !<< - >>! outside of the FreeRTOS kernel. !<< - *************************************************************************** - - FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - FOR A PARTICULAR PURPOSE. Full license text is available on the following - link: http://www.freertos.org/a00114.html - - *************************************************************************** - * * - * FreeRTOS provides completely free yet professionally developed, * - * robust, strictly quality controlled, supported, and cross * - * platform software that is more than just the market leader, it * - * is the industry's de facto standard. * - * * - * Help yourself get started quickly while simultaneously helping * - * to support the FreeRTOS project by purchasing a FreeRTOS * - * tutorial book, reference manual, or both: * - * http://www.FreeRTOS.org/Documentation * - * * - *************************************************************************** - - http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading - the FAQ page "My application does not run, what could be wrong?". Have you - defined configASSERT()? - - http://www.FreeRTOS.org/support - In return for receiving this top quality - embedded software for free we request you assist our global community by - participating in the support forum. - - http://www.FreeRTOS.org/training - Investing in training allows your team to - be as productive as possible as early as possible. Now you can receive - FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers - Ltd, and the world's leading authority on the world's leading RTOS. - - http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, - including FreeRTOS+Trace - an indispensable productivity tool, a DOS - compatible FAT file system, and our tiny thread aware UDP/IP stack. - - http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. - Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. - - http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High - Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS - licenses offer ticketed support, indemnification and commercial middleware. - - http://www.SafeRTOS.com - High Integrity Systems also provide a safety - engineered and independently SIL3 certified version for use in safety and - mission critical applications that require provable dependability. - - 1 tab == 4 spaces! -*/ + * FreeRTOS Kernel V10.3.1 + * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * http://www.FreeRTOS.org + * http://aws.amazon.com/freertos + * + * 1 tab == 4 spaces! + */ /*----------------------------------------------------------- * Portable layer API. Each function must be defined for each port. @@ -126,6 +84,14 @@ must be set in the compiler's include path. */ #define portNUM_CONFIGURABLE_REGIONS 1 #endif +#ifndef portHAS_STACK_OVERFLOW_CHECKING + #define portHAS_STACK_OVERFLOW_CHECKING 0 +#endif + +#ifndef portARCH_NAME + #define portARCH_NAME NULL +#endif + #ifdef __cplusplus extern "C" { #endif @@ -139,18 +105,39 @@ extern "C" { * */ #if( portUSING_MPU_WRAPPERS == 1 ) - PRIVILEGED_FUNCTION StackType_t *pxPortInitialiseStack( StackType_t *pxTopOfStack, TaskFunction_t pxCode, void *pvParameters, BaseType_t xRunPrivileged ) ; + #if( portHAS_STACK_OVERFLOW_CHECKING == 1 ) + StackType_t *pxPortInitialiseStack( StackType_t *pxTopOfStack, StackType_t *pxEndOfStack, TaskFunction_t pxCode, void *pvParameters, BaseType_t xRunPrivileged ) PRIVILEGED_FUNCTION; + #else + StackType_t *pxPortInitialiseStack( StackType_t *pxTopOfStack, TaskFunction_t pxCode, void *pvParameters, BaseType_t xRunPrivileged ) PRIVILEGED_FUNCTION; + #endif #else - PRIVILEGED_FUNCTION StackType_t *pxPortInitialiseStack( StackType_t *pxTopOfStack, TaskFunction_t pxCode, void *pvParameters ) ; + #if( portHAS_STACK_OVERFLOW_CHECKING == 1 ) + StackType_t *pxPortInitialiseStack( StackType_t *pxTopOfStack, StackType_t *pxEndOfStack, TaskFunction_t pxCode, void *pvParameters ) PRIVILEGED_FUNCTION; + #else + StackType_t *pxPortInitialiseStack( StackType_t *pxTopOfStack, TaskFunction_t pxCode, void *pvParameters ) PRIVILEGED_FUNCTION; + #endif #endif -/* Used by heap_5.c. */ +/* Used by heap_5.c to define the start address and size of each memory region +that together comprise the total FreeRTOS heap space. */ typedef struct HeapRegion { uint8_t *pucStartAddress; size_t xSizeInBytes; } HeapRegion_t; +/* Used to pass information about the heap out of vPortGetHeapStats(). */ +typedef struct xHeapStats +{ + size_t xAvailableHeapSpaceInBytes; /* The total heap size currently available - this is the sum of all the free blocks, not the largest block that can be allocated. */ + size_t xSizeOfLargestFreeBlockInBytes; /* The maximum size, in bytes, of all the free blocks within the heap at the time vPortGetHeapStats() is called. */ + size_t xSizeOfSmallestFreeBlockInBytes; /* The minimum size, in bytes, of all the free blocks within the heap at the time vPortGetHeapStats() is called. */ + size_t xNumberOfFreeBlocks; /* The number of free memory blocks within the heap at the time vPortGetHeapStats() is called. */ + size_t xMinimumEverFreeBytesRemaining; /* The minimum amount of total free memory (sum of all free blocks) there has been in the heap since the system booted. */ + size_t xNumberOfSuccessfulAllocations; /* The number of calls to pvPortMalloc() that have returned a valid memory block. */ + size_t xNumberOfSuccessfulFrees; /* The number of calls to vPortFree() that has successfully freed a block of memory. */ +} HeapStats_t; + /* * Used to define multiple heap regions for use by heap_5.c. This function * must be called before any calls to pvPortMalloc() - not creating a task, @@ -162,30 +149,35 @@ typedef struct HeapRegion * terminated by a HeapRegions_t structure that has a size of 0. The region * with the lowest start address must appear first in the array. */ -PRIVILEGED_FUNCTION void vPortDefineHeapRegions( const HeapRegion_t * const pxHeapRegions ); +void vPortDefineHeapRegions( const HeapRegion_t * const pxHeapRegions ) PRIVILEGED_FUNCTION; +/* + * Returns a HeapStats_t structure filled with information about the current + * heap state. + */ +void vPortGetHeapStats( HeapStats_t *pxHeapStats ); /* * Map to the memory management routines required for the port. */ -PRIVILEGED_FUNCTION void *pvPortMalloc( size_t xSize ); -PRIVILEGED_FUNCTION void vPortFree( void *pv ); -PRIVILEGED_FUNCTION void vPortInitialiseBlocks( void ); -PRIVILEGED_FUNCTION size_t xPortGetFreeHeapSize( void ); -PRIVILEGED_FUNCTION size_t xPortGetMinimumEverFreeHeapSize( void ); +void *pvPortMalloc( size_t xSize ) PRIVILEGED_FUNCTION; +void vPortFree( void *pv ) PRIVILEGED_FUNCTION; +void vPortInitialiseBlocks( void ) PRIVILEGED_FUNCTION; +size_t xPortGetFreeHeapSize( void ) PRIVILEGED_FUNCTION; +size_t xPortGetMinimumEverFreeHeapSize( void ) PRIVILEGED_FUNCTION; /* * Setup the hardware ready for the scheduler to take control. This generally * sets up a tick interrupt and sets timers for the correct tick frequency. */ -PRIVILEGED_FUNCTION BaseType_t xPortStartScheduler( void ); +BaseType_t xPortStartScheduler( void ) PRIVILEGED_FUNCTION; /* * Undo any hardware/ISR setup that was performed by xPortStartScheduler() so * the hardware is left in its original condition after the scheduler stops * executing. */ -PRIVILEGED_FUNCTION void vPortEndScheduler( void ); +void vPortEndScheduler( void ) PRIVILEGED_FUNCTION; /* * The structures and methods of manipulating the MPU are contained within the @@ -196,7 +188,7 @@ PRIVILEGED_FUNCTION void vPortEndScheduler( void ); */ #if( portUSING_MPU_WRAPPERS == 1 ) struct xMEMORY_REGION; - PRIVILEGED_FUNCTION void vPortStoreTaskMPUSettings( xMPU_SETTINGS *xMPUSettings, const struct xMEMORY_REGION * const xRegions, StackType_t *pxBottomOfStack, uint32_t ulStackDepth ); + void vPortStoreTaskMPUSettings( xMPU_SETTINGS *xMPUSettings, const struct xMEMORY_REGION * const xRegions, StackType_t *pxBottomOfStack, uint32_t ulStackDepth ) PRIVILEGED_FUNCTION; #endif #ifdef __cplusplus diff --git a/Firmware/Board/v3/Middlewares/Third_Party/FreeRTOS/Source/include/projdefs.h b/Firmware/Board/v3/Middlewares/Third_Party/FreeRTOS/Source/include/projdefs.h index 0b63fd8a..0d95130b 100644 --- a/Firmware/Board/v3/Middlewares/Third_Party/FreeRTOS/Source/include/projdefs.h +++ b/Firmware/Board/v3/Middlewares/Third_Party/FreeRTOS/Source/include/projdefs.h @@ -1,71 +1,29 @@ /* - FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. - All rights reserved - - VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. - - This file is part of the FreeRTOS distribution. - - FreeRTOS is free software; you can redistribute it and/or modify it under - the terms of the GNU General Public License (version 2) as published by the - Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception. - - *************************************************************************** - >>! NOTE: The modification to the GPL is included to allow you to !<< - >>! distribute a combined work that includes FreeRTOS without being !<< - >>! obliged to provide the source code for proprietary components !<< - >>! outside of the FreeRTOS kernel. !<< - *************************************************************************** - - FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - FOR A PARTICULAR PURPOSE. Full license text is available on the following - link: http://www.freertos.org/a00114.html - - *************************************************************************** - * * - * FreeRTOS provides completely free yet professionally developed, * - * robust, strictly quality controlled, supported, and cross * - * platform software that is more than just the market leader, it * - * is the industry's de facto standard. * - * * - * Help yourself get started quickly while simultaneously helping * - * to support the FreeRTOS project by purchasing a FreeRTOS * - * tutorial book, reference manual, or both: * - * http://www.FreeRTOS.org/Documentation * - * * - *************************************************************************** - - http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading - the FAQ page "My application does not run, what could be wrong?". Have you - defined configASSERT()? - - http://www.FreeRTOS.org/support - In return for receiving this top quality - embedded software for free we request you assist our global community by - participating in the support forum. - - http://www.FreeRTOS.org/training - Investing in training allows your team to - be as productive as possible as early as possible. Now you can receive - FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers - Ltd, and the world's leading authority on the world's leading RTOS. - - http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, - including FreeRTOS+Trace - an indispensable productivity tool, a DOS - compatible FAT file system, and our tiny thread aware UDP/IP stack. - - http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. - Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. - - http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High - Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS - licenses offer ticketed support, indemnification and commercial middleware. - - http://www.SafeRTOS.com - High Integrity Systems also provide a safety - engineered and independently SIL3 certified version for use in safety and - mission critical applications that require provable dependability. - - 1 tab == 4 spaces! -*/ + * FreeRTOS Kernel V10.3.1 + * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * http://www.FreeRTOS.org + * http://aws.amazon.com/freertos + * + * 1 tab == 4 spaces! + */ #ifndef PROJDEFS_H #define PROJDEFS_H @@ -152,8 +110,13 @@ itself. */ /* The following endian values are used by FreeRTOS+ components, not FreeRTOS itself. */ -#define pdFREERTOS_LITTLE_ENDIAN 0 -#define pdFREERTOS_BIG_ENDIAN 1 +#define pdFREERTOS_LITTLE_ENDIAN 0 +#define pdFREERTOS_BIG_ENDIAN 1 + +/* Re-defining endian values for generic naming. */ +#define pdLITTLE_ENDIAN pdFREERTOS_LITTLE_ENDIAN +#define pdBIG_ENDIAN pdFREERTOS_BIG_ENDIAN + #endif /* PROJDEFS_H */ diff --git a/Firmware/Board/v3/Middlewares/Third_Party/FreeRTOS/Source/include/queue.h b/Firmware/Board/v3/Middlewares/Third_Party/FreeRTOS/Source/include/queue.h index a64640c6..52ccca55 100644 --- a/Firmware/Board/v3/Middlewares/Third_Party/FreeRTOS/Source/include/queue.h +++ b/Firmware/Board/v3/Middlewares/Third_Party/FreeRTOS/Source/include/queue.h @@ -1,71 +1,29 @@ /* - FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. - All rights reserved - - VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. - - This file is part of the FreeRTOS distribution. - - FreeRTOS is free software; you can redistribute it and/or modify it under - the terms of the GNU General Public License (version 2) as published by the - Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception. - - *************************************************************************** - >>! NOTE: The modification to the GPL is included to allow you to !<< - >>! distribute a combined work that includes FreeRTOS without being !<< - >>! obliged to provide the source code for proprietary components !<< - >>! outside of the FreeRTOS kernel. !<< - *************************************************************************** - - FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - FOR A PARTICULAR PURPOSE. Full license text is available on the following - link: http://www.freertos.org/a00114.html - - *************************************************************************** - * * - * FreeRTOS provides completely free yet professionally developed, * - * robust, strictly quality controlled, supported, and cross * - * platform software that is more than just the market leader, it * - * is the industry's de facto standard. * - * * - * Help yourself get started quickly while simultaneously helping * - * to support the FreeRTOS project by purchasing a FreeRTOS * - * tutorial book, reference manual, or both: * - * http://www.FreeRTOS.org/Documentation * - * * - *************************************************************************** - - http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading - the FAQ page "My application does not run, what could be wrong?". Have you - defined configASSERT()? - - http://www.FreeRTOS.org/support - In return for receiving this top quality - embedded software for free we request you assist our global community by - participating in the support forum. - - http://www.FreeRTOS.org/training - Investing in training allows your team to - be as productive as possible as early as possible. Now you can receive - FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers - Ltd, and the world's leading authority on the world's leading RTOS. - - http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, - including FreeRTOS+Trace - an indispensable productivity tool, a DOS - compatible FAT file system, and our tiny thread aware UDP/IP stack. - - http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. - Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. - - http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High - Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS - licenses offer ticketed support, indemnification and commercial middleware. - - http://www.SafeRTOS.com - High Integrity Systems also provide a safety - engineered and independently SIL3 certified version for use in safety and - mission critical applications that require provable dependability. - - 1 tab == 4 spaces! -*/ + * FreeRTOS Kernel V10.3.1 + * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * http://www.FreeRTOS.org + * http://aws.amazon.com/freertos + * + * 1 tab == 4 spaces! + */ #ifndef QUEUE_H @@ -79,27 +37,29 @@ extern "C" { #endif +#include "task.h" /** * Type by which queues are referenced. For example, a call to xQueueCreate() * returns an QueueHandle_t variable that can then be used as a parameter to * xQueueSend(), xQueueReceive(), etc. */ -typedef void * QueueHandle_t; +struct QueueDefinition; /* Using old naming convention so as not to break kernel aware debuggers. */ +typedef struct QueueDefinition * QueueHandle_t; /** * Type by which queue sets are referenced. For example, a call to * xQueueCreateSet() returns an xQueueSet variable that can then be used as a * parameter to xQueueSelectFromSet(), xQueueAddToSet(), etc. */ -typedef void * QueueSetHandle_t; +typedef struct QueueDefinition * QueueSetHandle_t; /** * Queue sets can contain both queues and semaphores, so the * QueueSetMemberHandle_t is defined as a type to be used where a parameter or * return value can be either an QueueHandle_t or an SemaphoreHandle_t. */ -typedef void * QueueSetMemberHandle_t; +typedef struct QueueDefinition * QueueSetMemberHandle_t; /* For internal use only. */ #define queueSEND_TO_BACK ( ( BaseType_t ) 0 ) @@ -282,8 +242,6 @@ typedef void * QueueSetMemberHandle_t; ); *
* - * This is a macro that calls xQueueGenericSend(). - * * Post an item to the front of a queue. The item is queued by copy, not by * reference. This function must not be called from an interrupt service * routine. See xQueueSendFromISR () for an alternative which may be used @@ -689,19 +647,17 @@ typedef void * QueueSetMemberHandle_t; * \defgroup xQueueSend xQueueSend * \ingroup QueueManagement */ -PRIVILEGED_FUNCTION BaseType_t xQueueGenericSend( QueueHandle_t xQueue, const void * const pvItemToQueue, TickType_t xTicksToWait, const BaseType_t xCopyPosition ); +BaseType_t xQueueGenericSend( QueueHandle_t xQueue, const void * const pvItemToQueue, TickType_t xTicksToWait, const BaseType_t xCopyPosition ) PRIVILEGED_FUNCTION; /** * queue. h *
  BaseType_t xQueuePeek(
 							 QueueHandle_t xQueue,
-							 void *pvBuffer,
+							 void * const pvBuffer,
 							 TickType_t xTicksToWait
 						 );
* - * This is a macro that calls the xQueueGenericReceive() function. - * * Receive an item from a queue without removing the item from the queue. * The item is received by copy so a buffer of adequate size must be * provided. The number of bytes copied into the buffer was defined when @@ -782,10 +738,10 @@ PRIVILEGED_FUNCTION BaseType_t xQueueGenericSend( QueueHandle_t xQueue, const vo // ... Rest of task code. }
- * \defgroup xQueueReceive xQueueReceive + * \defgroup xQueuePeek xQueuePeek * \ingroup QueueManagement */ -#define xQueuePeek( xQueue, pvBuffer, xTicksToWait ) xQueueGenericReceive( ( xQueue ), ( pvBuffer ), ( xTicksToWait ), pdTRUE ) +BaseType_t xQueuePeek( QueueHandle_t xQueue, void * const pvBuffer, TickType_t xTicksToWait ) PRIVILEGED_FUNCTION; /** * queue. h @@ -818,7 +774,7 @@ PRIVILEGED_FUNCTION BaseType_t xQueueGenericSend( QueueHandle_t xQueue, const vo * \defgroup xQueuePeekFromISR xQueuePeekFromISR * \ingroup QueueManagement */ -PRIVILEGED_FUNCTION BaseType_t xQueuePeekFromISR( QueueHandle_t xQueue, void * const pvBuffer ); +BaseType_t xQueuePeekFromISR( QueueHandle_t xQueue, void * const pvBuffer ) PRIVILEGED_FUNCTION; /** * queue. h @@ -829,8 +785,6 @@ PRIVILEGED_FUNCTION BaseType_t xQueuePeekFromISR( QueueHandle_t xQueue, void * c TickType_t xTicksToWait );
* - * This is a macro that calls the xQueueGenericReceive() function. - * * Receive an item from a queue. The item is received by copy so a buffer of * adequate size must be provided. The number of bytes copied into the buffer * was defined when the queue was created. @@ -911,106 +865,7 @@ PRIVILEGED_FUNCTION BaseType_t xQueuePeekFromISR( QueueHandle_t xQueue, void * c * \defgroup xQueueReceive xQueueReceive * \ingroup QueueManagement */ -#define xQueueReceive( xQueue, pvBuffer, xTicksToWait ) xQueueGenericReceive( ( xQueue ), ( pvBuffer ), ( xTicksToWait ), pdFALSE ) - - -/** - * queue. h - *
- BaseType_t xQueueGenericReceive(
-									   QueueHandle_t	xQueue,
-									   void	*pvBuffer,
-									   TickType_t	xTicksToWait
-									   BaseType_t	xJustPeek
-									);
- * - * It is preferred that the macro xQueueReceive() be used rather than calling - * this function directly. - * - * Receive an item from a queue. The item is received by copy so a buffer of - * adequate size must be provided. The number of bytes copied into the buffer - * was defined when the queue was created. - * - * This function must not be used in an interrupt service routine. See - * xQueueReceiveFromISR for an alternative that can. - * - * @param xQueue The handle to the queue from which the item is to be - * received. - * - * @param pvBuffer Pointer to the buffer into which the received item will - * be copied. - * - * @param xTicksToWait The maximum amount of time the task should block - * waiting for an item to receive should the queue be empty at the time - * of the call. The time is defined in tick periods so the constant - * portTICK_PERIOD_MS should be used to convert to real time if this is required. - * xQueueGenericReceive() will return immediately if the queue is empty and - * xTicksToWait is 0. - * - * @param xJustPeek When set to true, the item received from the queue is not - * actually removed from the queue - meaning a subsequent call to - * xQueueReceive() will return the same item. When set to false, the item - * being received from the queue is also removed from the queue. - * - * @return pdTRUE if an item was successfully received from the queue, - * otherwise pdFALSE. - * - * Example usage: -
- struct AMessage
- {
-	char ucMessageID;
-	char ucData[ 20 ];
- } xMessage;
-
- QueueHandle_t xQueue;
-
- // Task to create a queue and post a value.
- void vATask( void *pvParameters )
- {
- struct AMessage *pxMessage;
-
-	// Create a queue capable of containing 10 pointers to AMessage structures.
-	// These should be passed by pointer as they contain a lot of data.
-	xQueue = xQueueCreate( 10, sizeof( struct AMessage * ) );
-	if( xQueue == 0 )
-	{
-		// Failed to create the queue.
-	}
-
-	// ...
-
-	// Send a pointer to a struct AMessage object.  Don't block if the
-	// queue is already full.
-	pxMessage = & xMessage;
-	xQueueSend( xQueue, ( void * ) &pxMessage, ( TickType_t ) 0 );
-
-	// ... Rest of task code.
- }
-
- // Task to receive from the queue.
- void vADifferentTask( void *pvParameters )
- {
- struct AMessage *pxRxedMessage;
-
-	if( xQueue != 0 )
-	{
-		// Receive a message on the created queue.  Block for 10 ticks if a
-		// message is not immediately available.
-		if( xQueueGenericReceive( xQueue, &( pxRxedMessage ), ( TickType_t ) 10 ) )
-		{
-			// pcRxedMessage now points to the struct AMessage variable posted
-			// by vATask.
-		}
-	}
-
-	// ... Rest of task code.
- }
- 
- * \defgroup xQueueReceive xQueueReceive - * \ingroup QueueManagement - */ -PRIVILEGED_FUNCTION BaseType_t xQueueGenericReceive( QueueHandle_t xQueue, void * const pvBuffer, TickType_t xTicksToWait, const BaseType_t xJustPeek ); +BaseType_t xQueueReceive( QueueHandle_t xQueue, void * const pvBuffer, TickType_t xTicksToWait ) PRIVILEGED_FUNCTION; /** * queue. h @@ -1025,7 +880,7 @@ PRIVILEGED_FUNCTION BaseType_t xQueueGenericReceive( QueueHandle_t xQueue, void * \defgroup uxQueueMessagesWaiting uxQueueMessagesWaiting * \ingroup QueueManagement */ -PRIVILEGED_FUNCTION UBaseType_t uxQueueMessagesWaiting( const QueueHandle_t xQueue ); +UBaseType_t uxQueueMessagesWaiting( const QueueHandle_t xQueue ) PRIVILEGED_FUNCTION; /** * queue. h @@ -1042,7 +897,7 @@ PRIVILEGED_FUNCTION UBaseType_t uxQueueMessagesWaiting( const QueueHandle_t xQue * \defgroup uxQueueMessagesWaiting uxQueueMessagesWaiting * \ingroup QueueManagement */ -PRIVILEGED_FUNCTION UBaseType_t uxQueueSpacesAvailable( const QueueHandle_t xQueue ); +UBaseType_t uxQueueSpacesAvailable( const QueueHandle_t xQueue ) PRIVILEGED_FUNCTION; /** * queue. h @@ -1056,7 +911,7 @@ PRIVILEGED_FUNCTION UBaseType_t uxQueueSpacesAvailable( const QueueHandle_t xQue * \defgroup vQueueDelete vQueueDelete * \ingroup QueueManagement */ -PRIVILEGED_FUNCTION void vQueueDelete( QueueHandle_t xQueue ); +void vQueueDelete( QueueHandle_t xQueue ) PRIVILEGED_FUNCTION; /** * queue. h @@ -1429,7 +1284,7 @@ uint32_t ulVarToSend, ulValReceived; // name of the yield function required is port specific. if( xHigherPriorityTaskWokenByPost ) { - taskYIELD_YIELD_FROM_ISR(); + portYIELD_FROM_ISR(); } }
@@ -1437,8 +1292,8 @@ uint32_t ulVarToSend, ulValReceived; * \defgroup xQueueSendFromISR xQueueSendFromISR * \ingroup QueueManagement */ -PRIVILEGED_FUNCTION BaseType_t xQueueGenericSendFromISR( QueueHandle_t xQueue, const void * const pvItemToQueue, BaseType_t * const pxHigherPriorityTaskWoken, const BaseType_t xCopyPosition ); -PRIVILEGED_FUNCTION BaseType_t xQueueGiveFromISR( QueueHandle_t xQueue, BaseType_t * const pxHigherPriorityTaskWoken ); +BaseType_t xQueueGenericSendFromISR( QueueHandle_t xQueue, const void * const pvItemToQueue, BaseType_t * const pxHigherPriorityTaskWoken, const BaseType_t xCopyPosition ) PRIVILEGED_FUNCTION; +BaseType_t xQueueGiveFromISR( QueueHandle_t xQueue, BaseType_t * const pxHigherPriorityTaskWoken ) PRIVILEGED_FUNCTION; /** * queue. h @@ -1527,15 +1382,15 @@ PRIVILEGED_FUNCTION BaseType_t xQueueGiveFromISR( QueueHandle_t xQueue, BaseType * \defgroup xQueueReceiveFromISR xQueueReceiveFromISR * \ingroup QueueManagement */ -PRIVILEGED_FUNCTION BaseType_t xQueueReceiveFromISR( QueueHandle_t xQueue, void * const pvBuffer, BaseType_t * const pxHigherPriorityTaskWoken ); +BaseType_t xQueueReceiveFromISR( QueueHandle_t xQueue, void * const pvBuffer, BaseType_t * const pxHigherPriorityTaskWoken ) PRIVILEGED_FUNCTION; /* * Utilities to query queues that are safe to use from an ISR. These utilities * should be used only from witin an ISR, or within a critical section. */ -PRIVILEGED_FUNCTION BaseType_t xQueueIsQueueEmptyFromISR( const QueueHandle_t xQueue ); -PRIVILEGED_FUNCTION BaseType_t xQueueIsQueueFullFromISR( const QueueHandle_t xQueue ); -PRIVILEGED_FUNCTION UBaseType_t uxQueueMessagesWaitingFromISR( const QueueHandle_t xQueue ); +BaseType_t xQueueIsQueueEmptyFromISR( const QueueHandle_t xQueue ) PRIVILEGED_FUNCTION; +BaseType_t xQueueIsQueueFullFromISR( const QueueHandle_t xQueue ) PRIVILEGED_FUNCTION; +UBaseType_t uxQueueMessagesWaitingFromISR( const QueueHandle_t xQueue ) PRIVILEGED_FUNCTION; /* * The functions defined above are for passing data to and from tasks. The @@ -1556,18 +1411,20 @@ BaseType_t xQueueCRReceive( QueueHandle_t xQueue, void *pvBuffer, TickType_t xTi * xSemaphoreCreateCounting() or xSemaphoreGetMutexHolder() instead of calling * these functions directly. */ -PRIVILEGED_FUNCTION QueueHandle_t xQueueCreateMutex( const uint8_t ucQueueType ); -PRIVILEGED_FUNCTION QueueHandle_t xQueueCreateMutexStatic( const uint8_t ucQueueType, StaticQueue_t *pxStaticQueue ); -PRIVILEGED_FUNCTION QueueHandle_t xQueueCreateCountingSemaphore( const UBaseType_t uxMaxCount, const UBaseType_t uxInitialCount ); -PRIVILEGED_FUNCTION QueueHandle_t xQueueCreateCountingSemaphoreStatic( const UBaseType_t uxMaxCount, const UBaseType_t uxInitialCount, StaticQueue_t *pxStaticQueue ); -PRIVILEGED_FUNCTION void* xQueueGetMutexHolder( QueueHandle_t xSemaphore ); +QueueHandle_t xQueueCreateMutex( const uint8_t ucQueueType ) PRIVILEGED_FUNCTION; +QueueHandle_t xQueueCreateMutexStatic( const uint8_t ucQueueType, StaticQueue_t *pxStaticQueue ) PRIVILEGED_FUNCTION; +QueueHandle_t xQueueCreateCountingSemaphore( const UBaseType_t uxMaxCount, const UBaseType_t uxInitialCount ) PRIVILEGED_FUNCTION; +QueueHandle_t xQueueCreateCountingSemaphoreStatic( const UBaseType_t uxMaxCount, const UBaseType_t uxInitialCount, StaticQueue_t *pxStaticQueue ) PRIVILEGED_FUNCTION; +BaseType_t xQueueSemaphoreTake( QueueHandle_t xQueue, TickType_t xTicksToWait ) PRIVILEGED_FUNCTION; +TaskHandle_t xQueueGetMutexHolder( QueueHandle_t xSemaphore ) PRIVILEGED_FUNCTION; +TaskHandle_t xQueueGetMutexHolderFromISR( QueueHandle_t xSemaphore ) PRIVILEGED_FUNCTION; /* * For internal use only. Use xSemaphoreTakeMutexRecursive() or * xSemaphoreGiveMutexRecursive() instead of calling these functions directly. */ -PRIVILEGED_FUNCTION BaseType_t xQueueTakeMutexRecursive( QueueHandle_t xMutex, TickType_t xTicksToWait ); -PRIVILEGED_FUNCTION BaseType_t xQueueGiveMutexRecursive( QueueHandle_t pxMutex ); +BaseType_t xQueueTakeMutexRecursive( QueueHandle_t xMutex, TickType_t xTicksToWait ) PRIVILEGED_FUNCTION; +BaseType_t xQueueGiveMutexRecursive( QueueHandle_t xMutex ) PRIVILEGED_FUNCTION; /* * Reset a queue back to its original empty state. The return value is now @@ -1598,7 +1455,7 @@ PRIVILEGED_FUNCTION BaseType_t xQueueGiveMutexRecursive( QueueHandle_t pxMutex ) * preferably in ROM/Flash), not on the stack. */ #if( configQUEUE_REGISTRY_SIZE > 0 ) - PRIVILEGED_FUNCTION void vQueueAddToRegistry( QueueHandle_t xQueue, const char *pcName ); /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ + void vQueueAddToRegistry( QueueHandle_t xQueue, const char *pcQueueName ) PRIVILEGED_FUNCTION; /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ #endif /* @@ -1612,7 +1469,7 @@ PRIVILEGED_FUNCTION BaseType_t xQueueGiveMutexRecursive( QueueHandle_t pxMutex ) * @param xQueue The handle of the queue being removed from the registry. */ #if( configQUEUE_REGISTRY_SIZE > 0 ) - PRIVILEGED_FUNCTION void vQueueUnregisterQueue( QueueHandle_t xQueue ); + void vQueueUnregisterQueue( QueueHandle_t xQueue ) PRIVILEGED_FUNCTION; #endif /* @@ -1627,7 +1484,7 @@ PRIVILEGED_FUNCTION BaseType_t xQueueGiveMutexRecursive( QueueHandle_t pxMutex ) * returned. */ #if( configQUEUE_REGISTRY_SIZE > 0 ) - PRIVILEGED_FUNCTION const char *pcQueueGetName( QueueHandle_t xQueue ); /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ + const char *pcQueueGetName( QueueHandle_t xQueue ) PRIVILEGED_FUNCTION; /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ #endif /* @@ -1636,7 +1493,7 @@ PRIVILEGED_FUNCTION BaseType_t xQueueGiveMutexRecursive( QueueHandle_t pxMutex ) * RTOS objects that use the queue structure as their base. */ #if( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) - PRIVILEGED_FUNCTION QueueHandle_t xQueueGenericCreate( const UBaseType_t uxQueueLength, const UBaseType_t uxItemSize, const uint8_t ucQueueType ); + QueueHandle_t xQueueGenericCreate( const UBaseType_t uxQueueLength, const UBaseType_t uxItemSize, const uint8_t ucQueueType ) PRIVILEGED_FUNCTION; #endif /* @@ -1645,7 +1502,7 @@ PRIVILEGED_FUNCTION BaseType_t xQueueGiveMutexRecursive( QueueHandle_t pxMutex ) * RTOS objects that use the queue structure as their base. */ #if( configSUPPORT_STATIC_ALLOCATION == 1 ) - PRIVILEGED_FUNCTION QueueHandle_t xQueueGenericCreateStatic( const UBaseType_t uxQueueLength, const UBaseType_t uxItemSize, uint8_t *pucQueueStorage, StaticQueue_t *pxStaticQueue, const uint8_t ucQueueType ); + QueueHandle_t xQueueGenericCreateStatic( const UBaseType_t uxQueueLength, const UBaseType_t uxItemSize, uint8_t *pucQueueStorage, StaticQueue_t *pxStaticQueue, const uint8_t ucQueueType ) PRIVILEGED_FUNCTION; #endif /* @@ -1696,7 +1553,7 @@ PRIVILEGED_FUNCTION BaseType_t xQueueGiveMutexRecursive( QueueHandle_t pxMutex ) * @return If the queue set is created successfully then a handle to the created * queue set is returned. Otherwise NULL is returned. */ -PRIVILEGED_FUNCTION QueueSetHandle_t xQueueCreateSet( const UBaseType_t uxEventQueueLength ); +QueueSetHandle_t xQueueCreateSet( const UBaseType_t uxEventQueueLength ) PRIVILEGED_FUNCTION; /* * Adds a queue or semaphore to a queue set that was previously created by a @@ -1720,7 +1577,7 @@ PRIVILEGED_FUNCTION QueueSetHandle_t xQueueCreateSet( const UBaseType_t uxEventQ * queue set because it is already a member of a different queue set then pdFAIL * is returned. */ -PRIVILEGED_FUNCTION BaseType_t xQueueAddToSet( QueueSetMemberHandle_t xQueueOrSemaphore, QueueSetHandle_t xQueueSet ); +BaseType_t xQueueAddToSet( QueueSetMemberHandle_t xQueueOrSemaphore, QueueSetHandle_t xQueueSet ) PRIVILEGED_FUNCTION; /* * Removes a queue or semaphore from a queue set. A queue or semaphore can only @@ -1739,7 +1596,7 @@ PRIVILEGED_FUNCTION BaseType_t xQueueAddToSet( QueueSetMemberHandle_t xQueueOrSe * then pdPASS is returned. If the queue was not in the queue set, or the * queue (or semaphore) was not empty, then pdFAIL is returned. */ -PRIVILEGED_FUNCTION BaseType_t xQueueRemoveFromSet( QueueSetMemberHandle_t xQueueOrSemaphore, QueueSetHandle_t xQueueSet ); +BaseType_t xQueueRemoveFromSet( QueueSetMemberHandle_t xQueueOrSemaphore, QueueSetHandle_t xQueueSet ) PRIVILEGED_FUNCTION; /* * xQueueSelectFromSet() selects from the members of a queue set a queue or @@ -1775,19 +1632,19 @@ PRIVILEGED_FUNCTION BaseType_t xQueueRemoveFromSet( QueueSetMemberHandle_t xQueu * in the queue set that is available, or NULL if no such queue or semaphore * exists before before the specified block time expires. */ -PRIVILEGED_FUNCTION QueueSetMemberHandle_t xQueueSelectFromSet( QueueSetHandle_t xQueueSet, const TickType_t xTicksToWait ); +QueueSetMemberHandle_t xQueueSelectFromSet( QueueSetHandle_t xQueueSet, const TickType_t xTicksToWait ) PRIVILEGED_FUNCTION; /* * A version of xQueueSelectFromSet() that can be used from an ISR. */ -PRIVILEGED_FUNCTION QueueSetMemberHandle_t xQueueSelectFromSetFromISR( QueueSetHandle_t xQueueSet ); +QueueSetMemberHandle_t xQueueSelectFromSetFromISR( QueueSetHandle_t xQueueSet ) PRIVILEGED_FUNCTION; /* Not public API functions. */ -PRIVILEGED_FUNCTION void vQueueWaitForMessageRestricted( QueueHandle_t xQueue, TickType_t xTicksToWait, const BaseType_t xWaitIndefinitely ) ; -PRIVILEGED_FUNCTION BaseType_t xQueueGenericReset( QueueHandle_t xQueue, BaseType_t xNewQueue ); -PRIVILEGED_FUNCTION void vQueueSetQueueNumber( QueueHandle_t xQueue, UBaseType_t uxQueueNumber ); -PRIVILEGED_FUNCTION UBaseType_t uxQueueGetQueueNumber( QueueHandle_t xQueue ); -PRIVILEGED_FUNCTION uint8_t ucQueueGetQueueType( QueueHandle_t xQueue ); +void vQueueWaitForMessageRestricted( QueueHandle_t xQueue, TickType_t xTicksToWait, const BaseType_t xWaitIndefinitely ) PRIVILEGED_FUNCTION; +BaseType_t xQueueGenericReset( QueueHandle_t xQueue, BaseType_t xNewQueue ) PRIVILEGED_FUNCTION; +void vQueueSetQueueNumber( QueueHandle_t xQueue, UBaseType_t uxQueueNumber ) PRIVILEGED_FUNCTION; +UBaseType_t uxQueueGetQueueNumber( QueueHandle_t xQueue ) PRIVILEGED_FUNCTION; +uint8_t ucQueueGetQueueType( QueueHandle_t xQueue ) PRIVILEGED_FUNCTION; #ifdef __cplusplus diff --git a/Firmware/Board/v3/Middlewares/Third_Party/FreeRTOS/Source/include/semphr.h b/Firmware/Board/v3/Middlewares/Third_Party/FreeRTOS/Source/include/semphr.h index a674b02a..787c7912 100644 --- a/Firmware/Board/v3/Middlewares/Third_Party/FreeRTOS/Source/include/semphr.h +++ b/Firmware/Board/v3/Middlewares/Third_Party/FreeRTOS/Source/include/semphr.h @@ -1,71 +1,29 @@ /* - FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. - All rights reserved - - VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. - - This file is part of the FreeRTOS distribution. - - FreeRTOS is free software; you can redistribute it and/or modify it under - the terms of the GNU General Public License (version 2) as published by the - Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception. - - *************************************************************************** - >>! NOTE: The modification to the GPL is included to allow you to !<< - >>! distribute a combined work that includes FreeRTOS without being !<< - >>! obliged to provide the source code for proprietary components !<< - >>! outside of the FreeRTOS kernel. !<< - *************************************************************************** - - FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - FOR A PARTICULAR PURPOSE. Full license text is available on the following - link: http://www.freertos.org/a00114.html - - *************************************************************************** - * * - * FreeRTOS provides completely free yet professionally developed, * - * robust, strictly quality controlled, supported, and cross * - * platform software that is more than just the market leader, it * - * is the industry's de facto standard. * - * * - * Help yourself get started quickly while simultaneously helping * - * to support the FreeRTOS project by purchasing a FreeRTOS * - * tutorial book, reference manual, or both: * - * http://www.FreeRTOS.org/Documentation * - * * - *************************************************************************** - - http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading - the FAQ page "My application does not run, what could be wrong?". Have you - defined configASSERT()? - - http://www.FreeRTOS.org/support - In return for receiving this top quality - embedded software for free we request you assist our global community by - participating in the support forum. - - http://www.FreeRTOS.org/training - Investing in training allows your team to - be as productive as possible as early as possible. Now you can receive - FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers - Ltd, and the world's leading authority on the world's leading RTOS. - - http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, - including FreeRTOS+Trace - an indispensable productivity tool, a DOS - compatible FAT file system, and our tiny thread aware UDP/IP stack. - - http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. - Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. - - http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High - Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS - licenses offer ticketed support, indemnification and commercial middleware. - - http://www.SafeRTOS.com - High Integrity Systems also provide a safety - engineered and independently SIL3 certified version for use in safety and - mission critical applications that require provable dependability. - - 1 tab == 4 spaces! -*/ + * FreeRTOS Kernel V10.3.1 + * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * http://www.FreeRTOS.org + * http://aws.amazon.com/freertos + * + * 1 tab == 4 spaces! + */ #ifndef SEMAPHORE_H #define SEMAPHORE_H @@ -328,7 +286,7 @@ typedef QueueHandle_t SemaphoreHandle_t; * \defgroup xSemaphoreTake xSemaphoreTake * \ingroup Semaphores */ -#define xSemaphoreTake( xSemaphore, xBlockTime ) xQueueGenericReceive( ( QueueHandle_t ) ( xSemaphore ), NULL, ( xBlockTime ), pdFALSE ) +#define xSemaphoreTake( xSemaphore, xBlockTime ) xQueueSemaphoreTake( ( xSemaphore ), ( xBlockTime ) ) /** * semphr. h @@ -392,23 +350,23 @@ typedef QueueHandle_t SemaphoreHandle_t; // ... // For some reason due to the nature of the code further calls to - // xSemaphoreTakeRecursive() are made on the same mutex. In real - // code these would not be just sequential calls as this would make - // no sense. Instead the calls are likely to be buried inside - // a more complex call structure. + // xSemaphoreTakeRecursive() are made on the same mutex. In real + // code these would not be just sequential calls as this would make + // no sense. Instead the calls are likely to be buried inside + // a more complex call structure. xSemaphoreTakeRecursive( xMutex, ( TickType_t ) 10 ); xSemaphoreTakeRecursive( xMutex, ( TickType_t ) 10 ); // The mutex has now been 'taken' three times, so will not be - // available to another task until it has also been given back - // three times. Again it is unlikely that real code would have - // these calls sequentially, but instead buried in a more complex - // call structure. This is just for illustrative purposes. + // available to another task until it has also been given back + // three times. Again it is unlikely that real code would have + // these calls sequentially, but instead buried in a more complex + // call structure. This is just for illustrative purposes. + xSemaphoreGiveRecursive( xMutex ); + xSemaphoreGiveRecursive( xMutex ); xSemaphoreGiveRecursive( xMutex ); - xSemaphoreGiveRecursive( xMutex ); - xSemaphoreGiveRecursive( xMutex ); - // Now the mutex can be taken by other tasks. + // Now the mutex can be taken by other tasks. } else { @@ -1154,6 +1112,17 @@ typedef QueueHandle_t SemaphoreHandle_t; */ #define xSemaphoreGetMutexHolder( xSemaphore ) xQueueGetMutexHolder( ( xSemaphore ) ) +/** + * semphr.h + *
TaskHandle_t xSemaphoreGetMutexHolderFromISR( SemaphoreHandle_t xMutex );
+ * + * If xMutex is indeed a mutex type semaphore, return the current mutex holder. + * If xMutex is not a mutex type semaphore, or the mutex is available (not held + * by a task), return NULL. + * + */ +#define xSemaphoreGetMutexHolderFromISR( xSemaphore ) xQueueGetMutexHolderFromISR( ( xSemaphore ) ) + /** * semphr.h *
UBaseType_t uxSemaphoreGetCount( SemaphoreHandle_t xSemaphore );
diff --git a/Firmware/Board/v3/Middlewares/Third_Party/FreeRTOS/Source/include/stack_macros.h b/Firmware/Board/v3/Middlewares/Third_Party/FreeRTOS/Source/include/stack_macros.h new file mode 100644 index 00000000..b5bac083 --- /dev/null +++ b/Firmware/Board/v3/Middlewares/Third_Party/FreeRTOS/Source/include/stack_macros.h @@ -0,0 +1,129 @@ +/* + * FreeRTOS Kernel V10.3.1 + * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * http://www.FreeRTOS.org + * http://aws.amazon.com/freertos + * + * 1 tab == 4 spaces! + */ + +#ifndef STACK_MACROS_H +#define STACK_MACROS_H + +/* + * Call the stack overflow hook function if the stack of the task being swapped + * out is currently overflowed, or looks like it might have overflowed in the + * past. + * + * Setting configCHECK_FOR_STACK_OVERFLOW to 1 will cause the macro to check + * the current stack state only - comparing the current top of stack value to + * the stack limit. Setting configCHECK_FOR_STACK_OVERFLOW to greater than 1 + * will also cause the last few stack bytes to be checked to ensure the value + * to which the bytes were set when the task was created have not been + * overwritten. Note this second test does not guarantee that an overflowed + * stack will always be recognised. + */ + +/*-----------------------------------------------------------*/ + +#if( ( configCHECK_FOR_STACK_OVERFLOW == 1 ) && ( portSTACK_GROWTH < 0 ) ) + + /* Only the current stack state is to be checked. */ + #define taskCHECK_FOR_STACK_OVERFLOW() \ + { \ + /* Is the currently saved stack pointer within the stack limit? */ \ + if( pxCurrentTCB->pxTopOfStack <= pxCurrentTCB->pxStack ) \ + { \ + vApplicationStackOverflowHook( ( TaskHandle_t ) pxCurrentTCB, pxCurrentTCB->pcTaskName ); \ + } \ + } + +#endif /* configCHECK_FOR_STACK_OVERFLOW == 1 */ +/*-----------------------------------------------------------*/ + +#if( ( configCHECK_FOR_STACK_OVERFLOW == 1 ) && ( portSTACK_GROWTH > 0 ) ) + + /* Only the current stack state is to be checked. */ + #define taskCHECK_FOR_STACK_OVERFLOW() \ + { \ + \ + /* Is the currently saved stack pointer within the stack limit? */ \ + if( pxCurrentTCB->pxTopOfStack >= pxCurrentTCB->pxEndOfStack ) \ + { \ + vApplicationStackOverflowHook( ( TaskHandle_t ) pxCurrentTCB, pxCurrentTCB->pcTaskName ); \ + } \ + } + +#endif /* configCHECK_FOR_STACK_OVERFLOW == 1 */ +/*-----------------------------------------------------------*/ + +#if( ( configCHECK_FOR_STACK_OVERFLOW > 1 ) && ( portSTACK_GROWTH < 0 ) ) + + #define taskCHECK_FOR_STACK_OVERFLOW() \ + { \ + const uint32_t * const pulStack = ( uint32_t * ) pxCurrentTCB->pxStack; \ + const uint32_t ulCheckValue = ( uint32_t ) 0xa5a5a5a5; \ + \ + if( ( pulStack[ 0 ] != ulCheckValue ) || \ + ( pulStack[ 1 ] != ulCheckValue ) || \ + ( pulStack[ 2 ] != ulCheckValue ) || \ + ( pulStack[ 3 ] != ulCheckValue ) ) \ + { \ + vApplicationStackOverflowHook( ( TaskHandle_t ) pxCurrentTCB, pxCurrentTCB->pcTaskName ); \ + } \ + } + +#endif /* #if( configCHECK_FOR_STACK_OVERFLOW > 1 ) */ +/*-----------------------------------------------------------*/ + +#if( ( configCHECK_FOR_STACK_OVERFLOW > 1 ) && ( portSTACK_GROWTH > 0 ) ) + + #define taskCHECK_FOR_STACK_OVERFLOW() \ + { \ + int8_t *pcEndOfStack = ( int8_t * ) pxCurrentTCB->pxEndOfStack; \ + static const uint8_t ucExpectedStackBytes[] = { tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, \ + tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, \ + tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, \ + tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, \ + tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE }; \ + \ + \ + pcEndOfStack -= sizeof( ucExpectedStackBytes ); \ + \ + /* Has the extremity of the task stack ever been written over? */ \ + if( memcmp( ( void * ) pcEndOfStack, ( void * ) ucExpectedStackBytes, sizeof( ucExpectedStackBytes ) ) != 0 ) \ + { \ + vApplicationStackOverflowHook( ( TaskHandle_t ) pxCurrentTCB, pxCurrentTCB->pcTaskName ); \ + } \ + } + +#endif /* #if( configCHECK_FOR_STACK_OVERFLOW > 1 ) */ +/*-----------------------------------------------------------*/ + +/* Remove stack overflow macro if not being used. */ +#ifndef taskCHECK_FOR_STACK_OVERFLOW + #define taskCHECK_FOR_STACK_OVERFLOW() +#endif + + + +#endif /* STACK_MACROS_H */ + diff --git a/Firmware/Board/v3/Middlewares/Third_Party/FreeRTOS/Source/include/stdint.readme b/Firmware/Board/v3/Middlewares/Third_Party/FreeRTOS/Source/include/stdint.readme new file mode 100644 index 00000000..4414c29e --- /dev/null +++ b/Firmware/Board/v3/Middlewares/Third_Party/FreeRTOS/Source/include/stdint.readme @@ -0,0 +1,27 @@ + +#ifndef FREERTOS_STDINT +#define FREERTOS_STDINT + +/******************************************************************************* + * THIS IS NOT A FULL stdint.h IMPLEMENTATION - It only contains the definitions + * necessary to build the FreeRTOS code. It is provided to allow FreeRTOS to be + * built using compilers that do not provide their own stdint.h definition. + * + * To use this file: + * + * 1) Copy this file into the directory that contains your FreeRTOSConfig.h + * header file, as that directory will already be in the compilers include + * path. + * + * 2) Rename the copied file stdint.h. + * + */ + +typedef signed char int8_t; +typedef unsigned char uint8_t; +typedef short int16_t; +typedef unsigned short uint16_t; +typedef long int32_t; +typedef unsigned long uint32_t; + +#endif /* FREERTOS_STDINT */ diff --git a/Firmware/Board/v3/Middlewares/Third_Party/FreeRTOS/Source/include/stream_buffer.h b/Firmware/Board/v3/Middlewares/Third_Party/FreeRTOS/Source/include/stream_buffer.h new file mode 100644 index 00000000..a8b68ad6 --- /dev/null +++ b/Firmware/Board/v3/Middlewares/Third_Party/FreeRTOS/Source/include/stream_buffer.h @@ -0,0 +1,859 @@ +/* + * FreeRTOS Kernel V10.3.1 + * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * http://www.FreeRTOS.org + * http://aws.amazon.com/freertos + * + * 1 tab == 4 spaces! + */ + +/* + * Stream buffers are used to send a continuous stream of data from one task or + * interrupt to another. Their implementation is light weight, making them + * particularly suited for interrupt to task and core to core communication + * scenarios. + * + * ***NOTE***: Uniquely among FreeRTOS objects, the stream buffer + * implementation (so also the message buffer implementation, as message buffers + * are built on top of stream buffers) assumes there is only one task or + * interrupt that will write to the buffer (the writer), and only one task or + * interrupt that will read from the buffer (the reader). It is safe for the + * writer and reader to be different tasks or interrupts, but, unlike other + * FreeRTOS objects, it is not safe to have multiple different writers or + * multiple different readers. If there are to be multiple different writers + * then the application writer must place each call to a writing API function + * (such as xStreamBufferSend()) inside a critical section and set the send + * block time to 0. Likewise, if there are to be multiple different readers + * then the application writer must place each call to a reading API function + * (such as xStreamBufferReceive()) inside a critical section section and set the + * receive block time to 0. + * + */ + +#ifndef STREAM_BUFFER_H +#define STREAM_BUFFER_H + +#ifndef INC_FREERTOS_H + #error "include FreeRTOS.h must appear in source files before include stream_buffer.h" +#endif + +#if defined( __cplusplus ) +extern "C" { +#endif + +/** + * Type by which stream buffers are referenced. For example, a call to + * xStreamBufferCreate() returns an StreamBufferHandle_t variable that can + * then be used as a parameter to xStreamBufferSend(), xStreamBufferReceive(), + * etc. + */ +struct StreamBufferDef_t; +typedef struct StreamBufferDef_t * StreamBufferHandle_t; + + +/** + * message_buffer.h + * +
+StreamBufferHandle_t xStreamBufferCreate( size_t xBufferSizeBytes, size_t xTriggerLevelBytes );
+
+ * + * Creates a new stream buffer using dynamically allocated memory. See + * xStreamBufferCreateStatic() for a version that uses statically allocated + * memory (memory that is allocated at compile time). + * + * configSUPPORT_DYNAMIC_ALLOCATION must be set to 1 or left undefined in + * FreeRTOSConfig.h for xStreamBufferCreate() to be available. + * + * @param xBufferSizeBytes The total number of bytes the stream buffer will be + * able to hold at any one time. + * + * @param xTriggerLevelBytes The number of bytes that must be in the stream + * buffer before a task that is blocked on the stream buffer to wait for data is + * moved out of the blocked state. For example, if a task is blocked on a read + * of an empty stream buffer that has a trigger level of 1 then the task will be + * unblocked when a single byte is written to the buffer or the task's block + * time expires. As another example, if a task is blocked on a read of an empty + * stream buffer that has a trigger level of 10 then the task will not be + * unblocked until the stream buffer contains at least 10 bytes or the task's + * block time expires. If a reading task's block time expires before the + * trigger level is reached then the task will still receive however many bytes + * are actually available. Setting a trigger level of 0 will result in a + * trigger level of 1 being used. It is not valid to specify a trigger level + * that is greater than the buffer size. + * + * @return If NULL is returned, then the stream buffer cannot be created + * because there is insufficient heap memory available for FreeRTOS to allocate + * the stream buffer data structures and storage area. A non-NULL value being + * returned indicates that the stream buffer has been created successfully - + * the returned value should be stored as the handle to the created stream + * buffer. + * + * Example use: +
+
+void vAFunction( void )
+{
+StreamBufferHandle_t xStreamBuffer;
+const size_t xStreamBufferSizeBytes = 100, xTriggerLevel = 10;
+
+    // Create a stream buffer that can hold 100 bytes.  The memory used to hold
+    // both the stream buffer structure and the data in the stream buffer is
+    // allocated dynamically.
+    xStreamBuffer = xStreamBufferCreate( xStreamBufferSizeBytes, xTriggerLevel );
+
+    if( xStreamBuffer == NULL )
+    {
+        // There was not enough heap memory space available to create the
+        // stream buffer.
+    }
+    else
+    {
+        // The stream buffer was created successfully and can now be used.
+    }
+}
+
+ * \defgroup xStreamBufferCreate xStreamBufferCreate + * \ingroup StreamBufferManagement + */ +#define xStreamBufferCreate( xBufferSizeBytes, xTriggerLevelBytes ) xStreamBufferGenericCreate( xBufferSizeBytes, xTriggerLevelBytes, pdFALSE ) + +/** + * stream_buffer.h + * +
+StreamBufferHandle_t xStreamBufferCreateStatic( size_t xBufferSizeBytes,
+                                                size_t xTriggerLevelBytes,
+                                                uint8_t *pucStreamBufferStorageArea,
+                                                StaticStreamBuffer_t *pxStaticStreamBuffer );
+
+ * Creates a new stream buffer using statically allocated memory. See + * xStreamBufferCreate() for a version that uses dynamically allocated memory. + * + * configSUPPORT_STATIC_ALLOCATION must be set to 1 in FreeRTOSConfig.h for + * xStreamBufferCreateStatic() to be available. + * + * @param xBufferSizeBytes The size, in bytes, of the buffer pointed to by the + * pucStreamBufferStorageArea parameter. + * + * @param xTriggerLevelBytes The number of bytes that must be in the stream + * buffer before a task that is blocked on the stream buffer to wait for data is + * moved out of the blocked state. For example, if a task is blocked on a read + * of an empty stream buffer that has a trigger level of 1 then the task will be + * unblocked when a single byte is written to the buffer or the task's block + * time expires. As another example, if a task is blocked on a read of an empty + * stream buffer that has a trigger level of 10 then the task will not be + * unblocked until the stream buffer contains at least 10 bytes or the task's + * block time expires. If a reading task's block time expires before the + * trigger level is reached then the task will still receive however many bytes + * are actually available. Setting a trigger level of 0 will result in a + * trigger level of 1 being used. It is not valid to specify a trigger level + * that is greater than the buffer size. + * + * @param pucStreamBufferStorageArea Must point to a uint8_t array that is at + * least xBufferSizeBytes + 1 big. This is the array to which streams are + * copied when they are written to the stream buffer. + * + * @param pxStaticStreamBuffer Must point to a variable of type + * StaticStreamBuffer_t, which will be used to hold the stream buffer's data + * structure. + * + * @return If the stream buffer is created successfully then a handle to the + * created stream buffer is returned. If either pucStreamBufferStorageArea or + * pxStaticstreamBuffer are NULL then NULL is returned. + * + * Example use: +
+
+// Used to dimension the array used to hold the streams.  The available space
+// will actually be one less than this, so 999.
+#define STORAGE_SIZE_BYTES 1000
+
+// Defines the memory that will actually hold the streams within the stream
+// buffer.
+static uint8_t ucStorageBuffer[ STORAGE_SIZE_BYTES ];
+
+// The variable used to hold the stream buffer structure.
+StaticStreamBuffer_t xStreamBufferStruct;
+
+void MyFunction( void )
+{
+StreamBufferHandle_t xStreamBuffer;
+const size_t xTriggerLevel = 1;
+
+    xStreamBuffer = xStreamBufferCreateStatic( sizeof( ucBufferStorage ),
+                                               xTriggerLevel,
+                                               ucBufferStorage,
+                                               &xStreamBufferStruct );
+
+    // As neither the pucStreamBufferStorageArea or pxStaticStreamBuffer
+    // parameters were NULL, xStreamBuffer will not be NULL, and can be used to
+    // reference the created stream buffer in other stream buffer API calls.
+
+    // Other code that uses the stream buffer can go here.
+}
+
+
+ * \defgroup xStreamBufferCreateStatic xStreamBufferCreateStatic + * \ingroup StreamBufferManagement + */ +#define xStreamBufferCreateStatic( xBufferSizeBytes, xTriggerLevelBytes, pucStreamBufferStorageArea, pxStaticStreamBuffer ) xStreamBufferGenericCreateStatic( xBufferSizeBytes, xTriggerLevelBytes, pdFALSE, pucStreamBufferStorageArea, pxStaticStreamBuffer ) + +/** + * stream_buffer.h + * +
+size_t xStreamBufferSend( StreamBufferHandle_t xStreamBuffer,
+                          const void *pvTxData,
+                          size_t xDataLengthBytes,
+                          TickType_t xTicksToWait );
+
+ * + * Sends bytes to a stream buffer. The bytes are copied into the stream buffer. + * + * ***NOTE***: Uniquely among FreeRTOS objects, the stream buffer + * implementation (so also the message buffer implementation, as message buffers + * are built on top of stream buffers) assumes there is only one task or + * interrupt that will write to the buffer (the writer), and only one task or + * interrupt that will read from the buffer (the reader). It is safe for the + * writer and reader to be different tasks or interrupts, but, unlike other + * FreeRTOS objects, it is not safe to have multiple different writers or + * multiple different readers. If there are to be multiple different writers + * then the application writer must place each call to a writing API function + * (such as xStreamBufferSend()) inside a critical section and set the send + * block time to 0. Likewise, if there are to be multiple different readers + * then the application writer must place each call to a reading API function + * (such as xStreamBufferReceive()) inside a critical section and set the receive + * block time to 0. + * + * Use xStreamBufferSend() to write to a stream buffer from a task. Use + * xStreamBufferSendFromISR() to write to a stream buffer from an interrupt + * service routine (ISR). + * + * @param xStreamBuffer The handle of the stream buffer to which a stream is + * being sent. + * + * @param pvTxData A pointer to the buffer that holds the bytes to be copied + * into the stream buffer. + * + * @param xDataLengthBytes The maximum number of bytes to copy from pvTxData + * into the stream buffer. + * + * @param xTicksToWait The maximum amount of time the task should remain in the + * Blocked state to wait for enough space to become available in the stream + * buffer, should the stream buffer contain too little space to hold the + * another xDataLengthBytes bytes. The block time is specified in tick periods, + * so the absolute time it represents is dependent on the tick frequency. The + * macro pdMS_TO_TICKS() can be used to convert a time specified in milliseconds + * into a time specified in ticks. Setting xTicksToWait to portMAX_DELAY will + * cause the task to wait indefinitely (without timing out), provided + * INCLUDE_vTaskSuspend is set to 1 in FreeRTOSConfig.h. If a task times out + * before it can write all xDataLengthBytes into the buffer it will still write + * as many bytes as possible. A task does not use any CPU time when it is in + * the blocked state. + * + * @return The number of bytes written to the stream buffer. If a task times + * out before it can write all xDataLengthBytes into the buffer it will still + * write as many bytes as possible. + * + * Example use: +
+void vAFunction( StreamBufferHandle_t xStreamBuffer )
+{
+size_t xBytesSent;
+uint8_t ucArrayToSend[] = { 0, 1, 2, 3 };
+char *pcStringToSend = "String to send";
+const TickType_t x100ms = pdMS_TO_TICKS( 100 );
+
+    // Send an array to the stream buffer, blocking for a maximum of 100ms to
+    // wait for enough space to be available in the stream buffer.
+    xBytesSent = xStreamBufferSend( xStreamBuffer, ( void * ) ucArrayToSend, sizeof( ucArrayToSend ), x100ms );
+
+    if( xBytesSent != sizeof( ucArrayToSend ) )
+    {
+        // The call to xStreamBufferSend() times out before there was enough
+        // space in the buffer for the data to be written, but it did
+        // successfully write xBytesSent bytes.
+    }
+
+    // Send the string to the stream buffer.  Return immediately if there is not
+    // enough space in the buffer.
+    xBytesSent = xStreamBufferSend( xStreamBuffer, ( void * ) pcStringToSend, strlen( pcStringToSend ), 0 );
+
+    if( xBytesSent != strlen( pcStringToSend ) )
+    {
+        // The entire string could not be added to the stream buffer because
+        // there was not enough free space in the buffer, but xBytesSent bytes
+        // were sent.  Could try again to send the remaining bytes.
+    }
+}
+
+ * \defgroup xStreamBufferSend xStreamBufferSend + * \ingroup StreamBufferManagement + */ +size_t xStreamBufferSend( StreamBufferHandle_t xStreamBuffer, + const void *pvTxData, + size_t xDataLengthBytes, + TickType_t xTicksToWait ) PRIVILEGED_FUNCTION; + +/** + * stream_buffer.h + * +
+size_t xStreamBufferSendFromISR( StreamBufferHandle_t xStreamBuffer,
+                                 const void *pvTxData,
+                                 size_t xDataLengthBytes,
+                                 BaseType_t *pxHigherPriorityTaskWoken );
+
+ * + * Interrupt safe version of the API function that sends a stream of bytes to + * the stream buffer. + * + * ***NOTE***: Uniquely among FreeRTOS objects, the stream buffer + * implementation (so also the message buffer implementation, as message buffers + * are built on top of stream buffers) assumes there is only one task or + * interrupt that will write to the buffer (the writer), and only one task or + * interrupt that will read from the buffer (the reader). It is safe for the + * writer and reader to be different tasks or interrupts, but, unlike other + * FreeRTOS objects, it is not safe to have multiple different writers or + * multiple different readers. If there are to be multiple different writers + * then the application writer must place each call to a writing API function + * (such as xStreamBufferSend()) inside a critical section and set the send + * block time to 0. Likewise, if there are to be multiple different readers + * then the application writer must place each call to a reading API function + * (such as xStreamBufferReceive()) inside a critical section and set the receive + * block time to 0. + * + * Use xStreamBufferSend() to write to a stream buffer from a task. Use + * xStreamBufferSendFromISR() to write to a stream buffer from an interrupt + * service routine (ISR). + * + * @param xStreamBuffer The handle of the stream buffer to which a stream is + * being sent. + * + * @param pvTxData A pointer to the data that is to be copied into the stream + * buffer. + * + * @param xDataLengthBytes The maximum number of bytes to copy from pvTxData + * into the stream buffer. + * + * @param pxHigherPriorityTaskWoken It is possible that a stream buffer will + * have a task blocked on it waiting for data. Calling + * xStreamBufferSendFromISR() can make data available, and so cause a task that + * was waiting for data to leave the Blocked state. If calling + * xStreamBufferSendFromISR() causes a task to leave the Blocked state, and the + * unblocked task has a priority higher than the currently executing task (the + * task that was interrupted), then, internally, xStreamBufferSendFromISR() + * will set *pxHigherPriorityTaskWoken to pdTRUE. If + * xStreamBufferSendFromISR() sets this value to pdTRUE, then normally a + * context switch should be performed before the interrupt is exited. This will + * ensure that the interrupt returns directly to the highest priority Ready + * state task. *pxHigherPriorityTaskWoken should be set to pdFALSE before it + * is passed into the function. See the example code below for an example. + * + * @return The number of bytes actually written to the stream buffer, which will + * be less than xDataLengthBytes if the stream buffer didn't have enough free + * space for all the bytes to be written. + * + * Example use: +
+// A stream buffer that has already been created.
+StreamBufferHandle_t xStreamBuffer;
+
+void vAnInterruptServiceRoutine( void )
+{
+size_t xBytesSent;
+char *pcStringToSend = "String to send";
+BaseType_t xHigherPriorityTaskWoken = pdFALSE; // Initialised to pdFALSE.
+
+    // Attempt to send the string to the stream buffer.
+    xBytesSent = xStreamBufferSendFromISR( xStreamBuffer,
+                                           ( void * ) pcStringToSend,
+                                           strlen( pcStringToSend ),
+                                           &xHigherPriorityTaskWoken );
+
+    if( xBytesSent != strlen( pcStringToSend ) )
+    {
+        // There was not enough free space in the stream buffer for the entire
+        // string to be written, ut xBytesSent bytes were written.
+    }
+
+    // If xHigherPriorityTaskWoken was set to pdTRUE inside
+    // xStreamBufferSendFromISR() then a task that has a priority above the
+    // priority of the currently executing task was unblocked and a context
+    // switch should be performed to ensure the ISR returns to the unblocked
+    // task.  In most FreeRTOS ports this is done by simply passing
+    // xHigherPriorityTaskWoken into taskYIELD_FROM_ISR(), which will test the
+    // variables value, and perform the context switch if necessary.  Check the
+    // documentation for the port in use for port specific instructions.
+    taskYIELD_FROM_ISR( xHigherPriorityTaskWoken );
+}
+
+ * \defgroup xStreamBufferSendFromISR xStreamBufferSendFromISR + * \ingroup StreamBufferManagement + */ +size_t xStreamBufferSendFromISR( StreamBufferHandle_t xStreamBuffer, + const void *pvTxData, + size_t xDataLengthBytes, + BaseType_t * const pxHigherPriorityTaskWoken ) PRIVILEGED_FUNCTION; + +/** + * stream_buffer.h + * +
+size_t xStreamBufferReceive( StreamBufferHandle_t xStreamBuffer,
+                             void *pvRxData,
+                             size_t xBufferLengthBytes,
+                             TickType_t xTicksToWait );
+
+ * + * Receives bytes from a stream buffer. + * + * ***NOTE***: Uniquely among FreeRTOS objects, the stream buffer + * implementation (so also the message buffer implementation, as message buffers + * are built on top of stream buffers) assumes there is only one task or + * interrupt that will write to the buffer (the writer), and only one task or + * interrupt that will read from the buffer (the reader). It is safe for the + * writer and reader to be different tasks or interrupts, but, unlike other + * FreeRTOS objects, it is not safe to have multiple different writers or + * multiple different readers. If there are to be multiple different writers + * then the application writer must place each call to a writing API function + * (such as xStreamBufferSend()) inside a critical section and set the send + * block time to 0. Likewise, if there are to be multiple different readers + * then the application writer must place each call to a reading API function + * (such as xStreamBufferReceive()) inside a critical section and set the receive + * block time to 0. + * + * Use xStreamBufferReceive() to read from a stream buffer from a task. Use + * xStreamBufferReceiveFromISR() to read from a stream buffer from an + * interrupt service routine (ISR). + * + * @param xStreamBuffer The handle of the stream buffer from which bytes are to + * be received. + * + * @param pvRxData A pointer to the buffer into which the received bytes will be + * copied. + * + * @param xBufferLengthBytes The length of the buffer pointed to by the + * pvRxData parameter. This sets the maximum number of bytes to receive in one + * call. xStreamBufferReceive will return as many bytes as possible up to a + * maximum set by xBufferLengthBytes. + * + * @param xTicksToWait The maximum amount of time the task should remain in the + * Blocked state to wait for data to become available if the stream buffer is + * empty. xStreamBufferReceive() will return immediately if xTicksToWait is + * zero. The block time is specified in tick periods, so the absolute time it + * represents is dependent on the tick frequency. The macro pdMS_TO_TICKS() can + * be used to convert a time specified in milliseconds into a time specified in + * ticks. Setting xTicksToWait to portMAX_DELAY will cause the task to wait + * indefinitely (without timing out), provided INCLUDE_vTaskSuspend is set to 1 + * in FreeRTOSConfig.h. A task does not use any CPU time when it is in the + * Blocked state. + * + * @return The number of bytes actually read from the stream buffer, which will + * be less than xBufferLengthBytes if the call to xStreamBufferReceive() timed + * out before xBufferLengthBytes were available. + * + * Example use: +
+void vAFunction( StreamBuffer_t xStreamBuffer )
+{
+uint8_t ucRxData[ 20 ];
+size_t xReceivedBytes;
+const TickType_t xBlockTime = pdMS_TO_TICKS( 20 );
+
+    // Receive up to another sizeof( ucRxData ) bytes from the stream buffer.
+    // Wait in the Blocked state (so not using any CPU processing time) for a
+    // maximum of 100ms for the full sizeof( ucRxData ) number of bytes to be
+    // available.
+    xReceivedBytes = xStreamBufferReceive( xStreamBuffer,
+                                           ( void * ) ucRxData,
+                                           sizeof( ucRxData ),
+                                           xBlockTime );
+
+    if( xReceivedBytes > 0 )
+    {
+        // A ucRxData contains another xRecievedBytes bytes of data, which can
+        // be processed here....
+    }
+}
+
+ * \defgroup xStreamBufferReceive xStreamBufferReceive + * \ingroup StreamBufferManagement + */ +size_t xStreamBufferReceive( StreamBufferHandle_t xStreamBuffer, + void *pvRxData, + size_t xBufferLengthBytes, + TickType_t xTicksToWait ) PRIVILEGED_FUNCTION; + +/** + * stream_buffer.h + * +
+size_t xStreamBufferReceiveFromISR( StreamBufferHandle_t xStreamBuffer,
+                                    void *pvRxData,
+                                    size_t xBufferLengthBytes,
+                                    BaseType_t *pxHigherPriorityTaskWoken );
+
+ * + * An interrupt safe version of the API function that receives bytes from a + * stream buffer. + * + * Use xStreamBufferReceive() to read bytes from a stream buffer from a task. + * Use xStreamBufferReceiveFromISR() to read bytes from a stream buffer from an + * interrupt service routine (ISR). + * + * @param xStreamBuffer The handle of the stream buffer from which a stream + * is being received. + * + * @param pvRxData A pointer to the buffer into which the received bytes are + * copied. + * + * @param xBufferLengthBytes The length of the buffer pointed to by the + * pvRxData parameter. This sets the maximum number of bytes to receive in one + * call. xStreamBufferReceive will return as many bytes as possible up to a + * maximum set by xBufferLengthBytes. + * + * @param pxHigherPriorityTaskWoken It is possible that a stream buffer will + * have a task blocked on it waiting for space to become available. Calling + * xStreamBufferReceiveFromISR() can make space available, and so cause a task + * that is waiting for space to leave the Blocked state. If calling + * xStreamBufferReceiveFromISR() causes a task to leave the Blocked state, and + * the unblocked task has a priority higher than the currently executing task + * (the task that was interrupted), then, internally, + * xStreamBufferReceiveFromISR() will set *pxHigherPriorityTaskWoken to pdTRUE. + * If xStreamBufferReceiveFromISR() sets this value to pdTRUE, then normally a + * context switch should be performed before the interrupt is exited. That will + * ensure the interrupt returns directly to the highest priority Ready state + * task. *pxHigherPriorityTaskWoken should be set to pdFALSE before it is + * passed into the function. See the code example below for an example. + * + * @return The number of bytes read from the stream buffer, if any. + * + * Example use: +
+// A stream buffer that has already been created.
+StreamBuffer_t xStreamBuffer;
+
+void vAnInterruptServiceRoutine( void )
+{
+uint8_t ucRxData[ 20 ];
+size_t xReceivedBytes;
+BaseType_t xHigherPriorityTaskWoken = pdFALSE;  // Initialised to pdFALSE.
+
+    // Receive the next stream from the stream buffer.
+    xReceivedBytes = xStreamBufferReceiveFromISR( xStreamBuffer,
+                                                  ( void * ) ucRxData,
+                                                  sizeof( ucRxData ),
+                                                  &xHigherPriorityTaskWoken );
+
+    if( xReceivedBytes > 0 )
+    {
+        // ucRxData contains xReceivedBytes read from the stream buffer.
+        // Process the stream here....
+    }
+
+    // If xHigherPriorityTaskWoken was set to pdTRUE inside
+    // xStreamBufferReceiveFromISR() then a task that has a priority above the
+    // priority of the currently executing task was unblocked and a context
+    // switch should be performed to ensure the ISR returns to the unblocked
+    // task.  In most FreeRTOS ports this is done by simply passing
+    // xHigherPriorityTaskWoken into taskYIELD_FROM_ISR(), which will test the
+    // variables value, and perform the context switch if necessary.  Check the
+    // documentation for the port in use for port specific instructions.
+    taskYIELD_FROM_ISR( xHigherPriorityTaskWoken );
+}
+
+ * \defgroup xStreamBufferReceiveFromISR xStreamBufferReceiveFromISR + * \ingroup StreamBufferManagement + */ +size_t xStreamBufferReceiveFromISR( StreamBufferHandle_t xStreamBuffer, + void *pvRxData, + size_t xBufferLengthBytes, + BaseType_t * const pxHigherPriorityTaskWoken ) PRIVILEGED_FUNCTION; + +/** + * stream_buffer.h + * +
+void vStreamBufferDelete( StreamBufferHandle_t xStreamBuffer );
+
+ * + * Deletes a stream buffer that was previously created using a call to + * xStreamBufferCreate() or xStreamBufferCreateStatic(). If the stream + * buffer was created using dynamic memory (that is, by xStreamBufferCreate()), + * then the allocated memory is freed. + * + * A stream buffer handle must not be used after the stream buffer has been + * deleted. + * + * @param xStreamBuffer The handle of the stream buffer to be deleted. + * + * \defgroup vStreamBufferDelete vStreamBufferDelete + * \ingroup StreamBufferManagement + */ +void vStreamBufferDelete( StreamBufferHandle_t xStreamBuffer ) PRIVILEGED_FUNCTION; + +/** + * stream_buffer.h + * +
+BaseType_t xStreamBufferIsFull( StreamBufferHandle_t xStreamBuffer );
+
+ * + * Queries a stream buffer to see if it is full. A stream buffer is full if it + * does not have any free space, and therefore cannot accept any more data. + * + * @param xStreamBuffer The handle of the stream buffer being queried. + * + * @return If the stream buffer is full then pdTRUE is returned. Otherwise + * pdFALSE is returned. + * + * \defgroup xStreamBufferIsFull xStreamBufferIsFull + * \ingroup StreamBufferManagement + */ +BaseType_t xStreamBufferIsFull( StreamBufferHandle_t xStreamBuffer ) PRIVILEGED_FUNCTION; + +/** + * stream_buffer.h + * +
+BaseType_t xStreamBufferIsEmpty( StreamBufferHandle_t xStreamBuffer );
+
+ * + * Queries a stream buffer to see if it is empty. A stream buffer is empty if + * it does not contain any data. + * + * @param xStreamBuffer The handle of the stream buffer being queried. + * + * @return If the stream buffer is empty then pdTRUE is returned. Otherwise + * pdFALSE is returned. + * + * \defgroup xStreamBufferIsEmpty xStreamBufferIsEmpty + * \ingroup StreamBufferManagement + */ +BaseType_t xStreamBufferIsEmpty( StreamBufferHandle_t xStreamBuffer ) PRIVILEGED_FUNCTION; + +/** + * stream_buffer.h + * +
+BaseType_t xStreamBufferReset( StreamBufferHandle_t xStreamBuffer );
+
+ * + * Resets a stream buffer to its initial, empty, state. Any data that was in + * the stream buffer is discarded. A stream buffer can only be reset if there + * are no tasks blocked waiting to either send to or receive from the stream + * buffer. + * + * @param xStreamBuffer The handle of the stream buffer being reset. + * + * @return If the stream buffer is reset then pdPASS is returned. If there was + * a task blocked waiting to send to or read from the stream buffer then the + * stream buffer is not reset and pdFAIL is returned. + * + * \defgroup xStreamBufferReset xStreamBufferReset + * \ingroup StreamBufferManagement + */ +BaseType_t xStreamBufferReset( StreamBufferHandle_t xStreamBuffer ) PRIVILEGED_FUNCTION; + +/** + * stream_buffer.h + * +
+size_t xStreamBufferSpacesAvailable( StreamBufferHandle_t xStreamBuffer );
+
+ * + * Queries a stream buffer to see how much free space it contains, which is + * equal to the amount of data that can be sent to the stream buffer before it + * is full. + * + * @param xStreamBuffer The handle of the stream buffer being queried. + * + * @return The number of bytes that can be written to the stream buffer before + * the stream buffer would be full. + * + * \defgroup xStreamBufferSpacesAvailable xStreamBufferSpacesAvailable + * \ingroup StreamBufferManagement + */ +size_t xStreamBufferSpacesAvailable( StreamBufferHandle_t xStreamBuffer ) PRIVILEGED_FUNCTION; + +/** + * stream_buffer.h + * +
+size_t xStreamBufferBytesAvailable( StreamBufferHandle_t xStreamBuffer );
+
+ * + * Queries a stream buffer to see how much data it contains, which is equal to + * the number of bytes that can be read from the stream buffer before the stream + * buffer would be empty. + * + * @param xStreamBuffer The handle of the stream buffer being queried. + * + * @return The number of bytes that can be read from the stream buffer before + * the stream buffer would be empty. + * + * \defgroup xStreamBufferBytesAvailable xStreamBufferBytesAvailable + * \ingroup StreamBufferManagement + */ +size_t xStreamBufferBytesAvailable( StreamBufferHandle_t xStreamBuffer ) PRIVILEGED_FUNCTION; + +/** + * stream_buffer.h + * +
+BaseType_t xStreamBufferSetTriggerLevel( StreamBufferHandle_t xStreamBuffer, size_t xTriggerLevel );
+
+ * + * A stream buffer's trigger level is the number of bytes that must be in the + * stream buffer before a task that is blocked on the stream buffer to + * wait for data is moved out of the blocked state. For example, if a task is + * blocked on a read of an empty stream buffer that has a trigger level of 1 + * then the task will be unblocked when a single byte is written to the buffer + * or the task's block time expires. As another example, if a task is blocked + * on a read of an empty stream buffer that has a trigger level of 10 then the + * task will not be unblocked until the stream buffer contains at least 10 bytes + * or the task's block time expires. If a reading task's block time expires + * before the trigger level is reached then the task will still receive however + * many bytes are actually available. Setting a trigger level of 0 will result + * in a trigger level of 1 being used. It is not valid to specify a trigger + * level that is greater than the buffer size. + * + * A trigger level is set when the stream buffer is created, and can be modified + * using xStreamBufferSetTriggerLevel(). + * + * @param xStreamBuffer The handle of the stream buffer being updated. + * + * @param xTriggerLevel The new trigger level for the stream buffer. + * + * @return If xTriggerLevel was less than or equal to the stream buffer's length + * then the trigger level will be updated and pdTRUE is returned. Otherwise + * pdFALSE is returned. + * + * \defgroup xStreamBufferSetTriggerLevel xStreamBufferSetTriggerLevel + * \ingroup StreamBufferManagement + */ +BaseType_t xStreamBufferSetTriggerLevel( StreamBufferHandle_t xStreamBuffer, size_t xTriggerLevel ) PRIVILEGED_FUNCTION; + +/** + * stream_buffer.h + * +
+BaseType_t xStreamBufferSendCompletedFromISR( StreamBufferHandle_t xStreamBuffer, BaseType_t *pxHigherPriorityTaskWoken );
+
+ * + * For advanced users only. + * + * The sbSEND_COMPLETED() macro is called from within the FreeRTOS APIs when + * data is sent to a message buffer or stream buffer. If there was a task that + * was blocked on the message or stream buffer waiting for data to arrive then + * the sbSEND_COMPLETED() macro sends a notification to the task to remove it + * from the Blocked state. xStreamBufferSendCompletedFromISR() does the same + * thing. It is provided to enable application writers to implement their own + * version of sbSEND_COMPLETED(), and MUST NOT BE USED AT ANY OTHER TIME. + * + * See the example implemented in FreeRTOS/Demo/Minimal/MessageBufferAMP.c for + * additional information. + * + * @param xStreamBuffer The handle of the stream buffer to which data was + * written. + * + * @param pxHigherPriorityTaskWoken *pxHigherPriorityTaskWoken should be + * initialised to pdFALSE before it is passed into + * xStreamBufferSendCompletedFromISR(). If calling + * xStreamBufferSendCompletedFromISR() removes a task from the Blocked state, + * and the task has a priority above the priority of the currently running task, + * then *pxHigherPriorityTaskWoken will get set to pdTRUE indicating that a + * context switch should be performed before exiting the ISR. + * + * @return If a task was removed from the Blocked state then pdTRUE is returned. + * Otherwise pdFALSE is returned. + * + * \defgroup xStreamBufferSendCompletedFromISR xStreamBufferSendCompletedFromISR + * \ingroup StreamBufferManagement + */ +BaseType_t xStreamBufferSendCompletedFromISR( StreamBufferHandle_t xStreamBuffer, BaseType_t *pxHigherPriorityTaskWoken ) PRIVILEGED_FUNCTION; + +/** + * stream_buffer.h + * +
+BaseType_t xStreamBufferReceiveCompletedFromISR( StreamBufferHandle_t xStreamBuffer, BaseType_t *pxHigherPriorityTaskWoken );
+
+ * + * For advanced users only. + * + * The sbRECEIVE_COMPLETED() macro is called from within the FreeRTOS APIs when + * data is read out of a message buffer or stream buffer. If there was a task + * that was blocked on the message or stream buffer waiting for data to arrive + * then the sbRECEIVE_COMPLETED() macro sends a notification to the task to + * remove it from the Blocked state. xStreamBufferReceiveCompletedFromISR() + * does the same thing. It is provided to enable application writers to + * implement their own version of sbRECEIVE_COMPLETED(), and MUST NOT BE USED AT + * ANY OTHER TIME. + * + * See the example implemented in FreeRTOS/Demo/Minimal/MessageBufferAMP.c for + * additional information. + * + * @param xStreamBuffer The handle of the stream buffer from which data was + * read. + * + * @param pxHigherPriorityTaskWoken *pxHigherPriorityTaskWoken should be + * initialised to pdFALSE before it is passed into + * xStreamBufferReceiveCompletedFromISR(). If calling + * xStreamBufferReceiveCompletedFromISR() removes a task from the Blocked state, + * and the task has a priority above the priority of the currently running task, + * then *pxHigherPriorityTaskWoken will get set to pdTRUE indicating that a + * context switch should be performed before exiting the ISR. + * + * @return If a task was removed from the Blocked state then pdTRUE is returned. + * Otherwise pdFALSE is returned. + * + * \defgroup xStreamBufferReceiveCompletedFromISR xStreamBufferReceiveCompletedFromISR + * \ingroup StreamBufferManagement + */ +BaseType_t xStreamBufferReceiveCompletedFromISR( StreamBufferHandle_t xStreamBuffer, BaseType_t *pxHigherPriorityTaskWoken ) PRIVILEGED_FUNCTION; + +/* Functions below here are not part of the public API. */ +StreamBufferHandle_t xStreamBufferGenericCreate( size_t xBufferSizeBytes, + size_t xTriggerLevelBytes, + BaseType_t xIsMessageBuffer ) PRIVILEGED_FUNCTION; + +StreamBufferHandle_t xStreamBufferGenericCreateStatic( size_t xBufferSizeBytes, + size_t xTriggerLevelBytes, + BaseType_t xIsMessageBuffer, + uint8_t * const pucStreamBufferStorageArea, + StaticStreamBuffer_t * const pxStaticStreamBuffer ) PRIVILEGED_FUNCTION; + +size_t xStreamBufferNextMessageLengthBytes( StreamBufferHandle_t xStreamBuffer ) PRIVILEGED_FUNCTION; + +#if( configUSE_TRACE_FACILITY == 1 ) + void vStreamBufferSetStreamBufferNumber( StreamBufferHandle_t xStreamBuffer, UBaseType_t uxStreamBufferNumber ) PRIVILEGED_FUNCTION; + UBaseType_t uxStreamBufferGetStreamBufferNumber( StreamBufferHandle_t xStreamBuffer ) PRIVILEGED_FUNCTION; + uint8_t ucStreamBufferGetStreamBufferType( StreamBufferHandle_t xStreamBuffer ) PRIVILEGED_FUNCTION; +#endif + +#if defined( __cplusplus ) +} +#endif + +#endif /* !defined( STREAM_BUFFER_H ) */ diff --git a/Firmware/Board/v3/Middlewares/Third_Party/FreeRTOS/Source/include/task.h b/Firmware/Board/v3/Middlewares/Third_Party/FreeRTOS/Source/include/task.h index cfa065eb..b0cc60b6 100644 --- a/Firmware/Board/v3/Middlewares/Third_Party/FreeRTOS/Source/include/task.h +++ b/Firmware/Board/v3/Middlewares/Third_Party/FreeRTOS/Source/include/task.h @@ -1,71 +1,29 @@ /* - FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. - All rights reserved - - VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. - - This file is part of the FreeRTOS distribution. - - FreeRTOS is free software; you can redistribute it and/or modify it under - the terms of the GNU General Public License (version 2) as published by the - Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception. - - *************************************************************************** - >>! NOTE: The modification to the GPL is included to allow you to !<< - >>! distribute a combined work that includes FreeRTOS without being !<< - >>! obliged to provide the source code for proprietary components !<< - >>! outside of the FreeRTOS kernel. !<< - *************************************************************************** - - FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - FOR A PARTICULAR PURPOSE. Full license text is available on the following - link: http://www.freertos.org/a00114.html - - *************************************************************************** - * * - * FreeRTOS provides completely free yet professionally developed, * - * robust, strictly quality controlled, supported, and cross * - * platform software that is more than just the market leader, it * - * is the industry's de facto standard. * - * * - * Help yourself get started quickly while simultaneously helping * - * to support the FreeRTOS project by purchasing a FreeRTOS * - * tutorial book, reference manual, or both: * - * http://www.FreeRTOS.org/Documentation * - * * - *************************************************************************** - - http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading - the FAQ page "My application does not run, what could be wrong?". Have you - defined configASSERT()? - - http://www.FreeRTOS.org/support - In return for receiving this top quality - embedded software for free we request you assist our global community by - participating in the support forum. - - http://www.FreeRTOS.org/training - Investing in training allows your team to - be as productive as possible as early as possible. Now you can receive - FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers - Ltd, and the world's leading authority on the world's leading RTOS. - - http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, - including FreeRTOS+Trace - an indispensable productivity tool, a DOS - compatible FAT file system, and our tiny thread aware UDP/IP stack. - - http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. - Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. - - http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High - Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS - licenses offer ticketed support, indemnification and commercial middleware. - - http://www.SafeRTOS.com - High Integrity Systems also provide a safety - engineered and independently SIL3 certified version for use in safety and - mission critical applications that require provable dependability. - - 1 tab == 4 spaces! -*/ + * FreeRTOS Kernel V10.3.1 + * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * http://www.FreeRTOS.org + * http://aws.amazon.com/freertos + * + * 1 tab == 4 spaces! + */ #ifndef INC_TASK_H @@ -85,10 +43,18 @@ extern "C" { * MACROS AND DEFINITIONS *----------------------------------------------------------*/ -#define tskKERNEL_VERSION_NUMBER "V9.0.0" -#define tskKERNEL_VERSION_MAJOR 9 -#define tskKERNEL_VERSION_MINOR 0 -#define tskKERNEL_VERSION_BUILD 0 +#define tskKERNEL_VERSION_NUMBER "V10.3.1" +#define tskKERNEL_VERSION_MAJOR 10 +#define tskKERNEL_VERSION_MINOR 3 +#define tskKERNEL_VERSION_BUILD 1 + +/* MPU region parameters passed in ulParameters + * of MemoryRegion_t struct. */ +#define tskMPU_REGION_READ_ONLY ( 1UL << 0UL ) +#define tskMPU_REGION_READ_WRITE ( 1UL << 1UL ) +#define tskMPU_REGION_EXECUTE_NEVER ( 1UL << 2UL ) +#define tskMPU_REGION_NORMAL_MEMORY ( 1UL << 3UL ) +#define tskMPU_REGION_DEVICE_MEMORY ( 1UL << 4UL ) /** * task. h @@ -100,7 +66,8 @@ extern "C" { * \defgroup TaskHandle_t TaskHandle_t * \ingroup Tasks */ -typedef void * TaskHandle_t; +struct tskTaskControlBlock; /* The old naming convention is used to prevent breaking kernel aware debuggers. */ +typedef struct tskTaskControlBlock* TaskHandle_t; /* * Defines the prototype to which the application task hook function must @@ -116,7 +83,7 @@ typedef enum eBlocked, /* The task being queried is in the Blocked state. */ eSuspended, /* The task being queried is in the Suspended state, or is in the Blocked state with an infinite time out. */ eDeleted, /* The task being queried has been deleted, but its TCB has not yet been freed. */ - eInvalid /* Used as an 'invalid state' value. */ + eInvalid /* Used as an 'invalid state' value. */ } eTaskState; /* Actions that can be performed when vTaskNotify() is called. */ @@ -155,11 +122,14 @@ typedef struct xTASK_PARAMETERS { TaskFunction_t pvTaskCode; const char * const pcName; /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ - uint16_t usStackDepth; + configSTACK_DEPTH_TYPE usStackDepth; void *pvParameters; UBaseType_t uxPriority; StackType_t *puxStackBuffer; MemoryRegion_t xRegions[ portNUM_CONFIGURABLE_REGIONS ]; + #if ( ( portUSING_MPU_WRAPPERS == 1 ) && ( configSUPPORT_STATIC_ALLOCATION == 1 ) ) + StaticTask_t * const pxTaskBuffer; + #endif } TaskParameters_t; /* Used with the uxTaskGetSystemState() function to return the state of each task @@ -174,7 +144,7 @@ typedef struct xTASK_STATUS UBaseType_t uxBasePriority; /* The priority to which the task will return if the task's current priority has been inherited to avoid unbounded priority inversion when obtaining a mutex. Only valid if configUSE_MUTEXES is defined as 1 in FreeRTOSConfig.h. */ uint32_t ulRunTimeCounter; /* The total run time allocated to the task so far, as defined by the run time stats clock. See http://www.freertos.org/rtos-run-time-stats.html. Only valid when configGENERATE_RUN_TIME_STATS is defined as 1 in FreeRTOSConfig.h. */ StackType_t *pxStackBase; /* Points to the lowest address of the task's stack area. */ - uint16_t usStackHighWaterMark; /* The minimum amount of stack space that has remained for the task since the task was created. The closer this value is to zero the closer the task has come to overflowing its stack. */ + configSTACK_DEPTH_TYPE usStackHighWaterMark; /* The minimum amount of stack space that has remained for the task since the task was created. The closer this value is to zero the closer the task has come to overflowing its stack. */ } TaskStatus_t; /* Possible return values for eTaskConfirmSleepModeStatus(). */ @@ -269,7 +239,7 @@ is used in assert() statements. */ BaseType_t xTaskCreate( TaskFunction_t pvTaskCode, const char * const pcName, - uint16_t usStackDepth, + configSTACK_DEPTH_TYPE usStackDepth, void *pvParameters, UBaseType_t uxPriority, TaskHandle_t *pvCreatedTask @@ -344,25 +314,25 @@ is used in assert() statements. */ // an automatic stack variable it might no longer exist, or at least have been corrupted, by the time // the new task attempts to access it. xTaskCreate( vTaskCode, "NAME", STACK_SIZE, &ucParameterToPass, tskIDLE_PRIORITY, &xHandle ); - configASSERT( xHandle ); + configASSERT( xHandle ); // Use the handle to delete the task. - if( xHandle != NULL ) - { - vTaskDelete( xHandle ); - } + if( xHandle != NULL ) + { + vTaskDelete( xHandle ); + } } * \defgroup xTaskCreate xTaskCreate * \ingroup Tasks */ #if( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) - PRIVILEGED_FUNCTION BaseType_t xTaskCreate( TaskFunction_t pxTaskCode, - const char * const pcName, - const uint16_t usStackDepth, + BaseType_t xTaskCreate( TaskFunction_t pxTaskCode, + const char * const pcName, /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ + const configSTACK_DEPTH_TYPE usStackDepth, void * const pvParameters, UBaseType_t uxPriority, - TaskHandle_t * const pxCreatedTask ); /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ + TaskHandle_t * const pxCreatedTask ) PRIVILEGED_FUNCTION; #endif /** @@ -414,9 +384,9 @@ is used in assert() statements. */ * memory to be allocated dynamically. * * @return If neither pxStackBuffer or pxTaskBuffer are NULL, then the task will - * be created and pdPASS is returned. If either pxStackBuffer or pxTaskBuffer - * are NULL then the task will not be created and - * errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY is returned. + * be created and a handle to the created task is returned. If either + * pxStackBuffer or pxTaskBuffer are NULL then the task will not be created and + * NULL is returned. * * Example usage:
@@ -473,13 +443,13 @@ is used in assert() statements. */
  * \ingroup Tasks
  */
 #if( configSUPPORT_STATIC_ALLOCATION == 1 )
-	PRIVILEGED_FUNCTION TaskHandle_t xTaskCreateStatic(	TaskFunction_t pxTaskCode,
-									const char * const pcName,
+	TaskHandle_t xTaskCreateStatic(	TaskFunction_t pxTaskCode,
+									const char * const pcName, /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
 									const uint32_t ulStackDepth,
 									void * const pvParameters,
 									UBaseType_t uxPriority,
 									StackType_t * const puxStackBuffer,
-									StaticTask_t * const pxTaskBuffer ); /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
+									StaticTask_t * const pxTaskBuffer ) PRIVILEGED_FUNCTION;
 #endif /* configSUPPORT_STATIC_ALLOCATION */
 
 /**
@@ -487,6 +457,8 @@ is used in assert() statements. */
  *
  BaseType_t xTaskCreateRestricted( TaskParameters_t *pxTaskDefinition, TaskHandle_t *pxCreatedTask );
* + * Only available when configSUPPORT_DYNAMIC_ALLOCATION is set to 1. + * * xTaskCreateRestricted() should only be used in systems that include an MPU * implementation. * @@ -494,6 +466,9 @@ is used in assert() statements. */ * The function parameters define the memory regions and associated access * permissions allocated to the task. * + * See xTaskCreateRestrictedStatic() for a version that does not use any + * dynamic memory allocation. + * * @param pxTaskDefinition Pointer to a structure that contains a member * for each of the normal xTaskCreate() parameters (see the xTaskCreate() API * documentation) plus an optional stack buffer and the memory region @@ -523,9 +498,9 @@ static const TaskParameters_t xCheckTaskParameters = // for full information. { // Base address Length Parameters - { cReadWriteArray, 32, portMPU_REGION_READ_WRITE }, - { cReadOnlyArray, 32, portMPU_REGION_READ_ONLY }, - { cPrivilegedOnlyAccessArray, 128, portMPU_REGION_PRIVILEGED_READ_WRITE } + { cReadWriteArray, 32, portMPU_REGION_READ_WRITE }, + { cReadOnlyArray, 32, portMPU_REGION_READ_ONLY }, + { cPrivilegedOnlyAccessArray, 128, portMPU_REGION_PRIVILEGED_READ_WRITE } } }; @@ -550,7 +525,95 @@ TaskHandle_t xHandle; * \ingroup Tasks */ #if( portUSING_MPU_WRAPPERS == 1 ) - PRIVILEGED_FUNCTION BaseType_t xTaskCreateRestricted( const TaskParameters_t * const pxTaskDefinition, TaskHandle_t *pxCreatedTask ); + BaseType_t xTaskCreateRestricted( const TaskParameters_t * const pxTaskDefinition, TaskHandle_t *pxCreatedTask ) PRIVILEGED_FUNCTION; +#endif + +/** + * task. h + *
+ BaseType_t xTaskCreateRestrictedStatic( TaskParameters_t *pxTaskDefinition, TaskHandle_t *pxCreatedTask );
+ * + * Only available when configSUPPORT_STATIC_ALLOCATION is set to 1. + * + * xTaskCreateRestrictedStatic() should only be used in systems that include an + * MPU implementation. + * + * Internally, within the FreeRTOS implementation, tasks use two blocks of + * memory. The first block is used to hold the task's data structures. The + * second block is used by the task as its stack. If a task is created using + * xTaskCreateRestricted() then the stack is provided by the application writer, + * and the memory used to hold the task's data structure is automatically + * dynamically allocated inside the xTaskCreateRestricted() function. If a task + * is created using xTaskCreateRestrictedStatic() then the application writer + * must provide the memory used to hold the task's data structures too. + * xTaskCreateRestrictedStatic() therefore allows a memory protected task to be + * created without using any dynamic memory allocation. + * + * @param pxTaskDefinition Pointer to a structure that contains a member + * for each of the normal xTaskCreate() parameters (see the xTaskCreate() API + * documentation) plus an optional stack buffer and the memory region + * definitions. If configSUPPORT_STATIC_ALLOCATION is set to 1 the structure + * contains an additional member, which is used to point to a variable of type + * StaticTask_t - which is then used to hold the task's data structure. + * + * @param pxCreatedTask Used to pass back a handle by which the created task + * can be referenced. + * + * @return pdPASS if the task was successfully created and added to a ready + * list, otherwise an error code defined in the file projdefs.h + * + * Example usage: +
+// Create an TaskParameters_t structure that defines the task to be created.
+// The StaticTask_t variable is only included in the structure when
+// configSUPPORT_STATIC_ALLOCATION is set to 1.  The PRIVILEGED_DATA macro can
+// be used to force the variable into the RTOS kernel's privileged data area.
+static PRIVILEGED_DATA StaticTask_t xTaskBuffer;
+static const TaskParameters_t xCheckTaskParameters =
+{
+	vATask,		// pvTaskCode - the function that implements the task.
+	"ATask",	// pcName - just a text name for the task to assist debugging.
+	100,		// usStackDepth	- the stack size DEFINED IN WORDS.
+	NULL,		// pvParameters - passed into the task function as the function parameters.
+	( 1UL | portPRIVILEGE_BIT ),// uxPriority - task priority, set the portPRIVILEGE_BIT if the task should run in a privileged state.
+	cStackBuffer,// puxStackBuffer - the buffer to be used as the task stack.
+
+	// xRegions - Allocate up to three separate memory regions for access by
+	// the task, with appropriate access permissions.  Different processors have
+	// different memory alignment requirements - refer to the FreeRTOS documentation
+	// for full information.
+	{
+		// Base address					Length	Parameters
+		{ cReadWriteArray,				32,		portMPU_REGION_READ_WRITE },
+		{ cReadOnlyArray,				32,		portMPU_REGION_READ_ONLY },
+		{ cPrivilegedOnlyAccessArray,	128,	portMPU_REGION_PRIVILEGED_READ_WRITE }
+	}
+
+	&xTaskBuffer; // Holds the task's data structure.
+};
+
+int main( void )
+{
+TaskHandle_t xHandle;
+
+	// Create a task from the const structure defined above.  The task handle
+	// is requested (the second parameter is not NULL) but in this case just for
+	// demonstration purposes as its not actually used.
+	xTaskCreateRestricted( &xRegTest1Parameters, &xHandle );
+
+	// Start the scheduler.
+	vTaskStartScheduler();
+
+	// Will only get here if there was insufficient memory to create the idle
+	// and/or timer task.
+	for( ;; );
+}
+   
+ * \defgroup xTaskCreateRestrictedStatic xTaskCreateRestrictedStatic + * \ingroup Tasks + */ +#if( ( portUSING_MPU_WRAPPERS == 1 ) && ( configSUPPORT_STATIC_ALLOCATION == 1 ) ) + BaseType_t xTaskCreateRestrictedStatic( const TaskParameters_t * const pxTaskDefinition, TaskHandle_t *pxCreatedTask ) PRIVILEGED_FUNCTION; #endif /** @@ -599,7 +662,7 @@ void vATask( void *pvParameters ) * \defgroup xTaskCreateRestricted xTaskCreateRestricted * \ingroup Tasks */ -PRIVILEGED_FUNCTION void vTaskAllocateMPURegions( TaskHandle_t xTask, const MemoryRegion_t * const pxRegions ); +void vTaskAllocateMPURegions( TaskHandle_t xTask, const MemoryRegion_t * const pxRegions ) PRIVILEGED_FUNCTION; /** * task. h @@ -640,7 +703,7 @@ PRIVILEGED_FUNCTION void vTaskAllocateMPURegions( TaskHandle_t xTask, const Memo * \defgroup vTaskDelete vTaskDelete * \ingroup Tasks */ -PRIVILEGED_FUNCTION void vTaskDelete( TaskHandle_t xTaskToDelete ); +void vTaskDelete( TaskHandle_t xTaskToDelete ) PRIVILEGED_FUNCTION; /*----------------------------------------------------------- * TASK CONTROL API @@ -692,7 +755,7 @@ PRIVILEGED_FUNCTION void vTaskDelete( TaskHandle_t xTaskToDelete ); * \defgroup vTaskDelay vTaskDelay * \ingroup TaskCtrl */ -PRIVILEGED_FUNCTION void vTaskDelay( const TickType_t xTicksToDelay ); +void vTaskDelay( const TickType_t xTicksToDelay ) PRIVILEGED_FUNCTION; /** * task. h @@ -751,7 +814,7 @@ PRIVILEGED_FUNCTION void vTaskDelay( const TickType_t xTicksToDelay ); * \defgroup vTaskDelayUntil vTaskDelayUntil * \ingroup TaskCtrl */ -PRIVILEGED_FUNCTION void vTaskDelayUntil( TickType_t * const pxPreviousWakeTime, const TickType_t xTimeIncrement ); +void vTaskDelayUntil( TickType_t * const pxPreviousWakeTime, const TickType_t xTimeIncrement ) PRIVILEGED_FUNCTION; /** * task. h @@ -768,6 +831,11 @@ PRIVILEGED_FUNCTION void vTaskDelayUntil( TickType_t * const pxPreviousWakeTime, * task will leave the Blocked state, and return from whichever function call * placed the task into the Blocked state. * + * There is no 'FromISR' version of this function as an interrupt would need to + * know which object a task was blocked on in order to know which actions to + * take. For example, if the task was blocked on a queue the interrupt handler + * would then need to know if the queue was locked. + * * @param xTask The handle of the task to remove from the Blocked state. * * @return If the task referenced by xTask was not in the Blocked state then @@ -776,11 +844,11 @@ PRIVILEGED_FUNCTION void vTaskDelayUntil( TickType_t * const pxPreviousWakeTime, * \defgroup xTaskAbortDelay xTaskAbortDelay * \ingroup TaskCtrl */ -PRIVILEGED_FUNCTION BaseType_t xTaskAbortDelay( TaskHandle_t xTask ); +BaseType_t xTaskAbortDelay( TaskHandle_t xTask ) PRIVILEGED_FUNCTION; /** * task. h - *
UBaseType_t uxTaskPriorityGet( TaskHandle_t xTask );
+ *
UBaseType_t uxTaskPriorityGet( const TaskHandle_t xTask );
* * INCLUDE_uxTaskPriorityGet must be defined as 1 for this function to be available. * See the configuration section for more information. @@ -823,15 +891,15 @@ PRIVILEGED_FUNCTION BaseType_t xTaskAbortDelay( TaskHandle_t xTask ); * \defgroup uxTaskPriorityGet uxTaskPriorityGet * \ingroup TaskCtrl */ -PRIVILEGED_FUNCTION UBaseType_t uxTaskPriorityGet( TaskHandle_t xTask ); +UBaseType_t uxTaskPriorityGet( const TaskHandle_t xTask ) PRIVILEGED_FUNCTION; /** * task. h - *
UBaseType_t uxTaskPriorityGetFromISR( TaskHandle_t xTask );
+ *
UBaseType_t uxTaskPriorityGetFromISR( const TaskHandle_t xTask );
* * A version of uxTaskPriorityGet() that can be used from an ISR. */ -PRIVILEGED_FUNCTION UBaseType_t uxTaskPriorityGetFromISR( TaskHandle_t xTask ); +UBaseType_t uxTaskPriorityGetFromISR( const TaskHandle_t xTask ) PRIVILEGED_FUNCTION; /** * task. h @@ -849,7 +917,7 @@ PRIVILEGED_FUNCTION UBaseType_t uxTaskPriorityGetFromISR( TaskHandle_t xTask ); * state of the task might change between the function being called, and the * functions return value being tested by the calling task. */ -PRIVILEGED_FUNCTION eTaskState eTaskGetState( TaskHandle_t xTask ); +eTaskState eTaskGetState( TaskHandle_t xTask ) PRIVILEGED_FUNCTION; /** * task. h @@ -905,7 +973,7 @@ PRIVILEGED_FUNCTION eTaskState eTaskGetState( TaskHandle_t xTask ); * \defgroup vTaskGetInfo vTaskGetInfo * \ingroup TaskCtrl */ -PRIVILEGED_FUNCTION void vTaskGetInfo( TaskHandle_t xTask, TaskStatus_t *pxTaskStatus, BaseType_t xGetFreeStackSpace, eTaskState eState ); +void vTaskGetInfo( TaskHandle_t xTask, TaskStatus_t *pxTaskStatus, BaseType_t xGetFreeStackSpace, eTaskState eState ) PRIVILEGED_FUNCTION; /** * task. h @@ -947,7 +1015,7 @@ PRIVILEGED_FUNCTION void vTaskGetInfo( TaskHandle_t xTask, TaskStatus_t *pxTaskS * \defgroup vTaskPrioritySet vTaskPrioritySet * \ingroup TaskCtrl */ -PRIVILEGED_FUNCTION void vTaskPrioritySet( TaskHandle_t xTask, UBaseType_t uxNewPriority ); +void vTaskPrioritySet( TaskHandle_t xTask, UBaseType_t uxNewPriority ) PRIVILEGED_FUNCTION; /** * task. h @@ -998,7 +1066,7 @@ PRIVILEGED_FUNCTION void vTaskPrioritySet( TaskHandle_t xTask, UBaseType_t uxNew * \defgroup vTaskSuspend vTaskSuspend * \ingroup TaskCtrl */ -PRIVILEGED_FUNCTION void vTaskSuspend( TaskHandle_t xTaskToSuspend ); +void vTaskSuspend( TaskHandle_t xTaskToSuspend ) PRIVILEGED_FUNCTION; /** * task. h @@ -1047,7 +1115,7 @@ PRIVILEGED_FUNCTION void vTaskSuspend( TaskHandle_t xTaskToSuspend ); * \defgroup vTaskResume vTaskResume * \ingroup TaskCtrl */ -PRIVILEGED_FUNCTION void vTaskResume( TaskHandle_t xTaskToResume ); +void vTaskResume( TaskHandle_t xTaskToResume ) PRIVILEGED_FUNCTION; /** * task. h @@ -1076,7 +1144,7 @@ PRIVILEGED_FUNCTION void vTaskResume( TaskHandle_t xTaskToResume ); * \defgroup vTaskResumeFromISR vTaskResumeFromISR * \ingroup TaskCtrl */ -PRIVILEGED_FUNCTION BaseType_t xTaskResumeFromISR( TaskHandle_t xTaskToResume ); +BaseType_t xTaskResumeFromISR( TaskHandle_t xTaskToResume ) PRIVILEGED_FUNCTION; /*----------------------------------------------------------- * SCHEDULER CONTROL @@ -1109,7 +1177,7 @@ PRIVILEGED_FUNCTION BaseType_t xTaskResumeFromISR( TaskHandle_t xTaskToResume ); * \defgroup vTaskStartScheduler vTaskStartScheduler * \ingroup SchedulerControl */ -PRIVILEGED_FUNCTION void vTaskStartScheduler( void ); +void vTaskStartScheduler( void ) PRIVILEGED_FUNCTION; /** * task. h @@ -1165,7 +1233,7 @@ PRIVILEGED_FUNCTION void vTaskStartScheduler( void ); * \defgroup vTaskEndScheduler vTaskEndScheduler * \ingroup SchedulerControl */ -PRIVILEGED_FUNCTION void vTaskEndScheduler( void ); +void vTaskEndScheduler( void ) PRIVILEGED_FUNCTION; /** * task. h @@ -1216,7 +1284,7 @@ PRIVILEGED_FUNCTION void vTaskEndScheduler( void ); * \defgroup vTaskSuspendAll vTaskSuspendAll * \ingroup SchedulerControl */ -PRIVILEGED_FUNCTION void vTaskSuspendAll( void ); +void vTaskSuspendAll( void ) PRIVILEGED_FUNCTION; /** * task. h @@ -1270,7 +1338,7 @@ PRIVILEGED_FUNCTION void vTaskSuspendAll( void ); * \defgroup xTaskResumeAll xTaskResumeAll * \ingroup SchedulerControl */ -PRIVILEGED_FUNCTION BaseType_t xTaskResumeAll( void ); +BaseType_t xTaskResumeAll( void ) PRIVILEGED_FUNCTION; /*----------------------------------------------------------- * TASK UTILITIES @@ -1285,7 +1353,7 @@ PRIVILEGED_FUNCTION BaseType_t xTaskResumeAll( void ); * \defgroup xTaskGetTickCount xTaskGetTickCount * \ingroup TaskUtils */ -PRIVILEGED_FUNCTION TickType_t xTaskGetTickCount( void ); +TickType_t xTaskGetTickCount( void ) PRIVILEGED_FUNCTION; /** * task. h @@ -1301,7 +1369,7 @@ PRIVILEGED_FUNCTION TickType_t xTaskGetTickCount( void ); * \defgroup xTaskGetTickCountFromISR xTaskGetTickCountFromISR * \ingroup TaskUtils */ -PRIVILEGED_FUNCTION TickType_t xTaskGetTickCountFromISR( void ); +TickType_t xTaskGetTickCountFromISR( void ) PRIVILEGED_FUNCTION; /** * task. h @@ -1315,7 +1383,7 @@ PRIVILEGED_FUNCTION TickType_t xTaskGetTickCountFromISR( void ); * \defgroup uxTaskGetNumberOfTasks uxTaskGetNumberOfTasks * \ingroup TaskUtils */ -PRIVILEGED_FUNCTION UBaseType_t uxTaskGetNumberOfTasks( void ); +UBaseType_t uxTaskGetNumberOfTasks( void ) PRIVILEGED_FUNCTION; /** * task. h @@ -1328,7 +1396,7 @@ PRIVILEGED_FUNCTION UBaseType_t uxTaskGetNumberOfTasks( void ); * \defgroup pcTaskGetName pcTaskGetName * \ingroup TaskUtils */ -PRIVILEGED_FUNCTION char *pcTaskGetName( TaskHandle_t xTaskToQuery ); /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ +char *pcTaskGetName( TaskHandle_t xTaskToQuery ) PRIVILEGED_FUNCTION; /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ /** * task. h @@ -1344,7 +1412,7 @@ PRIVILEGED_FUNCTION char *pcTaskGetName( TaskHandle_t xTaskToQuery ); /*lint !e9 * \defgroup pcTaskGetHandle pcTaskGetHandle * \ingroup TaskUtils */ -PRIVILEGED_FUNCTION TaskHandle_t xTaskGetHandle( const char *pcNameToQuery ); /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ +TaskHandle_t xTaskGetHandle( const char *pcNameToQuery ) PRIVILEGED_FUNCTION; /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ /** * task.h @@ -1358,6 +1426,12 @@ PRIVILEGED_FUNCTION TaskHandle_t xTaskGetHandle( const char *pcNameToQuery ); /* * a value of 1 means 4 bytes) since the task started. The smaller the returned * number the closer the task has come to overflowing its stack. * + * uxTaskGetStackHighWaterMark() and uxTaskGetStackHighWaterMark2() are the + * same except for their return type. Using configSTACK_DEPTH_TYPE allows the + * user to determine the return type. It gets around the problem of the value + * overflowing on 8-bit types without breaking backward compatibility for + * applications that expect an 8-bit return type. + * * @param xTask Handle of the task associated with the stack to be checked. * Set xTask to NULL to check the stack of the calling task. * @@ -1365,7 +1439,34 @@ PRIVILEGED_FUNCTION TaskHandle_t xTaskGetHandle( const char *pcNameToQuery ); /* * actual spaces on the stack rather than bytes) since the task referenced by * xTask was created. */ -PRIVILEGED_FUNCTION UBaseType_t uxTaskGetStackHighWaterMark( TaskHandle_t xTask ); +UBaseType_t uxTaskGetStackHighWaterMark( TaskHandle_t xTask ) PRIVILEGED_FUNCTION; + +/** + * task.h + *
configSTACK_DEPTH_TYPE uxTaskGetStackHighWaterMark2( TaskHandle_t xTask );
+ * + * INCLUDE_uxTaskGetStackHighWaterMark2 must be set to 1 in FreeRTOSConfig.h for + * this function to be available. + * + * Returns the high water mark of the stack associated with xTask. That is, + * the minimum free stack space there has been (in words, so on a 32 bit machine + * a value of 1 means 4 bytes) since the task started. The smaller the returned + * number the closer the task has come to overflowing its stack. + * + * uxTaskGetStackHighWaterMark() and uxTaskGetStackHighWaterMark2() are the + * same except for their return type. Using configSTACK_DEPTH_TYPE allows the + * user to determine the return type. It gets around the problem of the value + * overflowing on 8-bit types without breaking backward compatibility for + * applications that expect an 8-bit return type. + * + * @param xTask Handle of the task associated with the stack to be checked. + * Set xTask to NULL to check the stack of the calling task. + * + * @return The smallest amount of free stack space there has been (in words, so + * actual spaces on the stack rather than bytes) since the task referenced by + * xTask was created. + */ +configSTACK_DEPTH_TYPE uxTaskGetStackHighWaterMark2( TaskHandle_t xTask ) PRIVILEGED_FUNCTION; /* When using trace macros it is sometimes necessary to include task.h before FreeRTOS.h. When this is done TaskHookFunction_t will not yet have been defined, @@ -1383,15 +1484,26 @@ constant. */ * Passing xTask as NULL has the effect of setting the calling tasks hook * function. */ - PRIVILEGED_FUNCTION void vTaskSetApplicationTaskTag( TaskHandle_t xTask, TaskHookFunction_t pxHookFunction ); + void vTaskSetApplicationTaskTag( TaskHandle_t xTask, TaskHookFunction_t pxHookFunction ) PRIVILEGED_FUNCTION; /** * task.h *
void xTaskGetApplicationTaskTag( TaskHandle_t xTask );
* - * Returns the pxHookFunction value assigned to the task xTask. + * Returns the pxHookFunction value assigned to the task xTask. Do not + * call from an interrupt service routine - call + * xTaskGetApplicationTaskTagFromISR() instead. */ - PRIVILEGED_FUNCTION TaskHookFunction_t xTaskGetApplicationTaskTag( TaskHandle_t xTask ); + TaskHookFunction_t xTaskGetApplicationTaskTag( TaskHandle_t xTask ) PRIVILEGED_FUNCTION; + + /** + * task.h + *
void xTaskGetApplicationTaskTagFromISR( TaskHandle_t xTask );
+ * + * Returns the pxHookFunction value assigned to the task xTask. Can + * be called from an interrupt service routine. + */ + TaskHookFunction_t xTaskGetApplicationTaskTagFromISR( TaskHandle_t xTask ) PRIVILEGED_FUNCTION; #endif /* configUSE_APPLICATION_TASK_TAG ==1 */ #endif /* ifdef configUSE_APPLICATION_TASK_TAG */ @@ -1402,8 +1514,8 @@ constant. */ kernel does not use the pointers itself, so the application writer can use the pointers for any purpose they wish. The following two functions are used to set and query a pointer respectively. */ - PRIVILEGED_FUNCTION void vTaskSetThreadLocalStoragePointer( TaskHandle_t xTaskToSet, BaseType_t xIndex, void *pvValue ); - PRIVILEGED_FUNCTION void *pvTaskGetThreadLocalStoragePointer( TaskHandle_t xTaskToQuery, BaseType_t xIndex ); + void vTaskSetThreadLocalStoragePointer( TaskHandle_t xTaskToSet, BaseType_t xIndex, void *pvValue ) PRIVILEGED_FUNCTION; + void *pvTaskGetThreadLocalStoragePointer( TaskHandle_t xTaskToQuery, BaseType_t xIndex ) PRIVILEGED_FUNCTION; #endif @@ -1418,7 +1530,7 @@ constant. */ * wants. The return value is the value returned by the task hook function * registered by the user. */ -PRIVILEGED_FUNCTION BaseType_t xTaskCallApplicationTaskHook( TaskHandle_t xTask, void *pvParameter ); +BaseType_t xTaskCallApplicationTaskHook( TaskHandle_t xTask, void *pvParameter ) PRIVILEGED_FUNCTION; /** * xTaskGetIdleTaskHandle() is only available if @@ -1427,7 +1539,7 @@ PRIVILEGED_FUNCTION BaseType_t xTaskCallApplicationTaskHook( TaskHandle_t xTask, * Simply returns the handle of the idle task. It is not valid to call * xTaskGetIdleTaskHandle() before the scheduler has been started. */ -PRIVILEGED_FUNCTION TaskHandle_t xTaskGetIdleTaskHandle( void ); +TaskHandle_t xTaskGetIdleTaskHandle( void ) PRIVILEGED_FUNCTION; /** * configUSE_TRACE_FACILITY must be defined as 1 in FreeRTOSConfig.h for @@ -1526,7 +1638,7 @@ PRIVILEGED_FUNCTION TaskHandle_t xTaskGetIdleTaskHandle( void ); }
*/ -PRIVILEGED_FUNCTION UBaseType_t uxTaskGetSystemState( TaskStatus_t * const pxTaskStatusArray, const UBaseType_t uxArraySize, uint32_t * const pulTotalRunTime ); +UBaseType_t uxTaskGetSystemState( TaskStatus_t * const pxTaskStatusArray, const UBaseType_t uxArraySize, uint32_t * const pulTotalRunTime ) PRIVILEGED_FUNCTION; /** * task. h @@ -1573,7 +1685,7 @@ PRIVILEGED_FUNCTION UBaseType_t uxTaskGetSystemState( TaskStatus_t * const pxTas * \defgroup vTaskList vTaskList * \ingroup TaskUtils */ -PRIVILEGED_FUNCTION void vTaskList( char * pcWriteBuffer ); /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ +void vTaskList( char * pcWriteBuffer ) PRIVILEGED_FUNCTION; /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ /** * task. h @@ -1627,7 +1739,37 @@ PRIVILEGED_FUNCTION void vTaskList( char * pcWriteBuffer ); /*lint !e971 Unquali * \defgroup vTaskGetRunTimeStats vTaskGetRunTimeStats * \ingroup TaskUtils */ -PRIVILEGED_FUNCTION void vTaskGetRunTimeStats( char *pcWriteBuffer ); /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ +void vTaskGetRunTimeStats( char *pcWriteBuffer ) PRIVILEGED_FUNCTION; /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ + +/** +* task. h +*
uint32_t ulTaskGetIdleRunTimeCounter( void );
+* +* configGENERATE_RUN_TIME_STATS and configUSE_STATS_FORMATTING_FUNCTIONS +* must both be defined as 1 for this function to be available. The application +* must also then provide definitions for +* portCONFIGURE_TIMER_FOR_RUN_TIME_STATS() and portGET_RUN_TIME_COUNTER_VALUE() +* to configure a peripheral timer/counter and return the timers current count +* value respectively. The counter should be at least 10 times the frequency of +* the tick count. +* +* Setting configGENERATE_RUN_TIME_STATS to 1 will result in a total +* accumulated execution time being stored for each task. The resolution +* of the accumulated time value depends on the frequency of the timer +* configured by the portCONFIGURE_TIMER_FOR_RUN_TIME_STATS() macro. +* While uxTaskGetSystemState() and vTaskGetRunTimeStats() writes the total +* execution time of each task into a buffer, ulTaskGetIdleRunTimeCounter() +* returns the total execution time of just the idle task. +* +* @return The total run time of the idle task. This is the amount of time the +* idle task has actually been executing. The unit of time is dependent on the +* frequency configured using the portCONFIGURE_TIMER_FOR_RUN_TIME_STATS() and +* portGET_RUN_TIME_COUNTER_VALUE() macros. +* +* \defgroup ulTaskGetIdleRunTimeCounter ulTaskGetIdleRunTimeCounter +* \ingroup TaskUtils +*/ +uint32_t ulTaskGetIdleRunTimeCounter( void ) PRIVILEGED_FUNCTION; /** * task. h @@ -1708,7 +1850,7 @@ PRIVILEGED_FUNCTION void vTaskGetRunTimeStats( char *pcWriteBuffer ); /*lint !e9 * \defgroup xTaskNotify xTaskNotify * \ingroup TaskNotifications */ -PRIVILEGED_FUNCTION BaseType_t xTaskGenericNotify( TaskHandle_t xTaskToNotify, uint32_t ulValue, eNotifyAction eAction, uint32_t *pulPreviousNotificationValue ); +BaseType_t xTaskGenericNotify( TaskHandle_t xTaskToNotify, uint32_t ulValue, eNotifyAction eAction, uint32_t *pulPreviousNotificationValue ) PRIVILEGED_FUNCTION; #define xTaskNotify( xTaskToNotify, ulValue, eAction ) xTaskGenericNotify( ( xTaskToNotify ), ( ulValue ), ( eAction ), NULL ) #define xTaskNotifyAndQuery( xTaskToNotify, ulValue, eAction, pulPreviousNotifyValue ) xTaskGenericNotify( ( xTaskToNotify ), ( ulValue ), ( eAction ), ( pulPreviousNotifyValue ) ) @@ -1799,7 +1941,7 @@ PRIVILEGED_FUNCTION BaseType_t xTaskGenericNotify( TaskHandle_t xTaskToNotify, u * \defgroup xTaskNotify xTaskNotify * \ingroup TaskNotifications */ -PRIVILEGED_FUNCTION BaseType_t xTaskGenericNotifyFromISR( TaskHandle_t xTaskToNotify, uint32_t ulValue, eNotifyAction eAction, uint32_t *pulPreviousNotificationValue, BaseType_t *pxHigherPriorityTaskWoken ); +BaseType_t xTaskGenericNotifyFromISR( TaskHandle_t xTaskToNotify, uint32_t ulValue, eNotifyAction eAction, uint32_t *pulPreviousNotificationValue, BaseType_t *pxHigherPriorityTaskWoken ) PRIVILEGED_FUNCTION; #define xTaskNotifyFromISR( xTaskToNotify, ulValue, eAction, pxHigherPriorityTaskWoken ) xTaskGenericNotifyFromISR( ( xTaskToNotify ), ( ulValue ), ( eAction ), NULL, ( pxHigherPriorityTaskWoken ) ) #define xTaskNotifyAndQueryFromISR( xTaskToNotify, ulValue, eAction, pulPreviousNotificationValue, pxHigherPriorityTaskWoken ) xTaskGenericNotifyFromISR( ( xTaskToNotify ), ( ulValue ), ( eAction ), ( pulPreviousNotificationValue ), ( pxHigherPriorityTaskWoken ) ) @@ -1876,7 +2018,7 @@ PRIVILEGED_FUNCTION BaseType_t xTaskGenericNotifyFromISR( TaskHandle_t xTaskToNo * \defgroup xTaskNotifyWait xTaskNotifyWait * \ingroup TaskNotifications */ -PRIVILEGED_FUNCTION BaseType_t xTaskNotifyWait( uint32_t ulBitsToClearOnEntry, uint32_t ulBitsToClearOnExit, uint32_t *pulNotificationValue, TickType_t xTicksToWait ); +BaseType_t xTaskNotifyWait( uint32_t ulBitsToClearOnEntry, uint32_t ulBitsToClearOnExit, uint32_t *pulNotificationValue, TickType_t xTicksToWait ) PRIVILEGED_FUNCTION; /** * task. h @@ -1977,7 +2119,7 @@ PRIVILEGED_FUNCTION BaseType_t xTaskNotifyWait( uint32_t ulBitsToClearOnEntry, u * \defgroup xTaskNotifyWait xTaskNotifyWait * \ingroup TaskNotifications */ -PRIVILEGED_FUNCTION void vTaskNotifyGiveFromISR( TaskHandle_t xTaskToNotify, BaseType_t *pxHigherPriorityTaskWoken ); +void vTaskNotifyGiveFromISR( TaskHandle_t xTaskToNotify, BaseType_t *pxHigherPriorityTaskWoken ) PRIVILEGED_FUNCTION; /** * task. h @@ -2046,7 +2188,7 @@ PRIVILEGED_FUNCTION void vTaskNotifyGiveFromISR( TaskHandle_t xTaskToNotify, Bas * \defgroup ulTaskNotifyTake ulTaskNotifyTake * \ingroup TaskNotifications */ -PRIVILEGED_FUNCTION uint32_t ulTaskNotifyTake( BaseType_t xClearCountOnExit, TickType_t xTicksToWait ); +uint32_t ulTaskNotifyTake( BaseType_t xClearCountOnExit, TickType_t xTicksToWait ) PRIVILEGED_FUNCTION; /** * task. h @@ -2064,6 +2206,121 @@ PRIVILEGED_FUNCTION uint32_t ulTaskNotifyTake( BaseType_t xClearCountOnExit, Tic */ BaseType_t xTaskNotifyStateClear( TaskHandle_t xTask ); +/** +* task. h +*
uint32_t ulTaskNotifyValueClear( TaskHandle_t xTask, uint32_t ulBitsToClear );
+* +* Clears the bits specified by the ulBitsToClear bit mask in the notification +* value of the task referenced by xTask. +* +* Set ulBitsToClear to 0xffffffff (UINT_MAX on 32-bit architectures) to clear +* the notification value to 0. Set ulBitsToClear to 0 to query the task's +* notification value without clearing any bits. +* +* @return The value of the target task's notification value before the bits +* specified by ulBitsToClear were cleared. +* \defgroup ulTaskNotifyValueClear ulTaskNotifyValueClear +* \ingroup TaskNotifications +*/ +uint32_t ulTaskNotifyValueClear( TaskHandle_t xTask, uint32_t ulBitsToClear ) PRIVILEGED_FUNCTION; + +/** + * task.h + *
void vTaskSetTimeOutState( TimeOut_t * const pxTimeOut )
+ * + * Capture the current time for future use with xTaskCheckForTimeOut(). + * + * @param pxTimeOut Pointer to a timeout object into which the current time + * is to be captured. The captured time includes the tick count and the number + * of times the tick count has overflowed since the system first booted. + * \defgroup vTaskSetTimeOutState vTaskSetTimeOutState + * \ingroup TaskCtrl + */ +void vTaskSetTimeOutState( TimeOut_t * const pxTimeOut ) PRIVILEGED_FUNCTION; + +/** + * task.h + *
BaseType_t xTaskCheckForTimeOut( TimeOut_t * const pxTimeOut, TickType_t * const pxTicksToWait );
+ * + * Determines if pxTicksToWait ticks has passed since a time was captured + * using a call to vTaskSetTimeOutState(). The captured time includes the tick + * count and the number of times the tick count has overflowed. + * + * @param pxTimeOut The time status as captured previously using + * vTaskSetTimeOutState. If the timeout has not yet occurred, it is updated + * to reflect the current time status. + * @param pxTicksToWait The number of ticks to check for timeout i.e. if + * pxTicksToWait ticks have passed since pxTimeOut was last updated (either by + * vTaskSetTimeOutState() or xTaskCheckForTimeOut()), the timeout has occurred. + * If the timeout has not occurred, pxTIcksToWait is updated to reflect the + * number of remaining ticks. + * + * @return If timeout has occurred, pdTRUE is returned. Otherwise pdFALSE is + * returned and pxTicksToWait is updated to reflect the number of remaining + * ticks. + * + * @see https://www.freertos.org/xTaskCheckForTimeOut.html + * + * Example Usage: + *
+	// Driver library function used to receive uxWantedBytes from an Rx buffer
+	// that is filled by a UART interrupt. If there are not enough bytes in the
+	// Rx buffer then the task enters the Blocked state until it is notified that
+	// more data has been placed into the buffer. If there is still not enough
+	// data then the task re-enters the Blocked state, and xTaskCheckForTimeOut()
+	// is used to re-calculate the Block time to ensure the total amount of time
+	// spent in the Blocked state does not exceed MAX_TIME_TO_WAIT. This
+	// continues until either the buffer contains at least uxWantedBytes bytes,
+	// or the total amount of time spent in the Blocked state reaches
+	// MAX_TIME_TO_WAIT – at which point the task reads however many bytes are
+	// available up to a maximum of uxWantedBytes.
+
+	size_t xUART_Receive( uint8_t *pucBuffer, size_t uxWantedBytes )
+	{
+	size_t uxReceived = 0;
+	TickType_t xTicksToWait = MAX_TIME_TO_WAIT;
+	TimeOut_t xTimeOut;
+
+		// Initialize xTimeOut.  This records the time at which this function
+		// was entered.
+		vTaskSetTimeOutState( &xTimeOut );
+
+		// Loop until the buffer contains the wanted number of bytes, or a
+		// timeout occurs.
+		while( UART_bytes_in_rx_buffer( pxUARTInstance ) < uxWantedBytes )
+		{
+			// The buffer didn't contain enough data so this task is going to
+			// enter the Blocked state. Adjusting xTicksToWait to account for
+			// any time that has been spent in the Blocked state within this
+			// function so far to ensure the total amount of time spent in the
+			// Blocked state does not exceed MAX_TIME_TO_WAIT.
+			if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) != pdFALSE )
+			{
+				//Timed out before the wanted number of bytes were available,
+				// exit the loop.
+				break;
+			}
+
+			// Wait for a maximum of xTicksToWait ticks to be notified that the
+			// receive interrupt has placed more data into the buffer.
+			ulTaskNotifyTake( pdTRUE, xTicksToWait );
+		}
+
+		// Attempt to read uxWantedBytes from the receive buffer into pucBuffer.
+		// The actual number of bytes read (which might be less than
+		// uxWantedBytes) is returned.
+		uxReceived = UART_read_from_receive_buffer( pxUARTInstance,
+													pucBuffer,
+													uxWantedBytes );
+
+		return uxReceived;
+	}
+ 
+ * \defgroup xTaskCheckForTimeOut xTaskCheckForTimeOut + * \ingroup TaskCtrl + */ +BaseType_t xTaskCheckForTimeOut( TimeOut_t * const pxTimeOut, TickType_t * const pxTicksToWait ) PRIVILEGED_FUNCTION; + /*----------------------------------------------------------- * SCHEDULER INTERNALS AVAILABLE FOR PORTING PURPOSES *----------------------------------------------------------*/ @@ -2083,7 +2340,7 @@ BaseType_t xTaskNotifyStateClear( TaskHandle_t xTask ); * + Time slicing is in use and there is a task of equal priority to the * currently running task. */ -PRIVILEGED_FUNCTION BaseType_t xTaskIncrementTick( void ); +BaseType_t xTaskIncrementTick( void ) PRIVILEGED_FUNCTION; /* * THIS FUNCTION MUST NOT BE USED FROM APPLICATION CODE. IT IS AN @@ -2116,8 +2373,8 @@ PRIVILEGED_FUNCTION BaseType_t xTaskIncrementTick( void ); * portTICK_PERIOD_MS can be used to convert kernel ticks into a real time * period. */ -PRIVILEGED_FUNCTION void vTaskPlaceOnEventList( List_t * const pxEventList, const TickType_t xTicksToWait ); -PRIVILEGED_FUNCTION void vTaskPlaceOnUnorderedEventList( List_t * pxEventList, const TickType_t xItemValue, const TickType_t xTicksToWait ); +void vTaskPlaceOnEventList( List_t * const pxEventList, const TickType_t xTicksToWait ) PRIVILEGED_FUNCTION; +void vTaskPlaceOnUnorderedEventList( List_t * pxEventList, const TickType_t xItemValue, const TickType_t xTicksToWait ) PRIVILEGED_FUNCTION; /* * THIS FUNCTION MUST NOT BE USED FROM APPLICATION CODE. IT IS AN @@ -2130,7 +2387,7 @@ PRIVILEGED_FUNCTION void vTaskPlaceOnUnorderedEventList( List_t * pxEventList, c * indefinitely, whereas vTaskPlaceOnEventList() does. * */ -PRIVILEGED_FUNCTION void vTaskPlaceOnEventListRestricted( List_t * const pxEventList, TickType_t xTicksToWait, const BaseType_t xWaitIndefinitely ); +void vTaskPlaceOnEventListRestricted( List_t * const pxEventList, TickType_t xTicksToWait, const BaseType_t xWaitIndefinitely ) PRIVILEGED_FUNCTION; /* * THIS FUNCTION MUST NOT BE USED FROM APPLICATION CODE. IT IS AN @@ -2141,14 +2398,14 @@ PRIVILEGED_FUNCTION void vTaskPlaceOnEventListRestricted( List_t * const pxEvent * Removes a task from both the specified event list and the list of blocked * tasks, and places it on a ready queue. * - * xTaskRemoveFromEventList()/xTaskRemoveFromUnorderedEventList() will be called + * xTaskRemoveFromEventList()/vTaskRemoveFromUnorderedEventList() will be called * if either an event occurs to unblock a task, or the block timeout period * expires. * * xTaskRemoveFromEventList() is used when the event list is in task priority * order. It removes the list item from the head of the event list as that will * have the highest priority owning task of all the tasks on the event list. - * xTaskRemoveFromUnorderedEventList() is used when the event list is not + * vTaskRemoveFromUnorderedEventList() is used when the event list is not * ordered and the event list items hold something other than the owning tasks * priority. In this case the event list item value is updated to the value * passed in the xItemValue parameter. @@ -2156,8 +2413,8 @@ PRIVILEGED_FUNCTION void vTaskPlaceOnEventListRestricted( List_t * const pxEvent * @return pdTRUE if the task being removed has a higher priority than the task * making the call, otherwise pdFALSE. */ -PRIVILEGED_FUNCTION BaseType_t xTaskRemoveFromEventList( const List_t * const pxEventList ); -PRIVILEGED_FUNCTION BaseType_t xTaskRemoveFromUnorderedEventList( ListItem_t * pxEventListItem, const TickType_t xItemValue ); +BaseType_t xTaskRemoveFromEventList( const List_t * const pxEventList ) PRIVILEGED_FUNCTION; +void vTaskRemoveFromUnorderedEventList( ListItem_t * pxEventListItem, const TickType_t xItemValue ) PRIVILEGED_FUNCTION; /* * THIS FUNCTION MUST NOT BE USED FROM APPLICATION CODE. IT IS ONLY @@ -2167,64 +2424,63 @@ PRIVILEGED_FUNCTION BaseType_t xTaskRemoveFromUnorderedEventList( ListItem_t * p * Sets the pointer to the current TCB to the TCB of the highest priority task * that is ready to run. */ -PRIVILEGED_FUNCTION void vTaskSwitchContext( void ); +portDONT_DISCARD void vTaskSwitchContext( void ) PRIVILEGED_FUNCTION; /* * THESE FUNCTIONS MUST NOT BE USED FROM APPLICATION CODE. THEY ARE USED BY * THE EVENT BITS MODULE. */ -PRIVILEGED_FUNCTION TickType_t uxTaskResetEventItemValue( void ); +TickType_t uxTaskResetEventItemValue( void ) PRIVILEGED_FUNCTION; /* * Return the handle of the calling task. */ -PRIVILEGED_FUNCTION TaskHandle_t xTaskGetCurrentTaskHandle( void ); - -/* - * Capture the current time status for future reference. - */ -PRIVILEGED_FUNCTION void vTaskSetTimeOutState( TimeOut_t * const pxTimeOut ); - -/* - * Compare the time status now with that previously captured to see if the - * timeout has expired. - */ -PRIVILEGED_FUNCTION BaseType_t xTaskCheckForTimeOut( TimeOut_t * const pxTimeOut, TickType_t * const pxTicksToWait ); +TaskHandle_t xTaskGetCurrentTaskHandle( void ) PRIVILEGED_FUNCTION; /* * Shortcut used by the queue implementation to prevent unnecessary call to * taskYIELD(); */ -PRIVILEGED_FUNCTION void vTaskMissedYield( void ); +void vTaskMissedYield( void ) PRIVILEGED_FUNCTION; /* * Returns the scheduler state as taskSCHEDULER_RUNNING, * taskSCHEDULER_NOT_STARTED or taskSCHEDULER_SUSPENDED. */ -PRIVILEGED_FUNCTION BaseType_t xTaskGetSchedulerState( void ); +BaseType_t xTaskGetSchedulerState( void ) PRIVILEGED_FUNCTION; /* * Raises the priority of the mutex holder to that of the calling task should * the mutex holder have a priority less than the calling task. */ -PRIVILEGED_FUNCTION void vTaskPriorityInherit( TaskHandle_t const pxMutexHolder ); +BaseType_t xTaskPriorityInherit( TaskHandle_t const pxMutexHolder ) PRIVILEGED_FUNCTION; /* * Set the priority of a task back to its proper priority in the case that it * inherited a higher priority while it was holding a semaphore. */ -PRIVILEGED_FUNCTION BaseType_t xTaskPriorityDisinherit( TaskHandle_t const pxMutexHolder ); +BaseType_t xTaskPriorityDisinherit( TaskHandle_t const pxMutexHolder ) PRIVILEGED_FUNCTION; + +/* + * If a higher priority task attempting to obtain a mutex caused a lower + * priority task to inherit the higher priority task's priority - but the higher + * priority task then timed out without obtaining the mutex, then the lower + * priority task will disinherit the priority again - but only down as far as + * the highest priority task that is still waiting for the mutex (if there were + * more than one task waiting for the mutex). + */ +void vTaskPriorityDisinheritAfterTimeout( TaskHandle_t const pxMutexHolder, UBaseType_t uxHighestPriorityWaitingTask ) PRIVILEGED_FUNCTION; /* * Get the uxTCBNumber assigned to the task referenced by the xTask parameter. */ -PRIVILEGED_FUNCTION UBaseType_t uxTaskGetTaskNumber( TaskHandle_t xTask ); +UBaseType_t uxTaskGetTaskNumber( TaskHandle_t xTask ) PRIVILEGED_FUNCTION; /* * Set the uxTaskNumber of the task referenced by the xTask parameter to * uxHandle. */ -PRIVILEGED_FUNCTION void vTaskSetTaskNumber( TaskHandle_t xTask, const UBaseType_t uxHandle ); +void vTaskSetTaskNumber( TaskHandle_t xTask, const UBaseType_t uxHandle ) PRIVILEGED_FUNCTION; /* * Only available when configUSE_TICKLESS_IDLE is set to 1. @@ -2234,10 +2490,23 @@ PRIVILEGED_FUNCTION void vTaskSetTaskNumber( TaskHandle_t xTask, const UBaseType * to date with the actual execution time by being skipped forward by a time * equal to the idle period. */ -PRIVILEGED_FUNCTION void vTaskStepTick( const TickType_t xTicksToJump ); +void vTaskStepTick( const TickType_t xTicksToJump ) PRIVILEGED_FUNCTION; + +/* Correct the tick count value after the application code has held +interrupts disabled for an extended period. xTicksToCatchUp is the number +of tick interrupts that have been missed due to interrupts being disabled. +Its value is not computed automatically, so must be computed by the +application writer. + +This function is similar to vTaskStepTick(), however, unlike +vTaskStepTick(), xTaskCatchUpTicks() may move the tick count forward past a +time at which a task should be removed from the blocked state. That means +tasks may have to be removed from the blocked state as the tick count is +moved. */ +BaseType_t xTaskCatchUpTicks( TickType_t xTicksToCatchUp ) PRIVILEGED_FUNCTION; /* - * Only avilable when configUSE_TICKLESS_IDLE is set to 1. + * Only available when configUSE_TICKLESS_IDLE is set to 1. * Provided for use within portSUPPRESS_TICKS_AND_SLEEP() to allow the port * specific sleep function to determine if it is ok to proceed with the sleep, * and if it is ok to proceed, if it is ok to sleep indefinitely. @@ -2250,13 +2519,20 @@ PRIVILEGED_FUNCTION void vTaskStepTick( const TickType_t xTicksToJump ); * critical section between the timer being stopped and the sleep mode being * entered to ensure it is ok to proceed into the sleep mode. */ -PRIVILEGED_FUNCTION eSleepModeStatus eTaskConfirmSleepModeStatus( void ); +eSleepModeStatus eTaskConfirmSleepModeStatus( void ) PRIVILEGED_FUNCTION; /* * For internal use only. Increment the mutex held count when a mutex is * taken and return the handle of the task that has taken the mutex. */ -PRIVILEGED_FUNCTION void *pvTaskIncrementMutexHeldCount( void ); +TaskHandle_t pvTaskIncrementMutexHeldCount( void ) PRIVILEGED_FUNCTION; + +/* + * For internal use only. Same as vTaskSetTimeOutState(), but without a critial + * section. + */ +void vTaskInternalSetTimeOutState( TimeOut_t * const pxTimeOut ) PRIVILEGED_FUNCTION; + #ifdef __cplusplus } diff --git a/Firmware/Board/v3/Middlewares/Third_Party/FreeRTOS/Source/include/timers.h b/Firmware/Board/v3/Middlewares/Third_Party/FreeRTOS/Source/include/timers.h index 2f430f37..1b6d7f97 100644 --- a/Firmware/Board/v3/Middlewares/Third_Party/FreeRTOS/Source/include/timers.h +++ b/Firmware/Board/v3/Middlewares/Third_Party/FreeRTOS/Source/include/timers.h @@ -1,71 +1,29 @@ /* - FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. - All rights reserved - - VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. - - This file is part of the FreeRTOS distribution. - - FreeRTOS is free software; you can redistribute it and/or modify it under - the terms of the GNU General Public License (version 2) as published by the - Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception. - - *************************************************************************** - >>! NOTE: The modification to the GPL is included to allow you to !<< - >>! distribute a combined work that includes FreeRTOS without being !<< - >>! obliged to provide the source code for proprietary components !<< - >>! outside of the FreeRTOS kernel. !<< - *************************************************************************** - - FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - FOR A PARTICULAR PURPOSE. Full license text is available on the following - link: http://www.freertos.org/a00114.html - - *************************************************************************** - * * - * FreeRTOS provides completely free yet professionally developed, * - * robust, strictly quality controlled, supported, and cross * - * platform software that is more than just the market leader, it * - * is the industry's de facto standard. * - * * - * Help yourself get started quickly while simultaneously helping * - * to support the FreeRTOS project by purchasing a FreeRTOS * - * tutorial book, reference manual, or both: * - * http://www.FreeRTOS.org/Documentation * - * * - *************************************************************************** - - http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading - the FAQ page "My application does not run, what could be wrong?". Have you - defined configASSERT()? - - http://www.FreeRTOS.org/support - In return for receiving this top quality - embedded software for free we request you assist our global community by - participating in the support forum. - - http://www.FreeRTOS.org/training - Investing in training allows your team to - be as productive as possible as early as possible. Now you can receive - FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers - Ltd, and the world's leading authority on the world's leading RTOS. - - http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, - including FreeRTOS+Trace - an indispensable productivity tool, a DOS - compatible FAT file system, and our tiny thread aware UDP/IP stack. - - http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. - Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. - - http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High - Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS - licenses offer ticketed support, indemnification and commercial middleware. - - http://www.SafeRTOS.com - High Integrity Systems also provide a safety - engineered and independently SIL3 certified version for use in safety and - mission critical applications that require provable dependability. - - 1 tab == 4 spaces! -*/ + * FreeRTOS Kernel V10.3.1 + * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * http://www.FreeRTOS.org + * http://aws.amazon.com/freertos + * + * 1 tab == 4 spaces! + */ #ifndef TIMERS_H @@ -75,10 +33,10 @@ #error "include FreeRTOS.h must appear in source files before include timers.h" #endif -/*lint -e537 This headers are only multiply included if the application code +/*lint -save -e537 This headers are only multiply included if the application code happens to also be including task.h. */ #include "task.h" -/*lint +e537 */ +/*lint -restore */ #ifdef __cplusplus extern "C" { @@ -115,7 +73,8 @@ or interrupt version of the queue send function should be used. */ * reference the subject timer in calls to other software timer API functions * (for example, xTimerStart(), xTimerReset(), etc.). */ -typedef void * TimerHandle_t; +struct tmrTimerControl; /* The old naming convention is used to prevent breaking kernel aware debuggers. */ +typedef struct tmrTimerControl * TimerHandle_t; /* * Defines the prototype to which timer callback functions must conform. @@ -266,11 +225,11 @@ typedef void (*PendedFunction_t)( void *, uint32_t ); * @endverbatim */ #if( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) - PRIVILEGED_FUNCTION TimerHandle_t xTimerCreate( const char * const pcTimerName, + TimerHandle_t xTimerCreate( const char * const pcTimerName, /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ const TickType_t xTimerPeriodInTicks, const UBaseType_t uxAutoReload, void * const pvTimerID, - TimerCallbackFunction_t pxCallbackFunction ); /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ + TimerCallbackFunction_t pxCallbackFunction ) PRIVILEGED_FUNCTION; #endif /** @@ -396,12 +355,12 @@ typedef void (*PendedFunction_t)( void *, uint32_t ); * @endverbatim */ #if( configSUPPORT_STATIC_ALLOCATION == 1 ) - PRIVILEGED_FUNCTION TimerHandle_t xTimerCreateStatic( const char * const pcTimerName, + TimerHandle_t xTimerCreateStatic( const char * const pcTimerName, /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ const TickType_t xTimerPeriodInTicks, const UBaseType_t uxAutoReload, void * const pvTimerID, TimerCallbackFunction_t pxCallbackFunction, - StaticTimer_t *pxTimerBuffer ); /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ + StaticTimer_t *pxTimerBuffer ) PRIVILEGED_FUNCTION; #endif /* configSUPPORT_STATIC_ALLOCATION */ /** @@ -424,7 +383,7 @@ typedef void (*PendedFunction_t)( void *, uint32_t ); * * See the xTimerCreate() API function example usage scenario. */ -PRIVILEGED_FUNCTION void *pvTimerGetTimerID( const TimerHandle_t xTimer ); +void *pvTimerGetTimerID( const TimerHandle_t xTimer ) PRIVILEGED_FUNCTION; /** * void vTimerSetTimerID( TimerHandle_t xTimer, void *pvNewID ); @@ -445,7 +404,7 @@ PRIVILEGED_FUNCTION void *pvTimerGetTimerID( const TimerHandle_t xTimer ); * * See the xTimerCreate() API function example usage scenario. */ -PRIVILEGED_FUNCTION void vTimerSetTimerID( TimerHandle_t xTimer, void *pvNewID ); +void vTimerSetTimerID( TimerHandle_t xTimer, void *pvNewID ) PRIVILEGED_FUNCTION; /** * BaseType_t xTimerIsTimerActive( TimerHandle_t xTimer ); @@ -482,7 +441,7 @@ PRIVILEGED_FUNCTION void vTimerSetTimerID( TimerHandle_t xTimer, void *pvNewID ) * } * @endverbatim */ -PRIVILEGED_FUNCTION BaseType_t xTimerIsTimerActive( TimerHandle_t xTimer ); +BaseType_t xTimerIsTimerActive( TimerHandle_t xTimer ) PRIVILEGED_FUNCTION; /** * TaskHandle_t xTimerGetTimerDaemonTaskHandle( void ); @@ -490,7 +449,7 @@ PRIVILEGED_FUNCTION BaseType_t xTimerIsTimerActive( TimerHandle_t xTimer ); * Simply returns the handle of the timer service/daemon task. It it not valid * to call xTimerGetTimerDaemonTaskHandle() before the scheduler has been started. */ -PRIVILEGED_FUNCTION TaskHandle_t xTimerGetTimerDaemonTaskHandle( void ); +TaskHandle_t xTimerGetTimerDaemonTaskHandle( void ) PRIVILEGED_FUNCTION; /** * BaseType_t xTimerStart( TimerHandle_t xTimer, TickType_t xTicksToWait ); @@ -1225,7 +1184,7 @@ PRIVILEGED_FUNCTION TaskHandle_t xTimerGetTimerDaemonTaskHandle( void ); * } * @endverbatim */ -PRIVILEGED_FUNCTION BaseType_t xTimerPendFunctionCallFromISR( PendedFunction_t xFunctionToPend, void *pvParameter1, uint32_t ulParameter2, BaseType_t *pxHigherPriorityTaskWoken ); +BaseType_t xTimerPendFunctionCallFromISR( PendedFunction_t xFunctionToPend, void *pvParameter1, uint32_t ulParameter2, BaseType_t *pxHigherPriorityTaskWoken ) PRIVILEGED_FUNCTION; /** * BaseType_t xTimerPendFunctionCall( PendedFunction_t xFunctionToPend, @@ -1259,7 +1218,7 @@ PRIVILEGED_FUNCTION BaseType_t xTimerPendFunctionCallFromISR( PendedFunction_t x * timer daemon task, otherwise pdFALSE is returned. * */ -PRIVILEGED_FUNCTION BaseType_t xTimerPendFunctionCall( PendedFunction_t xFunctionToPend, void *pvParameter1, uint32_t ulParameter2, TickType_t xTicksToWait ); +BaseType_t xTimerPendFunctionCall( PendedFunction_t xFunctionToPend, void *pvParameter1, uint32_t ulParameter2, TickType_t xTicksToWait ) PRIVILEGED_FUNCTION; /** * const char * const pcTimerGetName( TimerHandle_t xTimer ); @@ -1270,7 +1229,38 @@ PRIVILEGED_FUNCTION BaseType_t xTimerPendFunctionCall( PendedFunction_t xFunctio * * @return The name assigned to the timer specified by the xTimer parameter. */ -PRIVILEGED_FUNCTION const char * pcTimerGetName( TimerHandle_t xTimer ); /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ +const char * pcTimerGetName( TimerHandle_t xTimer ) PRIVILEGED_FUNCTION; /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ + +/** + * void vTimerSetReloadMode( TimerHandle_t xTimer, const UBaseType_t uxAutoReload ); + * + * Updates a timer to be either an auto-reload timer, in which case the timer + * automatically resets itself each time it expires, or a one-shot timer, in + * which case the timer will only expire once unless it is manually restarted. + * + * @param xTimer The handle of the timer being updated. + * + * @param uxAutoReload If uxAutoReload is set to pdTRUE then the timer will + * expire repeatedly with a frequency set by the timer's period (see the + * xTimerPeriodInTicks parameter of the xTimerCreate() API function). If + * uxAutoReload is set to pdFALSE then the timer will be a one-shot timer and + * enter the dormant state after it expires. + */ +void vTimerSetReloadMode( TimerHandle_t xTimer, const UBaseType_t uxAutoReload ) PRIVILEGED_FUNCTION; + +/** +* UBaseType_t uxTimerGetReloadMode( TimerHandle_t xTimer ); +* +* Queries a timer to determine if it is an auto-reload timer, in which case the timer +* automatically resets itself each time it expires, or a one-shot timer, in +* which case the timer will only expire once unless it is manually restarted. +* +* @param xTimer The handle of the timer being queried. +* +* @return If the timer is an auto-reload timer then pdTRUE is returned, otherwise +* pdFALSE is returned. +*/ +UBaseType_t uxTimerGetReloadMode( TimerHandle_t xTimer ) PRIVILEGED_FUNCTION; /** * TickType_t xTimerGetPeriod( TimerHandle_t xTimer ); @@ -1281,7 +1271,7 @@ PRIVILEGED_FUNCTION const char * pcTimerGetName( TimerHandle_t xTimer ); /*lint * * @return The period of the timer in ticks. */ -PRIVILEGED_FUNCTION TickType_t xTimerGetPeriod( TimerHandle_t xTimer ); +TickType_t xTimerGetPeriod( TimerHandle_t xTimer ) PRIVILEGED_FUNCTION; /** * TickType_t xTimerGetExpiryTime( TimerHandle_t xTimer ); @@ -1296,14 +1286,19 @@ PRIVILEGED_FUNCTION TickType_t xTimerGetPeriod( TimerHandle_t xTimer ); * will next expire is returned. If the timer is not running then the return * value is undefined. */ -PRIVILEGED_FUNCTION TickType_t xTimerGetExpiryTime( TimerHandle_t xTimer ); +TickType_t xTimerGetExpiryTime( TimerHandle_t xTimer ) PRIVILEGED_FUNCTION; /* * Functions beyond this part are not part of the public API and are intended * for use by the kernel only. */ -PRIVILEGED_FUNCTION BaseType_t xTimerCreateTimerTask( void ); -PRIVILEGED_FUNCTION BaseType_t xTimerGenericCommand( TimerHandle_t xTimer, const BaseType_t xCommandID, const TickType_t xOptionalValue, BaseType_t * const pxHigherPriorityTaskWoken, const TickType_t xTicksToWait ); +BaseType_t xTimerCreateTimerTask( void ) PRIVILEGED_FUNCTION; +BaseType_t xTimerGenericCommand( TimerHandle_t xTimer, const BaseType_t xCommandID, const TickType_t xOptionalValue, BaseType_t * const pxHigherPriorityTaskWoken, const TickType_t xTicksToWait ) PRIVILEGED_FUNCTION; + +#if( configUSE_TRACE_FACILITY == 1 ) + void vTimerSetTimerNumber( TimerHandle_t xTimer, UBaseType_t uxTimerNumber ) PRIVILEGED_FUNCTION; + UBaseType_t uxTimerGetTimerNumber( TimerHandle_t xTimer ) PRIVILEGED_FUNCTION; +#endif #ifdef __cplusplus } diff --git a/Firmware/Board/v3/Middlewares/Third_Party/FreeRTOS/Source/list.c b/Firmware/Board/v3/Middlewares/Third_Party/FreeRTOS/Source/list.c index 5e207c16..7618ee8b 100644 --- a/Firmware/Board/v3/Middlewares/Third_Party/FreeRTOS/Source/list.c +++ b/Firmware/Board/v3/Middlewares/Third_Party/FreeRTOS/Source/list.c @@ -1,71 +1,29 @@ /* - FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. - All rights reserved - - VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. - - This file is part of the FreeRTOS distribution. - - FreeRTOS is free software; you can redistribute it and/or modify it under - the terms of the GNU General Public License (version 2) as published by the - Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception. - - *************************************************************************** - >>! NOTE: The modification to the GPL is included to allow you to !<< - >>! distribute a combined work that includes FreeRTOS without being !<< - >>! obliged to provide the source code for proprietary components !<< - >>! outside of the FreeRTOS kernel. !<< - *************************************************************************** - - FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - FOR A PARTICULAR PURPOSE. Full license text is available on the following - link: http://www.freertos.org/a00114.html - - *************************************************************************** - * * - * FreeRTOS provides completely free yet professionally developed, * - * robust, strictly quality controlled, supported, and cross * - * platform software that is more than just the market leader, it * - * is the industry's de facto standard. * - * * - * Help yourself get started quickly while simultaneously helping * - * to support the FreeRTOS project by purchasing a FreeRTOS * - * tutorial book, reference manual, or both: * - * http://www.FreeRTOS.org/Documentation * - * * - *************************************************************************** - - http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading - the FAQ page "My application does not run, what could be wrong?". Have you - defined configASSERT()? - - http://www.FreeRTOS.org/support - In return for receiving this top quality - embedded software for free we request you assist our global community by - participating in the support forum. - - http://www.FreeRTOS.org/training - Investing in training allows your team to - be as productive as possible as early as possible. Now you can receive - FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers - Ltd, and the world's leading authority on the world's leading RTOS. - - http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, - including FreeRTOS+Trace - an indispensable productivity tool, a DOS - compatible FAT file system, and our tiny thread aware UDP/IP stack. - - http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. - Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. - - http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High - Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS - licenses offer ticketed support, indemnification and commercial middleware. - - http://www.SafeRTOS.com - High Integrity Systems also provide a safety - engineered and independently SIL3 certified version for use in safety and - mission critical applications that require provable dependability. - - 1 tab == 4 spaces! -*/ + * FreeRTOS Kernel V10.3.1 + * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * http://www.FreeRTOS.org + * http://aws.amazon.com/freertos + * + * 1 tab == 4 spaces! + */ #include @@ -81,7 +39,7 @@ void vListInitialise( List_t * const pxList ) /* The list structure contains a list item which is used to mark the end of the list. To initialise the list the list end is inserted as the only list entry. */ - pxList->pxIndex = ( ListItem_t * ) &( pxList->xListEnd ); /*lint !e826 !e740 The mini list structure is used as the list end to save RAM. This is checked and valid. */ + pxList->pxIndex = ( ListItem_t * ) &( pxList->xListEnd ); /*lint !e826 !e740 !e9087 The mini list structure is used as the list end to save RAM. This is checked and valid. */ /* The list end value is the highest possible value in the list to ensure it remains at the end of the list. */ @@ -89,8 +47,8 @@ void vListInitialise( List_t * const pxList ) /* The list end next and previous pointers point to itself so we know when the list is empty. */ - pxList->xListEnd.pxNext = ( ListItem_t * ) &( pxList->xListEnd ); /*lint !e826 !e740 The mini list structure is used as the list end to save RAM. This is checked and valid. */ - pxList->xListEnd.pxPrevious = ( ListItem_t * ) &( pxList->xListEnd );/*lint !e826 !e740 The mini list structure is used as the list end to save RAM. This is checked and valid. */ + pxList->xListEnd.pxNext = ( ListItem_t * ) &( pxList->xListEnd ); /*lint !e826 !e740 !e9087 The mini list structure is used as the list end to save RAM. This is checked and valid. */ + pxList->xListEnd.pxPrevious = ( ListItem_t * ) &( pxList->xListEnd );/*lint !e826 !e740 !e9087 The mini list structure is used as the list end to save RAM. This is checked and valid. */ pxList->uxNumberOfItems = ( UBaseType_t ) 0U; @@ -104,7 +62,7 @@ void vListInitialise( List_t * const pxList ) void vListInitialiseItem( ListItem_t * const pxItem ) { /* Make sure the list item is not recorded as being on a list. */ - pxItem->pvContainer = NULL; + pxItem->pxContainer = NULL; /* Write known values into the list item if configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */ @@ -136,7 +94,7 @@ ListItem_t * const pxIndex = pxList->pxIndex; pxIndex->pxPrevious = pxNewListItem; /* Remember which list the item is in. */ - pxNewListItem->pvContainer = ( void * ) pxList; + pxNewListItem->pxContainer = pxList; ( pxList->uxNumberOfItems )++; } @@ -156,7 +114,7 @@ const TickType_t xValueOfInsertion = pxNewListItem->xItemValue; /* Insert the new list item into the list, sorted in xItemValue order. If the list already contains a list item with the same item value then the - new list item should be placed after it. This ensures that TCB's which are + new list item should be placed after it. This ensures that TCBs which are stored in ready lists (all of which have the same xItemValue value) get a share of the CPU. However, if the xItemValue is the same as the back marker the iteration loop below will not end. Therefore the value is checked @@ -169,18 +127,18 @@ const TickType_t xValueOfInsertion = pxNewListItem->xItemValue; { /* *** NOTE *********************************************************** If you find your application is crashing here then likely causes are - listed below. In addition see http://www.freertos.org/FAQHelp.html for + listed below. In addition see https://www.freertos.org/FAQHelp.html for more tips, and ensure configASSERT() is defined! - http://www.freertos.org/a00110.html#configASSERT + https://www.freertos.org/a00110.html#configASSERT 1) Stack overflow - - see http://www.freertos.org/Stacks-and-stack-overflow-checking.html + see https://www.freertos.org/Stacks-and-stack-overflow-checking.html 2) Incorrect interrupt priority assignment, especially on Cortex-M parts where numerically high priority values denote low actual interrupt priorities, which can seem counter intuitive. See - http://www.freertos.org/RTOS-Cortex-M3-M4.html and the definition + https://www.freertos.org/RTOS-Cortex-M3-M4.html and the definition of configMAX_SYSCALL_INTERRUPT_PRIORITY on - http://www.freertos.org/a00110.html + https://www.freertos.org/a00110.html 3) Calling an API function from within a critical section or when the scheduler is suspended, or calling an API function that does not end in "FromISR" from an interrupt. @@ -189,7 +147,7 @@ const TickType_t xValueOfInsertion = pxNewListItem->xItemValue; before vTaskStartScheduler() has been called?). **********************************************************************/ - for( pxIterator = ( ListItem_t * ) &( pxList->xListEnd ); pxIterator->pxNext->xItemValue <= xValueOfInsertion; pxIterator = pxIterator->pxNext ) /*lint !e826 !e740 The mini list structure is used as the list end to save RAM. This is checked and valid. */ + for( pxIterator = ( ListItem_t * ) &( pxList->xListEnd ); pxIterator->pxNext->xItemValue <= xValueOfInsertion; pxIterator = pxIterator->pxNext ) /*lint !e826 !e740 !e9087 The mini list structure is used as the list end to save RAM. This is checked and valid. *//*lint !e440 The iterator moves to a different value, not xValueOfInsertion. */ { /* There is nothing to do here, just iterating to the wanted insertion position. */ @@ -203,7 +161,7 @@ const TickType_t xValueOfInsertion = pxNewListItem->xItemValue; /* Remember which list the item is in. This allows fast removal of the item later. */ - pxNewListItem->pvContainer = ( void * ) pxList; + pxNewListItem->pxContainer = pxList; ( pxList->uxNumberOfItems )++; } @@ -213,7 +171,7 @@ UBaseType_t uxListRemove( ListItem_t * const pxItemToRemove ) { /* The list item knows which list it is in. Obtain the list from the list item. */ -List_t * const pxList = ( List_t * ) pxItemToRemove->pvContainer; +List_t * const pxList = pxItemToRemove->pxContainer; pxItemToRemove->pxNext->pxPrevious = pxItemToRemove->pxPrevious; pxItemToRemove->pxPrevious->pxNext = pxItemToRemove->pxNext; @@ -231,7 +189,7 @@ List_t * const pxList = ( List_t * ) pxItemToRemove->pvContainer; mtCOVERAGE_TEST_MARKER(); } - pxItemToRemove->pvContainer = NULL; + pxItemToRemove->pxContainer = NULL; ( pxList->uxNumberOfItems )--; return pxList->uxNumberOfItems; diff --git a/Firmware/Board/v3/Middlewares/Third_Party/FreeRTOS/Source/portable/GCC/ARM_CM4F/port.c b/Firmware/Board/v3/Middlewares/Third_Party/FreeRTOS/Source/portable/GCC/ARM_CM4F/port.c index d5feca9e..89a912c0 100644 --- a/Firmware/Board/v3/Middlewares/Third_Party/FreeRTOS/Source/portable/GCC/ARM_CM4F/port.c +++ b/Firmware/Board/v3/Middlewares/Third_Party/FreeRTOS/Source/portable/GCC/ARM_CM4F/port.c @@ -1,71 +1,29 @@ /* - FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. - All rights reserved - - VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. - - This file is part of the FreeRTOS distribution. - - FreeRTOS is free software; you can redistribute it and/or modify it under - the terms of the GNU General Public License (version 2) as published by the - Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception. - - *************************************************************************** - >>! NOTE: The modification to the GPL is included to allow you to !<< - >>! distribute a combined work that includes FreeRTOS without being !<< - >>! obliged to provide the source code for proprietary components !<< - >>! outside of the FreeRTOS kernel. !<< - *************************************************************************** - - FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - FOR A PARTICULAR PURPOSE. Full license text is available on the following - link: http://www.freertos.org/a00114.html - - *************************************************************************** - * * - * FreeRTOS provides completely free yet professionally developed, * - * robust, strictly quality controlled, supported, and cross * - * platform software that is more than just the market leader, it * - * is the industry's de facto standard. * - * * - * Help yourself get started quickly while simultaneously helping * - * to support the FreeRTOS project by purchasing a FreeRTOS * - * tutorial book, reference manual, or both: * - * http://www.FreeRTOS.org/Documentation * - * * - *************************************************************************** - - http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading - the FAQ page "My application does not run, what could be wrong?". Have you - defined configASSERT()? - - http://www.FreeRTOS.org/support - In return for receiving this top quality - embedded software for free we request you assist our global community by - participating in the support forum. - - http://www.FreeRTOS.org/training - Investing in training allows your team to - be as productive as possible as early as possible. Now you can receive - FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers - Ltd, and the world's leading authority on the world's leading RTOS. - - http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, - including FreeRTOS+Trace - an indispensable productivity tool, a DOS - compatible FAT file system, and our tiny thread aware UDP/IP stack. - - http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. - Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. - - http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High - Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS - licenses offer ticketed support, indemnification and commercial middleware. - - http://www.SafeRTOS.com - High Integrity Systems also provide a safety - engineered and independently SIL3 certified version for use in safety and - mission critical applications that require provable dependability. - - 1 tab == 4 spaces! -*/ + * FreeRTOS Kernel V10.3.1 + * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * http://www.FreeRTOS.org + * http://aws.amazon.com/freertos + * + * 1 tab == 4 spaces! + */ /*----------------------------------------------------------- * Implementation of functions defined in portable.h for the ARM CM4F port. @@ -129,7 +87,7 @@ r0p1 port. */ /* Constants required to set up the initial stack. */ #define portINITIAL_XPSR ( 0x01000000 ) -#define portINITIAL_EXEC_RETURN ( 0xfffffffd ) +#define portINITIAL_EXC_RETURN ( 0xfffffffd ) /* The systick is a 24-bit counter. */ #define portMAX_24_BIT_NUMBER ( 0xffffffUL ) @@ -152,10 +110,6 @@ debugger. */ #define portTASK_RETURN_ADDRESS prvTaskExitError #endif -/* Each task maintains its own interrupt status in the critical nesting -variable. */ -static UBaseType_t uxCriticalNesting = 0xaaaaaaaa; - /* * Setup the timer to generate the tick interrupts. The implementation in this * file is weak to allow application writers to change the timer used to @@ -187,10 +141,14 @@ static void prvTaskExitError( void ); /*-----------------------------------------------------------*/ +/* Each task maintains its own interrupt status in the critical nesting +variable. */ +static UBaseType_t uxCriticalNesting = 0xaaaaaaaa; + /* * The number of SysTick increments that make up one tick period. */ -#if configUSE_TICKLESS_IDLE == 1 +#if( configUSE_TICKLESS_IDLE == 1 ) static uint32_t ulTimerCountsForOneTick = 0; #endif /* configUSE_TICKLESS_IDLE */ @@ -198,7 +156,7 @@ static void prvTaskExitError( void ); * The maximum number of tick periods that can be suppressed is limited by the * 24 bit resolution of the SysTick timer. */ -#if configUSE_TICKLESS_IDLE == 1 +#if( configUSE_TICKLESS_IDLE == 1 ) static uint32_t xMaximumPossibleSuppressedTicks = 0; #endif /* configUSE_TICKLESS_IDLE */ @@ -206,7 +164,7 @@ static void prvTaskExitError( void ); * Compensate for the CPU cycles that pass while the SysTick is stopped (low * power functionality only. */ -#if configUSE_TICKLESS_IDLE == 1 +#if( configUSE_TICKLESS_IDLE == 1 ) static uint32_t ulStoppedTimerCompensation = 0; #endif /* configUSE_TICKLESS_IDLE */ @@ -215,7 +173,7 @@ static void prvTaskExitError( void ); * FreeRTOS API functions are not called from interrupts that have been assigned * a priority above configMAX_SYSCALL_INTERRUPT_PRIORITY. */ -#if ( configASSERT_DEFINED == 1 ) +#if( configASSERT_DEFINED == 1 ) static uint8_t ucMaxSysCallPriority = 0; static uint32_t ulMaxPRIGROUPValue = 0; static const volatile uint8_t * const pcInterruptPriorityRegisters = ( const volatile uint8_t * const ) portNVIC_IP_REGISTERS_OFFSET_16; @@ -248,7 +206,7 @@ StackType_t *pxPortInitialiseStack( StackType_t *pxTopOfStack, TaskFunction_t px /* A save method is being used that requires each task to maintain its own exec return value. */ pxTopOfStack--; - *pxTopOfStack = portINITIAL_EXEC_RETURN; + *pxTopOfStack = portINITIAL_EXC_RETURN; pxTopOfStack -= 8; /* R11, R10, R9, R8, R7, R6, R5 and R4. */ @@ -258,6 +216,8 @@ StackType_t *pxPortInitialiseStack( StackType_t *pxTopOfStack, TaskFunction_t px static void prvTaskExitError( void ) { +volatile uint32_t ulDummy = 0; + /* A function that implements a task must not exit or attempt to return to its caller as there is nothing to return to. If a task wants to exit it should instead call vTaskDelete( NULL ). @@ -266,7 +226,16 @@ static void prvTaskExitError( void ) defined, then stop here so application writers can catch the error. */ configASSERT( uxCriticalNesting == ~0UL ); portDISABLE_INTERRUPTS(); - for( ;; ); + while( ulDummy == 0 ) + { + /* This file calls prvTaskExitError() after the scheduler has been + started to remove a compiler warning about the function being defined + but never called. ulDummy is used purely to quieten other warnings + about code appearing after this function is called - making ulDummy + volatile makes the compiler think the function could return and + therefore not output an 'unreachable code' warning for code that appears + after it. */ + } } /*-----------------------------------------------------------*/ @@ -291,11 +260,17 @@ void vPortSVCHandler( void ) static void prvPortStartFirstTask( void ) { + /* Start the first task. This also clears the bit that indicates the FPU is + in use in case the FPU was used before the scheduler was started - which + would otherwise result in the unnecessary leaving of space in the SVC stack + for lazy saving of FPU registers. */ __asm volatile( " ldr r0, =0xE000ED08 \n" /* Use the NVIC offset register to locate the stack. */ " ldr r0, [r0] \n" " ldr r0, [r0] \n" " msr msp, r0 \n" /* Set the msp back to the start of the stack. */ + " mov r0, #0 \n" /* Clear the bit that indicates the FPU is in use, see comment above. */ + " msr control, r0 \n" " cpsie i \n" /* Globally enable interrupts. */ " cpsie f \n" " dsb \n" @@ -354,6 +329,24 @@ BaseType_t xPortStartScheduler( void ) ucMaxPriorityValue <<= ( uint8_t ) 0x01; } + #ifdef __NVIC_PRIO_BITS + { + /* Check the CMSIS configuration that defines the number of + priority bits matches the number of priority bits actually queried + from the hardware. */ + configASSERT( ( portMAX_PRIGROUP_BITS - ulMaxPRIGROUPValue ) == __NVIC_PRIO_BITS ); + } + #endif + + #ifdef configPRIO_BITS + { + /* Check the FreeRTOS configuration that defines the number of + priority bits matches the number of priority bits actually queried + from the hardware. */ + configASSERT( ( portMAX_PRIGROUP_BITS - ulMaxPRIGROUPValue ) == configPRIO_BITS ); + } + #endif + /* Shift the priority group value back to its position within the AIRCR register. */ ulMaxPRIGROUPValue <<= portPRIGROUP_SHIFT; @@ -388,7 +381,10 @@ BaseType_t xPortStartScheduler( void ) /* Should never get here as the tasks will now be executing! Call the task exit error function to prevent compiler warnings about a static function not being called in the case that the application writer overrides this - functionality by defining configTASK_RETURN_ADDRESS. */ + functionality by defining configTASK_RETURN_ADDRESS. Call + vTaskSwitchContext() so link time optimisation does not remove the + symbol. */ + vTaskSwitchContext(); prvTaskExitError(); /* Should not get here! */ @@ -449,10 +445,9 @@ void xPortPendSVHandler( void ) " vstmdbeq r0!, {s16-s31} \n" " \n" " stmdb r0!, {r4-r11, r14} \n" /* Save the core registers. */ - " \n" " str r0, [r2] \n" /* Save the new top of stack into the first member of the TCB. */ " \n" - " stmdb sp!, {r3} \n" + " stmdb sp!, {r0, r3} \n" " mov r0, %0 \n" " msr basepri, r0 \n" " dsb \n" @@ -460,7 +455,7 @@ void xPortPendSVHandler( void ) " bl vTaskSwitchContext \n" " mov r0, #0 \n" " msr basepri, r0 \n" - " ldmia sp!, {r3} \n" + " ldmia sp!, {r0, r3} \n" " \n" " ldr r1, [r3] \n" /* The first item in pxCurrentTCB is the task top of stack. */ " ldr r0, [r1] \n" @@ -510,11 +505,11 @@ void xPortSysTickHandler( void ) } /*-----------------------------------------------------------*/ -#if configUSE_TICKLESS_IDLE == 1 +#if( configUSE_TICKLESS_IDLE == 1 ) __attribute__((weak)) void vPortSuppressTicksAndSleep( TickType_t xExpectedIdleTime ) { - uint32_t ulReloadValue, ulCompleteTickPeriods, ulCompletedSysTickDecrements, ulSysTickCTRL; + uint32_t ulReloadValue, ulCompleteTickPeriods, ulCompletedSysTickDecrements; TickType_t xModifiableIdleTime; /* Make sure the SysTick reload value does not overflow the counter. */ @@ -540,7 +535,7 @@ void xPortSysTickHandler( void ) /* Enter a critical section but don't use the taskENTER_CRITICAL() method as that will mask interrupts that should exit sleep mode. */ - __asm volatile( "cpsid i" ); + __asm volatile( "cpsid i" ::: "memory" ); __asm volatile( "dsb" ); __asm volatile( "isb" ); @@ -561,7 +556,7 @@ void xPortSysTickHandler( void ) /* Re-enable interrupts - see comments above the cpsid instruction() above. */ - __asm volatile( "cpsie i" ); + __asm volatile( "cpsie i" ::: "memory" ); } else { @@ -581,32 +576,50 @@ void xPortSysTickHandler( void ) should not be executed again. However, the original expected idle time variable must remain unmodified, so a copy is taken. */ xModifiableIdleTime = xExpectedIdleTime; - configPRE_SLEEP_PROCESSING( &xModifiableIdleTime ); + configPRE_SLEEP_PROCESSING( xModifiableIdleTime ); if( xModifiableIdleTime > 0 ) { - __asm volatile( "dsb" ); + __asm volatile( "dsb" ::: "memory" ); __asm volatile( "wfi" ); __asm volatile( "isb" ); } - configPOST_SLEEP_PROCESSING( &xExpectedIdleTime ); + configPOST_SLEEP_PROCESSING( xExpectedIdleTime ); - /* Stop SysTick. Again, the time the SysTick is stopped for is - accounted for as best it can be, but using the tickless mode will - inevitably result in some tiny drift of the time maintained by the - kernel with respect to calendar time. */ - ulSysTickCTRL = portNVIC_SYSTICK_CTRL_REG; - portNVIC_SYSTICK_CTRL_REG = ( ulSysTickCTRL & ~portNVIC_SYSTICK_ENABLE_BIT ); + /* Re-enable interrupts to allow the interrupt that brought the MCU + out of sleep mode to execute immediately. see comments above + __disable_interrupt() call above. */ + __asm volatile( "cpsie i" ::: "memory" ); + __asm volatile( "dsb" ); + __asm volatile( "isb" ); - /* Re-enable interrupts - see comments above the cpsid instruction() - above. */ - __asm volatile( "cpsie i" ); + /* Disable interrupts again because the clock is about to be stopped + and interrupts that execute while the clock is stopped will increase + any slippage between the time maintained by the RTOS and calendar + time. */ + __asm volatile( "cpsid i" ::: "memory" ); + __asm volatile( "dsb" ); + __asm volatile( "isb" ); - if( ( ulSysTickCTRL & portNVIC_SYSTICK_COUNT_FLAG_BIT ) != 0 ) + /* Disable the SysTick clock without reading the + portNVIC_SYSTICK_CTRL_REG register to ensure the + portNVIC_SYSTICK_COUNT_FLAG_BIT is not cleared if it is set. Again, + the time the SysTick is stopped for is accounted for as best it can + be, but using the tickless mode will inevitably result in some tiny + drift of the time maintained by the kernel with respect to calendar + time*/ + portNVIC_SYSTICK_CTRL_REG = ( portNVIC_SYSTICK_CLK_BIT | portNVIC_SYSTICK_INT_BIT ); + + /* Determine if the SysTick clock has already counted to zero and + been set back to the current reload value (the reload back being + correct for the entire expected idle time) or if the SysTick is yet + to count to zero (in which case an interrupt other than the SysTick + must have brought the system out of sleep mode). */ + if( ( portNVIC_SYSTICK_CTRL_REG & portNVIC_SYSTICK_COUNT_FLAG_BIT ) != 0 ) { uint32_t ulCalculatedLoadValue; - /* The tick interrupt has already executed, and the SysTick - count reloaded with ulReloadValue. Reset the + /* The tick interrupt is already pending, and the SysTick count + reloaded with ulReloadValue. Reset the portNVIC_SYSTICK_LOAD_REG with whatever remains of this tick period. */ ulCalculatedLoadValue = ( ulTimerCountsForOneTick - 1UL ) - ( ulReloadValue - portNVIC_SYSTICK_CURRENT_VALUE_REG ); @@ -621,11 +634,9 @@ void xPortSysTickHandler( void ) portNVIC_SYSTICK_LOAD_REG = ulCalculatedLoadValue; - /* The tick interrupt handler will already have pended the tick - processing in the kernel. As the pending tick will be - processed as soon as this function exits, the tick value - maintained by the tick is stepped forward by one less than the - time spent waiting. */ + /* As the pending tick will be processed as soon as this + function exits, the tick value maintained by the tick is stepped + forward by one less than the time spent waiting. */ ulCompleteTickPeriods = xExpectedIdleTime - 1UL; } else @@ -647,17 +658,14 @@ void xPortSysTickHandler( void ) /* Restart SysTick so it runs from portNVIC_SYSTICK_LOAD_REG again, then set portNVIC_SYSTICK_LOAD_REG back to its standard - value. The critical section is used to ensure the tick interrupt - can only execute once in the case that the reload register is near - zero. */ + value. */ portNVIC_SYSTICK_CURRENT_VALUE_REG = 0UL; - portENTER_CRITICAL(); - { - portNVIC_SYSTICK_CTRL_REG |= portNVIC_SYSTICK_ENABLE_BIT; - vTaskStepTick( ulCompleteTickPeriods ); - portNVIC_SYSTICK_LOAD_REG = ulTimerCountsForOneTick - 1UL; - } - portEXIT_CRITICAL(); + portNVIC_SYSTICK_CTRL_REG |= portNVIC_SYSTICK_ENABLE_BIT; + vTaskStepTick( ulCompleteTickPeriods ); + portNVIC_SYSTICK_LOAD_REG = ulTimerCountsForOneTick - 1UL; + + /* Exit with interrupts enabled. */ + __asm volatile( "cpsie i" ::: "memory" ); } } @@ -671,7 +679,7 @@ void xPortSysTickHandler( void ) __attribute__(( weak )) void vPortSetupTimerInterrupt( void ) { /* Calculate the constants required to configure the tick interrupt. */ - #if configUSE_TICKLESS_IDLE == 1 + #if( configUSE_TICKLESS_IDLE == 1 ) { ulTimerCountsForOneTick = ( configSYSTICK_CLOCK_HZ / configTICK_RATE_HZ ); xMaximumPossibleSuppressedTicks = portMAX_24_BIT_NUMBER / ulTimerCountsForOneTick; @@ -679,6 +687,10 @@ __attribute__(( weak )) void vPortSetupTimerInterrupt( void ) } #endif /* configUSE_TICKLESS_IDLE */ + /* Stop and clear the SysTick. */ + portNVIC_SYSTICK_CTRL_REG = 0UL; + portNVIC_SYSTICK_CURRENT_VALUE_REG = 0UL; + /* Configure SysTick to interrupt at the requested rate. */ portNVIC_SYSTICK_LOAD_REG = ( configSYSTICK_CLOCK_HZ / configTICK_RATE_HZ ) - 1UL; portNVIC_SYSTICK_CTRL_REG = ( portNVIC_SYSTICK_CLK_BIT | portNVIC_SYSTICK_INT_BIT | portNVIC_SYSTICK_ENABLE_BIT ); @@ -708,7 +720,7 @@ static void vPortEnableVFP( void ) uint8_t ucCurrentPriority; /* Obtain the number of the currently executing interrupt. */ - __asm volatile( "mrs %0, ipsr" : "=r"( ulCurrentInterrupt ) ); + __asm volatile( "mrs %0, ipsr" : "=r"( ulCurrentInterrupt ) :: "memory" ); /* Is the interrupt number a user defined interrupt? */ if( ulCurrentInterrupt >= portFIRST_USER_INTERRUPT_NUMBER ) @@ -754,7 +766,7 @@ static void vPortEnableVFP( void ) devices by calling NVIC_SetPriorityGrouping( 0 ); before starting the scheduler. Note however that some vendor specific peripheral libraries assume a non-zero priority group setting, in which cases using a value - of zero will result in unpredicable behaviour. */ + of zero will result in unpredictable behaviour. */ configASSERT( ( portAIRCR_REG & portPRIORITY_GROUP_MASK ) <= ulMaxPRIGROUPValue ); } diff --git a/Firmware/Board/v3/Middlewares/Third_Party/FreeRTOS/Source/portable/GCC/ARM_CM4F/portmacro.h b/Firmware/Board/v3/Middlewares/Third_Party/FreeRTOS/Source/portable/GCC/ARM_CM4F/portmacro.h index d44fc922..d0a566a7 100644 --- a/Firmware/Board/v3/Middlewares/Third_Party/FreeRTOS/Source/portable/GCC/ARM_CM4F/portmacro.h +++ b/Firmware/Board/v3/Middlewares/Third_Party/FreeRTOS/Source/portable/GCC/ARM_CM4F/portmacro.h @@ -1,71 +1,29 @@ /* - FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. - All rights reserved - - VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. - - This file is part of the FreeRTOS distribution. - - FreeRTOS is free software; you can redistribute it and/or modify it under - the terms of the GNU General Public License (version 2) as published by the - Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception. - - *************************************************************************** - >>! NOTE: The modification to the GPL is included to allow you to !<< - >>! distribute a combined work that includes FreeRTOS without being !<< - >>! obliged to provide the source code for proprietary components !<< - >>! outside of the FreeRTOS kernel. !<< - *************************************************************************** - - FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - FOR A PARTICULAR PURPOSE. Full license text is available on the following - link: http://www.freertos.org/a00114.html - - *************************************************************************** - * * - * FreeRTOS provides completely free yet professionally developed, * - * robust, strictly quality controlled, supported, and cross * - * platform software that is more than just the market leader, it * - * is the industry's de facto standard. * - * * - * Help yourself get started quickly while simultaneously helping * - * to support the FreeRTOS project by purchasing a FreeRTOS * - * tutorial book, reference manual, or both: * - * http://www.FreeRTOS.org/Documentation * - * * - *************************************************************************** - - http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading - the FAQ page "My application does not run, what could be wrong?". Have you - defined configASSERT()? - - http://www.FreeRTOS.org/support - In return for receiving this top quality - embedded software for free we request you assist our global community by - participating in the support forum. - - http://www.FreeRTOS.org/training - Investing in training allows your team to - be as productive as possible as early as possible. Now you can receive - FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers - Ltd, and the world's leading authority on the world's leading RTOS. - - http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, - including FreeRTOS+Trace - an indispensable productivity tool, a DOS - compatible FAT file system, and our tiny thread aware UDP/IP stack. - - http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. - Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. - - http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High - Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS - licenses offer ticketed support, indemnification and commercial middleware. - - http://www.SafeRTOS.com - High Integrity Systems also provide a safety - engineered and independently SIL3 certified version for use in safety and - mission critical applications that require provable dependability. - - 1 tab == 4 spaces! -*/ + * FreeRTOS Kernel V10.3.1 + * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * http://www.FreeRTOS.org + * http://aws.amazon.com/freertos + * + * 1 tab == 4 spaces! + */ #ifndef PORTMACRO_H @@ -125,7 +83,7 @@ typedef unsigned long UBaseType_t; \ /* Barriers are normally not required but do ensure the code is completely \ within the specified behaviour for the architecture. */ \ - __asm volatile( "dsb" ); \ + __asm volatile( "dsb" ::: "memory" ); \ __asm volatile( "isb" ); \ } @@ -173,7 +131,7 @@ not necessary for to use this port. They are defined so the common demo files { uint8_t ucReturn; - __asm volatile ( "clz %0, %1" : "=r" ( ucReturn ) : "r" ( ulBitmap ) ); + __asm volatile ( "clz %0, %1" : "=r" ( ucReturn ) : "r" ( ulBitmap ) : "memory" ); return ucReturn; } @@ -214,7 +172,7 @@ uint32_t ulCurrentInterrupt; BaseType_t xReturn; /* Obtain the number of the currently executing interrupt. */ - __asm volatile( "mrs %0, ipsr" : "=r"( ulCurrentInterrupt ) ); + __asm volatile( "mrs %0, ipsr" : "=r"( ulCurrentInterrupt ) :: "memory" ); if( ulCurrentInterrupt == 0 ) { @@ -240,7 +198,7 @@ uint32_t ulNewBASEPRI; " msr basepri, %0 \n" \ " isb \n" \ " dsb \n" \ - :"=r" (ulNewBASEPRI) : "i" ( configMAX_SYSCALL_INTERRUPT_PRIORITY ) + :"=r" (ulNewBASEPRI) : "i" ( configMAX_SYSCALL_INTERRUPT_PRIORITY ) : "memory" ); } @@ -257,7 +215,7 @@ uint32_t ulOriginalBASEPRI, ulNewBASEPRI; " msr basepri, %1 \n" \ " isb \n" \ " dsb \n" \ - :"=r" (ulOriginalBASEPRI), "=r" (ulNewBASEPRI) : "i" ( configMAX_SYSCALL_INTERRUPT_PRIORITY ) + :"=r" (ulOriginalBASEPRI), "=r" (ulNewBASEPRI) : "i" ( configMAX_SYSCALL_INTERRUPT_PRIORITY ) : "memory" ); /* This return will not be reached but is necessary to prevent compiler @@ -270,11 +228,12 @@ portFORCE_INLINE static void vPortSetBASEPRI( uint32_t ulNewMaskValue ) { __asm volatile ( - " msr basepri, %0 " :: "r" ( ulNewMaskValue ) + " msr basepri, %0 " :: "r" ( ulNewMaskValue ) : "memory" ); } /*-----------------------------------------------------------*/ +#define portMEMORY_BARRIER() __asm volatile( "" ::: "memory" ) #ifdef __cplusplus } diff --git a/Firmware/Board/v3/Middlewares/Third_Party/FreeRTOS/Source/portable/MemMang/ReadMe.url b/Firmware/Board/v3/Middlewares/Third_Party/FreeRTOS/Source/portable/MemMang/ReadMe.url new file mode 100644 index 00000000..6c23737d --- /dev/null +++ b/Firmware/Board/v3/Middlewares/Third_Party/FreeRTOS/Source/portable/MemMang/ReadMe.url @@ -0,0 +1,5 @@ +[{000214A0-0000-0000-C000-000000000046}] +Prop3=19,2 +[InternetShortcut] +URL=http://www.freertos.org/a00111.html +IDList= diff --git a/Firmware/Board/v3/Middlewares/Third_Party/FreeRTOS/Source/portable/MemMang/heap_4.c b/Firmware/Board/v3/Middlewares/Third_Party/FreeRTOS/Source/portable/MemMang/heap_4.c index e7c7ade6..eaf443f4 100644 --- a/Firmware/Board/v3/Middlewares/Third_Party/FreeRTOS/Source/portable/MemMang/heap_4.c +++ b/Firmware/Board/v3/Middlewares/Third_Party/FreeRTOS/Source/portable/MemMang/heap_4.c @@ -1,71 +1,29 @@ /* - FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. - All rights reserved - - VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. - - This file is part of the FreeRTOS distribution. - - FreeRTOS is free software; you can redistribute it and/or modify it under - the terms of the GNU General Public License (version 2) as published by the - Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception. - - *************************************************************************** - >>! NOTE: The modification to the GPL is included to allow you to !<< - >>! distribute a combined work that includes FreeRTOS without being !<< - >>! obliged to provide the source code for proprietary components !<< - >>! outside of the FreeRTOS kernel. !<< - *************************************************************************** - - FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - FOR A PARTICULAR PURPOSE. Full license text is available on the following - link: http://www.freertos.org/a00114.html - - *************************************************************************** - * * - * FreeRTOS provides completely free yet professionally developed, * - * robust, strictly quality controlled, supported, and cross * - * platform software that is more than just the market leader, it * - * is the industry's de facto standard. * - * * - * Help yourself get started quickly while simultaneously helping * - * to support the FreeRTOS project by purchasing a FreeRTOS * - * tutorial book, reference manual, or both: * - * http://www.FreeRTOS.org/Documentation * - * * - *************************************************************************** - - http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading - the FAQ page "My application does not run, what could be wrong?". Have you - defined configASSERT()? - - http://www.FreeRTOS.org/support - In return for receiving this top quality - embedded software for free we request you assist our global community by - participating in the support forum. - - http://www.FreeRTOS.org/training - Investing in training allows your team to - be as productive as possible as early as possible. Now you can receive - FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers - Ltd, and the world's leading authority on the world's leading RTOS. - - http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, - including FreeRTOS+Trace - an indispensable productivity tool, a DOS - compatible FAT file system, and our tiny thread aware UDP/IP stack. - - http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. - Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. - - http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High - Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS - licenses offer ticketed support, indemnification and commercial middleware. - - http://www.SafeRTOS.com - High Integrity Systems also provide a safety - engineered and independently SIL3 certified version for use in safety and - mission critical applications that require provable dependability. - - 1 tab == 4 spaces! -*/ + * FreeRTOS Kernel V10.3.1 + * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * http://www.FreeRTOS.org + * http://aws.amazon.com/freertos + * + * 1 tab == 4 spaces! + */ /* * A sample implementation of pvPortMalloc() and vPortFree() that combines @@ -139,10 +97,12 @@ static const size_t xHeapStructSize = ( sizeof( BlockLink_t ) + ( ( size_t ) ( p /* Create a couple of list links to mark the start and end of the list. */ static BlockLink_t xStart, *pxEnd = NULL; -/* Keeps track of the number of free bytes remaining, but says nothing about -fragmentation. */ +/* Keeps track of the number of calls to allocate and free memory as well as the +number of free bytes remaining, but says nothing about fragmentation. */ static size_t xFreeBytesRemaining = 0U; static size_t xMinimumEverFreeBytesRemaining = 0U; +static size_t xNumberOfSuccessfulAllocations = 0; +static size_t xNumberOfSuccessfulFrees = 0; /* Gets set to the top bit of an size_t type. When this bit in the xBlockSize member of an BlockLink_t structure is set then the block belongs to the @@ -263,6 +223,7 @@ void *pvReturn = NULL; by the application and has no "next" block. */ pxBlock->xBlockSize |= xBlockAllocatedBit; pxBlock->pxNextFreeBlock = NULL; + xNumberOfSuccessfulAllocations++; } else { @@ -334,6 +295,7 @@ BlockLink_t *pxLink; xFreeBytesRemaining += pxLink->xBlockSize; traceFREE( pv, pxLink->xBlockSize ); prvInsertBlockIntoFreeList( ( ( BlockLink_t * ) pxLink ) ); + xNumberOfSuccessfulFrees++; } ( void ) xTaskResumeAll(); } @@ -475,4 +437,56 @@ uint8_t *puc; mtCOVERAGE_TEST_MARKER(); } } +/*-----------------------------------------------------------*/ + +void vPortGetHeapStats( HeapStats_t *pxHeapStats ) +{ +BlockLink_t *pxBlock; +size_t xBlocks = 0, xMaxSize = 0, xMinSize = portMAX_DELAY; /* portMAX_DELAY used as a portable way of getting the maximum value. */ + + vTaskSuspendAll(); + { + pxBlock = xStart.pxNextFreeBlock; + + /* pxBlock will be NULL if the heap has not been initialised. The heap + is initialised automatically when the first allocation is made. */ + if( pxBlock != NULL ) + { + do + { + /* Increment the number of blocks and record the largest block seen + so far. */ + xBlocks++; + + if( pxBlock->xBlockSize > xMaxSize ) + { + xMaxSize = pxBlock->xBlockSize; + } + + if( pxBlock->xBlockSize < xMinSize ) + { + xMinSize = pxBlock->xBlockSize; + } + + /* Move to the next block in the chain until the last block is + reached. */ + pxBlock = pxBlock->pxNextFreeBlock; + } while( pxBlock != pxEnd ); + } + } + xTaskResumeAll(); + + pxHeapStats->xSizeOfLargestFreeBlockInBytes = xMaxSize; + pxHeapStats->xSizeOfSmallestFreeBlockInBytes = xMinSize; + pxHeapStats->xNumberOfFreeBlocks = xBlocks; + + taskENTER_CRITICAL(); + { + pxHeapStats->xAvailableHeapSpaceInBytes = xFreeBytesRemaining; + pxHeapStats->xNumberOfSuccessfulAllocations = xNumberOfSuccessfulAllocations; + pxHeapStats->xNumberOfSuccessfulFrees = xNumberOfSuccessfulFrees; + pxHeapStats->xMinimumEverFreeBytesRemaining = xMinimumEverFreeBytesRemaining; + } + taskEXIT_CRITICAL(); +} diff --git a/Firmware/Board/v3/Middlewares/Third_Party/FreeRTOS/Source/queue.c b/Firmware/Board/v3/Middlewares/Third_Party/FreeRTOS/Source/queue.c index 056d4be1..b3203b80 100644 --- a/Firmware/Board/v3/Middlewares/Third_Party/FreeRTOS/Source/queue.c +++ b/Firmware/Board/v3/Middlewares/Third_Party/FreeRTOS/Source/queue.c @@ -1,71 +1,29 @@ /* - FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. - All rights reserved - - VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. - - This file is part of the FreeRTOS distribution. - - FreeRTOS is free software; you can redistribute it and/or modify it under - the terms of the GNU General Public License (version 2) as published by the - Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception. - - *************************************************************************** - >>! NOTE: The modification to the GPL is included to allow you to !<< - >>! distribute a combined work that includes FreeRTOS without being !<< - >>! obliged to provide the source code for proprietary components !<< - >>! outside of the FreeRTOS kernel. !<< - *************************************************************************** - - FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - FOR A PARTICULAR PURPOSE. Full license text is available on the following - link: http://www.freertos.org/a00114.html - - *************************************************************************** - * * - * FreeRTOS provides completely free yet professionally developed, * - * robust, strictly quality controlled, supported, and cross * - * platform software that is more than just the market leader, it * - * is the industry's de facto standard. * - * * - * Help yourself get started quickly while simultaneously helping * - * to support the FreeRTOS project by purchasing a FreeRTOS * - * tutorial book, reference manual, or both: * - * http://www.FreeRTOS.org/Documentation * - * * - *************************************************************************** - - http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading - the FAQ page "My application does not run, what could be wrong?". Have you - defined configASSERT()? - - http://www.FreeRTOS.org/support - In return for receiving this top quality - embedded software for free we request you assist our global community by - participating in the support forum. - - http://www.FreeRTOS.org/training - Investing in training allows your team to - be as productive as possible as early as possible. Now you can receive - FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers - Ltd, and the world's leading authority on the world's leading RTOS. - - http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, - including FreeRTOS+Trace - an indispensable productivity tool, a DOS - compatible FAT file system, and our tiny thread aware UDP/IP stack. - - http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. - Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. - - http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High - Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS - licenses offer ticketed support, indemnification and commercial middleware. - - http://www.SafeRTOS.com - High Integrity Systems also provide a safety - engineered and independently SIL3 certified version for use in safety and - mission critical applications that require provable dependability. - - 1 tab == 4 spaces! -*/ + * FreeRTOS Kernel V10.3.1 + * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * http://www.FreeRTOS.org + * http://aws.amazon.com/freertos + * + * 1 tab == 4 spaces! + */ #include #include @@ -83,11 +41,11 @@ task.h is included from an application file. */ #include "croutine.h" #endif -/* Lint e961 and e750 are suppressed as a MISRA exception justified because the -MPU ports require MPU_WRAPPERS_INCLUDED_FROM_API_FILE to be defined for the -header files above, but not in this file, in order to generate the correct -privileged Vs unprivileged linkage and placement. */ -#undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE /*lint !e961 !e750. */ +/* Lint e9021, e961 and e750 are suppressed as a MISRA exception justified +because the MPU ports require MPU_WRAPPERS_INCLUDED_FROM_API_FILE to be defined +for the header files above, but not in this file, in order to generate the +correct privileged Vs unprivileged linkage and placement. */ +#undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE /*lint !e961 !e750 !e9021. */ /* Constants used with the cRxLock and cTxLock structure members. */ @@ -98,17 +56,26 @@ privileged Vs unprivileged linkage and placement. */ pcTail members are used as pointers into the queue storage area. When the Queue_t structure is used to represent a mutex pcHead and pcTail pointers are not necessary, and the pcHead pointer is set to NULL to indicate that the -pcTail pointer actually points to the mutex holder (if any). Map alternative -names to the pcHead and pcTail structure members to ensure the readability of -the code is maintained despite this dual use of two structure members. An -alternative implementation would be to use a union, but use of a union is -against the coding standard (although an exception to the standard has been -permitted where the dual use also significantly changes the type of the -structure member). */ -#define pxMutexHolder pcTail +structure instead holds a pointer to the mutex holder (if any). Map alternative +names to the pcHead and structure member to ensure the readability of the code +is maintained. The QueuePointers_t and SemaphoreData_t types are used to form +a union as their usage is mutually exclusive dependent on what the queue is +being used for. */ #define uxQueueType pcHead #define queueQUEUE_IS_MUTEX NULL +typedef struct QueuePointers +{ + int8_t *pcTail; /*< Points to the byte at the end of the queue storage area. Once more byte is allocated than necessary to store the queue items, this is used as a marker. */ + int8_t *pcReadFrom; /*< Points to the last place that a queued item was read from when the structure is used as a queue. */ +} QueuePointers_t; + +typedef struct SemaphoreData +{ + TaskHandle_t xMutexHolder; /*< The handle of the task that holds the mutex. */ + UBaseType_t uxRecursiveCallCount;/*< Maintains a count of the number of times a recursive mutex has been recursively 'taken' when the structure is used as a mutex. */ +} SemaphoreData_t; + /* Semaphores do not actually store or copy data, so have an item size of zero. */ #define queueSEMAPHORE_QUEUE_ITEM_LENGTH ( ( UBaseType_t ) 0 ) @@ -125,18 +92,17 @@ zero. */ /* * Definition of the queue used by the scheduler. * Items are queued by copy, not reference. See the following link for the - * rationale: http://www.freertos.org/Embedded-RTOS-Queues.html + * rationale: https://www.freertos.org/Embedded-RTOS-Queues.html */ -typedef struct QueueDefinition +typedef struct QueueDefinition /* The old naming convention is used to prevent breaking kernel aware debuggers. */ { int8_t *pcHead; /*< Points to the beginning of the queue storage area. */ - int8_t *pcTail; /*< Points to the byte at the end of the queue storage area. Once more byte is allocated than necessary to store the queue items, this is used as a marker. */ int8_t *pcWriteTo; /*< Points to the free next place in the storage area. */ - union /* Use of a union is an exception to the coding standard to ensure two mutually exclusive structure members don't appear simultaneously (wasting RAM). */ + union { - int8_t *pcReadFrom; /*< Points to the last place that a queued item was read from when the structure is used as a queue. */ - UBaseType_t uxRecursiveCallCount;/*< Maintains a count of the number of times a recursive mutex has been recursively 'taken' when the structure is used as a mutex. */ + QueuePointers_t xQueue; /*< Data required exclusively when this structure is used as a queue. */ + SemaphoreData_t xSemaphore; /*< Data required exclusively when this structure is used as a semaphore. */ } u; List_t xTasksWaitingToSend; /*< List of tasks that are blocked waiting to post onto this queue. Stored in priority order. */ @@ -205,46 +171,46 @@ typedef xQUEUE Queue_t; * to indicate that a task may require unblocking. When the queue in unlocked * these lock counts are inspected, and the appropriate action taken. */ -PRIVILEGED_FUNCTION static void prvUnlockQueue( Queue_t * const pxQueue ); +static void prvUnlockQueue( Queue_t * const pxQueue ) PRIVILEGED_FUNCTION; /* * Uses a critical section to determine if there is any data in a queue. * * @return pdTRUE if the queue contains no items, otherwise pdFALSE. */ -PRIVILEGED_FUNCTION static BaseType_t prvIsQueueEmpty( const Queue_t *pxQueue ); +static BaseType_t prvIsQueueEmpty( const Queue_t *pxQueue ) PRIVILEGED_FUNCTION; /* * Uses a critical section to determine if there is any space in a queue. * * @return pdTRUE if there is no space, otherwise pdFALSE; */ -PRIVILEGED_FUNCTION static BaseType_t prvIsQueueFull( const Queue_t *pxQueue ); +static BaseType_t prvIsQueueFull( const Queue_t *pxQueue ) PRIVILEGED_FUNCTION; /* * Copies an item into the queue, either at the front of the queue or the * back of the queue. */ -PRIVILEGED_FUNCTION static BaseType_t prvCopyDataToQueue( Queue_t * const pxQueue, const void *pvItemToQueue, const BaseType_t xPosition ); +static BaseType_t prvCopyDataToQueue( Queue_t * const pxQueue, const void *pvItemToQueue, const BaseType_t xPosition ) PRIVILEGED_FUNCTION; /* * Copies an item out of a queue. */ -PRIVILEGED_FUNCTION static void prvCopyDataFromQueue( Queue_t * const pxQueue, void * const pvBuffer ); +static void prvCopyDataFromQueue( Queue_t * const pxQueue, void * const pvBuffer ) PRIVILEGED_FUNCTION; #if ( configUSE_QUEUE_SETS == 1 ) /* * Checks to see if a queue is a member of a queue set, and if so, notifies * the queue set that the queue contains data. */ - PRIVILEGED_FUNCTION static BaseType_t prvNotifyQueueSetContainer( const Queue_t * const pxQueue, const BaseType_t xCopyPosition ); + static BaseType_t prvNotifyQueueSetContainer( const Queue_t * const pxQueue ) PRIVILEGED_FUNCTION; #endif /* * Called after a Queue_t structure has been allocated either statically or * dynamically to fill in the structure's members. */ -PRIVILEGED_FUNCTION static void prvInitialiseNewQueue( const UBaseType_t uxQueueLength, const UBaseType_t uxItemSize, uint8_t *pucQueueStorage, const uint8_t ucQueueType, Queue_t *pxNewQueue ); +static void prvInitialiseNewQueue( const UBaseType_t uxQueueLength, const UBaseType_t uxItemSize, uint8_t *pucQueueStorage, const uint8_t ucQueueType, Queue_t *pxNewQueue ) PRIVILEGED_FUNCTION; /* * Mutexes are a special type of queue. When a mutex is created, first the @@ -252,9 +218,19 @@ PRIVILEGED_FUNCTION static void prvInitialiseNewQueue( const UBaseType_t uxQueue * as a mutex. */ #if( configUSE_MUTEXES == 1 ) - PRIVILEGED_FUNCTION static void prvInitialiseMutex( Queue_t *pxNewQueue ); + static void prvInitialiseMutex( Queue_t *pxNewQueue ) PRIVILEGED_FUNCTION; #endif +#if( configUSE_MUTEXES == 1 ) + /* + * If a task waiting for a mutex causes the mutex holder to inherit a + * priority, but the waiting task times out, then the holder should + * disinherit the priority - but only down to the highest priority of any + * other tasks that are waiting for the same mutex. This function returns + * that priority. + */ + static UBaseType_t prvGetDisinheritPriorityAfterTimeout( const Queue_t * const pxQueue ) PRIVILEGED_FUNCTION; +#endif /*-----------------------------------------------------------*/ /* @@ -278,16 +254,16 @@ PRIVILEGED_FUNCTION static void prvInitialiseNewQueue( const UBaseType_t uxQueue BaseType_t xQueueGenericReset( QueueHandle_t xQueue, BaseType_t xNewQueue ) { -Queue_t * const pxQueue = ( Queue_t * ) xQueue; +Queue_t * const pxQueue = xQueue; configASSERT( pxQueue ); taskENTER_CRITICAL(); { - pxQueue->pcTail = pxQueue->pcHead + ( pxQueue->uxLength * pxQueue->uxItemSize ); + pxQueue->u.xQueue.pcTail = pxQueue->pcHead + ( pxQueue->uxLength * pxQueue->uxItemSize ); /*lint !e9016 Pointer arithmetic allowed on char types, especially when it assists conveying intent. */ pxQueue->uxMessagesWaiting = ( UBaseType_t ) 0U; pxQueue->pcWriteTo = pxQueue->pcHead; - pxQueue->u.pcReadFrom = pxQueue->pcHead + ( ( pxQueue->uxLength - ( UBaseType_t ) 1U ) * pxQueue->uxItemSize ); + pxQueue->u.xQueue.pcReadFrom = pxQueue->pcHead + ( ( pxQueue->uxLength - 1U ) * pxQueue->uxItemSize ); /*lint !e9016 Pointer arithmetic allowed on char types, especially when it assists conveying intent. */ pxQueue->cRxLock = queueUNLOCKED; pxQueue->cTxLock = queueUNLOCKED; @@ -353,13 +329,14 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue; the real queue and semaphore structures. */ volatile size_t xSize = sizeof( StaticQueue_t ); configASSERT( xSize == sizeof( Queue_t ) ); + ( void ) xSize; /* Keeps lint quiet when configASSERT() is not defined. */ } #endif /* configASSERT_DEFINED */ /* The address of a statically allocated queue was passed in, use it. The address of a statically allocated storage area was also passed in but is already set. */ - pxNewQueue = ( Queue_t * ) pxStaticQueue; /*lint !e740 Unusual cast is ok as the structures are designed to have the same alignment, and the size is checked by an assert. */ + pxNewQueue = ( Queue_t * ) pxStaticQueue; /*lint !e740 !e9087 Unusual cast is ok as the structures are designed to have the same alignment, and the size is checked by an assert. */ if( pxNewQueue != NULL ) { @@ -374,6 +351,11 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue; prvInitialiseNewQueue( uxQueueLength, uxItemSize, pucQueueStorage, ucQueueType, pxNewQueue ); } + else + { + traceQUEUE_CREATE_FAILED( ucQueueType ); + mtCOVERAGE_TEST_MARKER(); + } return pxNewQueue; } @@ -391,25 +373,28 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue; configASSERT( uxQueueLength > ( UBaseType_t ) 0 ); - if( uxItemSize == ( UBaseType_t ) 0 ) - { - /* There is not going to be a queue storage area. */ - xQueueSizeInBytes = ( size_t ) 0; - } - else - { - /* Allocate enough space to hold the maximum number of items that - can be in the queue at any time. */ - xQueueSizeInBytes = ( size_t ) ( uxQueueLength * uxItemSize ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */ - } + /* Allocate enough space to hold the maximum number of items that + can be in the queue at any time. It is valid for uxItemSize to be + zero in the case the queue is used as a semaphore. */ + xQueueSizeInBytes = ( size_t ) ( uxQueueLength * uxItemSize ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */ - pxNewQueue = ( Queue_t * ) pvPortMalloc( sizeof( Queue_t ) + xQueueSizeInBytes ); + /* Allocate the queue and storage area. Justification for MISRA + deviation as follows: pvPortMalloc() always ensures returned memory + blocks are aligned per the requirements of the MCU stack. In this case + pvPortMalloc() must return a pointer that is guaranteed to meet the + alignment requirements of the Queue_t structure - which in this case + is an int8_t *. Therefore, whenever the stack alignment requirements + are greater than or equal to the pointer to char requirements the cast + is safe. In other cases alignment requirements are not strict (one or + two bytes). */ + pxNewQueue = ( Queue_t * ) pvPortMalloc( sizeof( Queue_t ) + xQueueSizeInBytes ); /*lint !e9087 !e9079 see comment above. */ if( pxNewQueue != NULL ) { /* Jump past the queue structure to find the location of the queue storage area. */ - pucQueueStorage = ( ( uint8_t * ) pxNewQueue ) + sizeof( Queue_t ); + pucQueueStorage = ( uint8_t * ) pxNewQueue; + pucQueueStorage += sizeof( Queue_t ); /*lint !e9016 Pointer arithmetic allowed on char types, especially when it assists conveying intent. */ #if( configSUPPORT_STATIC_ALLOCATION == 1 ) { @@ -422,6 +407,11 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue; prvInitialiseNewQueue( uxQueueLength, uxItemSize, pucQueueStorage, ucQueueType, pxNewQueue ); } + else + { + traceQUEUE_CREATE_FAILED( ucQueueType ); + mtCOVERAGE_TEST_MARKER(); + } return pxNewQueue; } @@ -481,11 +471,11 @@ static void prvInitialiseNewQueue( const UBaseType_t uxQueueLength, const UBaseT correctly for a generic queue, but this function is creating a mutex. Overwrite those members that need to be set differently - in particular the information required for priority inheritance. */ - pxNewQueue->pxMutexHolder = NULL; + pxNewQueue->u.xSemaphore.xMutexHolder = NULL; pxNewQueue->uxQueueType = queueQUEUE_IS_MUTEX; /* In case this is a recursive mutex. */ - pxNewQueue->u.uxRecursiveCallCount = 0; + pxNewQueue->u.xSemaphore.uxRecursiveCallCount = 0; traceCREATE_MUTEX( pxNewQueue ); @@ -505,13 +495,13 @@ static void prvInitialiseNewQueue( const UBaseType_t uxQueueLength, const UBaseT QueueHandle_t xQueueCreateMutex( const uint8_t ucQueueType ) { - Queue_t *pxNewQueue; + QueueHandle_t xNewQueue; const UBaseType_t uxMutexLength = ( UBaseType_t ) 1, uxMutexSize = ( UBaseType_t ) 0; - pxNewQueue = ( Queue_t * ) xQueueGenericCreate( uxMutexLength, uxMutexSize, ucQueueType ); - prvInitialiseMutex( pxNewQueue ); + xNewQueue = xQueueGenericCreate( uxMutexLength, uxMutexSize, ucQueueType ); + prvInitialiseMutex( ( Queue_t * ) xNewQueue ); - return pxNewQueue; + return xNewQueue; } #endif /* configUSE_MUTEXES */ @@ -521,17 +511,17 @@ static void prvInitialiseNewQueue( const UBaseType_t uxQueueLength, const UBaseT QueueHandle_t xQueueCreateMutexStatic( const uint8_t ucQueueType, StaticQueue_t *pxStaticQueue ) { - Queue_t *pxNewQueue; + QueueHandle_t xNewQueue; const UBaseType_t uxMutexLength = ( UBaseType_t ) 1, uxMutexSize = ( UBaseType_t ) 0; /* Prevent compiler warnings about unused parameters if configUSE_TRACE_FACILITY does not equal 1. */ ( void ) ucQueueType; - pxNewQueue = ( Queue_t * ) xQueueGenericCreateStatic( uxMutexLength, uxMutexSize, NULL, pxStaticQueue, ucQueueType ); - prvInitialiseMutex( pxNewQueue ); + xNewQueue = xQueueGenericCreateStatic( uxMutexLength, uxMutexSize, NULL, pxStaticQueue, ucQueueType ); + prvInitialiseMutex( ( Queue_t * ) xNewQueue ); - return pxNewQueue; + return xNewQueue; } #endif /* configUSE_MUTEXES */ @@ -539,9 +529,10 @@ static void prvInitialiseNewQueue( const UBaseType_t uxQueueLength, const UBaseT #if ( ( configUSE_MUTEXES == 1 ) && ( INCLUDE_xSemaphoreGetMutexHolder == 1 ) ) - void* xQueueGetMutexHolder( QueueHandle_t xSemaphore ) + TaskHandle_t xQueueGetMutexHolder( QueueHandle_t xSemaphore ) { - void *pxReturn; + TaskHandle_t pxReturn; + Queue_t * const pxSemaphore = ( Queue_t * ) xSemaphore; /* This function is called by xSemaphoreGetMutexHolder(), and should not be called directly. Note: This is a good way of determining if the @@ -550,9 +541,9 @@ static void prvInitialiseNewQueue( const UBaseType_t uxQueueLength, const UBaseT following critical section exiting and the function returning. */ taskENTER_CRITICAL(); { - if( ( ( Queue_t * ) xSemaphore )->uxQueueType == queueQUEUE_IS_MUTEX ) + if( pxSemaphore->uxQueueType == queueQUEUE_IS_MUTEX ) { - pxReturn = ( void * ) ( ( Queue_t * ) xSemaphore )->pxMutexHolder; + pxReturn = pxSemaphore->u.xSemaphore.xMutexHolder; } else { @@ -567,6 +558,32 @@ static void prvInitialiseNewQueue( const UBaseType_t uxQueueLength, const UBaseT #endif /*-----------------------------------------------------------*/ +#if ( ( configUSE_MUTEXES == 1 ) && ( INCLUDE_xSemaphoreGetMutexHolder == 1 ) ) + + TaskHandle_t xQueueGetMutexHolderFromISR( QueueHandle_t xSemaphore ) + { + TaskHandle_t pxReturn; + + configASSERT( xSemaphore ); + + /* Mutexes cannot be used in interrupt service routines, so the mutex + holder should not change in an ISR, and therefore a critical section is + not required here. */ + if( ( ( Queue_t * ) xSemaphore )->uxQueueType == queueQUEUE_IS_MUTEX ) + { + pxReturn = ( ( Queue_t * ) xSemaphore )->u.xSemaphore.xMutexHolder; + } + else + { + pxReturn = NULL; + } + + return pxReturn; + } /*lint !e818 xSemaphore cannot be a pointer to const because it is a typedef. */ + +#endif +/*-----------------------------------------------------------*/ + #if ( configUSE_RECURSIVE_MUTEXES == 1 ) BaseType_t xQueueGiveMutexRecursive( QueueHandle_t xMutex ) @@ -576,25 +593,25 @@ static void prvInitialiseNewQueue( const UBaseType_t uxQueueLength, const UBaseT configASSERT( pxMutex ); - /* If this is the task that holds the mutex then pxMutexHolder will not + /* If this is the task that holds the mutex then xMutexHolder will not change outside of this task. If this task does not hold the mutex then pxMutexHolder can never coincidentally equal the tasks handle, and as this is the only condition we are interested in it does not matter if pxMutexHolder is accessed simultaneously by another task. Therefore no mutual exclusion is required to test the pxMutexHolder variable. */ - if( pxMutex->pxMutexHolder == ( void * ) xTaskGetCurrentTaskHandle() ) /*lint !e961 Not a redundant cast as TaskHandle_t is a typedef. */ + if( pxMutex->u.xSemaphore.xMutexHolder == xTaskGetCurrentTaskHandle() ) { traceGIVE_MUTEX_RECURSIVE( pxMutex ); - /* uxRecursiveCallCount cannot be zero if pxMutexHolder is equal to + /* uxRecursiveCallCount cannot be zero if xMutexHolder is equal to the task handle, therefore no underflow check is required. Also, uxRecursiveCallCount is only modified by the mutex holder, and as there can only be one, no mutual exclusion is required to modify the uxRecursiveCallCount member. */ - ( pxMutex->u.uxRecursiveCallCount )--; + ( pxMutex->u.xSemaphore.uxRecursiveCallCount )--; /* Has the recursive call count unwound to 0? */ - if( pxMutex->u.uxRecursiveCallCount == ( UBaseType_t ) 0 ) + if( pxMutex->u.xSemaphore.uxRecursiveCallCount == ( UBaseType_t ) 0 ) { /* Return the mutex. This will automatically unblock any other task that might be waiting to access the mutex. */ @@ -636,21 +653,21 @@ static void prvInitialiseNewQueue( const UBaseType_t uxQueueLength, const UBaseT traceTAKE_MUTEX_RECURSIVE( pxMutex ); - if( pxMutex->pxMutexHolder == ( void * ) xTaskGetCurrentTaskHandle() ) /*lint !e961 Cast is not redundant as TaskHandle_t is a typedef. */ + if( pxMutex->u.xSemaphore.xMutexHolder == xTaskGetCurrentTaskHandle() ) { - ( pxMutex->u.uxRecursiveCallCount )++; + ( pxMutex->u.xSemaphore.uxRecursiveCallCount )++; xReturn = pdPASS; } else { - xReturn = xQueueGenericReceive( pxMutex, NULL, xTicksToWait, pdFALSE ); + xReturn = xQueueSemaphoreTake( pxMutex, xTicksToWait ); /* pdPASS will only be returned if the mutex was successfully obtained. The calling task may have entered the Blocked state before reaching here. */ if( xReturn != pdFAIL ) { - ( pxMutex->u.uxRecursiveCallCount )++; + ( pxMutex->u.xSemaphore.uxRecursiveCallCount )++; } else { @@ -724,7 +741,7 @@ BaseType_t xQueueGenericSend( QueueHandle_t xQueue, const void * const pvItemToQ { BaseType_t xEntryTimeSet = pdFALSE, xYieldRequired; TimeOut_t xTimeOut; -Queue_t * const pxQueue = ( Queue_t * ) xQueue; +Queue_t * const pxQueue = xQueue; configASSERT( pxQueue ); configASSERT( !( ( pvItemToQueue == NULL ) && ( pxQueue->uxItemSize != ( UBaseType_t ) 0U ) ) ); @@ -736,9 +753,9 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue; #endif - /* This function relaxes the coding standard somewhat to allow return - statements within the function itself. This is done in the interest - of execution time efficiency. */ + /*lint -save -e904 This function relaxes the coding standard somewhat to + allow return statements within the function itself. This is done in the + interest of execution time efficiency. */ for( ;; ) { taskENTER_CRITICAL(); @@ -750,13 +767,23 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue; if( ( pxQueue->uxMessagesWaiting < pxQueue->uxLength ) || ( xCopyPosition == queueOVERWRITE ) ) { traceQUEUE_SEND( pxQueue ); - xYieldRequired = prvCopyDataToQueue( pxQueue, pvItemToQueue, xCopyPosition ); #if ( configUSE_QUEUE_SETS == 1 ) { + const UBaseType_t uxPreviousMessagesWaiting = pxQueue->uxMessagesWaiting; + + xYieldRequired = prvCopyDataToQueue( pxQueue, pvItemToQueue, xCopyPosition ); + if( pxQueue->pxQueueSetContainer != NULL ) { - if( prvNotifyQueueSetContainer( pxQueue, xCopyPosition ) != pdFALSE ) + if( ( xCopyPosition == queueOVERWRITE ) && ( uxPreviousMessagesWaiting != ( UBaseType_t ) 0 ) ) + { + /* Do not notify the queue set as an existing item + was overwritten in the queue so the number of items + in the queue has not changed. */ + mtCOVERAGE_TEST_MARKER(); + } + else if( prvNotifyQueueSetContainer( pxQueue ) != pdFALSE ) { /* The queue is a member of a queue set, and posting to the queue set caused a higher priority task to @@ -803,6 +830,8 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue; } #else /* configUSE_QUEUE_SETS */ { + xYieldRequired = prvCopyDataToQueue( pxQueue, pvItemToQueue, xCopyPosition ); + /* If there was a task waiting for data to arrive on the queue then unblock it now. */ if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE ) @@ -855,7 +884,7 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue; { /* The queue was full and a block time was specified so configure the timeout structure. */ - vTaskSetTimeOutState( &xTimeOut ); + vTaskInternalSetTimeOutState( &xTimeOut ); xEntryTimeSet = pdTRUE; } else @@ -882,8 +911,8 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue; vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToSend ), xTicksToWait ); /* Unlocking the queue means queue events can effect the - event list. It is possible that interrupts occurring now - remove this task from the event list again - but as the + event list. It is possible that interrupts occurring now + remove this task from the event list again - but as the scheduler is suspended the task will go onto the pending ready last instead of the actual ready list. */ prvUnlockQueue( pxQueue ); @@ -914,7 +943,7 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue; traceQUEUE_SEND_FAILED( pxQueue ); return errQUEUE_FULL; } - } + } /*lint -restore */ } /*-----------------------------------------------------------*/ @@ -922,7 +951,7 @@ BaseType_t xQueueGenericSendFromISR( QueueHandle_t xQueue, const void * const pv { BaseType_t xReturn; UBaseType_t uxSavedInterruptStatus; -Queue_t * const pxQueue = ( Queue_t * ) xQueue; +Queue_t * const pxQueue = xQueue; configASSERT( pxQueue ); configASSERT( !( ( pvItemToQueue == NULL ) && ( pxQueue->uxItemSize != ( UBaseType_t ) 0U ) ) ); @@ -954,6 +983,7 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue; if( ( pxQueue->uxMessagesWaiting < pxQueue->uxLength ) || ( xCopyPosition == queueOVERWRITE ) ) { const int8_t cTxLock = pxQueue->cTxLock; + const UBaseType_t uxPreviousMessagesWaiting = pxQueue->uxMessagesWaiting; traceQUEUE_SEND_FROM_ISR( pxQueue ); @@ -972,7 +1002,14 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue; { if( pxQueue->pxQueueSetContainer != NULL ) { - if( prvNotifyQueueSetContainer( pxQueue, xCopyPosition ) != pdFALSE ) + if( ( xCopyPosition == queueOVERWRITE ) && ( uxPreviousMessagesWaiting != ( UBaseType_t ) 0 ) ) + { + /* Do not notify the queue set as an existing item + was overwritten in the queue so the number of items + in the queue has not changed. */ + mtCOVERAGE_TEST_MARKER(); + } + else if( prvNotifyQueueSetContainer( pxQueue ) != pdFALSE ) { /* The queue is a member of a queue set, and posting to the queue set caused a higher priority task to @@ -1045,6 +1082,9 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue; { mtCOVERAGE_TEST_MARKER(); } + + /* Not used in this path. */ + ( void ) uxPreviousMessagesWaiting; } #endif /* configUSE_QUEUE_SETS */ } @@ -1073,7 +1113,7 @@ BaseType_t xQueueGiveFromISR( QueueHandle_t xQueue, BaseType_t * const pxHigherP { BaseType_t xReturn; UBaseType_t uxSavedInterruptStatus; -Queue_t * const pxQueue = ( Queue_t * ) xQueue; +Queue_t * const pxQueue = xQueue; /* Similar to xQueueGenericSendFromISR() but used with semaphores where the item size is 0. Don't directly wake a task that was blocked on a queue @@ -1090,7 +1130,7 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue; /* Normally a mutex would not be given from an interrupt, especially if there is a mutex holder, as priority inheritance makes no sense for an interrupts, only tasks. */ - configASSERT( !( ( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX ) && ( pxQueue->pxMutexHolder != NULL ) ) ); + configASSERT( !( ( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX ) && ( pxQueue->u.xSemaphore.xMutexHolder != NULL ) ) ); /* RTOS ports that support interrupt nesting have the concept of a maximum system call (or maximum API call) interrupt priority. Interrupts that are @@ -1127,7 +1167,7 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue; can be assumed there is no mutex holder and no need to determine if priority disinheritance is needed. Simply increase the count of messages (semaphores) available. */ - pxQueue->uxMessagesWaiting = uxMessagesWaiting + 1; + pxQueue->uxMessagesWaiting = uxMessagesWaiting + ( UBaseType_t ) 1; /* The event list is not altered if the queue is locked. This will be done when the queue is unlocked later. */ @@ -1137,7 +1177,7 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue; { if( pxQueue->pxQueueSetContainer != NULL ) { - if( prvNotifyQueueSetContainer( pxQueue, queueSEND_TO_BACK ) != pdFALSE ) + if( prvNotifyQueueSetContainer( pxQueue ) != pdFALSE ) { /* The semaphore is a member of a queue set, and posting to the queue set caused a higher priority @@ -1234,25 +1274,30 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue; } /*-----------------------------------------------------------*/ -BaseType_t xQueueGenericReceive( QueueHandle_t xQueue, void * const pvBuffer, TickType_t xTicksToWait, const BaseType_t xJustPeeking ) +BaseType_t xQueueReceive( QueueHandle_t xQueue, void * const pvBuffer, TickType_t xTicksToWait ) { BaseType_t xEntryTimeSet = pdFALSE; TimeOut_t xTimeOut; -int8_t *pcOriginalReadPosition; -Queue_t * const pxQueue = ( Queue_t * ) xQueue; +Queue_t * const pxQueue = xQueue; - configASSERT( pxQueue ); - configASSERT( !( ( pvBuffer == NULL ) && ( pxQueue->uxItemSize != ( UBaseType_t ) 0U ) ) ); + /* Check the pointer is not NULL. */ + configASSERT( ( pxQueue ) ); + + /* The buffer into which data is received can only be NULL if the data size + is zero (so no data is copied into the buffer. */ + configASSERT( !( ( ( pvBuffer ) == NULL ) && ( ( pxQueue )->uxItemSize != ( UBaseType_t ) 0U ) ) ); + + /* Cannot block if the scheduler is suspended. */ #if ( ( INCLUDE_xTaskGetSchedulerState == 1 ) || ( configUSE_TIMERS == 1 ) ) { configASSERT( !( ( xTaskGetSchedulerState() == taskSCHEDULER_SUSPENDED ) && ( xTicksToWait != 0 ) ) ); } #endif - /* This function relaxes the coding standard somewhat to allow return - statements within the function itself. This is done in the interest - of execution time efficiency. */ + /*lint -save -e904 This function relaxes the coding standard somewhat to + allow return statements within the function itself. This is done in the + interest of execution time efficiency. */ for( ;; ) { taskENTER_CRITICAL(); @@ -1263,44 +1308,19 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue; must be the highest priority task wanting to access the queue. */ if( uxMessagesWaiting > ( UBaseType_t ) 0 ) { - /* Remember the read position in case the queue is only being - peeked. */ - pcOriginalReadPosition = pxQueue->u.pcReadFrom; - + /* Data available, remove one item. */ prvCopyDataFromQueue( pxQueue, pvBuffer ); + traceQUEUE_RECEIVE( pxQueue ); + pxQueue->uxMessagesWaiting = uxMessagesWaiting - ( UBaseType_t ) 1; - if( xJustPeeking == pdFALSE ) + /* There is now space in the queue, were any tasks waiting to + post to the queue? If so, unblock the highest priority waiting + task. */ + if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) == pdFALSE ) { - traceQUEUE_RECEIVE( pxQueue ); - - /* Actually removing data, not just peeking. */ - pxQueue->uxMessagesWaiting = uxMessagesWaiting - 1; - - #if ( configUSE_MUTEXES == 1 ) + if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE ) { - if( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX ) - { - /* Record the information required to implement - priority inheritance should it become necessary. */ - pxQueue->pxMutexHolder = ( int8_t * ) pvTaskIncrementMutexHeldCount(); /*lint !e961 Cast is not redundant as TaskHandle_t is a typedef. */ - } - else - { - mtCOVERAGE_TEST_MARKER(); - } - } - #endif /* configUSE_MUTEXES */ - - if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) == pdFALSE ) - { - if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE ) - { - queueYIELD_IF_USING_PREEMPTION(); - } - else - { - mtCOVERAGE_TEST_MARKER(); - } + queueYIELD_IF_USING_PREEMPTION(); } else { @@ -1309,30 +1329,7 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue; } else { - traceQUEUE_PEEK( pxQueue ); - - /* The data is not being removed, so reset the read - pointer. */ - pxQueue->u.pcReadFrom = pcOriginalReadPosition; - - /* The data is being left in the queue, so see if there are - any other tasks waiting for the data. */ - if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE ) - { - if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE ) - { - /* The task waiting has a higher priority than this task. */ - queueYIELD_IF_USING_PREEMPTION(); - } - else - { - mtCOVERAGE_TEST_MARKER(); - } - } - else - { - mtCOVERAGE_TEST_MARKER(); - } + mtCOVERAGE_TEST_MARKER(); } taskEXIT_CRITICAL(); @@ -1352,7 +1349,7 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue; { /* The queue was empty and a block time was specified so configure the timeout structure. */ - vTaskSetTimeOutState( &xTimeOut ); + vTaskInternalSetTimeOutState( &xTimeOut ); xEntryTimeSet = pdTRUE; } else @@ -1373,6 +1370,181 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue; /* Update the timeout state to see if it has expired yet. */ if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE ) { + /* The timeout has not expired. If the queue is still empty place + the task on the list of tasks waiting to receive from the queue. */ + if( prvIsQueueEmpty( pxQueue ) != pdFALSE ) + { + traceBLOCKING_ON_QUEUE_RECEIVE( pxQueue ); + vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToReceive ), xTicksToWait ); + prvUnlockQueue( pxQueue ); + if( xTaskResumeAll() == pdFALSE ) + { + portYIELD_WITHIN_API(); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + /* The queue contains data again. Loop back to try and read the + data. */ + prvUnlockQueue( pxQueue ); + ( void ) xTaskResumeAll(); + } + } + else + { + /* Timed out. If there is no data in the queue exit, otherwise loop + back and attempt to read the data. */ + prvUnlockQueue( pxQueue ); + ( void ) xTaskResumeAll(); + + if( prvIsQueueEmpty( pxQueue ) != pdFALSE ) + { + traceQUEUE_RECEIVE_FAILED( pxQueue ); + return errQUEUE_EMPTY; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + } /*lint -restore */ +} +/*-----------------------------------------------------------*/ + +BaseType_t xQueueSemaphoreTake( QueueHandle_t xQueue, TickType_t xTicksToWait ) +{ +BaseType_t xEntryTimeSet = pdFALSE; +TimeOut_t xTimeOut; +Queue_t * const pxQueue = xQueue; + +#if( configUSE_MUTEXES == 1 ) + BaseType_t xInheritanceOccurred = pdFALSE; +#endif + + /* Check the queue pointer is not NULL. */ + configASSERT( ( pxQueue ) ); + + /* Check this really is a semaphore, in which case the item size will be + 0. */ + configASSERT( pxQueue->uxItemSize == 0 ); + + /* Cannot block if the scheduler is suspended. */ + #if ( ( INCLUDE_xTaskGetSchedulerState == 1 ) || ( configUSE_TIMERS == 1 ) ) + { + configASSERT( !( ( xTaskGetSchedulerState() == taskSCHEDULER_SUSPENDED ) && ( xTicksToWait != 0 ) ) ); + } + #endif + + + /*lint -save -e904 This function relaxes the coding standard somewhat to allow return + statements within the function itself. This is done in the interest + of execution time efficiency. */ + for( ;; ) + { + taskENTER_CRITICAL(); + { + /* Semaphores are queues with an item size of 0, and where the + number of messages in the queue is the semaphore's count value. */ + const UBaseType_t uxSemaphoreCount = pxQueue->uxMessagesWaiting; + + /* Is there data in the queue now? To be running the calling task + must be the highest priority task wanting to access the queue. */ + if( uxSemaphoreCount > ( UBaseType_t ) 0 ) + { + traceQUEUE_RECEIVE( pxQueue ); + + /* Semaphores are queues with a data size of zero and where the + messages waiting is the semaphore's count. Reduce the count. */ + pxQueue->uxMessagesWaiting = uxSemaphoreCount - ( UBaseType_t ) 1; + + #if ( configUSE_MUTEXES == 1 ) + { + if( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX ) + { + /* Record the information required to implement + priority inheritance should it become necessary. */ + pxQueue->u.xSemaphore.xMutexHolder = pvTaskIncrementMutexHeldCount(); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + #endif /* configUSE_MUTEXES */ + + /* Check to see if other tasks are blocked waiting to give the + semaphore, and if so, unblock the highest priority such task. */ + if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) == pdFALSE ) + { + if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE ) + { + queueYIELD_IF_USING_PREEMPTION(); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + + taskEXIT_CRITICAL(); + return pdPASS; + } + else + { + if( xTicksToWait == ( TickType_t ) 0 ) + { + /* For inheritance to have occurred there must have been an + initial timeout, and an adjusted timeout cannot become 0, as + if it were 0 the function would have exited. */ + #if( configUSE_MUTEXES == 1 ) + { + configASSERT( xInheritanceOccurred == pdFALSE ); + } + #endif /* configUSE_MUTEXES */ + + /* The semaphore count was 0 and no block time is specified + (or the block time has expired) so exit now. */ + taskEXIT_CRITICAL(); + traceQUEUE_RECEIVE_FAILED( pxQueue ); + return errQUEUE_EMPTY; + } + else if( xEntryTimeSet == pdFALSE ) + { + /* The semaphore count was 0 and a block time was specified + so configure the timeout structure ready to block. */ + vTaskInternalSetTimeOutState( &xTimeOut ); + xEntryTimeSet = pdTRUE; + } + else + { + /* Entry time was already set. */ + mtCOVERAGE_TEST_MARKER(); + } + } + } + taskEXIT_CRITICAL(); + + /* Interrupts and other tasks can give to and take from the semaphore + now the critical section has been exited. */ + + vTaskSuspendAll(); + prvLockQueue( pxQueue ); + + /* Update the timeout state to see if it has expired yet. */ + if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE ) + { + /* A block time is specified and not expired. If the semaphore + count is 0 then enter the Blocked state to wait for a semaphore to + become available. As semaphores are implemented with queues the + queue being empty is equivalent to the semaphore count being 0. */ if( prvIsQueueEmpty( pxQueue ) != pdFALSE ) { traceBLOCKING_ON_QUEUE_RECEIVE( pxQueue ); @@ -1383,7 +1555,7 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue; { taskENTER_CRITICAL(); { - vTaskPriorityInherit( ( void * ) pxQueue->pxMutexHolder ); + xInheritanceOccurred = xTaskPriorityInherit( pxQueue->u.xSemaphore.xMutexHolder ); } taskEXIT_CRITICAL(); } @@ -1407,18 +1579,48 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue; } else { - /* Try again. */ + /* There was no timeout and the semaphore count was not 0, so + attempt to take the semaphore again. */ prvUnlockQueue( pxQueue ); ( void ) xTaskResumeAll(); } } else { + /* Timed out. */ prvUnlockQueue( pxQueue ); ( void ) xTaskResumeAll(); + /* If the semaphore count is 0 exit now as the timeout has + expired. Otherwise return to attempt to take the semaphore that is + known to be available. As semaphores are implemented by queues the + queue being empty is equivalent to the semaphore count being 0. */ if( prvIsQueueEmpty( pxQueue ) != pdFALSE ) { + #if ( configUSE_MUTEXES == 1 ) + { + /* xInheritanceOccurred could only have be set if + pxQueue->uxQueueType == queueQUEUE_IS_MUTEX so no need to + test the mutex type again to check it is actually a mutex. */ + if( xInheritanceOccurred != pdFALSE ) + { + taskENTER_CRITICAL(); + { + UBaseType_t uxHighestWaitingPriority; + + /* This task blocking on the mutex caused another + task to inherit this task's priority. Now this task + has timed out the priority should be disinherited + again, but only as low as the next highest priority + task that is waiting for the same mutex. */ + uxHighestWaitingPriority = prvGetDisinheritPriorityAfterTimeout( pxQueue ); + vTaskPriorityDisinheritAfterTimeout( pxQueue->u.xSemaphore.xMutexHolder, uxHighestWaitingPriority ); + } + taskEXIT_CRITICAL(); + } + } + #endif /* configUSE_MUTEXES */ + traceQUEUE_RECEIVE_FAILED( pxQueue ); return errQUEUE_EMPTY; } @@ -1427,7 +1629,156 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue; mtCOVERAGE_TEST_MARKER(); } } + } /*lint -restore */ +} +/*-----------------------------------------------------------*/ + +BaseType_t xQueuePeek( QueueHandle_t xQueue, void * const pvBuffer, TickType_t xTicksToWait ) +{ +BaseType_t xEntryTimeSet = pdFALSE; +TimeOut_t xTimeOut; +int8_t *pcOriginalReadPosition; +Queue_t * const pxQueue = xQueue; + + /* Check the pointer is not NULL. */ + configASSERT( ( pxQueue ) ); + + /* The buffer into which data is received can only be NULL if the data size + is zero (so no data is copied into the buffer. */ + configASSERT( !( ( ( pvBuffer ) == NULL ) && ( ( pxQueue )->uxItemSize != ( UBaseType_t ) 0U ) ) ); + + /* Cannot block if the scheduler is suspended. */ + #if ( ( INCLUDE_xTaskGetSchedulerState == 1 ) || ( configUSE_TIMERS == 1 ) ) + { + configASSERT( !( ( xTaskGetSchedulerState() == taskSCHEDULER_SUSPENDED ) && ( xTicksToWait != 0 ) ) ); } + #endif + + + /*lint -save -e904 This function relaxes the coding standard somewhat to + allow return statements within the function itself. This is done in the + interest of execution time efficiency. */ + for( ;; ) + { + taskENTER_CRITICAL(); + { + const UBaseType_t uxMessagesWaiting = pxQueue->uxMessagesWaiting; + + /* Is there data in the queue now? To be running the calling task + must be the highest priority task wanting to access the queue. */ + if( uxMessagesWaiting > ( UBaseType_t ) 0 ) + { + /* Remember the read position so it can be reset after the data + is read from the queue as this function is only peeking the + data, not removing it. */ + pcOriginalReadPosition = pxQueue->u.xQueue.pcReadFrom; + + prvCopyDataFromQueue( pxQueue, pvBuffer ); + traceQUEUE_PEEK( pxQueue ); + + /* The data is not being removed, so reset the read pointer. */ + pxQueue->u.xQueue.pcReadFrom = pcOriginalReadPosition; + + /* The data is being left in the queue, so see if there are + any other tasks waiting for the data. */ + if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE ) + { + if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE ) + { + /* The task waiting has a higher priority than this task. */ + queueYIELD_IF_USING_PREEMPTION(); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + + taskEXIT_CRITICAL(); + return pdPASS; + } + else + { + if( xTicksToWait == ( TickType_t ) 0 ) + { + /* The queue was empty and no block time is specified (or + the block time has expired) so leave now. */ + taskEXIT_CRITICAL(); + traceQUEUE_PEEK_FAILED( pxQueue ); + return errQUEUE_EMPTY; + } + else if( xEntryTimeSet == pdFALSE ) + { + /* The queue was empty and a block time was specified so + configure the timeout structure ready to enter the blocked + state. */ + vTaskInternalSetTimeOutState( &xTimeOut ); + xEntryTimeSet = pdTRUE; + } + else + { + /* Entry time was already set. */ + mtCOVERAGE_TEST_MARKER(); + } + } + } + taskEXIT_CRITICAL(); + + /* Interrupts and other tasks can send to and receive from the queue + now the critical section has been exited. */ + + vTaskSuspendAll(); + prvLockQueue( pxQueue ); + + /* Update the timeout state to see if it has expired yet. */ + if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE ) + { + /* Timeout has not expired yet, check to see if there is data in the + queue now, and if not enter the Blocked state to wait for data. */ + if( prvIsQueueEmpty( pxQueue ) != pdFALSE ) + { + traceBLOCKING_ON_QUEUE_PEEK( pxQueue ); + vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToReceive ), xTicksToWait ); + prvUnlockQueue( pxQueue ); + if( xTaskResumeAll() == pdFALSE ) + { + portYIELD_WITHIN_API(); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + /* There is data in the queue now, so don't enter the blocked + state, instead return to try and obtain the data. */ + prvUnlockQueue( pxQueue ); + ( void ) xTaskResumeAll(); + } + } + else + { + /* The timeout has expired. If there is still no data in the queue + exit, otherwise go back and try to read the data again. */ + prvUnlockQueue( pxQueue ); + ( void ) xTaskResumeAll(); + + if( prvIsQueueEmpty( pxQueue ) != pdFALSE ) + { + traceQUEUE_PEEK_FAILED( pxQueue ); + return errQUEUE_EMPTY; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + } /*lint -restore */ } /*-----------------------------------------------------------*/ @@ -1435,7 +1786,7 @@ BaseType_t xQueueReceiveFromISR( QueueHandle_t xQueue, void * const pvBuffer, Ba { BaseType_t xReturn; UBaseType_t uxSavedInterruptStatus; -Queue_t * const pxQueue = ( Queue_t * ) xQueue; +Queue_t * const pxQueue = xQueue; configASSERT( pxQueue ); configASSERT( !( ( pvBuffer == NULL ) && ( pxQueue->uxItemSize != ( UBaseType_t ) 0U ) ) ); @@ -1468,7 +1819,7 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue; traceQUEUE_RECEIVE_FROM_ISR( pxQueue ); prvCopyDataFromQueue( pxQueue, pvBuffer ); - pxQueue->uxMessagesWaiting = uxMessagesWaiting - 1; + pxQueue->uxMessagesWaiting = uxMessagesWaiting - ( UBaseType_t ) 1; /* If the queue is locked the event list will not be modified. Instead update the lock count so the task that unlocks the queue @@ -1527,7 +1878,7 @@ BaseType_t xQueuePeekFromISR( QueueHandle_t xQueue, void * const pvBuffer ) BaseType_t xReturn; UBaseType_t uxSavedInterruptStatus; int8_t *pcOriginalReadPosition; -Queue_t * const pxQueue = ( Queue_t * ) xQueue; +Queue_t * const pxQueue = xQueue; configASSERT( pxQueue ); configASSERT( !( ( pvBuffer == NULL ) && ( pxQueue->uxItemSize != ( UBaseType_t ) 0U ) ) ); @@ -1558,9 +1909,9 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue; /* Remember the read position so it can be reset as nothing is actually being removed from the queue. */ - pcOriginalReadPosition = pxQueue->u.pcReadFrom; + pcOriginalReadPosition = pxQueue->u.xQueue.pcReadFrom; prvCopyDataFromQueue( pxQueue, pvBuffer ); - pxQueue->u.pcReadFrom = pcOriginalReadPosition; + pxQueue->u.xQueue.pcReadFrom = pcOriginalReadPosition; xReturn = pdPASS; } @@ -1595,9 +1946,8 @@ UBaseType_t uxReturn; UBaseType_t uxQueueSpacesAvailable( const QueueHandle_t xQueue ) { UBaseType_t uxReturn; -Queue_t *pxQueue; +Queue_t * const pxQueue = xQueue; - pxQueue = ( Queue_t * ) xQueue; configASSERT( pxQueue ); taskENTER_CRITICAL(); @@ -1613,10 +1963,10 @@ Queue_t *pxQueue; UBaseType_t uxQueueMessagesWaitingFromISR( const QueueHandle_t xQueue ) { UBaseType_t uxReturn; +Queue_t * const pxQueue = xQueue; - configASSERT( xQueue ); - - uxReturn = ( ( Queue_t * ) xQueue )->uxMessagesWaiting; + configASSERT( pxQueue ); + uxReturn = pxQueue->uxMessagesWaiting; return uxReturn; } /*lint !e818 Pointer cannot be declared const as xQueue is a typedef not pointer. */ @@ -1624,7 +1974,7 @@ UBaseType_t uxReturn; void vQueueDelete( QueueHandle_t xQueue ) { -Queue_t * const pxQueue = ( Queue_t * ) xQueue; +Queue_t * const pxQueue = xQueue; configASSERT( pxQueue ); traceQUEUE_DELETE( pxQueue ); @@ -1694,6 +2044,33 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue; #endif /* configUSE_TRACE_FACILITY */ /*-----------------------------------------------------------*/ +#if( configUSE_MUTEXES == 1 ) + + static UBaseType_t prvGetDisinheritPriorityAfterTimeout( const Queue_t * const pxQueue ) + { + UBaseType_t uxHighestPriorityOfWaitingTasks; + + /* If a task waiting for a mutex causes the mutex holder to inherit a + priority, but the waiting task times out, then the holder should + disinherit the priority - but only down to the highest priority of any + other tasks that are waiting for the same mutex. For this purpose, + return the priority of the highest priority task that is waiting for the + mutex. */ + if( listCURRENT_LIST_LENGTH( &( pxQueue->xTasksWaitingToReceive ) ) > 0U ) + { + uxHighestPriorityOfWaitingTasks = ( UBaseType_t ) configMAX_PRIORITIES - ( UBaseType_t ) listGET_ITEM_VALUE_OF_HEAD_ENTRY( &( pxQueue->xTasksWaitingToReceive ) ); + } + else + { + uxHighestPriorityOfWaitingTasks = tskIDLE_PRIORITY; + } + + return uxHighestPriorityOfWaitingTasks; + } + +#endif /* configUSE_MUTEXES */ +/*-----------------------------------------------------------*/ + static BaseType_t prvCopyDataToQueue( Queue_t * const pxQueue, const void *pvItemToQueue, const BaseType_t xPosition ) { BaseType_t xReturn = pdFALSE; @@ -1710,8 +2087,8 @@ UBaseType_t uxMessagesWaiting; if( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX ) { /* The mutex is no longer being held. */ - xReturn = xTaskPriorityDisinherit( ( void * ) pxQueue->pxMutexHolder ); - pxQueue->pxMutexHolder = NULL; + xReturn = xTaskPriorityDisinherit( pxQueue->u.xSemaphore.xMutexHolder ); + pxQueue->u.xSemaphore.xMutexHolder = NULL; } else { @@ -1722,9 +2099,9 @@ UBaseType_t uxMessagesWaiting; } else if( xPosition == queueSEND_TO_BACK ) { - ( void ) memcpy( ( void * ) pxQueue->pcWriteTo, pvItemToQueue, ( size_t ) pxQueue->uxItemSize ); /*lint !e961 !e418 MISRA exception as the casts are only redundant for some ports, plus previous logic ensures a null pointer can only be passed to memcpy() if the copy size is 0. */ - pxQueue->pcWriteTo += pxQueue->uxItemSize; - if( pxQueue->pcWriteTo >= pxQueue->pcTail ) /*lint !e946 MISRA exception justified as comparison of pointers is the cleanest solution. */ + ( void ) memcpy( ( void * ) pxQueue->pcWriteTo, pvItemToQueue, ( size_t ) pxQueue->uxItemSize ); /*lint !e961 !e418 !e9087 MISRA exception as the casts are only redundant for some ports, plus previous logic ensures a null pointer can only be passed to memcpy() if the copy size is 0. Cast to void required by function signature and safe as no alignment requirement and copy length specified in bytes. */ + pxQueue->pcWriteTo += pxQueue->uxItemSize; /*lint !e9016 Pointer arithmetic on char types ok, especially in this use case where it is the clearest way of conveying intent. */ + if( pxQueue->pcWriteTo >= pxQueue->u.xQueue.pcTail ) /*lint !e946 MISRA exception justified as comparison of pointers is the cleanest solution. */ { pxQueue->pcWriteTo = pxQueue->pcHead; } @@ -1735,11 +2112,11 @@ UBaseType_t uxMessagesWaiting; } else { - ( void ) memcpy( ( void * ) pxQueue->u.pcReadFrom, pvItemToQueue, ( size_t ) pxQueue->uxItemSize ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */ - pxQueue->u.pcReadFrom -= pxQueue->uxItemSize; - if( pxQueue->u.pcReadFrom < pxQueue->pcHead ) /*lint !e946 MISRA exception justified as comparison of pointers is the cleanest solution. */ + ( void ) memcpy( ( void * ) pxQueue->u.xQueue.pcReadFrom, pvItemToQueue, ( size_t ) pxQueue->uxItemSize ); /*lint !e961 !e9087 !e418 MISRA exception as the casts are only redundant for some ports. Cast to void required by function signature and safe as no alignment requirement and copy length specified in bytes. Assert checks null pointer only used when length is 0. */ + pxQueue->u.xQueue.pcReadFrom -= pxQueue->uxItemSize; + if( pxQueue->u.xQueue.pcReadFrom < pxQueue->pcHead ) /*lint !e946 MISRA exception justified as comparison of pointers is the cleanest solution. */ { - pxQueue->u.pcReadFrom = ( pxQueue->pcTail - pxQueue->uxItemSize ); + pxQueue->u.xQueue.pcReadFrom = ( pxQueue->u.xQueue.pcTail - pxQueue->uxItemSize ); } else { @@ -1767,7 +2144,7 @@ UBaseType_t uxMessagesWaiting; } } - pxQueue->uxMessagesWaiting = uxMessagesWaiting + 1; + pxQueue->uxMessagesWaiting = uxMessagesWaiting + ( UBaseType_t ) 1; return xReturn; } @@ -1777,16 +2154,16 @@ static void prvCopyDataFromQueue( Queue_t * const pxQueue, void * const pvBuffer { if( pxQueue->uxItemSize != ( UBaseType_t ) 0 ) { - pxQueue->u.pcReadFrom += pxQueue->uxItemSize; - if( pxQueue->u.pcReadFrom >= pxQueue->pcTail ) /*lint !e946 MISRA exception justified as use of the relational operator is the cleanest solutions. */ + pxQueue->u.xQueue.pcReadFrom += pxQueue->uxItemSize; /*lint !e9016 Pointer arithmetic on char types ok, especially in this use case where it is the clearest way of conveying intent. */ + if( pxQueue->u.xQueue.pcReadFrom >= pxQueue->u.xQueue.pcTail ) /*lint !e946 MISRA exception justified as use of the relational operator is the cleanest solutions. */ { - pxQueue->u.pcReadFrom = pxQueue->pcHead; + pxQueue->u.xQueue.pcReadFrom = pxQueue->pcHead; } else { mtCOVERAGE_TEST_MARKER(); } - ( void ) memcpy( ( void * ) pvBuffer, ( void * ) pxQueue->u.pcReadFrom, ( size_t ) pxQueue->uxItemSize ); /*lint !e961 !e418 MISRA exception as the casts are only redundant for some ports. Also previous logic ensures a null pointer can only be passed to memcpy() when the count is 0. */ + ( void ) memcpy( ( void * ) pvBuffer, ( void * ) pxQueue->u.xQueue.pcReadFrom, ( size_t ) pxQueue->uxItemSize ); /*lint !e961 !e418 !e9087 MISRA exception as the casts are only redundant for some ports. Also previous logic ensures a null pointer can only be passed to memcpy() when the count is 0. Cast to void required by function signature and safe as no alignment requirement and copy length specified in bytes. */ } } /*-----------------------------------------------------------*/ @@ -1812,7 +2189,7 @@ static void prvUnlockQueue( Queue_t * const pxQueue ) { if( pxQueue->pxQueueSetContainer != NULL ) { - if( prvNotifyQueueSetContainer( pxQueue, queueSEND_TO_BACK ) != pdFALSE ) + if( prvNotifyQueueSetContainer( pxQueue ) != pdFALSE ) { /* The queue is a member of a queue set, and posting to the queue set caused a higher priority task to unblock. @@ -1935,9 +2312,10 @@ BaseType_t xReturn; BaseType_t xQueueIsQueueEmptyFromISR( const QueueHandle_t xQueue ) { BaseType_t xReturn; +Queue_t * const pxQueue = xQueue; - configASSERT( xQueue ); - if( ( ( Queue_t * ) xQueue )->uxMessagesWaiting == ( UBaseType_t ) 0 ) + configASSERT( pxQueue ); + if( pxQueue->uxMessagesWaiting == ( UBaseType_t ) 0 ) { xReturn = pdTRUE; } @@ -1974,9 +2352,10 @@ BaseType_t xReturn; BaseType_t xQueueIsQueueFullFromISR( const QueueHandle_t xQueue ) { BaseType_t xReturn; +Queue_t * const pxQueue = xQueue; - configASSERT( xQueue ); - if( ( ( Queue_t * ) xQueue )->uxMessagesWaiting == ( ( Queue_t * ) xQueue )->uxLength ) + configASSERT( pxQueue ); + if( pxQueue->uxMessagesWaiting == pxQueue->uxLength ) { xReturn = pdTRUE; } @@ -1994,7 +2373,7 @@ BaseType_t xReturn; BaseType_t xQueueCRSend( QueueHandle_t xQueue, const void *pvItemToQueue, TickType_t xTicksToWait ) { BaseType_t xReturn; - Queue_t * const pxQueue = ( Queue_t * ) xQueue; + Queue_t * const pxQueue = xQueue; /* If the queue is already full we may have to block. A critical section is required to prevent an interrupt removing something from the queue @@ -2071,7 +2450,7 @@ BaseType_t xReturn; BaseType_t xQueueCRReceive( QueueHandle_t xQueue, void *pvBuffer, TickType_t xTicksToWait ) { BaseType_t xReturn; - Queue_t * const pxQueue = ( Queue_t * ) xQueue; + Queue_t * const pxQueue = xQueue; /* If the queue is already empty we may have to block. A critical section is required to prevent an interrupt adding something to the queue @@ -2108,17 +2487,17 @@ BaseType_t xReturn; if( pxQueue->uxMessagesWaiting > ( UBaseType_t ) 0 ) { /* Data is available from the queue. */ - pxQueue->u.pcReadFrom += pxQueue->uxItemSize; - if( pxQueue->u.pcReadFrom >= pxQueue->pcTail ) + pxQueue->u.xQueue.pcReadFrom += pxQueue->uxItemSize; + if( pxQueue->u.xQueue.pcReadFrom >= pxQueue->u.xQueue.pcTail ) { - pxQueue->u.pcReadFrom = pxQueue->pcHead; + pxQueue->u.xQueue.pcReadFrom = pxQueue->pcHead; } else { mtCOVERAGE_TEST_MARKER(); } --( pxQueue->uxMessagesWaiting ); - ( void ) memcpy( ( void * ) pvBuffer, ( void * ) pxQueue->u.pcReadFrom, ( unsigned ) pxQueue->uxItemSize ); + ( void ) memcpy( ( void * ) pvBuffer, ( void * ) pxQueue->u.xQueue.pcReadFrom, ( unsigned ) pxQueue->uxItemSize ); xReturn = pdPASS; @@ -2160,7 +2539,7 @@ BaseType_t xReturn; BaseType_t xQueueCRSendFromISR( QueueHandle_t xQueue, const void *pvItemToQueue, BaseType_t xCoRoutinePreviouslyWoken ) { - Queue_t * const pxQueue = ( Queue_t * ) xQueue; + Queue_t * const pxQueue = xQueue; /* Cannot block within an ISR so if there is no space on the queue then exit without doing anything. */ @@ -2209,24 +2588,24 @@ BaseType_t xReturn; BaseType_t xQueueCRReceiveFromISR( QueueHandle_t xQueue, void *pvBuffer, BaseType_t *pxCoRoutineWoken ) { BaseType_t xReturn; - Queue_t * const pxQueue = ( Queue_t * ) xQueue; + Queue_t * const pxQueue = xQueue; /* We cannot block from an ISR, so check there is data available. If not then just leave without doing anything. */ if( pxQueue->uxMessagesWaiting > ( UBaseType_t ) 0 ) { /* Copy the data from the queue. */ - pxQueue->u.pcReadFrom += pxQueue->uxItemSize; - if( pxQueue->u.pcReadFrom >= pxQueue->pcTail ) + pxQueue->u.xQueue.pcReadFrom += pxQueue->uxItemSize; + if( pxQueue->u.xQueue.pcReadFrom >= pxQueue->u.xQueue.pcTail ) { - pxQueue->u.pcReadFrom = pxQueue->pcHead; + pxQueue->u.xQueue.pcReadFrom = pxQueue->pcHead; } else { mtCOVERAGE_TEST_MARKER(); } --( pxQueue->uxMessagesWaiting ); - ( void ) memcpy( ( void * ) pvBuffer, ( void * ) pxQueue->u.pcReadFrom, ( unsigned ) pxQueue->uxItemSize ); + ( void ) memcpy( ( void * ) pvBuffer, ( void * ) pxQueue->u.xQueue.pcReadFrom, ( unsigned ) pxQueue->uxItemSize ); if( ( *pxCoRoutineWoken ) == pdFALSE ) { @@ -2316,7 +2695,7 @@ BaseType_t xReturn; } return pcReturn; - } + } /*lint !e818 xQueue cannot be a pointer to const because it is a typedef. */ #endif /* configQUEUE_REGISTRY_SIZE */ /*-----------------------------------------------------------*/ @@ -2357,7 +2736,7 @@ BaseType_t xReturn; void vQueueWaitForMessageRestricted( QueueHandle_t xQueue, TickType_t xTicksToWait, const BaseType_t xWaitIndefinitely ) { - Queue_t * const pxQueue = ( Queue_t * ) xQueue; + Queue_t * const pxQueue = xQueue; /* This function should not be called by application code hence the 'Restricted' in its name. It is not part of the public API. It is @@ -2395,7 +2774,7 @@ BaseType_t xReturn; { QueueSetHandle_t pxQueue; - pxQueue = xQueueGenericCreate( uxEventQueueLength, sizeof( Queue_t * ), queueQUEUE_TYPE_SET ); + pxQueue = xQueueGenericCreate( uxEventQueueLength, ( UBaseType_t ) sizeof( Queue_t * ), queueQUEUE_TYPE_SET ); return pxQueue; } @@ -2478,7 +2857,7 @@ BaseType_t xReturn; { QueueSetMemberHandle_t xReturn = NULL; - ( void ) xQueueGenericReceive( ( QueueHandle_t ) xQueueSet, &xReturn, xTicksToWait, pdFALSE ); /*lint !e961 Casting from one typedef to another is not redundant. */ + ( void ) xQueueReceive( ( QueueHandle_t ) xQueueSet, &xReturn, xTicksToWait ); /*lint !e961 Casting from one typedef to another is not redundant. */ return xReturn; } @@ -2500,7 +2879,7 @@ BaseType_t xReturn; #if ( configUSE_QUEUE_SETS == 1 ) - static BaseType_t prvNotifyQueueSetContainer( const Queue_t * const pxQueue, const BaseType_t xCopyPosition ) + static BaseType_t prvNotifyQueueSetContainer( const Queue_t * const pxQueue ) { Queue_t *pxQueueSetContainer = pxQueue->pxQueueSetContainer; BaseType_t xReturn = pdFALSE; @@ -2517,7 +2896,7 @@ BaseType_t xReturn; traceQUEUE_SEND( pxQueueSetContainer ); /* The data copied is the handle of the queue that contains data. */ - xReturn = prvCopyDataToQueue( pxQueueSetContainer, &pxQueue, xCopyPosition ); + xReturn = prvCopyDataToQueue( pxQueueSetContainer, &pxQueue, queueSEND_TO_BACK ); if( cTxLock == queueUNLOCKED ) { diff --git a/Firmware/Board/v3/Middlewares/Third_Party/FreeRTOS/Source/readme.txt b/Firmware/Board/v3/Middlewares/Third_Party/FreeRTOS/Source/readme.txt new file mode 100644 index 00000000..58480c56 --- /dev/null +++ b/Firmware/Board/v3/Middlewares/Third_Party/FreeRTOS/Source/readme.txt @@ -0,0 +1,17 @@ +Each real time kernel port consists of three files that contain the core kernel +components and are common to every port, and one or more files that are +specific to a particular microcontroller and or compiler. + ++ The FreeRTOS/Source directory contains the three files that are common to +every port - list.c, queue.c and tasks.c. The kernel is contained within these +three files. croutine.c implements the optional co-routine functionality - which +is normally only used on very memory limited systems. + ++ The FreeRTOS/Source/Portable directory contains the files that are specific to +a particular microcontroller and or compiler. + ++ The FreeRTOS/Source/include directory contains the real time kernel header +files. + +See the readme file in the FreeRTOS/Source/Portable directory for more +information. \ No newline at end of file diff --git a/Firmware/Board/v3/Middlewares/Third_Party/FreeRTOS/Source/stream_buffer.c b/Firmware/Board/v3/Middlewares/Third_Party/FreeRTOS/Source/stream_buffer.c new file mode 100644 index 00000000..7ad5d54a --- /dev/null +++ b/Firmware/Board/v3/Middlewares/Third_Party/FreeRTOS/Source/stream_buffer.c @@ -0,0 +1,1263 @@ +/* + * FreeRTOS Kernel V10.3.1 + * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * http://www.FreeRTOS.org + * http://aws.amazon.com/freertos + * + * 1 tab == 4 spaces! + */ + +/* Standard includes. */ +#include +#include + +/* Defining MPU_WRAPPERS_INCLUDED_FROM_API_FILE prevents task.h from redefining +all the API functions to use the MPU wrappers. That should only be done when +task.h is included from an application file. */ +#define MPU_WRAPPERS_INCLUDED_FROM_API_FILE + +/* FreeRTOS includes. */ +#include "FreeRTOS.h" +#include "task.h" +#include "stream_buffer.h" + +#if( configUSE_TASK_NOTIFICATIONS != 1 ) + #error configUSE_TASK_NOTIFICATIONS must be set to 1 to build stream_buffer.c +#endif + +/* Lint e961, e9021 and e750 are suppressed as a MISRA exception justified +because the MPU ports require MPU_WRAPPERS_INCLUDED_FROM_API_FILE to be defined +for the header files above, but not in this file, in order to generate the +correct privileged Vs unprivileged linkage and placement. */ +#undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE /*lint !e961 !e750 !e9021. */ + +/* If the user has not provided application specific Rx notification macros, +or #defined the notification macros away, them provide default implementations +that uses task notifications. */ +/*lint -save -e9026 Function like macros allowed and needed here so they can be overidden. */ +#ifndef sbRECEIVE_COMPLETED + #define sbRECEIVE_COMPLETED( pxStreamBuffer ) \ + vTaskSuspendAll(); \ + { \ + if( ( pxStreamBuffer )->xTaskWaitingToSend != NULL ) \ + { \ + ( void ) xTaskNotify( ( pxStreamBuffer )->xTaskWaitingToSend, \ + ( uint32_t ) 0, \ + eNoAction ); \ + ( pxStreamBuffer )->xTaskWaitingToSend = NULL; \ + } \ + } \ + ( void ) xTaskResumeAll(); +#endif /* sbRECEIVE_COMPLETED */ + +#ifndef sbRECEIVE_COMPLETED_FROM_ISR + #define sbRECEIVE_COMPLETED_FROM_ISR( pxStreamBuffer, \ + pxHigherPriorityTaskWoken ) \ + { \ + UBaseType_t uxSavedInterruptStatus; \ + \ + uxSavedInterruptStatus = ( UBaseType_t ) portSET_INTERRUPT_MASK_FROM_ISR(); \ + { \ + if( ( pxStreamBuffer )->xTaskWaitingToSend != NULL ) \ + { \ + ( void ) xTaskNotifyFromISR( ( pxStreamBuffer )->xTaskWaitingToSend, \ + ( uint32_t ) 0, \ + eNoAction, \ + pxHigherPriorityTaskWoken ); \ + ( pxStreamBuffer )->xTaskWaitingToSend = NULL; \ + } \ + } \ + portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus ); \ + } +#endif /* sbRECEIVE_COMPLETED_FROM_ISR */ + +/* If the user has not provided an application specific Tx notification macro, +or #defined the notification macro away, them provide a default implementation +that uses task notifications. */ +#ifndef sbSEND_COMPLETED + #define sbSEND_COMPLETED( pxStreamBuffer ) \ + vTaskSuspendAll(); \ + { \ + if( ( pxStreamBuffer )->xTaskWaitingToReceive != NULL ) \ + { \ + ( void ) xTaskNotify( ( pxStreamBuffer )->xTaskWaitingToReceive, \ + ( uint32_t ) 0, \ + eNoAction ); \ + ( pxStreamBuffer )->xTaskWaitingToReceive = NULL; \ + } \ + } \ + ( void ) xTaskResumeAll(); +#endif /* sbSEND_COMPLETED */ + +#ifndef sbSEND_COMPLETE_FROM_ISR + #define sbSEND_COMPLETE_FROM_ISR( pxStreamBuffer, pxHigherPriorityTaskWoken ) \ + { \ + UBaseType_t uxSavedInterruptStatus; \ + \ + uxSavedInterruptStatus = ( UBaseType_t ) portSET_INTERRUPT_MASK_FROM_ISR(); \ + { \ + if( ( pxStreamBuffer )->xTaskWaitingToReceive != NULL ) \ + { \ + ( void ) xTaskNotifyFromISR( ( pxStreamBuffer )->xTaskWaitingToReceive, \ + ( uint32_t ) 0, \ + eNoAction, \ + pxHigherPriorityTaskWoken ); \ + ( pxStreamBuffer )->xTaskWaitingToReceive = NULL; \ + } \ + } \ + portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus ); \ + } +#endif /* sbSEND_COMPLETE_FROM_ISR */ +/*lint -restore (9026) */ + +/* The number of bytes used to hold the length of a message in the buffer. */ +#define sbBYTES_TO_STORE_MESSAGE_LENGTH ( sizeof( configMESSAGE_BUFFER_LENGTH_TYPE ) ) + +/* Bits stored in the ucFlags field of the stream buffer. */ +#define sbFLAGS_IS_MESSAGE_BUFFER ( ( uint8_t ) 1 ) /* Set if the stream buffer was created as a message buffer, in which case it holds discrete messages rather than a stream. */ +#define sbFLAGS_IS_STATICALLY_ALLOCATED ( ( uint8_t ) 2 ) /* Set if the stream buffer was created using statically allocated memory. */ + +/*-----------------------------------------------------------*/ + +/* Structure that hold state information on the buffer. */ +typedef struct StreamBufferDef_t /*lint !e9058 Style convention uses tag. */ +{ + volatile size_t xTail; /* Index to the next item to read within the buffer. */ + volatile size_t xHead; /* Index to the next item to write within the buffer. */ + size_t xLength; /* The length of the buffer pointed to by pucBuffer. */ + size_t xTriggerLevelBytes; /* The number of bytes that must be in the stream buffer before a task that is waiting for data is unblocked. */ + volatile TaskHandle_t xTaskWaitingToReceive; /* Holds the handle of a task waiting for data, or NULL if no tasks are waiting. */ + volatile TaskHandle_t xTaskWaitingToSend; /* Holds the handle of a task waiting to send data to a message buffer that is full. */ + uint8_t *pucBuffer; /* Points to the buffer itself - that is - the RAM that stores the data passed through the buffer. */ + uint8_t ucFlags; + + #if ( configUSE_TRACE_FACILITY == 1 ) + UBaseType_t uxStreamBufferNumber; /* Used for tracing purposes. */ + #endif +} StreamBuffer_t; + +/* + * The number of bytes available to be read from the buffer. + */ +static size_t prvBytesInBuffer( const StreamBuffer_t * const pxStreamBuffer ) PRIVILEGED_FUNCTION; + +/* + * Add xCount bytes from pucData into the pxStreamBuffer message buffer. + * Returns the number of bytes written, which will either equal xCount in the + * success case, or 0 if there was not enough space in the buffer (in which case + * no data is written into the buffer). + */ +static size_t prvWriteBytesToBuffer( StreamBuffer_t * const pxStreamBuffer, const uint8_t *pucData, size_t xCount ) PRIVILEGED_FUNCTION; + +/* + * If the stream buffer is being used as a message buffer, then reads an entire + * message out of the buffer. If the stream buffer is being used as a stream + * buffer then read as many bytes as possible from the buffer. + * prvReadBytesFromBuffer() is called to actually extract the bytes from the + * buffer's data storage area. + */ +static size_t prvReadMessageFromBuffer( StreamBuffer_t *pxStreamBuffer, + void *pvRxData, + size_t xBufferLengthBytes, + size_t xBytesAvailable, + size_t xBytesToStoreMessageLength ) PRIVILEGED_FUNCTION; + +/* + * If the stream buffer is being used as a message buffer, then writes an entire + * message to the buffer. If the stream buffer is being used as a stream + * buffer then write as many bytes as possible to the buffer. + * prvWriteBytestoBuffer() is called to actually send the bytes to the buffer's + * data storage area. + */ +static size_t prvWriteMessageToBuffer( StreamBuffer_t * const pxStreamBuffer, + const void * pvTxData, + size_t xDataLengthBytes, + size_t xSpace, + size_t xRequiredSpace ) PRIVILEGED_FUNCTION; + +/* + * Read xMaxCount bytes from the pxStreamBuffer message buffer and write them + * to pucData. + */ +static size_t prvReadBytesFromBuffer( StreamBuffer_t *pxStreamBuffer, + uint8_t *pucData, + size_t xMaxCount, + size_t xBytesAvailable ) PRIVILEGED_FUNCTION; + +/* + * Called by both pxStreamBufferCreate() and pxStreamBufferCreateStatic() to + * initialise the members of the newly created stream buffer structure. + */ +static void prvInitialiseNewStreamBuffer( StreamBuffer_t * const pxStreamBuffer, + uint8_t * const pucBuffer, + size_t xBufferSizeBytes, + size_t xTriggerLevelBytes, + uint8_t ucFlags ) PRIVILEGED_FUNCTION; + +/*-----------------------------------------------------------*/ + +#if( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) + + StreamBufferHandle_t xStreamBufferGenericCreate( size_t xBufferSizeBytes, size_t xTriggerLevelBytes, BaseType_t xIsMessageBuffer ) + { + uint8_t *pucAllocatedMemory; + uint8_t ucFlags; + + /* In case the stream buffer is going to be used as a message buffer + (that is, it will hold discrete messages with a little meta data that + says how big the next message is) check the buffer will be large enough + to hold at least one message. */ + if( xIsMessageBuffer == pdTRUE ) + { + /* Is a message buffer but not statically allocated. */ + ucFlags = sbFLAGS_IS_MESSAGE_BUFFER; + configASSERT( xBufferSizeBytes > sbBYTES_TO_STORE_MESSAGE_LENGTH ); + } + else + { + /* Not a message buffer and not statically allocated. */ + ucFlags = 0; + configASSERT( xBufferSizeBytes > 0 ); + } + configASSERT( xTriggerLevelBytes <= xBufferSizeBytes ); + + /* A trigger level of 0 would cause a waiting task to unblock even when + the buffer was empty. */ + if( xTriggerLevelBytes == ( size_t ) 0 ) + { + xTriggerLevelBytes = ( size_t ) 1; + } + + /* A stream buffer requires a StreamBuffer_t structure and a buffer. + Both are allocated in a single call to pvPortMalloc(). The + StreamBuffer_t structure is placed at the start of the allocated memory + and the buffer follows immediately after. The requested size is + incremented so the free space is returned as the user would expect - + this is a quirk of the implementation that means otherwise the free + space would be reported as one byte smaller than would be logically + expected. */ + xBufferSizeBytes++; + pucAllocatedMemory = ( uint8_t * ) pvPortMalloc( xBufferSizeBytes + sizeof( StreamBuffer_t ) ); /*lint !e9079 malloc() only returns void*. */ + + if( pucAllocatedMemory != NULL ) + { + prvInitialiseNewStreamBuffer( ( StreamBuffer_t * ) pucAllocatedMemory, /* Structure at the start of the allocated memory. */ /*lint !e9087 Safe cast as allocated memory is aligned. */ /*lint !e826 Area is not too small and alignment is guaranteed provided malloc() behaves as expected and returns aligned buffer. */ + pucAllocatedMemory + sizeof( StreamBuffer_t ), /* Storage area follows. */ /*lint !e9016 Indexing past structure valid for uint8_t pointer, also storage area has no alignment requirement. */ + xBufferSizeBytes, + xTriggerLevelBytes, + ucFlags ); + + traceSTREAM_BUFFER_CREATE( ( ( StreamBuffer_t * ) pucAllocatedMemory ), xIsMessageBuffer ); + } + else + { + traceSTREAM_BUFFER_CREATE_FAILED( xIsMessageBuffer ); + } + + return ( StreamBufferHandle_t ) pucAllocatedMemory; /*lint !e9087 !e826 Safe cast as allocated memory is aligned. */ + } + +#endif /* configSUPPORT_DYNAMIC_ALLOCATION */ +/*-----------------------------------------------------------*/ + +#if( configSUPPORT_STATIC_ALLOCATION == 1 ) + + StreamBufferHandle_t xStreamBufferGenericCreateStatic( size_t xBufferSizeBytes, + size_t xTriggerLevelBytes, + BaseType_t xIsMessageBuffer, + uint8_t * const pucStreamBufferStorageArea, + StaticStreamBuffer_t * const pxStaticStreamBuffer ) + { + StreamBuffer_t * const pxStreamBuffer = ( StreamBuffer_t * ) pxStaticStreamBuffer; /*lint !e740 !e9087 Safe cast as StaticStreamBuffer_t is opaque Streambuffer_t. */ + StreamBufferHandle_t xReturn; + uint8_t ucFlags; + + configASSERT( pucStreamBufferStorageArea ); + configASSERT( pxStaticStreamBuffer ); + configASSERT( xTriggerLevelBytes <= xBufferSizeBytes ); + + /* A trigger level of 0 would cause a waiting task to unblock even when + the buffer was empty. */ + if( xTriggerLevelBytes == ( size_t ) 0 ) + { + xTriggerLevelBytes = ( size_t ) 1; + } + + if( xIsMessageBuffer != pdFALSE ) + { + /* Statically allocated message buffer. */ + ucFlags = sbFLAGS_IS_MESSAGE_BUFFER | sbFLAGS_IS_STATICALLY_ALLOCATED; + } + else + { + /* Statically allocated stream buffer. */ + ucFlags = sbFLAGS_IS_STATICALLY_ALLOCATED; + } + + /* In case the stream buffer is going to be used as a message buffer + (that is, it will hold discrete messages with a little meta data that + says how big the next message is) check the buffer will be large enough + to hold at least one message. */ + configASSERT( xBufferSizeBytes > sbBYTES_TO_STORE_MESSAGE_LENGTH ); + + #if( configASSERT_DEFINED == 1 ) + { + /* Sanity check that the size of the structure used to declare a + variable of type StaticStreamBuffer_t equals the size of the real + message buffer structure. */ + volatile size_t xSize = sizeof( StaticStreamBuffer_t ); + configASSERT( xSize == sizeof( StreamBuffer_t ) ); + } /*lint !e529 xSize is referenced is configASSERT() is defined. */ + #endif /* configASSERT_DEFINED */ + + if( ( pucStreamBufferStorageArea != NULL ) && ( pxStaticStreamBuffer != NULL ) ) + { + prvInitialiseNewStreamBuffer( pxStreamBuffer, + pucStreamBufferStorageArea, + xBufferSizeBytes, + xTriggerLevelBytes, + ucFlags ); + + /* Remember this was statically allocated in case it is ever deleted + again. */ + pxStreamBuffer->ucFlags |= sbFLAGS_IS_STATICALLY_ALLOCATED; + + traceSTREAM_BUFFER_CREATE( pxStreamBuffer, xIsMessageBuffer ); + + xReturn = ( StreamBufferHandle_t ) pxStaticStreamBuffer; /*lint !e9087 Data hiding requires cast to opaque type. */ + } + else + { + xReturn = NULL; + traceSTREAM_BUFFER_CREATE_STATIC_FAILED( xReturn, xIsMessageBuffer ); + } + + return xReturn; + } + +#endif /* ( configSUPPORT_STATIC_ALLOCATION == 1 ) */ +/*-----------------------------------------------------------*/ + +void vStreamBufferDelete( StreamBufferHandle_t xStreamBuffer ) +{ +StreamBuffer_t * pxStreamBuffer = xStreamBuffer; + + configASSERT( pxStreamBuffer ); + + traceSTREAM_BUFFER_DELETE( xStreamBuffer ); + + if( ( pxStreamBuffer->ucFlags & sbFLAGS_IS_STATICALLY_ALLOCATED ) == ( uint8_t ) pdFALSE ) + { + #if( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) + { + /* Both the structure and the buffer were allocated using a single call + to pvPortMalloc(), hence only one call to vPortFree() is required. */ + vPortFree( ( void * ) pxStreamBuffer ); /*lint !e9087 Standard free() semantics require void *, plus pxStreamBuffer was allocated by pvPortMalloc(). */ + } + #else + { + /* Should not be possible to get here, ucFlags must be corrupt. + Force an assert. */ + configASSERT( xStreamBuffer == ( StreamBufferHandle_t ) ~0 ); + } + #endif + } + else + { + /* The structure and buffer were not allocated dynamically and cannot be + freed - just scrub the structure so future use will assert. */ + ( void ) memset( pxStreamBuffer, 0x00, sizeof( StreamBuffer_t ) ); + } +} +/*-----------------------------------------------------------*/ + +BaseType_t xStreamBufferReset( StreamBufferHandle_t xStreamBuffer ) +{ +StreamBuffer_t * const pxStreamBuffer = xStreamBuffer; +BaseType_t xReturn = pdFAIL; + +#if( configUSE_TRACE_FACILITY == 1 ) + UBaseType_t uxStreamBufferNumber; +#endif + + configASSERT( pxStreamBuffer ); + + #if( configUSE_TRACE_FACILITY == 1 ) + { + /* Store the stream buffer number so it can be restored after the + reset. */ + uxStreamBufferNumber = pxStreamBuffer->uxStreamBufferNumber; + } + #endif + + /* Can only reset a message buffer if there are no tasks blocked on it. */ + taskENTER_CRITICAL(); + { + if( pxStreamBuffer->xTaskWaitingToReceive == NULL ) + { + if( pxStreamBuffer->xTaskWaitingToSend == NULL ) + { + prvInitialiseNewStreamBuffer( pxStreamBuffer, + pxStreamBuffer->pucBuffer, + pxStreamBuffer->xLength, + pxStreamBuffer->xTriggerLevelBytes, + pxStreamBuffer->ucFlags ); + xReturn = pdPASS; + + #if( configUSE_TRACE_FACILITY == 1 ) + { + pxStreamBuffer->uxStreamBufferNumber = uxStreamBufferNumber; + } + #endif + + traceSTREAM_BUFFER_RESET( xStreamBuffer ); + } + } + } + taskEXIT_CRITICAL(); + + return xReturn; +} +/*-----------------------------------------------------------*/ + +BaseType_t xStreamBufferSetTriggerLevel( StreamBufferHandle_t xStreamBuffer, size_t xTriggerLevel ) +{ +StreamBuffer_t * const pxStreamBuffer = xStreamBuffer; +BaseType_t xReturn; + + configASSERT( pxStreamBuffer ); + + /* It is not valid for the trigger level to be 0. */ + if( xTriggerLevel == ( size_t ) 0 ) + { + xTriggerLevel = ( size_t ) 1; + } + + /* The trigger level is the number of bytes that must be in the stream + buffer before a task that is waiting for data is unblocked. */ + if( xTriggerLevel <= pxStreamBuffer->xLength ) + { + pxStreamBuffer->xTriggerLevelBytes = xTriggerLevel; + xReturn = pdPASS; + } + else + { + xReturn = pdFALSE; + } + + return xReturn; +} +/*-----------------------------------------------------------*/ + +size_t xStreamBufferSpacesAvailable( StreamBufferHandle_t xStreamBuffer ) +{ +const StreamBuffer_t * const pxStreamBuffer = xStreamBuffer; +size_t xSpace; + + configASSERT( pxStreamBuffer ); + + xSpace = pxStreamBuffer->xLength + pxStreamBuffer->xTail; + xSpace -= pxStreamBuffer->xHead; + xSpace -= ( size_t ) 1; + + if( xSpace >= pxStreamBuffer->xLength ) + { + xSpace -= pxStreamBuffer->xLength; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + + return xSpace; +} +/*-----------------------------------------------------------*/ + +size_t xStreamBufferBytesAvailable( StreamBufferHandle_t xStreamBuffer ) +{ +const StreamBuffer_t * const pxStreamBuffer = xStreamBuffer; +size_t xReturn; + + configASSERT( pxStreamBuffer ); + + xReturn = prvBytesInBuffer( pxStreamBuffer ); + return xReturn; +} +/*-----------------------------------------------------------*/ + +size_t xStreamBufferSend( StreamBufferHandle_t xStreamBuffer, + const void *pvTxData, + size_t xDataLengthBytes, + TickType_t xTicksToWait ) +{ +StreamBuffer_t * const pxStreamBuffer = xStreamBuffer; +size_t xReturn, xSpace = 0; +size_t xRequiredSpace = xDataLengthBytes; +TimeOut_t xTimeOut; + + configASSERT( pvTxData ); + configASSERT( pxStreamBuffer ); + + /* This send function is used to write to both message buffers and stream + buffers. If this is a message buffer then the space needed must be + increased by the amount of bytes needed to store the length of the + message. */ + if( ( pxStreamBuffer->ucFlags & sbFLAGS_IS_MESSAGE_BUFFER ) != ( uint8_t ) 0 ) + { + xRequiredSpace += sbBYTES_TO_STORE_MESSAGE_LENGTH; + + /* Overflow? */ + configASSERT( xRequiredSpace > xDataLengthBytes ); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + + if( xTicksToWait != ( TickType_t ) 0 ) + { + vTaskSetTimeOutState( &xTimeOut ); + + do + { + /* Wait until the required number of bytes are free in the message + buffer. */ + taskENTER_CRITICAL(); + { + xSpace = xStreamBufferSpacesAvailable( pxStreamBuffer ); + + if( xSpace < xRequiredSpace ) + { + /* Clear notification state as going to wait for space. */ + ( void ) xTaskNotifyStateClear( NULL ); + + /* Should only be one writer. */ + configASSERT( pxStreamBuffer->xTaskWaitingToSend == NULL ); + pxStreamBuffer->xTaskWaitingToSend = xTaskGetCurrentTaskHandle(); + } + else + { + taskEXIT_CRITICAL(); + break; + } + } + taskEXIT_CRITICAL(); + + traceBLOCKING_ON_STREAM_BUFFER_SEND( xStreamBuffer ); + ( void ) xTaskNotifyWait( ( uint32_t ) 0, ( uint32_t ) 0, NULL, xTicksToWait ); + pxStreamBuffer->xTaskWaitingToSend = NULL; + + } while( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE ); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + + if( xSpace == ( size_t ) 0 ) + { + xSpace = xStreamBufferSpacesAvailable( pxStreamBuffer ); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + + xReturn = prvWriteMessageToBuffer( pxStreamBuffer, pvTxData, xDataLengthBytes, xSpace, xRequiredSpace ); + + if( xReturn > ( size_t ) 0 ) + { + traceSTREAM_BUFFER_SEND( xStreamBuffer, xReturn ); + + /* Was a task waiting for the data? */ + if( prvBytesInBuffer( pxStreamBuffer ) >= pxStreamBuffer->xTriggerLevelBytes ) + { + sbSEND_COMPLETED( pxStreamBuffer ); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + mtCOVERAGE_TEST_MARKER(); + traceSTREAM_BUFFER_SEND_FAILED( xStreamBuffer ); + } + + return xReturn; +} +/*-----------------------------------------------------------*/ + +size_t xStreamBufferSendFromISR( StreamBufferHandle_t xStreamBuffer, + const void *pvTxData, + size_t xDataLengthBytes, + BaseType_t * const pxHigherPriorityTaskWoken ) +{ +StreamBuffer_t * const pxStreamBuffer = xStreamBuffer; +size_t xReturn, xSpace; +size_t xRequiredSpace = xDataLengthBytes; + + configASSERT( pvTxData ); + configASSERT( pxStreamBuffer ); + + /* This send function is used to write to both message buffers and stream + buffers. If this is a message buffer then the space needed must be + increased by the amount of bytes needed to store the length of the + message. */ + if( ( pxStreamBuffer->ucFlags & sbFLAGS_IS_MESSAGE_BUFFER ) != ( uint8_t ) 0 ) + { + xRequiredSpace += sbBYTES_TO_STORE_MESSAGE_LENGTH; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + + xSpace = xStreamBufferSpacesAvailable( pxStreamBuffer ); + xReturn = prvWriteMessageToBuffer( pxStreamBuffer, pvTxData, xDataLengthBytes, xSpace, xRequiredSpace ); + + if( xReturn > ( size_t ) 0 ) + { + /* Was a task waiting for the data? */ + if( prvBytesInBuffer( pxStreamBuffer ) >= pxStreamBuffer->xTriggerLevelBytes ) + { + sbSEND_COMPLETE_FROM_ISR( pxStreamBuffer, pxHigherPriorityTaskWoken ); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + + traceSTREAM_BUFFER_SEND_FROM_ISR( xStreamBuffer, xReturn ); + + return xReturn; +} +/*-----------------------------------------------------------*/ + +static size_t prvWriteMessageToBuffer( StreamBuffer_t * const pxStreamBuffer, + const void * pvTxData, + size_t xDataLengthBytes, + size_t xSpace, + size_t xRequiredSpace ) +{ + BaseType_t xShouldWrite; + size_t xReturn; + + if( xSpace == ( size_t ) 0 ) + { + /* Doesn't matter if this is a stream buffer or a message buffer, there + is no space to write. */ + xShouldWrite = pdFALSE; + } + else if( ( pxStreamBuffer->ucFlags & sbFLAGS_IS_MESSAGE_BUFFER ) == ( uint8_t ) 0 ) + { + /* This is a stream buffer, as opposed to a message buffer, so writing a + stream of bytes rather than discrete messages. Write as many bytes as + possible. */ + xShouldWrite = pdTRUE; + xDataLengthBytes = configMIN( xDataLengthBytes, xSpace ); + } + else if( xSpace >= xRequiredSpace ) + { + /* This is a message buffer, as opposed to a stream buffer, and there + is enough space to write both the message length and the message itself + into the buffer. Start by writing the length of the data, the data + itself will be written later in this function. */ + xShouldWrite = pdTRUE; + ( void ) prvWriteBytesToBuffer( pxStreamBuffer, ( const uint8_t * ) &( xDataLengthBytes ), sbBYTES_TO_STORE_MESSAGE_LENGTH ); + } + else + { + /* There is space available, but not enough space. */ + xShouldWrite = pdFALSE; + } + + if( xShouldWrite != pdFALSE ) + { + /* Writes the data itself. */ + xReturn = prvWriteBytesToBuffer( pxStreamBuffer, ( const uint8_t * ) pvTxData, xDataLengthBytes ); /*lint !e9079 Storage buffer is implemented as uint8_t for ease of sizing, alighment and access. */ + } + else + { + xReturn = 0; + } + + return xReturn; +} +/*-----------------------------------------------------------*/ + +size_t xStreamBufferReceive( StreamBufferHandle_t xStreamBuffer, + void *pvRxData, + size_t xBufferLengthBytes, + TickType_t xTicksToWait ) +{ +StreamBuffer_t * const pxStreamBuffer = xStreamBuffer; +size_t xReceivedLength = 0, xBytesAvailable, xBytesToStoreMessageLength; + + configASSERT( pvRxData ); + configASSERT( pxStreamBuffer ); + + /* This receive function is used by both message buffers, which store + discrete messages, and stream buffers, which store a continuous stream of + bytes. Discrete messages include an additional + sbBYTES_TO_STORE_MESSAGE_LENGTH bytes that hold the length of the + message. */ + if( ( pxStreamBuffer->ucFlags & sbFLAGS_IS_MESSAGE_BUFFER ) != ( uint8_t ) 0 ) + { + xBytesToStoreMessageLength = sbBYTES_TO_STORE_MESSAGE_LENGTH; + } + else + { + xBytesToStoreMessageLength = 0; + } + + if( xTicksToWait != ( TickType_t ) 0 ) + { + /* Checking if there is data and clearing the notification state must be + performed atomically. */ + taskENTER_CRITICAL(); + { + xBytesAvailable = prvBytesInBuffer( pxStreamBuffer ); + + /* If this function was invoked by a message buffer read then + xBytesToStoreMessageLength holds the number of bytes used to hold + the length of the next discrete message. If this function was + invoked by a stream buffer read then xBytesToStoreMessageLength will + be 0. */ + if( xBytesAvailable <= xBytesToStoreMessageLength ) + { + /* Clear notification state as going to wait for data. */ + ( void ) xTaskNotifyStateClear( NULL ); + + /* Should only be one reader. */ + configASSERT( pxStreamBuffer->xTaskWaitingToReceive == NULL ); + pxStreamBuffer->xTaskWaitingToReceive = xTaskGetCurrentTaskHandle(); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + taskEXIT_CRITICAL(); + + if( xBytesAvailable <= xBytesToStoreMessageLength ) + { + /* Wait for data to be available. */ + traceBLOCKING_ON_STREAM_BUFFER_RECEIVE( xStreamBuffer ); + ( void ) xTaskNotifyWait( ( uint32_t ) 0, ( uint32_t ) 0, NULL, xTicksToWait ); + pxStreamBuffer->xTaskWaitingToReceive = NULL; + + /* Recheck the data available after blocking. */ + xBytesAvailable = prvBytesInBuffer( pxStreamBuffer ); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + xBytesAvailable = prvBytesInBuffer( pxStreamBuffer ); + } + + /* Whether receiving a discrete message (where xBytesToStoreMessageLength + holds the number of bytes used to store the message length) or a stream of + bytes (where xBytesToStoreMessageLength is zero), the number of bytes + available must be greater than xBytesToStoreMessageLength to be able to + read bytes from the buffer. */ + if( xBytesAvailable > xBytesToStoreMessageLength ) + { + xReceivedLength = prvReadMessageFromBuffer( pxStreamBuffer, pvRxData, xBufferLengthBytes, xBytesAvailable, xBytesToStoreMessageLength ); + + /* Was a task waiting for space in the buffer? */ + if( xReceivedLength != ( size_t ) 0 ) + { + traceSTREAM_BUFFER_RECEIVE( xStreamBuffer, xReceivedLength ); + sbRECEIVE_COMPLETED( pxStreamBuffer ); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + traceSTREAM_BUFFER_RECEIVE_FAILED( xStreamBuffer ); + mtCOVERAGE_TEST_MARKER(); + } + + return xReceivedLength; +} +/*-----------------------------------------------------------*/ + +size_t xStreamBufferNextMessageLengthBytes( StreamBufferHandle_t xStreamBuffer ) +{ +StreamBuffer_t * const pxStreamBuffer = xStreamBuffer; +size_t xReturn, xBytesAvailable, xOriginalTail; +configMESSAGE_BUFFER_LENGTH_TYPE xTempReturn; + + configASSERT( pxStreamBuffer ); + + /* Ensure the stream buffer is being used as a message buffer. */ + if( ( pxStreamBuffer->ucFlags & sbFLAGS_IS_MESSAGE_BUFFER ) != ( uint8_t ) 0 ) + { + xBytesAvailable = prvBytesInBuffer( pxStreamBuffer ); + if( xBytesAvailable > sbBYTES_TO_STORE_MESSAGE_LENGTH ) + { + /* The number of bytes available is greater than the number of bytes + required to hold the length of the next message, so another message + is available. Return its length without removing the length bytes + from the buffer. A copy of the tail is stored so the buffer can be + returned to its prior state as the message is not actually being + removed from the buffer. */ + xOriginalTail = pxStreamBuffer->xTail; + ( void ) prvReadBytesFromBuffer( pxStreamBuffer, ( uint8_t * ) &xTempReturn, sbBYTES_TO_STORE_MESSAGE_LENGTH, xBytesAvailable ); + xReturn = ( size_t ) xTempReturn; + pxStreamBuffer->xTail = xOriginalTail; + } + else + { + /* The minimum amount of bytes in a message buffer is + ( sbBYTES_TO_STORE_MESSAGE_LENGTH + 1 ), so if xBytesAvailable is + less than sbBYTES_TO_STORE_MESSAGE_LENGTH the only other valid + value is 0. */ + configASSERT( xBytesAvailable == 0 ); + xReturn = 0; + } + } + else + { + xReturn = 0; + } + + return xReturn; +} +/*-----------------------------------------------------------*/ + +size_t xStreamBufferReceiveFromISR( StreamBufferHandle_t xStreamBuffer, + void *pvRxData, + size_t xBufferLengthBytes, + BaseType_t * const pxHigherPriorityTaskWoken ) +{ +StreamBuffer_t * const pxStreamBuffer = xStreamBuffer; +size_t xReceivedLength = 0, xBytesAvailable, xBytesToStoreMessageLength; + + configASSERT( pvRxData ); + configASSERT( pxStreamBuffer ); + + /* This receive function is used by both message buffers, which store + discrete messages, and stream buffers, which store a continuous stream of + bytes. Discrete messages include an additional + sbBYTES_TO_STORE_MESSAGE_LENGTH bytes that hold the length of the + message. */ + if( ( pxStreamBuffer->ucFlags & sbFLAGS_IS_MESSAGE_BUFFER ) != ( uint8_t ) 0 ) + { + xBytesToStoreMessageLength = sbBYTES_TO_STORE_MESSAGE_LENGTH; + } + else + { + xBytesToStoreMessageLength = 0; + } + + xBytesAvailable = prvBytesInBuffer( pxStreamBuffer ); + + /* Whether receiving a discrete message (where xBytesToStoreMessageLength + holds the number of bytes used to store the message length) or a stream of + bytes (where xBytesToStoreMessageLength is zero), the number of bytes + available must be greater than xBytesToStoreMessageLength to be able to + read bytes from the buffer. */ + if( xBytesAvailable > xBytesToStoreMessageLength ) + { + xReceivedLength = prvReadMessageFromBuffer( pxStreamBuffer, pvRxData, xBufferLengthBytes, xBytesAvailable, xBytesToStoreMessageLength ); + + /* Was a task waiting for space in the buffer? */ + if( xReceivedLength != ( size_t ) 0 ) + { + sbRECEIVE_COMPLETED_FROM_ISR( pxStreamBuffer, pxHigherPriorityTaskWoken ); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + + traceSTREAM_BUFFER_RECEIVE_FROM_ISR( xStreamBuffer, xReceivedLength ); + + return xReceivedLength; +} +/*-----------------------------------------------------------*/ + +static size_t prvReadMessageFromBuffer( StreamBuffer_t *pxStreamBuffer, + void *pvRxData, + size_t xBufferLengthBytes, + size_t xBytesAvailable, + size_t xBytesToStoreMessageLength ) +{ +size_t xOriginalTail, xReceivedLength, xNextMessageLength; +configMESSAGE_BUFFER_LENGTH_TYPE xTempNextMessageLength; + + if( xBytesToStoreMessageLength != ( size_t ) 0 ) + { + /* A discrete message is being received. First receive the length + of the message. A copy of the tail is stored so the buffer can be + returned to its prior state if the length of the message is too + large for the provided buffer. */ + xOriginalTail = pxStreamBuffer->xTail; + ( void ) prvReadBytesFromBuffer( pxStreamBuffer, ( uint8_t * ) &xTempNextMessageLength, xBytesToStoreMessageLength, xBytesAvailable ); + xNextMessageLength = ( size_t ) xTempNextMessageLength; + + /* Reduce the number of bytes available by the number of bytes just + read out. */ + xBytesAvailable -= xBytesToStoreMessageLength; + + /* Check there is enough space in the buffer provided by the + user. */ + if( xNextMessageLength > xBufferLengthBytes ) + { + /* The user has provided insufficient space to read the message + so return the buffer to its previous state (so the length of + the message is in the buffer again). */ + pxStreamBuffer->xTail = xOriginalTail; + xNextMessageLength = 0; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + /* A stream of bytes is being received (as opposed to a discrete + message), so read as many bytes as possible. */ + xNextMessageLength = xBufferLengthBytes; + } + + /* Read the actual data. */ + xReceivedLength = prvReadBytesFromBuffer( pxStreamBuffer, ( uint8_t * ) pvRxData, xNextMessageLength, xBytesAvailable ); /*lint !e9079 Data storage area is implemented as uint8_t array for ease of sizing, indexing and alignment. */ + + return xReceivedLength; +} +/*-----------------------------------------------------------*/ + +BaseType_t xStreamBufferIsEmpty( StreamBufferHandle_t xStreamBuffer ) +{ +const StreamBuffer_t * const pxStreamBuffer = xStreamBuffer; +BaseType_t xReturn; +size_t xTail; + + configASSERT( pxStreamBuffer ); + + /* True if no bytes are available. */ + xTail = pxStreamBuffer->xTail; + if( pxStreamBuffer->xHead == xTail ) + { + xReturn = pdTRUE; + } + else + { + xReturn = pdFALSE; + } + + return xReturn; +} +/*-----------------------------------------------------------*/ + +BaseType_t xStreamBufferIsFull( StreamBufferHandle_t xStreamBuffer ) +{ +BaseType_t xReturn; +size_t xBytesToStoreMessageLength; +const StreamBuffer_t * const pxStreamBuffer = xStreamBuffer; + + configASSERT( pxStreamBuffer ); + + /* This generic version of the receive function is used by both message + buffers, which store discrete messages, and stream buffers, which store a + continuous stream of bytes. Discrete messages include an additional + sbBYTES_TO_STORE_MESSAGE_LENGTH bytes that hold the length of the message. */ + if( ( pxStreamBuffer->ucFlags & sbFLAGS_IS_MESSAGE_BUFFER ) != ( uint8_t ) 0 ) + { + xBytesToStoreMessageLength = sbBYTES_TO_STORE_MESSAGE_LENGTH; + } + else + { + xBytesToStoreMessageLength = 0; + } + + /* True if the available space equals zero. */ + if( xStreamBufferSpacesAvailable( xStreamBuffer ) <= xBytesToStoreMessageLength ) + { + xReturn = pdTRUE; + } + else + { + xReturn = pdFALSE; + } + + return xReturn; +} +/*-----------------------------------------------------------*/ + +BaseType_t xStreamBufferSendCompletedFromISR( StreamBufferHandle_t xStreamBuffer, BaseType_t *pxHigherPriorityTaskWoken ) +{ +StreamBuffer_t * const pxStreamBuffer = xStreamBuffer; +BaseType_t xReturn; +UBaseType_t uxSavedInterruptStatus; + + configASSERT( pxStreamBuffer ); + + uxSavedInterruptStatus = ( UBaseType_t ) portSET_INTERRUPT_MASK_FROM_ISR(); + { + if( ( pxStreamBuffer )->xTaskWaitingToReceive != NULL ) + { + ( void ) xTaskNotifyFromISR( ( pxStreamBuffer )->xTaskWaitingToReceive, + ( uint32_t ) 0, + eNoAction, + pxHigherPriorityTaskWoken ); + ( pxStreamBuffer )->xTaskWaitingToReceive = NULL; + xReturn = pdTRUE; + } + else + { + xReturn = pdFALSE; + } + } + portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus ); + + return xReturn; +} +/*-----------------------------------------------------------*/ + +BaseType_t xStreamBufferReceiveCompletedFromISR( StreamBufferHandle_t xStreamBuffer, BaseType_t *pxHigherPriorityTaskWoken ) +{ +StreamBuffer_t * const pxStreamBuffer = xStreamBuffer; +BaseType_t xReturn; +UBaseType_t uxSavedInterruptStatus; + + configASSERT( pxStreamBuffer ); + + uxSavedInterruptStatus = ( UBaseType_t ) portSET_INTERRUPT_MASK_FROM_ISR(); + { + if( ( pxStreamBuffer )->xTaskWaitingToSend != NULL ) + { + ( void ) xTaskNotifyFromISR( ( pxStreamBuffer )->xTaskWaitingToSend, + ( uint32_t ) 0, + eNoAction, + pxHigherPriorityTaskWoken ); + ( pxStreamBuffer )->xTaskWaitingToSend = NULL; + xReturn = pdTRUE; + } + else + { + xReturn = pdFALSE; + } + } + portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus ); + + return xReturn; +} +/*-----------------------------------------------------------*/ + +static size_t prvWriteBytesToBuffer( StreamBuffer_t * const pxStreamBuffer, const uint8_t *pucData, size_t xCount ) +{ +size_t xNextHead, xFirstLength; + + configASSERT( xCount > ( size_t ) 0 ); + + xNextHead = pxStreamBuffer->xHead; + + /* Calculate the number of bytes that can be added in the first write - + which may be less than the total number of bytes that need to be added if + the buffer will wrap back to the beginning. */ + xFirstLength = configMIN( pxStreamBuffer->xLength - xNextHead, xCount ); + + /* Write as many bytes as can be written in the first write. */ + configASSERT( ( xNextHead + xFirstLength ) <= pxStreamBuffer->xLength ); + ( void ) memcpy( ( void* ) ( &( pxStreamBuffer->pucBuffer[ xNextHead ] ) ), ( const void * ) pucData, xFirstLength ); /*lint !e9087 memcpy() requires void *. */ + + /* If the number of bytes written was less than the number that could be + written in the first write... */ + if( xCount > xFirstLength ) + { + /* ...then write the remaining bytes to the start of the buffer. */ + configASSERT( ( xCount - xFirstLength ) <= pxStreamBuffer->xLength ); + ( void ) memcpy( ( void * ) pxStreamBuffer->pucBuffer, ( const void * ) &( pucData[ xFirstLength ] ), xCount - xFirstLength ); /*lint !e9087 memcpy() requires void *. */ + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + + xNextHead += xCount; + if( xNextHead >= pxStreamBuffer->xLength ) + { + xNextHead -= pxStreamBuffer->xLength; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + + pxStreamBuffer->xHead = xNextHead; + + return xCount; +} +/*-----------------------------------------------------------*/ + +static size_t prvReadBytesFromBuffer( StreamBuffer_t *pxStreamBuffer, uint8_t *pucData, size_t xMaxCount, size_t xBytesAvailable ) +{ +size_t xCount, xFirstLength, xNextTail; + + /* Use the minimum of the wanted bytes and the available bytes. */ + xCount = configMIN( xBytesAvailable, xMaxCount ); + + if( xCount > ( size_t ) 0 ) + { + xNextTail = pxStreamBuffer->xTail; + + /* Calculate the number of bytes that can be read - which may be + less than the number wanted if the data wraps around to the start of + the buffer. */ + xFirstLength = configMIN( pxStreamBuffer->xLength - xNextTail, xCount ); + + /* Obtain the number of bytes it is possible to obtain in the first + read. Asserts check bounds of read and write. */ + configASSERT( xFirstLength <= xMaxCount ); + configASSERT( ( xNextTail + xFirstLength ) <= pxStreamBuffer->xLength ); + ( void ) memcpy( ( void * ) pucData, ( const void * ) &( pxStreamBuffer->pucBuffer[ xNextTail ] ), xFirstLength ); /*lint !e9087 memcpy() requires void *. */ + + /* If the total number of wanted bytes is greater than the number + that could be read in the first read... */ + if( xCount > xFirstLength ) + { + /*...then read the remaining bytes from the start of the buffer. */ + configASSERT( xCount <= xMaxCount ); + ( void ) memcpy( ( void * ) &( pucData[ xFirstLength ] ), ( void * ) ( pxStreamBuffer->pucBuffer ), xCount - xFirstLength ); /*lint !e9087 memcpy() requires void *. */ + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + + /* Move the tail pointer to effectively remove the data read from + the buffer. */ + xNextTail += xCount; + + if( xNextTail >= pxStreamBuffer->xLength ) + { + xNextTail -= pxStreamBuffer->xLength; + } + + pxStreamBuffer->xTail = xNextTail; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + + return xCount; +} +/*-----------------------------------------------------------*/ + +static size_t prvBytesInBuffer( const StreamBuffer_t * const pxStreamBuffer ) +{ +/* Returns the distance between xTail and xHead. */ +size_t xCount; + + xCount = pxStreamBuffer->xLength + pxStreamBuffer->xHead; + xCount -= pxStreamBuffer->xTail; + if ( xCount >= pxStreamBuffer->xLength ) + { + xCount -= pxStreamBuffer->xLength; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + + return xCount; +} +/*-----------------------------------------------------------*/ + +static void prvInitialiseNewStreamBuffer( StreamBuffer_t * const pxStreamBuffer, + uint8_t * const pucBuffer, + size_t xBufferSizeBytes, + size_t xTriggerLevelBytes, + uint8_t ucFlags ) +{ + /* Assert here is deliberately writing to the entire buffer to ensure it can + be written to without generating exceptions, and is setting the buffer to a + known value to assist in development/debugging. */ + #if( configASSERT_DEFINED == 1 ) + { + /* The value written just has to be identifiable when looking at the + memory. Don't use 0xA5 as that is the stack fill value and could + result in confusion as to what is actually being observed. */ + const BaseType_t xWriteValue = 0x55; + configASSERT( memset( pucBuffer, ( int ) xWriteValue, xBufferSizeBytes ) == pucBuffer ); + } /*lint !e529 !e438 xWriteValue is only used if configASSERT() is defined. */ + #endif + + ( void ) memset( ( void * ) pxStreamBuffer, 0x00, sizeof( StreamBuffer_t ) ); /*lint !e9087 memset() requires void *. */ + pxStreamBuffer->pucBuffer = pucBuffer; + pxStreamBuffer->xLength = xBufferSizeBytes; + pxStreamBuffer->xTriggerLevelBytes = xTriggerLevelBytes; + pxStreamBuffer->ucFlags = ucFlags; +} + +#if ( configUSE_TRACE_FACILITY == 1 ) + + UBaseType_t uxStreamBufferGetStreamBufferNumber( StreamBufferHandle_t xStreamBuffer ) + { + return xStreamBuffer->uxStreamBufferNumber; + } + +#endif /* configUSE_TRACE_FACILITY */ +/*-----------------------------------------------------------*/ + +#if ( configUSE_TRACE_FACILITY == 1 ) + + void vStreamBufferSetStreamBufferNumber( StreamBufferHandle_t xStreamBuffer, UBaseType_t uxStreamBufferNumber ) + { + xStreamBuffer->uxStreamBufferNumber = uxStreamBufferNumber; + } + +#endif /* configUSE_TRACE_FACILITY */ +/*-----------------------------------------------------------*/ + +#if ( configUSE_TRACE_FACILITY == 1 ) + + uint8_t ucStreamBufferGetStreamBufferType( StreamBufferHandle_t xStreamBuffer ) + { + return ( xStreamBuffer->ucFlags & sbFLAGS_IS_MESSAGE_BUFFER ); + } + +#endif /* configUSE_TRACE_FACILITY */ +/*-----------------------------------------------------------*/ diff --git a/Firmware/Board/v3/Middlewares/Third_Party/FreeRTOS/Source/tasks.c b/Firmware/Board/v3/Middlewares/Third_Party/FreeRTOS/Source/tasks.c index 5c68c6a2..f6a6a9b4 100644 --- a/Firmware/Board/v3/Middlewares/Third_Party/FreeRTOS/Source/tasks.c +++ b/Firmware/Board/v3/Middlewares/Third_Party/FreeRTOS/Source/tasks.c @@ -1,71 +1,29 @@ /* - FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. - All rights reserved - - VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. - - This file is part of the FreeRTOS distribution. - - FreeRTOS is free software; you can redistribute it and/or modify it under - the terms of the GNU General Public License (version 2) as published by the - Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception. - - *************************************************************************** - >>! NOTE: The modification to the GPL is included to allow you to !<< - >>! distribute a combined work that includes FreeRTOS without being !<< - >>! obliged to provide the source code for proprietary components !<< - >>! outside of the FreeRTOS kernel. !<< - *************************************************************************** - - FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - FOR A PARTICULAR PURPOSE. Full license text is available on the following - link: http://www.freertos.org/a00114.html - - *************************************************************************** - * * - * FreeRTOS provides completely free yet professionally developed, * - * robust, strictly quality controlled, supported, and cross * - * platform software that is more than just the market leader, it * - * is the industry's de facto standard. * - * * - * Help yourself get started quickly while simultaneously helping * - * to support the FreeRTOS project by purchasing a FreeRTOS * - * tutorial book, reference manual, or both: * - * http://www.FreeRTOS.org/Documentation * - * * - *************************************************************************** - - http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading - the FAQ page "My application does not run, what could be wrong?". Have you - defined configASSERT()? - - http://www.FreeRTOS.org/support - In return for receiving this top quality - embedded software for free we request you assist our global community by - participating in the support forum. - - http://www.FreeRTOS.org/training - Investing in training allows your team to - be as productive as possible as early as possible. Now you can receive - FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers - Ltd, and the world's leading authority on the world's leading RTOS. - - http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, - including FreeRTOS+Trace - an indispensable productivity tool, a DOS - compatible FAT file system, and our tiny thread aware UDP/IP stack. - - http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. - Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. - - http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High - Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS - licenses offer ticketed support, indemnification and commercial middleware. - - http://www.SafeRTOS.com - High Integrity Systems also provide a safety - engineered and independently SIL3 certified version for use in safety and - mission critical applications that require provable dependability. - - 1 tab == 4 spaces! -*/ + * FreeRTOS Kernel V10.3.1 + * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * http://www.FreeRTOS.org + * http://aws.amazon.com/freertos + * + * 1 tab == 4 spaces! + */ /* Standard includes. */ #include @@ -80,13 +38,13 @@ task.h is included from an application file. */ #include "FreeRTOS.h" #include "task.h" #include "timers.h" -#include "StackMacros.h" +#include "stack_macros.h" -/* Lint e961 and e750 are suppressed as a MISRA exception justified because the -MPU ports require MPU_WRAPPERS_INCLUDED_FROM_API_FILE to be defined for the -header files above, but not in this file, in order to generate the correct -privileged Vs unprivileged linkage and placement. */ -#undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE /*lint !e961 !e750. */ +/* Lint e9021, e961 and e750 are suppressed as a MISRA exception justified +because the MPU ports require MPU_WRAPPERS_INCLUDED_FROM_API_FILE to be defined +for the header files above, but not in this file, in order to generate the +correct privileged Vs unprivileged linkage and placement. */ +#undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE /*lint !e961 !e750 !e9021. */ /* Set configUSE_STATS_FORMATTING_FUNCTIONS to 2 to include the stats formatting functions but without including stdio.h here. */ @@ -117,29 +75,24 @@ functions but without including stdio.h here. */ */ #define tskSTACK_FILL_BYTE ( 0xa5U ) -/* Sometimes the FreeRTOSConfig.h settings only allow a task to be created using -dynamically allocated RAM, in which case when any task is deleted it is known -that both the task's stack and TCB need to be freed. Sometimes the -FreeRTOSConfig.h settings only allow a task to be created using statically -allocated RAM, in which case when any task is deleted it is known that neither -the task's stack or TCB should be freed. Sometimes the FreeRTOSConfig.h -settings allow a task to be created using either statically or dynamically -allocated RAM, in which case a member of the TCB is used to record whether the -stack and/or TCB were allocated statically or dynamically, so when a task is -deleted the RAM that was allocated dynamically is freed again and no attempt is -made to free the RAM that was allocated statically. -tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE is only true if it is possible for a -task to be created using either statically or dynamically allocated RAM. Note -that if portUSING_MPU_WRAPPERS is 1 then a protected task can be created with -a statically allocated stack and a dynamically allocated TCB. */ -#define tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE ( ( ( configSUPPORT_STATIC_ALLOCATION == 1 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) ) || ( portUSING_MPU_WRAPPERS == 1 ) ) +/* Bits used to recored how a task's stack and TCB were allocated. */ #define tskDYNAMICALLY_ALLOCATED_STACK_AND_TCB ( ( uint8_t ) 0 ) #define tskSTATICALLY_ALLOCATED_STACK_ONLY ( ( uint8_t ) 1 ) #define tskSTATICALLY_ALLOCATED_STACK_AND_TCB ( ( uint8_t ) 2 ) +/* If any of the following are set then task stacks are filled with a known +value so the high water mark can be determined. If none of the following are +set then don't fill the stack so there is no unnecessary dependency on memset. */ +#if( ( configCHECK_FOR_STACK_OVERFLOW > 1 ) || ( configUSE_TRACE_FACILITY == 1 ) || ( INCLUDE_uxTaskGetStackHighWaterMark == 1 ) || ( INCLUDE_uxTaskGetStackHighWaterMark2 == 1 ) ) + #define tskSET_NEW_STACKS_TO_KNOWN_VALUE 1 +#else + #define tskSET_NEW_STACKS_TO_KNOWN_VALUE 0 +#endif + /* * Macros used by vListTask to indicate which state a task is in. */ +#define tskRUNNING_CHAR ( 'X' ) #define tskBLOCKED_CHAR ( 'B' ) #define tskREADY_CHAR ( 'R' ) #define tskDELETED_CHAR ( 'D' ) @@ -153,6 +106,12 @@ a statically allocated stack and a dynamically allocated TCB. */ #define static #endif +/* The name allocated to the Idle task. This can be overridden by defining +configIDLE_TASK_NAME in FreeRTOSConfig.h. */ +#ifndef configIDLE_TASK_NAME + #define configIDLE_TASK_NAME "IDLE" +#endif + #if ( configUSE_PORT_OPTIMISED_TASK_SELECTION == 0 ) /* If configUSE_PORT_OPTIMISED_TASK_SELECTION is 0 then task selection is @@ -269,7 +228,7 @@ count overflows. */ * task should be used in place of the parameter. This macro simply checks to * see if the parameter is NULL and returns a pointer to the appropriate TCB. */ -#define prvGetTCBFromHandle( pxHandle ) ( ( ( pxHandle ) == NULL ) ? ( TCB_t * ) pxCurrentTCB : ( TCB_t * ) ( pxHandle ) ) +#define prvGetTCBFromHandle( pxHandle ) ( ( ( pxHandle ) == NULL ) ? pxCurrentTCB : ( pxHandle ) ) /* The item value of the event list item is normally used to hold the priority of the task to which it belongs (coded to allow it to be held in reverse @@ -290,7 +249,7 @@ to its original value when it is released. */ * and stores task state information, including a pointer to the task's context * (the task's run time environment, including register values) */ -typedef struct tskTaskControlBlock +typedef struct tskTaskControlBlock /* The old naming convention is used to prevent breaking kernel aware debuggers. */ { volatile StackType_t *pxTopOfStack; /*< Points to the location of the last item placed on the tasks stack. THIS MUST BE THE FIRST MEMBER OF THE TCB STRUCT. */ @@ -304,8 +263,8 @@ typedef struct tskTaskControlBlock StackType_t *pxStack; /*< Points to the start of the stack. */ char pcTaskName[ configMAX_TASK_NAME_LEN ];/*< Descriptive name given to the task when created. Facilitates debugging only. */ /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ - #if ( portSTACK_GROWTH > 0 ) - StackType_t *pxEndOfStack; /*< Points to the end of the stack on architectures where the stack grows up from low memory. */ + #if ( ( portSTACK_GROWTH > 0 ) || ( configRECORD_STACK_HIGH_ADDRESS == 1 ) ) + StackType_t *pxEndOfStack; /*< Points to the highest valid address for the stack. */ #endif #if ( portCRITICAL_NESTING_IN_TCB == 1 ) @@ -327,7 +286,7 @@ typedef struct tskTaskControlBlock #endif #if( configNUM_THREAD_LOCAL_STORAGE_POINTERS > 0 ) - void *pvThreadLocalStoragePointers[ configNUM_THREAD_LOCAL_STORAGE_POINTERS ]; + void *pvThreadLocalStoragePointers[ configNUM_THREAD_LOCAL_STORAGE_POINTERS ]; #endif #if( configGENERATE_RUN_TIME_STATS == 1 ) @@ -341,7 +300,10 @@ typedef struct tskTaskControlBlock responsible for resulting newlib operation. User must be familiar with newlib and must provide system-wide implementations of the necessary stubs. Be warned that (at the time of writing) the current newlib design - implements a system-wide malloc() that must be provided with locks. */ + implements a system-wide malloc() that must be provided with locks. + + See the third party link http://www.nadler.com/embedded/newlibAndFreeRTOS.html + for additional information. */ struct _reent xNewLib_reent; #endif @@ -350,9 +312,9 @@ typedef struct tskTaskControlBlock volatile uint8_t ucNotifyState; #endif - /* See the comments above the definition of + /* See the comments in FreeRTOS.h with the definition of tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE. */ - #if( tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE != 0 ) + #if( tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE != 0 ) /*lint !e731 !e9029 Macro has been consolidated for readability reasons. */ uint8_t ucStaticallyAllocated; /*< Set to pdTRUE if the task is a statically allocated to ensure no attempt is made to free the memory. */ #endif @@ -360,18 +322,24 @@ typedef struct tskTaskControlBlock uint8_t ucDelayAborted; #endif + #if( configUSE_POSIX_ERRNO == 1 ) + int iTaskErrno; + #endif + } tskTCB; /* The old tskTCB name is maintained above then typedefed to the new TCB_t name below to enable the use of older kernel aware debuggers. */ typedef tskTCB TCB_t; -/*lint -e956 A manual analysis and inspection has been used to determine which -static variables must be declared volatile. */ +/*lint -save -e956 A manual analysis and inspection has been used to determine +which static variables must be declared volatile. */ +PRIVILEGED_DATA TCB_t * volatile pxCurrentTCB = NULL; -PRIVILEGED_INITIALIZED_DATA TCB_t * volatile pxCurrentTCB = NULL; - -/* Lists for ready and blocked tasks. --------------------*/ +/* Lists for ready and blocked tasks. -------------------- +xDelayedTaskList1 and xDelayedTaskList2 could be move to function scople but +doing so breaks some kernel aware debuggers and debuggers that rely on removing +the static qualifier. */ PRIVILEGED_DATA static List_t pxReadyTasksLists[ configMAX_PRIORITIES ];/*< Prioritised ready tasks. */ PRIVILEGED_DATA static List_t xDelayedTaskList1; /*< Delayed tasks. */ PRIVILEGED_DATA static List_t xDelayedTaskList2; /*< Delayed tasks (two lists are used - one for delays that have overflowed the current tick count. */ @@ -382,7 +350,7 @@ PRIVILEGED_DATA static List_t xPendingReadyList; /*< Tasks that have been r #if( INCLUDE_vTaskDelete == 1 ) PRIVILEGED_DATA static List_t xTasksWaitingTermination; /*< Tasks that have been deleted - but their memory not yet freed. */ - PRIVILEGED_INITIALIZED_DATA static volatile UBaseType_t uxDeletedTasksWaitingCleanUp = ( UBaseType_t ) 0U; + PRIVILEGED_DATA static volatile UBaseType_t uxDeletedTasksWaitingCleanUp = ( UBaseType_t ) 0U; #endif @@ -392,17 +360,23 @@ PRIVILEGED_DATA static List_t xPendingReadyList; /*< Tasks that have been r #endif +/* Global POSIX errno. Its value is changed upon context switching to match +the errno of the currently running task. */ +#if ( configUSE_POSIX_ERRNO == 1 ) + int FreeRTOS_errno = 0; +#endif + /* Other file private variables. --------------------------------*/ -PRIVILEGED_INITIALIZED_DATA static volatile UBaseType_t uxCurrentNumberOfTasks = ( UBaseType_t ) 0U; -PRIVILEGED_INITIALIZED_DATA static volatile TickType_t xTickCount = ( TickType_t ) 0U; -PRIVILEGED_INITIALIZED_DATA static volatile UBaseType_t uxTopReadyPriority = tskIDLE_PRIORITY; -PRIVILEGED_INITIALIZED_DATA static volatile BaseType_t xSchedulerRunning = pdFALSE; -PRIVILEGED_INITIALIZED_DATA static volatile UBaseType_t uxPendedTicks = ( UBaseType_t ) 0U; -PRIVILEGED_INITIALIZED_DATA static volatile BaseType_t xYieldPending = pdFALSE; -PRIVILEGED_INITIALIZED_DATA static volatile BaseType_t xNumOfOverflows = ( BaseType_t ) 0; -PRIVILEGED_INITIALIZED_DATA static UBaseType_t uxTaskNumber = ( UBaseType_t ) 0U; -PRIVILEGED_INITIALIZED_DATA static volatile TickType_t xNextTaskUnblockTime = ( TickType_t ) 0U; /* Initialised to portMAX_DELAY before the scheduler starts. */ -PRIVILEGED_INITIALIZED_DATA static TaskHandle_t xIdleTaskHandle = NULL; /*< Holds the handle of the idle task. The idle task is created automatically when the scheduler is started. */ +PRIVILEGED_DATA static volatile UBaseType_t uxCurrentNumberOfTasks = ( UBaseType_t ) 0U; +PRIVILEGED_DATA static volatile TickType_t xTickCount = ( TickType_t ) configINITIAL_TICK_COUNT; +PRIVILEGED_DATA static volatile UBaseType_t uxTopReadyPriority = tskIDLE_PRIORITY; +PRIVILEGED_DATA static volatile BaseType_t xSchedulerRunning = pdFALSE; +PRIVILEGED_DATA static volatile TickType_t xPendedTicks = ( TickType_t ) 0U; +PRIVILEGED_DATA static volatile BaseType_t xYieldPending = pdFALSE; +PRIVILEGED_DATA static volatile BaseType_t xNumOfOverflows = ( BaseType_t ) 0; +PRIVILEGED_DATA static UBaseType_t uxTaskNumber = ( UBaseType_t ) 0U; +PRIVILEGED_DATA static volatile TickType_t xNextTaskUnblockTime = ( TickType_t ) 0U; /* Initialised to portMAX_DELAY before the scheduler starts. */ +PRIVILEGED_DATA static TaskHandle_t xIdleTaskHandle = NULL; /*< Holds the handle of the idle task. The idle task is created automatically when the scheduler is started. */ /* Context switches are held pending while the scheduler is suspended. Also, interrupts must not manipulate the xStateListItem of a TCB, or any of the @@ -412,30 +386,38 @@ moves the task's event list item into the xPendingReadyList, ready for the kernel to move the task from the pending ready list into the real ready list when the scheduler is unsuspended. The pending ready list itself can only be accessed from a critical section. */ -PRIVILEGED_INITIALIZED_DATA static volatile UBaseType_t uxSchedulerSuspended = ( UBaseType_t ) pdFALSE; +PRIVILEGED_DATA static volatile UBaseType_t uxSchedulerSuspended = ( UBaseType_t ) pdFALSE; #if ( configGENERATE_RUN_TIME_STATS == 1 ) - PRIVILEGED_INITIALIZED_DATA static uint32_t ulTaskSwitchedInTime = 0UL; /*< Holds the value of a timer/counter the last time a task was switched in. */ - PRIVILEGED_INITIALIZED_DATA static uint32_t ulTotalRunTime = 0UL; /*< Holds the total amount of execution time as defined by the run time counter clock. */ + /* Do not move these variables to function scope as doing so prevents the + code working with debuggers that need to remove the static qualifier. */ + PRIVILEGED_DATA static uint32_t ulTaskSwitchedInTime = 0UL; /*< Holds the value of a timer/counter the last time a task was switched in. */ + PRIVILEGED_DATA static uint32_t ulTotalRunTime = 0UL; /*< Holds the total amount of execution time as defined by the run time counter clock. */ #endif -/*lint +e956 */ +/*lint -restore */ /*-----------------------------------------------------------*/ /* Callback function prototypes. --------------------------*/ #if( configCHECK_FOR_STACK_OVERFLOW > 0 ) + extern void vApplicationStackOverflowHook( TaskHandle_t xTask, char *pcTaskName ); + #endif #if( configUSE_TICK_HOOK > 0 ) - extern void vApplicationTickHook( void ); + + extern void vApplicationTickHook( void ); /*lint !e526 Symbol not defined as it is an application callback. */ + #endif #if( configSUPPORT_STATIC_ALLOCATION == 1 ) - extern void vApplicationGetIdleTaskMemory( StaticTask_t **ppxIdleTaskTCBBuffer, StackType_t **ppxIdleTaskStackBuffer, uint32_t *pulIdleTaskStackSize ); + + extern void vApplicationGetIdleTaskMemory( StaticTask_t **ppxIdleTaskTCBBuffer, StackType_t **ppxIdleTaskStackBuffer, uint32_t *pulIdleTaskStackSize ); /*lint !e526 Symbol not defined as it is an application callback. */ + #endif /* File private functions. --------------------------------*/ @@ -446,14 +428,16 @@ PRIVILEGED_INITIALIZED_DATA static volatile UBaseType_t uxSchedulerSuspended = ( * is in any other state. */ #if ( INCLUDE_vTaskSuspend == 1 ) - PRIVILEGED_FUNCTION static BaseType_t prvTaskIsTaskSuspended( const TaskHandle_t xTask ); + + static BaseType_t prvTaskIsTaskSuspended( const TaskHandle_t xTask ) PRIVILEGED_FUNCTION; + #endif /* INCLUDE_vTaskSuspend */ /* * Utility to ready all the lists used by the scheduler. This is called * automatically upon the creation of the first task. */ -PRIVILEGED_FUNCTION static void prvInitialiseTaskLists( void ); +static void prvInitialiseTaskLists( void ) PRIVILEGED_FUNCTION; /* * The idle task, which as all tasks is implemented as a never ending loop. @@ -477,7 +461,7 @@ static portTASK_FUNCTION_PROTO( prvIdleTask, pvParameters ); */ #if ( INCLUDE_vTaskDelete == 1 ) - PRIVILEGED_FUNCTION static void prvDeleteTCB( TCB_t *pxTCB ); + static void prvDeleteTCB( TCB_t *pxTCB ) PRIVILEGED_FUNCTION; #endif @@ -486,13 +470,13 @@ static portTASK_FUNCTION_PROTO( prvIdleTask, pvParameters ); * in the list of tasks waiting to be deleted. If so the task is cleaned up * and its TCB deleted. */ -PRIVILEGED_FUNCTION static void prvCheckTasksWaitingTermination( void ); +static void prvCheckTasksWaitingTermination( void ) PRIVILEGED_FUNCTION; /* * The currently executing task is entering the Blocked state. Add the task to * either the current or the overflow delayed task list. */ -PRIVILEGED_FUNCTION static void prvAddCurrentTaskToDelayedList( TickType_t xTicksToWait, const BaseType_t xCanBlockIndefinitely ); +static void prvAddCurrentTaskToDelayedList( TickType_t xTicksToWait, const BaseType_t xCanBlockIndefinitely ) PRIVILEGED_FUNCTION; /* * Fills an TaskStatus_t structure with information on each task that is @@ -504,7 +488,7 @@ PRIVILEGED_FUNCTION static void prvAddCurrentTaskToDelayedList( TickType_t xTick */ #if ( configUSE_TRACE_FACILITY == 1 ) - PRIVILEGED_FUNCTION static UBaseType_t prvListTasksWithinSingleList( TaskStatus_t *pxTaskStatusArray, List_t *pxList, eTaskState eState ); + static UBaseType_t prvListTasksWithinSingleList( TaskStatus_t *pxTaskStatusArray, List_t *pxList, eTaskState eState ) PRIVILEGED_FUNCTION; #endif @@ -514,7 +498,7 @@ PRIVILEGED_FUNCTION static void prvAddCurrentTaskToDelayedList( TickType_t xTick */ #if ( INCLUDE_xTaskGetHandle == 1 ) - PRIVILEGED_FUNCTION static TCB_t *prvSearchForNameWithinSingleList( List_t *pxList, const char pcNameToQuery[] ); + static TCB_t *prvSearchForNameWithinSingleList( List_t *pxList, const char pcNameToQuery[] ) PRIVILEGED_FUNCTION; #endif @@ -523,9 +507,9 @@ PRIVILEGED_FUNCTION static void prvAddCurrentTaskToDelayedList( TickType_t xTick * This function determines the 'high water mark' of the task stack by * determining how much of the stack remains at the original preset value. */ -#if ( ( configUSE_TRACE_FACILITY == 1 ) || ( INCLUDE_uxTaskGetStackHighWaterMark == 1 ) ) +#if ( ( configUSE_TRACE_FACILITY == 1 ) || ( INCLUDE_uxTaskGetStackHighWaterMark == 1 ) || ( INCLUDE_uxTaskGetStackHighWaterMark2 == 1 ) ) - PRIVILEGED_FUNCTION static uint16_t prvTaskCheckFreeStackSpace( const uint8_t * pucStackByte ); + static configSTACK_DEPTH_TYPE prvTaskCheckFreeStackSpace( const uint8_t * pucStackByte ) PRIVILEGED_FUNCTION; #endif @@ -540,7 +524,7 @@ PRIVILEGED_FUNCTION static void prvAddCurrentTaskToDelayedList( TickType_t xTick */ #if ( configUSE_TICKLESS_IDLE != 0 ) - PRIVILEGED_FUNCTION static TickType_t prvGetExpectedIdleTime( void ); + static TickType_t prvGetExpectedIdleTime( void ) PRIVILEGED_FUNCTION; #endif @@ -556,7 +540,7 @@ static void prvResetNextTaskUnblockTime( void ); * Helper function used to pad task names with spaces when printing out * human readable tables of task information. */ - PRIVILEGED_FUNCTION static char *prvWriteNameToBuffer( char *pcBuffer, const char *pcTaskName ); + static char *prvWriteNameToBuffer( char *pcBuffer, const char *pcTaskName ) PRIVILEGED_FUNCTION; #endif @@ -564,32 +548,43 @@ static void prvResetNextTaskUnblockTime( void ); * Called after a Task_t structure has been allocated either statically or * dynamically to fill in the structure's members. */ -PRIVILEGED_FUNCTION static void prvInitialiseNewTask( TaskFunction_t pxTaskCode, - const char * const pcName, +static void prvInitialiseNewTask( TaskFunction_t pxTaskCode, + const char * const pcName, /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ const uint32_t ulStackDepth, void * const pvParameters, UBaseType_t uxPriority, TaskHandle_t * const pxCreatedTask, TCB_t *pxNewTCB, - const MemoryRegion_t * const xRegions ); /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ + const MemoryRegion_t * const xRegions ) PRIVILEGED_FUNCTION; /* * Called after a new task has been created and initialised to place the task * under the control of the scheduler. */ -PRIVILEGED_FUNCTION static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB ); +static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB ) PRIVILEGED_FUNCTION; + +/* + * freertos_tasks_c_additions_init() should only be called if the user definable + * macro FREERTOS_TASKS_C_ADDITIONS_INIT() is defined, as that is the only macro + * called by the function. + */ +#ifdef FREERTOS_TASKS_C_ADDITIONS_INIT + + static void freertos_tasks_c_additions_init( void ) PRIVILEGED_FUNCTION; + +#endif /*-----------------------------------------------------------*/ #if( configSUPPORT_STATIC_ALLOCATION == 1 ) TaskHandle_t xTaskCreateStatic( TaskFunction_t pxTaskCode, - const char * const pcName, + const char * const pcName, /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ const uint32_t ulStackDepth, void * const pvParameters, UBaseType_t uxPriority, StackType_t * const puxStackBuffer, - StaticTask_t * const pxTaskBuffer ) /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ + StaticTask_t * const pxTaskBuffer ) { TCB_t *pxNewTCB; TaskHandle_t xReturn; @@ -597,20 +592,32 @@ PRIVILEGED_FUNCTION static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB ); configASSERT( puxStackBuffer != NULL ); configASSERT( pxTaskBuffer != NULL ); + #if( configASSERT_DEFINED == 1 ) + { + /* Sanity check that the size of the structure used to declare a + variable of type StaticTask_t equals the size of the real task + structure. */ + volatile size_t xSize = sizeof( StaticTask_t ); + configASSERT( xSize == sizeof( TCB_t ) ); + ( void ) xSize; /* Prevent lint warning when configASSERT() is not used. */ + } + #endif /* configASSERT_DEFINED */ + + if( ( pxTaskBuffer != NULL ) && ( puxStackBuffer != NULL ) ) { /* The memory used for the task's TCB and stack are passed into this function - use them. */ - pxNewTCB = ( TCB_t * ) pxTaskBuffer; /*lint !e740 Unusual cast is ok as the structures are designed to have the same alignment, and the size is checked by an assert. */ + pxNewTCB = ( TCB_t * ) pxTaskBuffer; /*lint !e740 !e9087 Unusual cast is ok as the structures are designed to have the same alignment, and the size is checked by an assert. */ pxNewTCB->pxStack = ( StackType_t * ) puxStackBuffer; - #if( tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE != 0 ) + #if( tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE != 0 ) /*lint !e731 !e9029 Macro has been consolidated for readability reasons. */ { /* Tasks can be created statically or dynamically, so note this task was created statically in case the task is later deleted. */ pxNewTCB->ucStaticallyAllocated = tskSTATICALLY_ALLOCATED_STACK_AND_TCB; } - #endif /* configSUPPORT_DYNAMIC_ALLOCATION */ + #endif /* tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE */ prvInitialiseNewTask( pxTaskCode, pcName, ulStackDepth, pvParameters, uxPriority, &xReturn, pxNewTCB, NULL ); prvAddNewTaskToReadyList( pxNewTCB ); @@ -626,7 +633,53 @@ PRIVILEGED_FUNCTION static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB ); #endif /* SUPPORT_STATIC_ALLOCATION */ /*-----------------------------------------------------------*/ -#if( portUSING_MPU_WRAPPERS == 1 ) +#if( ( portUSING_MPU_WRAPPERS == 1 ) && ( configSUPPORT_STATIC_ALLOCATION == 1 ) ) + + BaseType_t xTaskCreateRestrictedStatic( const TaskParameters_t * const pxTaskDefinition, TaskHandle_t *pxCreatedTask ) + { + TCB_t *pxNewTCB; + BaseType_t xReturn = errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY; + + configASSERT( pxTaskDefinition->puxStackBuffer != NULL ); + configASSERT( pxTaskDefinition->pxTaskBuffer != NULL ); + + if( ( pxTaskDefinition->puxStackBuffer != NULL ) && ( pxTaskDefinition->pxTaskBuffer != NULL ) ) + { + /* Allocate space for the TCB. Where the memory comes from depends + on the implementation of the port malloc function and whether or + not static allocation is being used. */ + pxNewTCB = ( TCB_t * ) pxTaskDefinition->pxTaskBuffer; + + /* Store the stack location in the TCB. */ + pxNewTCB->pxStack = pxTaskDefinition->puxStackBuffer; + + #if( tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE != 0 ) + { + /* Tasks can be created statically or dynamically, so note this + task was created statically in case the task is later deleted. */ + pxNewTCB->ucStaticallyAllocated = tskSTATICALLY_ALLOCATED_STACK_AND_TCB; + } + #endif /* tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE */ + + prvInitialiseNewTask( pxTaskDefinition->pvTaskCode, + pxTaskDefinition->pcName, + ( uint32_t ) pxTaskDefinition->usStackDepth, + pxTaskDefinition->pvParameters, + pxTaskDefinition->uxPriority, + pxCreatedTask, pxNewTCB, + pxTaskDefinition->xRegions ); + + prvAddNewTaskToReadyList( pxNewTCB ); + xReturn = pdPASS; + } + + return xReturn; + } + +#endif /* ( portUSING_MPU_WRAPPERS == 1 ) && ( configSUPPORT_STATIC_ALLOCATION == 1 ) */ +/*-----------------------------------------------------------*/ + +#if( ( portUSING_MPU_WRAPPERS == 1 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) ) BaseType_t xTaskCreateRestricted( const TaskParameters_t * const pxTaskDefinition, TaskHandle_t *pxCreatedTask ) { @@ -647,10 +700,14 @@ PRIVILEGED_FUNCTION static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB ); /* Store the stack location in the TCB. */ pxNewTCB->pxStack = pxTaskDefinition->puxStackBuffer; - /* Tasks can be created statically or dynamically, so note - this task had a statically allocated stack in case it is - later deleted. The TCB was allocated dynamically. */ - pxNewTCB->ucStaticallyAllocated = tskSTATICALLY_ALLOCATED_STACK_ONLY; + #if( tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE != 0 ) + { + /* Tasks can be created statically or dynamically, so note + this task had a statically allocated stack in case it is + later deleted. The TCB was allocated dynamically. */ + pxNewTCB->ucStaticallyAllocated = tskSTATICALLY_ALLOCATED_STACK_ONLY; + } + #endif /* tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE */ prvInitialiseNewTask( pxTaskDefinition->pvTaskCode, pxTaskDefinition->pcName, @@ -674,11 +731,11 @@ PRIVILEGED_FUNCTION static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB ); #if( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) BaseType_t xTaskCreate( TaskFunction_t pxTaskCode, - const char * const pcName, - const uint16_t usStackDepth, + const char * const pcName, /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ + const configSTACK_DEPTH_TYPE usStackDepth, void * const pvParameters, UBaseType_t uxPriority, - TaskHandle_t * const pxCreatedTask ) /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ + TaskHandle_t * const pxCreatedTask ) { TCB_t *pxNewTCB; BaseType_t xReturn; @@ -713,12 +770,12 @@ PRIVILEGED_FUNCTION static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB ); StackType_t *pxStack; /* Allocate space for the stack used by the task being created. */ - pxStack = ( StackType_t * ) pvPortMalloc( ( ( ( size_t ) usStackDepth ) * sizeof( StackType_t ) ) ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */ + pxStack = pvPortMalloc( ( ( ( size_t ) usStackDepth ) * sizeof( StackType_t ) ) ); /*lint !e9079 All values returned by pvPortMalloc() have at least the alignment required by the MCU's stack and this allocation is the stack. */ if( pxStack != NULL ) { /* Allocate space for the TCB. */ - pxNewTCB = ( TCB_t * ) pvPortMalloc( sizeof( TCB_t ) ); /*lint !e961 MISRA exception as the casts are only redundant for some paths. */ + pxNewTCB = ( TCB_t * ) pvPortMalloc( sizeof( TCB_t ) ); /*lint !e9087 !e9079 All values returned by pvPortMalloc() have at least the alignment required by the MCU's stack, and the first member of TCB_t is always a pointer to the task's stack. */ if( pxNewTCB != NULL ) { @@ -741,13 +798,13 @@ PRIVILEGED_FUNCTION static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB ); if( pxNewTCB != NULL ) { - #if( tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE != 0 ) + #if( tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE != 0 ) /*lint !e9029 !e731 Macro has been consolidated for readability reasons. */ { /* Tasks can be created statically or dynamically, so note this task was created dynamically in case it is later deleted. */ pxNewTCB->ucStaticallyAllocated = tskDYNAMICALLY_ALLOCATED_STACK_AND_TCB; } - #endif /* configSUPPORT_STATIC_ALLOCATION */ + #endif /* tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE */ prvInitialiseNewTask( pxTaskCode, pcName, ( uint32_t ) usStackDepth, pvParameters, uxPriority, pxCreatedTask, pxNewTCB, NULL ); prvAddNewTaskToReadyList( pxNewTCB ); @@ -765,13 +822,13 @@ PRIVILEGED_FUNCTION static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB ); /*-----------------------------------------------------------*/ static void prvInitialiseNewTask( TaskFunction_t pxTaskCode, - const char * const pcName, + const char * const pcName, /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ const uint32_t ulStackDepth, void * const pvParameters, UBaseType_t uxPriority, TaskHandle_t * const pxCreatedTask, TCB_t *pxNewTCB, - const MemoryRegion_t * const xRegions ) /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ + const MemoryRegion_t * const xRegions ) { StackType_t *pxTopOfStack; UBaseType_t x; @@ -791,12 +848,12 @@ UBaseType_t x; #endif /* portUSING_MPU_WRAPPERS == 1 */ /* Avoid dependency on memset() if it is not required. */ - #if( ( configCHECK_FOR_STACK_OVERFLOW > 1 ) || ( configUSE_TRACE_FACILITY == 1 ) || ( INCLUDE_uxTaskGetStackHighWaterMark == 1 ) ) + #if( tskSET_NEW_STACKS_TO_KNOWN_VALUE == 1 ) { /* Fill the stack with a known value to assist debugging. */ ( void ) memset( pxNewTCB->pxStack, ( int ) tskSTACK_FILL_BYTE, ( size_t ) ulStackDepth * sizeof( StackType_t ) ); } - #endif /* ( ( configCHECK_FOR_STACK_OVERFLOW > 1 ) || ( ( configUSE_TRACE_FACILITY == 1 ) || ( INCLUDE_uxTaskGetStackHighWaterMark == 1 ) ) ) */ + #endif /* tskSET_NEW_STACKS_TO_KNOWN_VALUE */ /* Calculate the top of stack address. This depends on whether the stack grows from high memory to low (as per the 80x86) or vice versa. @@ -804,11 +861,19 @@ UBaseType_t x; by the port. */ #if( portSTACK_GROWTH < 0 ) { - pxTopOfStack = pxNewTCB->pxStack + ( ulStackDepth - ( uint32_t ) 1 ); - pxTopOfStack = ( StackType_t * ) ( ( ( portPOINTER_SIZE_TYPE ) pxTopOfStack ) & ( ~( ( portPOINTER_SIZE_TYPE ) portBYTE_ALIGNMENT_MASK ) ) ); /*lint !e923 MISRA exception. Avoiding casts between pointers and integers is not practical. Size differences accounted for using portPOINTER_SIZE_TYPE type. */ + pxTopOfStack = &( pxNewTCB->pxStack[ ulStackDepth - ( uint32_t ) 1 ] ); + pxTopOfStack = ( StackType_t * ) ( ( ( portPOINTER_SIZE_TYPE ) pxTopOfStack ) & ( ~( ( portPOINTER_SIZE_TYPE ) portBYTE_ALIGNMENT_MASK ) ) ); /*lint !e923 !e9033 !e9078 MISRA exception. Avoiding casts between pointers and integers is not practical. Size differences accounted for using portPOINTER_SIZE_TYPE type. Checked by assert(). */ /* Check the alignment of the calculated top of stack is correct. */ configASSERT( ( ( ( portPOINTER_SIZE_TYPE ) pxTopOfStack & ( portPOINTER_SIZE_TYPE ) portBYTE_ALIGNMENT_MASK ) == 0UL ) ); + + #if( configRECORD_STACK_HIGH_ADDRESS == 1 ) + { + /* Also record the stack's high address, which may assist + debugging. */ + pxNewTCB->pxEndOfStack = pxTopOfStack; + } + #endif /* configRECORD_STACK_HIGH_ADDRESS */ } #else /* portSTACK_GROWTH */ { @@ -824,26 +889,35 @@ UBaseType_t x; #endif /* portSTACK_GROWTH */ /* Store the task name in the TCB. */ - for( x = ( UBaseType_t ) 0; x < ( UBaseType_t ) configMAX_TASK_NAME_LEN; x++ ) + if( pcName != NULL ) { - pxNewTCB->pcTaskName[ x ] = pcName[ x ]; + for( x = ( UBaseType_t ) 0; x < ( UBaseType_t ) configMAX_TASK_NAME_LEN; x++ ) + { + pxNewTCB->pcTaskName[ x ] = pcName[ x ]; - /* Don't copy all configMAX_TASK_NAME_LEN if the string is shorter than - configMAX_TASK_NAME_LEN characters just in case the memory after the - string is not accessible (extremely unlikely). */ - if( pcName[ x ] == 0x00 ) - { - break; - } - else - { - mtCOVERAGE_TEST_MARKER(); + /* Don't copy all configMAX_TASK_NAME_LEN if the string is shorter than + configMAX_TASK_NAME_LEN characters just in case the memory after the + string is not accessible (extremely unlikely). */ + if( pcName[ x ] == ( char ) 0x00 ) + { + break; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } } + + /* Ensure the name string is terminated in the case that the string length + was greater or equal to configMAX_TASK_NAME_LEN. */ + pxNewTCB->pcTaskName[ configMAX_TASK_NAME_LEN - 1 ] = '\0'; + } + else + { + /* The task has not been given a name, so just ensure there is a NULL + terminator when it is read out. */ + pxNewTCB->pcTaskName[ 0 ] = 0x00; } - - /* Ensure the name string is terminated in the case that the string length - was greater or equal to configMAX_TASK_NAME_LEN. */ - pxNewTCB->pcTaskName[ configMAX_TASK_NAME_LEN - 1 ] = '\0'; /* This is used as an array index so must ensure it's not too large. First remove the privilege bit if one is present. */ @@ -922,7 +996,9 @@ UBaseType_t x; #if ( configUSE_NEWLIB_REENTRANT == 1 ) { - /* Initialise this task's Newlib reent structure. */ + /* Initialise this task's Newlib reent structure. + See the third party link http://www.nadler.com/embedded/newlibAndFreeRTOS.html + for additional information. */ _REENT_INIT_PTR( ( &( pxNewTCB->xNewLib_reent ) ) ); } #endif @@ -936,18 +1012,56 @@ UBaseType_t x; /* Initialize the TCB stack to look as if the task was already running, but had been interrupted by the scheduler. The return address is set to the start of the task function. Once the stack has been initialised - the top of stack variable is updated. */ + the top of stack variable is updated. */ #if( portUSING_MPU_WRAPPERS == 1 ) { - pxNewTCB->pxTopOfStack = pxPortInitialiseStack( pxTopOfStack, pxTaskCode, pvParameters, xRunPrivileged ); + /* If the port has capability to detect stack overflow, + pass the stack end address to the stack initialization + function as well. */ + #if( portHAS_STACK_OVERFLOW_CHECKING == 1 ) + { + #if( portSTACK_GROWTH < 0 ) + { + pxNewTCB->pxTopOfStack = pxPortInitialiseStack( pxTopOfStack, pxNewTCB->pxStack, pxTaskCode, pvParameters, xRunPrivileged ); + } + #else /* portSTACK_GROWTH */ + { + pxNewTCB->pxTopOfStack = pxPortInitialiseStack( pxTopOfStack, pxNewTCB->pxEndOfStack, pxTaskCode, pvParameters, xRunPrivileged ); + } + #endif /* portSTACK_GROWTH */ + } + #else /* portHAS_STACK_OVERFLOW_CHECKING */ + { + pxNewTCB->pxTopOfStack = pxPortInitialiseStack( pxTopOfStack, pxTaskCode, pvParameters, xRunPrivileged ); + } + #endif /* portHAS_STACK_OVERFLOW_CHECKING */ } #else /* portUSING_MPU_WRAPPERS */ { - pxNewTCB->pxTopOfStack = pxPortInitialiseStack( pxTopOfStack, pxTaskCode, pvParameters ); + /* If the port has capability to detect stack overflow, + pass the stack end address to the stack initialization + function as well. */ + #if( portHAS_STACK_OVERFLOW_CHECKING == 1 ) + { + #if( portSTACK_GROWTH < 0 ) + { + pxNewTCB->pxTopOfStack = pxPortInitialiseStack( pxTopOfStack, pxNewTCB->pxStack, pxTaskCode, pvParameters ); + } + #else /* portSTACK_GROWTH */ + { + pxNewTCB->pxTopOfStack = pxPortInitialiseStack( pxTopOfStack, pxNewTCB->pxEndOfStack, pxTaskCode, pvParameters ); + } + #endif /* portSTACK_GROWTH */ + } + #else /* portHAS_STACK_OVERFLOW_CHECKING */ + { + pxNewTCB->pxTopOfStack = pxPortInitialiseStack( pxTopOfStack, pxTaskCode, pvParameters ); + } + #endif /* portHAS_STACK_OVERFLOW_CHECKING */ } #endif /* portUSING_MPU_WRAPPERS */ - if( ( void * ) pxCreatedTask != NULL ) + if( pxCreatedTask != NULL ) { /* Pass the handle out in an anonymous way. The handle can be used to change the created task's priority, delete the created task, etc.*/ @@ -1055,7 +1169,7 @@ static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB ) being deleted. */ pxTCB = prvGetTCBFromHandle( xTaskToDelete ); - /* Remove task from the ready list. */ + /* Remove task from the ready/delayed list. */ if( uxListRemove( &( pxTCB->xStateListItem ) ) == ( UBaseType_t ) 0 ) { taskRESET_READY_PRIORITY( pxTCB->uxPriority ); @@ -1095,6 +1209,10 @@ static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB ) check the xTasksWaitingTermination list. */ ++uxDeletedTasksWaitingCleanUp; + /* Call the delete hook before portPRE_TASK_DELETE_HOOK() as + portPRE_TASK_DELETE_HOOK() does not return in the Win32 port. */ + traceTASK_DELETE( pxTCB ); + /* The pre-delete hook is primarily for the Windows simulator, in which Windows specific clean up operations are performed, after which it is not possible to yield away from this task - @@ -1105,14 +1223,13 @@ static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB ) else { --uxCurrentNumberOfTasks; + traceTASK_DELETE( pxTCB ); prvDeleteTCB( pxTCB ); /* Reset the next expected unblock time in case it referred to the task that has just been deleted. */ prvResetNextTaskUnblockTime(); } - - traceTASK_DELETE( pxTCB ); } taskEXIT_CRITICAL(); @@ -1264,13 +1381,13 @@ static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB ) #endif /* INCLUDE_vTaskDelay */ /*-----------------------------------------------------------*/ -#if( ( INCLUDE_eTaskGetState == 1 ) || ( configUSE_TRACE_FACILITY == 1 ) ) +#if( ( INCLUDE_eTaskGetState == 1 ) || ( configUSE_TRACE_FACILITY == 1 ) || ( INCLUDE_xTaskAbortDelay == 1 ) ) eTaskState eTaskGetState( TaskHandle_t xTask ) { eTaskState eReturn; - List_t *pxStateList; - const TCB_t * const pxTCB = ( TCB_t * ) xTask; + List_t const * pxStateList, *pxDelayedList, *pxOverflowedDelayedList; + const TCB_t * const pxTCB = xTask; configASSERT( pxTCB ); @@ -1283,11 +1400,13 @@ static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB ) { taskENTER_CRITICAL(); { - pxStateList = ( List_t * ) listLIST_ITEM_CONTAINER( &( pxTCB->xStateListItem ) ); + pxStateList = listLIST_ITEM_CONTAINER( &( pxTCB->xStateListItem ) ); + pxDelayedList = pxDelayedTaskList; + pxOverflowedDelayedList = pxOverflowDelayedTaskList; } taskEXIT_CRITICAL(); - if( ( pxStateList == pxDelayedTaskList ) || ( pxStateList == pxOverflowDelayedTaskList ) ) + if( ( pxStateList == pxDelayedList ) || ( pxStateList == pxOverflowedDelayedList ) ) { /* The task being queried is referenced from one of the Blocked lists. */ @@ -1298,11 +1417,30 @@ static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB ) else if( pxStateList == &xSuspendedTaskList ) { /* The task being queried is referenced from the suspended - list. Is it genuinely suspended or is it block + list. Is it genuinely suspended or is it blocked indefinitely? */ if( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) == NULL ) { - eReturn = eSuspended; + #if( configUSE_TASK_NOTIFICATIONS == 1 ) + { + /* The task does not appear on the event list item of + and of the RTOS objects, but could still be in the + blocked state if it is waiting on its notification + rather than waiting on an object. */ + if( pxTCB->ucNotifyState == taskWAITING_NOTIFICATION ) + { + eReturn = eBlocked; + } + else + { + eReturn = eSuspended; + } + } + #else + { + eReturn = eSuspended; + } + #endif } else { @@ -1337,15 +1475,15 @@ static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB ) #if ( INCLUDE_uxTaskPriorityGet == 1 ) - UBaseType_t uxTaskPriorityGet( TaskHandle_t xTask ) + UBaseType_t uxTaskPriorityGet( const TaskHandle_t xTask ) { - TCB_t *pxTCB; + TCB_t const *pxTCB; UBaseType_t uxReturn; taskENTER_CRITICAL(); { - /* If null is passed in here then it is the priority of the that - called uxTaskPriorityGet() that is being queried. */ + /* If null is passed in here then it is the priority of the task + that called uxTaskPriorityGet() that is being queried. */ pxTCB = prvGetTCBFromHandle( xTask ); uxReturn = pxTCB->uxPriority; } @@ -1359,9 +1497,9 @@ static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB ) #if ( INCLUDE_uxTaskPriorityGet == 1 ) - UBaseType_t uxTaskPriorityGetFromISR( TaskHandle_t xTask ) + UBaseType_t uxTaskPriorityGetFromISR( const TaskHandle_t xTask ) { - TCB_t *pxTCB; + TCB_t const *pxTCB; UBaseType_t uxReturn, uxSavedInterruptState; /* RTOS ports that support interrupt nesting have the concept of a @@ -1379,7 +1517,7 @@ static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB ) separate interrupt safe API to ensure interrupt entry is as fast and as simple as possible. More information (albeit Cortex-M specific) is provided on the following link: - http://www.freertos.org/RTOS-Cortex-M3-M4.html */ + https://www.freertos.org/RTOS-Cortex-M3-M4.html */ portASSERT_IF_INTERRUPT_PRIORITY_INVALID(); uxSavedInterruptState = portSET_INTERRUPT_MASK_FROM_ISR(); @@ -1515,14 +1653,14 @@ static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB ) } /* If the task is in the blocked or suspended list we need do - nothing more than change it's priority variable. However, if + nothing more than change its priority variable. However, if the task is in a ready list it needs to be removed and placed in the list appropriate to its new priority. */ if( listIS_CONTAINED_WITHIN( &( pxReadyTasksLists[ uxPriorityUsedOnEntry ] ), &( pxTCB->xStateListItem ) ) != pdFALSE ) { - /* The task is currently in its ready list - remove before adding - it to it's new ready list. As we are in a critical section we - can do this even if the scheduler is suspended. */ + /* The task is currently in its ready list - remove before + adding it to it's new ready list. As we are in a critical + section we can do this even if the scheduler is suspended. */ if( uxListRemove( &( pxTCB->xStateListItem ) ) == ( UBaseType_t ) 0 ) { /* It is known that the task is in its ready list so @@ -1597,6 +1735,17 @@ static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB ) } vListInsertEnd( &xSuspendedTaskList, &( pxTCB->xStateListItem ) ); + + #if( configUSE_TASK_NOTIFICATIONS == 1 ) + { + if( pxTCB->ucNotifyState == taskWAITING_NOTIFICATION ) + { + /* The task was blocked to wait for a notification, but is + now suspended, so no notification was received. */ + pxTCB->ucNotifyState = taskNOT_WAITING_NOTIFICATION; + } + } + #endif } taskEXIT_CRITICAL(); @@ -1628,7 +1777,7 @@ static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB ) /* The scheduler is not running, but the task that was pointed to by pxCurrentTCB has just been suspended and pxCurrentTCB must be adjusted to point to a different task. */ - if( listCURRENT_LIST_LENGTH( &xSuspendedTaskList ) == uxCurrentNumberOfTasks ) + if( listCURRENT_LIST_LENGTH( &xSuspendedTaskList ) == uxCurrentNumberOfTasks ) /*lint !e931 Right has no side effect, just volatile. */ { /* No other tasks are ready, so set pxCurrentTCB back to NULL so when the next task is created pxCurrentTCB will @@ -1656,7 +1805,7 @@ static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB ) static BaseType_t prvTaskIsTaskSuspended( const TaskHandle_t xTask ) { BaseType_t xReturn = pdFALSE; - const TCB_t * const pxTCB = ( TCB_t * ) xTask; + const TCB_t * const pxTCB = xTask; /* Accesses xPendingReadyList so must be called from a critical section. */ @@ -1672,7 +1821,7 @@ static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB ) { /* Is it in the suspended list because it is in the Suspended state, or because is is blocked with no timeout? */ - if( listIS_CONTAINED_WITHIN( NULL, &( pxTCB->xEventListItem ) ) != pdFALSE ) + if( listIS_CONTAINED_WITHIN( NULL, &( pxTCB->xEventListItem ) ) != pdFALSE ) /*lint !e961. The cast is only redundant when NULL is used. */ { xReturn = pdTRUE; } @@ -1701,14 +1850,14 @@ static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB ) void vTaskResume( TaskHandle_t xTaskToResume ) { - TCB_t * const pxTCB = ( TCB_t * ) xTaskToResume; + TCB_t * const pxTCB = xTaskToResume; /* It does not make sense to resume the calling task. */ configASSERT( xTaskToResume ); /* The parameter cannot be NULL as it is impossible to resume the currently executing task. */ - if( ( pxTCB != NULL ) && ( pxTCB != pxCurrentTCB ) ) + if( ( pxTCB != pxCurrentTCB ) && ( pxTCB != NULL ) ) { taskENTER_CRITICAL(); { @@ -1716,12 +1865,12 @@ static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB ) { traceTASK_RESUME( pxTCB ); - /* As we are in a critical section we can access the ready - lists even if the scheduler is suspended. */ + /* The ready list can be accessed even if the scheduler is + suspended because this is inside a critical section. */ ( void ) uxListRemove( &( pxTCB->xStateListItem ) ); prvAddTaskToReadyList( pxTCB ); - /* We may have just resumed a higher priority task. */ + /* A higher priority task may have just been resumed. */ if( pxTCB->uxPriority >= pxCurrentTCB->uxPriority ) { /* This yield may not cause the task just resumed to run, @@ -1756,7 +1905,7 @@ static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB ) BaseType_t xTaskResumeFromISR( TaskHandle_t xTaskToResume ) { BaseType_t xYieldRequired = pdFALSE; - TCB_t * const pxTCB = ( TCB_t * ) xTaskToResume; + TCB_t * const pxTCB = xTaskToResume; UBaseType_t uxSavedInterruptStatus; configASSERT( xTaskToResume ); @@ -1776,7 +1925,7 @@ static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB ) separate interrupt safe API to ensure interrupt entry is as fast and as simple as possible. More information (albeit Cortex-M specific) is provided on the following link: - http://www.freertos.org/RTOS-Cortex-M3-M4.html */ + https://www.freertos.org/RTOS-Cortex-M3-M4.html */ portASSERT_IF_INTERRUPT_PRIORITY_INVALID(); uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR(); @@ -1838,10 +1987,10 @@ BaseType_t xReturn; address of the RAM then create the idle task. */ vApplicationGetIdleTaskMemory( &pxIdleTaskTCBBuffer, &pxIdleTaskStackBuffer, &ulIdleTaskStackSize ); xIdleTaskHandle = xTaskCreateStatic( prvIdleTask, - "IDLE", + configIDLE_TASK_NAME, ulIdleTaskStackSize, - ( void * ) NULL, - ( tskIDLE_PRIORITY | portPRIVILEGE_BIT ), + ( void * ) NULL, /*lint !e961. The cast is not redundant for all compilers. */ + portPRIVILEGE_BIT, /* In effect ( tskIDLE_PRIORITY | portPRIVILEGE_BIT ), but tskIDLE_PRIORITY is zero. */ pxIdleTaskStackBuffer, pxIdleTaskTCBBuffer ); /*lint !e961 MISRA exception, justified as it is not a redundant explicit cast to all supported compilers. */ @@ -1858,9 +2007,10 @@ BaseType_t xReturn; { /* The Idle task is being created using dynamically allocated RAM. */ xReturn = xTaskCreate( prvIdleTask, - "IDLE", configMINIMAL_STACK_SIZE, + configIDLE_TASK_NAME, + configMINIMAL_STACK_SIZE, ( void * ) NULL, - ( tskIDLE_PRIORITY | portPRIVILEGE_BIT ), + portPRIVILEGE_BIT, /* In effect ( tskIDLE_PRIORITY | portPRIVILEGE_BIT ), but tskIDLE_PRIORITY is zero. */ &xIdleTaskHandle ); /*lint !e961 MISRA exception, justified as it is not a redundant explicit cast to all supported compilers. */ } #endif /* configSUPPORT_STATIC_ALLOCATION */ @@ -1880,6 +2030,15 @@ BaseType_t xReturn; if( xReturn == pdPASS ) { + /* freertos_tasks_c_additions_init() should only be called if the user + definable macro FREERTOS_TASKS_C_ADDITIONS_INIT() is defined, as that is + the only macro called by the function. */ + #ifdef FREERTOS_TASKS_C_ADDITIONS_INIT + { + freertos_tasks_c_additions_init(); + } + #endif + /* Interrupts are turned off here, to ensure a tick does not occur before or during the call to xPortStartScheduler(). The stacks of the created tasks contain a status word with interrupts switched on @@ -1890,20 +2049,27 @@ BaseType_t xReturn; #if ( configUSE_NEWLIB_REENTRANT == 1 ) { /* Switch Newlib's _impure_ptr variable to point to the _reent - structure specific to the task that will run first. */ + structure specific to the task that will run first. + See the third party link http://www.nadler.com/embedded/newlibAndFreeRTOS.html + for additional information. */ _impure_ptr = &( pxCurrentTCB->xNewLib_reent ); } #endif /* configUSE_NEWLIB_REENTRANT */ xNextTaskUnblockTime = portMAX_DELAY; xSchedulerRunning = pdTRUE; - xTickCount = ( TickType_t ) 0U; + xTickCount = ( TickType_t ) configINITIAL_TICK_COUNT; /* If configGENERATE_RUN_TIME_STATS is defined then the following macro must be defined to configure the timer/counter used to generate - the run time counter time base. */ + the run time counter time base. NOTE: If configGENERATE_RUN_TIME_STATS + is set to 0 and the following line fails to build then ensure you do not + have portCONFIGURE_TIMER_FOR_RUN_TIME_STATS() defined in your + FreeRTOSConfig.h file. */ portCONFIGURE_TIMER_FOR_RUN_TIME_STATS(); + traceTASK_SWITCHED_IN(); + /* Setting up the timer tick is hardware specific and thus in the portable interface. */ if( xPortStartScheduler() != pdFALSE ) @@ -1947,7 +2113,18 @@ void vTaskSuspendAll( void ) BaseType_t. Please read Richard Barry's reply in the following link to a post in the FreeRTOS support forum before reporting this as a bug! - http://goo.gl/wu4acr */ + + /* portSOFRWARE_BARRIER() is only implemented for emulated/simulated ports that + do not otherwise exhibit real time behaviour. */ + portSOFTWARE_BARRIER(); + + /* The scheduler is suspended if uxSchedulerSuspended is non-zero. An increment + is used to allow calls to vTaskSuspendAll() to nest. */ ++uxSchedulerSuspended; + + /* Enforces ordering for ports and optimised compilers that may otherwise place + the above increment elsewhere. */ + portMEMORY_BARRIER(); } /*----------------------------------------------------------*/ @@ -2040,7 +2217,7 @@ BaseType_t xAlreadyYielded = pdFALSE; appropriate ready list. */ while( listLIST_IS_EMPTY( &xPendingReadyList ) == pdFALSE ) { - pxTCB = ( TCB_t * ) listGET_OWNER_OF_HEAD_ENTRY( ( &xPendingReadyList ) ); + pxTCB = listGET_OWNER_OF_HEAD_ENTRY( ( &xPendingReadyList ) ); /*lint !e9079 void * is used as this macro is used with timers and co-routines too. Alignment is known to be fine as the type of the pointer stored and retrieved is the same. */ ( void ) uxListRemove( &( pxTCB->xEventListItem ) ); ( void ) uxListRemove( &( pxTCB->xStateListItem ) ); prvAddTaskToReadyList( pxTCB ); @@ -2073,9 +2250,9 @@ BaseType_t xAlreadyYielded = pdFALSE; not slip, and that any delayed tasks are resumed at the correct time. */ { - UBaseType_t uxPendedCounts = uxPendedTicks; /* Non-volatile copy. */ + TickType_t xPendedCounts = xPendedTicks; /* Non-volatile copy. */ - if( uxPendedCounts > ( UBaseType_t ) 0U ) + if( xPendedCounts > ( TickType_t ) 0U ) { do { @@ -2087,10 +2264,10 @@ BaseType_t xAlreadyYielded = pdFALSE; { mtCOVERAGE_TEST_MARKER(); } - --uxPendedCounts; - } while( uxPendedCounts > ( UBaseType_t ) 0U ); + --xPendedCounts; + } while( xPendedCounts > ( TickType_t ) 0U ); - uxPendedTicks = 0; + xPendedTicks = 0; } else { @@ -2157,7 +2334,7 @@ UBaseType_t uxSavedInterruptStatus; system call interrupt priority. FreeRTOS maintains a separate interrupt safe API to ensure interrupt entry is as fast and as simple as possible. More information (albeit Cortex-M specific) is provided on the following - link: http://www.freertos.org/RTOS-Cortex-M3-M4.html */ + link: https://www.freertos.org/RTOS-Cortex-M3-M4.html */ portASSERT_IF_INTERRUPT_PRIORITY_INVALID(); uxSavedInterruptStatus = portTICK_TYPE_SET_INTERRUPT_MASK_FROM_ISR(); @@ -2197,19 +2374,21 @@ TCB_t *pxTCB; TCB_t *pxNextTCB, *pxFirstTCB, *pxReturn = NULL; UBaseType_t x; char cNextChar; + BaseType_t xBreakLoop; /* This function is called with the scheduler suspended. */ if( listCURRENT_LIST_LENGTH( pxList ) > ( UBaseType_t ) 0 ) { - listGET_OWNER_OF_NEXT_ENTRY( pxFirstTCB, pxList ); + listGET_OWNER_OF_NEXT_ENTRY( pxFirstTCB, pxList ); /*lint !e9079 void * is used as this macro is used with timers and co-routines too. Alignment is known to be fine as the type of the pointer stored and retrieved is the same. */ do { - listGET_OWNER_OF_NEXT_ENTRY( pxNextTCB, pxList ); + listGET_OWNER_OF_NEXT_ENTRY( pxNextTCB, pxList ); /*lint !e9079 void * is used as this macro is used with timers and co-routines too. Alignment is known to be fine as the type of the pointer stored and retrieved is the same. */ /* Check each character in the name looking for a match or mismatch. */ + xBreakLoop = pdFALSE; for( x = ( UBaseType_t ) 0; x < ( UBaseType_t ) configMAX_TASK_NAME_LEN; x++ ) { cNextChar = pxNextTCB->pcTaskName[ x ]; @@ -2217,19 +2396,24 @@ TCB_t *pxTCB; if( cNextChar != pcNameToQuery[ x ] ) { /* Characters didn't match. */ - break; + xBreakLoop = pdTRUE; } - else if( cNextChar == 0x00 ) + else if( cNextChar == ( char ) 0x00 ) { /* Both strings terminated, a match must have been found. */ pxReturn = pxNextTCB; - break; + xBreakLoop = pdTRUE; } else { mtCOVERAGE_TEST_MARKER(); } + + if( xBreakLoop != pdFALSE ) + { + break; + } } if( pxReturn != NULL ) @@ -2310,7 +2494,7 @@ TCB_t *pxTCB; } ( void ) xTaskResumeAll(); - return ( TaskHandle_t ) pxTCB; + return pxTCB; } #endif /* INCLUDE_xTaskGetHandle */ @@ -2422,12 +2606,30 @@ implementations require configUSE_TICKLESS_IDLE to be set to a value other than #endif /* configUSE_TICKLESS_IDLE */ /*----------------------------------------------------------*/ +BaseType_t xTaskCatchUpTicks( TickType_t xTicksToCatchUp ) +{ +BaseType_t xYieldRequired = pdFALSE; + + /* Must not be called with the scheduler suspended as the implementation + relies on xPendedTicks being wound down to 0 in xTaskResumeAll(). */ + configASSERT( uxSchedulerSuspended == 0 ); + + /* Use xPendedTicks to mimic xTicksToCatchUp number of ticks occurring when + the scheduler is suspended so the ticks are executed in xTaskResumeAll(). */ + vTaskSuspendAll(); + xPendedTicks += xTicksToCatchUp; + xYieldRequired = xTaskResumeAll(); + + return xYieldRequired; +} +/*----------------------------------------------------------*/ + #if ( INCLUDE_xTaskAbortDelay == 1 ) BaseType_t xTaskAbortDelay( TaskHandle_t xTask ) { - TCB_t *pxTCB = ( TCB_t * ) xTask; - BaseType_t xReturn = pdFALSE; + TCB_t *pxTCB = xTask; + BaseType_t xReturn; configASSERT( pxTCB ); @@ -2437,6 +2639,8 @@ implementations require configUSE_TICKLESS_IDLE to be set to a value other than it is actually in the Blocked state. */ if( eTaskGetState( xTask ) == eBlocked ) { + xReturn = pdPASS; + /* Remove the reference to the task from the blocked list. An interrupt won't touch the xStateListItem because the scheduler is suspended. */ @@ -2451,6 +2655,10 @@ implementations require configUSE_TICKLESS_IDLE to be set to a value other than if( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) != NULL ) { ( void ) uxListRemove( &( pxTCB->xEventListItem ) ); + + /* This lets the task know it was forcibly removed from the + blocked state so it should not re-evaluate its block time and + then block again. */ pxTCB->ucDelayAborted = pdTRUE; } else @@ -2485,10 +2693,10 @@ implementations require configUSE_TICKLESS_IDLE to be set to a value other than } else { - mtCOVERAGE_TEST_MARKER(); + xReturn = pdFAIL; } } - xTaskResumeAll(); + ( void ) xTaskResumeAll(); return xReturn; } @@ -2510,13 +2718,13 @@ BaseType_t xSwitchRequired = pdFALSE; { /* Minor optimisation. The tick count cannot change in this block. */ - const TickType_t xConstTickCount = xTickCount + 1; + const TickType_t xConstTickCount = xTickCount + ( TickType_t ) 1; /* Increment the RTOS tick, switching the delayed and overflowed delayed lists if it wraps to 0. */ xTickCount = xConstTickCount; - if( xConstTickCount == ( TickType_t ) 0U ) + if( xConstTickCount == ( TickType_t ) 0U ) /*lint !e774 'if' does not always evaluate to false as it is looking for an overflow. */ { taskSWITCH_DELAYED_LISTS(); } @@ -2549,7 +2757,7 @@ BaseType_t xSwitchRequired = pdFALSE; item at the head of the delayed list. This is the time at which the task at the head of the delayed list must be removed from the Blocked state. */ - pxTCB = ( TCB_t * ) listGET_OWNER_OF_HEAD_ENTRY( pxDelayedTaskList ); + pxTCB = listGET_OWNER_OF_HEAD_ENTRY( pxDelayedTaskList ); /*lint !e9079 void * is used as this macro is used with timers and co-routines too. Alignment is known to be fine as the type of the pointer stored and retrieved is the same. */ xItemValue = listGET_LIST_ITEM_VALUE( &( pxTCB->xStateListItem ) ); if( xConstTickCount < xItemValue ) @@ -2560,7 +2768,7 @@ BaseType_t xSwitchRequired = pdFALSE; state - so record the item value in xNextTaskUnblockTime. */ xNextTaskUnblockTime = xItemValue; - break; + break; /*lint !e9011 Code structure here is deedmed easier to understand with multiple breaks. */ } else { @@ -2627,7 +2835,7 @@ BaseType_t xSwitchRequired = pdFALSE; { /* Guard against the tick hook being called when the pended tick count is being unwound (when the scheduler is being unlocked). */ - if( uxPendedTicks == ( UBaseType_t ) 0U ) + if( xPendedTicks == ( TickType_t ) 0 ) { vApplicationTickHook(); } @@ -2637,10 +2845,23 @@ BaseType_t xSwitchRequired = pdFALSE; } } #endif /* configUSE_TICK_HOOK */ + + #if ( configUSE_PREEMPTION == 1 ) + { + if( xYieldPending != pdFALSE ) + { + xSwitchRequired = pdTRUE; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + #endif /* configUSE_PREEMPTION */ } else { - ++uxPendedTicks; + ++xPendedTicks; /* The tick hook gets called at regular intervals, even if the scheduler is locked. */ @@ -2651,19 +2872,6 @@ BaseType_t xSwitchRequired = pdFALSE; #endif } - #if ( configUSE_PREEMPTION == 1 ) - { - if( xYieldPending != pdFALSE ) - { - xSwitchRequired = pdTRUE; - } - else - { - mtCOVERAGE_TEST_MARKER(); - } - } - #endif /* configUSE_PREEMPTION */ - return xSwitchRequired; } /*-----------------------------------------------------------*/ @@ -2682,13 +2890,15 @@ BaseType_t xSwitchRequired = pdFALSE; } else { - xTCB = ( TCB_t * ) xTask; + xTCB = xTask; } /* Save the hook function in the TCB. A critical section is required as the value can be accessed from an interrupt. */ taskENTER_CRITICAL(); + { xTCB->pxTaskTag = pxHookFunction; + } taskEXIT_CRITICAL(); } @@ -2699,24 +2909,17 @@ BaseType_t xSwitchRequired = pdFALSE; TaskHookFunction_t xTaskGetApplicationTaskTag( TaskHandle_t xTask ) { - TCB_t *xTCB; + TCB_t *pxTCB; TaskHookFunction_t xReturn; - /* If xTask is NULL then we are setting our own task hook. */ - if( xTask == NULL ) - { - xTCB = ( TCB_t * ) pxCurrentTCB; - } - else - { - xTCB = ( TCB_t * ) xTask; - } + /* If xTask is NULL then set the calling task's hook. */ + pxTCB = prvGetTCBFromHandle( xTask ); /* Save the hook function in the TCB. A critical section is required as the value can be accessed from an interrupt. */ taskENTER_CRITICAL(); { - xReturn = xTCB->pxTaskTag; + xReturn = pxTCB->pxTaskTag; } taskEXIT_CRITICAL(); @@ -2726,6 +2929,31 @@ BaseType_t xSwitchRequired = pdFALSE; #endif /* configUSE_APPLICATION_TASK_TAG */ /*-----------------------------------------------------------*/ +#if ( configUSE_APPLICATION_TASK_TAG == 1 ) + + TaskHookFunction_t xTaskGetApplicationTaskTagFromISR( TaskHandle_t xTask ) + { + TCB_t *pxTCB; + TaskHookFunction_t xReturn; + UBaseType_t uxSavedInterruptStatus; + + /* If xTask is NULL then set the calling task's hook. */ + pxTCB = prvGetTCBFromHandle( xTask ); + + /* Save the hook function in the TCB. A critical section is required as + the value can be accessed from an interrupt. */ + uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR(); + { + xReturn = pxTCB->pxTaskTag; + } + portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus ); + + return xReturn; + } + +#endif /* configUSE_APPLICATION_TASK_TAG */ +/*-----------------------------------------------------------*/ + #if ( configUSE_APPLICATION_TASK_TAG == 1 ) BaseType_t xTaskCallApplicationTaskHook( TaskHandle_t xTask, void *pvParameter ) @@ -2736,11 +2964,11 @@ BaseType_t xSwitchRequired = pdFALSE; /* If xTask is NULL then we are calling our own task hook. */ if( xTask == NULL ) { - xTCB = ( TCB_t * ) pxCurrentTCB; + xTCB = pxCurrentTCB; } else { - xTCB = ( TCB_t * ) xTask; + xTCB = xTask; } if( xTCB->pxTaskTag != NULL ) @@ -2773,43 +3001,59 @@ void vTaskSwitchContext( void ) #if ( configGENERATE_RUN_TIME_STATS == 1 ) { - #ifdef portALT_GET_RUN_TIME_COUNTER_VALUE - portALT_GET_RUN_TIME_COUNTER_VALUE( ulTotalRunTime ); - #else - ulTotalRunTime = portGET_RUN_TIME_COUNTER_VALUE(); - #endif + #ifdef portALT_GET_RUN_TIME_COUNTER_VALUE + portALT_GET_RUN_TIME_COUNTER_VALUE( ulTotalRunTime ); + #else + ulTotalRunTime = portGET_RUN_TIME_COUNTER_VALUE(); + #endif - /* Add the amount of time the task has been running to the - accumulated time so far. The time the task started running was - stored in ulTaskSwitchedInTime. Note that there is no overflow - protection here so count values are only valid until the timer - overflows. The guard against negative values is to protect - against suspect run time stat counter implementations - which - are provided by the application, not the kernel. */ - if( ulTotalRunTime > ulTaskSwitchedInTime ) - { - pxCurrentTCB->ulRunTimeCounter += ( ulTotalRunTime - ulTaskSwitchedInTime ); - } - else - { - mtCOVERAGE_TEST_MARKER(); - } - ulTaskSwitchedInTime = ulTotalRunTime; + /* Add the amount of time the task has been running to the + accumulated time so far. The time the task started running was + stored in ulTaskSwitchedInTime. Note that there is no overflow + protection here so count values are only valid until the timer + overflows. The guard against negative values is to protect + against suspect run time stat counter implementations - which + are provided by the application, not the kernel. */ + if( ulTotalRunTime > ulTaskSwitchedInTime ) + { + pxCurrentTCB->ulRunTimeCounter += ( ulTotalRunTime - ulTaskSwitchedInTime ); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + ulTaskSwitchedInTime = ulTotalRunTime; } #endif /* configGENERATE_RUN_TIME_STATS */ /* Check for stack overflow, if configured. */ taskCHECK_FOR_STACK_OVERFLOW(); + /* Before the currently running task is switched out, save its errno. */ + #if( configUSE_POSIX_ERRNO == 1 ) + { + pxCurrentTCB->iTaskErrno = FreeRTOS_errno; + } + #endif + /* Select a new task to run using either the generic C or port optimised asm code. */ - taskSELECT_HIGHEST_PRIORITY_TASK(); + taskSELECT_HIGHEST_PRIORITY_TASK(); /*lint !e9079 void * is used as this macro is used with timers and co-routines too. Alignment is known to be fine as the type of the pointer stored and retrieved is the same. */ traceTASK_SWITCHED_IN(); + /* After the new task is switched in, update the global errno. */ + #if( configUSE_POSIX_ERRNO == 1 ) + { + FreeRTOS_errno = pxCurrentTCB->iTaskErrno; + } + #endif + #if ( configUSE_NEWLIB_REENTRANT == 1 ) { /* Switch Newlib's _impure_ptr variable to point to the _reent - structure specific to this task. */ + structure specific to this task. + See the third party link http://www.nadler.com/embedded/newlibAndFreeRTOS.html + for additional information. */ _impure_ptr = &( pxCurrentTCB->xNewLib_reent ); } #endif /* configUSE_NEWLIB_REENTRANT */ @@ -2909,7 +3153,7 @@ BaseType_t xReturn; This function assumes that a check has already been made to ensure that pxEventList is not empty. */ - pxUnblockedTCB = ( TCB_t * ) listGET_OWNER_OF_HEAD_ENTRY( pxEventList ); + pxUnblockedTCB = listGET_OWNER_OF_HEAD_ENTRY( pxEventList ); /*lint !e9079 void * is used as this macro is used with timers and co-routines too. Alignment is known to be fine as the type of the pointer stored and retrieved is the same. */ configASSERT( pxUnblockedTCB ); ( void ) uxListRemove( &( pxUnblockedTCB->xEventListItem ) ); @@ -2917,6 +3161,20 @@ BaseType_t xReturn; { ( void ) uxListRemove( &( pxUnblockedTCB->xStateListItem ) ); prvAddTaskToReadyList( pxUnblockedTCB ); + + #if( configUSE_TICKLESS_IDLE != 0 ) + { + /* If a task is blocked on a kernel object then xNextTaskUnblockTime + might be set to the blocked task's time out time. If the task is + unblocked for a reason other than a timeout xNextTaskUnblockTime is + normally left unchanged, because it is automatically reset to a new + value when the tick count equals xNextTaskUnblockTime. However if + tickless idling is used it might be more important to enter sleep mode + at the earliest possible time - so reset xNextTaskUnblockTime here to + ensure it is updated at the earliest possible time. */ + prvResetNextTaskUnblockTime(); + } + #endif } else { @@ -2941,6 +3199,27 @@ BaseType_t xReturn; xReturn = pdFALSE; } + return xReturn; +} +/*-----------------------------------------------------------*/ + +void vTaskRemoveFromUnorderedEventList( ListItem_t * pxEventListItem, const TickType_t xItemValue ) +{ +TCB_t *pxUnblockedTCB; + + /* THIS FUNCTION MUST BE CALLED WITH THE SCHEDULER SUSPENDED. It is used by + the event flags implementation. */ + configASSERT( uxSchedulerSuspended != pdFALSE ); + + /* Store the new item value in the event list. */ + listSET_LIST_ITEM_VALUE( pxEventListItem, xItemValue | taskEVENT_LIST_ITEM_VALUE_IN_USE ); + + /* Remove the event list form the event flag. Interrupts do not access + event flags. */ + pxUnblockedTCB = listGET_LIST_ITEM_OWNER( pxEventListItem ); /*lint !e9079 void * is used as this macro is used with timers and co-routines too. Alignment is known to be fine as the type of the pointer stored and retrieved is the same. */ + configASSERT( pxUnblockedTCB ); + ( void ) uxListRemove( pxEventListItem ); + #if( configUSE_TICKLESS_IDLE != 0 ) { /* If a task is blocked on a kernel object then xNextTaskUnblockTime @@ -2955,28 +3234,6 @@ BaseType_t xReturn; } #endif - return xReturn; -} -/*-----------------------------------------------------------*/ - -BaseType_t xTaskRemoveFromUnorderedEventList( ListItem_t * pxEventListItem, const TickType_t xItemValue ) -{ -TCB_t *pxUnblockedTCB; -BaseType_t xReturn; - - /* THIS FUNCTION MUST BE CALLED WITH THE SCHEDULER SUSPENDED. It is used by - the event flags implementation. */ - configASSERT( uxSchedulerSuspended != pdFALSE ); - - /* Store the new item value in the event list. */ - listSET_LIST_ITEM_VALUE( pxEventListItem, xItemValue | taskEVENT_LIST_ITEM_VALUE_IN_USE ); - - /* Remove the event list form the event flag. Interrupts do not access - event flags. */ - pxUnblockedTCB = ( TCB_t * ) listGET_LIST_ITEM_OWNER( pxEventListItem ); - configASSERT( pxUnblockedTCB ); - ( void ) uxListRemove( pxEventListItem ); - /* Remove the task from the delayed list and add it to the ready list. The scheduler is suspended so interrupts will not be accessing the ready lists. */ @@ -2985,28 +3242,30 @@ BaseType_t xReturn; if( pxUnblockedTCB->uxPriority > pxCurrentTCB->uxPriority ) { - /* Return true if the task removed from the event list has - a higher priority than the calling task. This allows - the calling task to know if it should force a context - switch now. */ - xReturn = pdTRUE; - - /* Mark that a yield is pending in case the user is not using the - "xHigherPriorityTaskWoken" parameter to an ISR safe FreeRTOS function. */ + /* The unblocked task has a priority above that of the calling task, so + a context switch is required. This function is called with the + scheduler suspended so xYieldPending is set so the context switch + occurs immediately that the scheduler is resumed (unsuspended). */ xYieldPending = pdTRUE; } - else - { - xReturn = pdFALSE; - } - - return xReturn; } /*-----------------------------------------------------------*/ void vTaskSetTimeOutState( TimeOut_t * const pxTimeOut ) { configASSERT( pxTimeOut ); + taskENTER_CRITICAL(); + { + pxTimeOut->xOverflowCount = xNumOfOverflows; + pxTimeOut->xTimeOnEntering = xTickCount; + } + taskEXIT_CRITICAL(); +} +/*-----------------------------------------------------------*/ + +void vTaskInternalSetTimeOutState( TimeOut_t * const pxTimeOut ) +{ + /* For internal use only as it does not use a critical section. */ pxTimeOut->xOverflowCount = xNumOfOverflows; pxTimeOut->xTimeOnEntering = xTickCount; } @@ -3023,9 +3282,10 @@ BaseType_t xReturn; { /* Minor optimisation. The tick count cannot change in this block. */ const TickType_t xConstTickCount = xTickCount; + const TickType_t xElapsedTime = xConstTickCount - pxTimeOut->xTimeOnEntering; #if( INCLUDE_xTaskAbortDelay == 1 ) - if( pxCurrentTCB->ucDelayAborted != pdFALSE ) + if( pxCurrentTCB->ucDelayAborted != ( uint8_t ) pdFALSE ) { /* The delay was aborted, which is not the same as a time out, but has the same result. */ @@ -3055,15 +3315,16 @@ BaseType_t xReturn; was called. */ xReturn = pdTRUE; } - else if( ( ( TickType_t ) ( xConstTickCount - pxTimeOut->xTimeOnEntering ) ) < *pxTicksToWait ) /*lint !e961 Explicit casting is only redundant with some compilers, whereas others require it to prevent integer conversion errors. */ + else if( xElapsedTime < *pxTicksToWait ) /*lint !e961 Explicit casting is only redundant with some compilers, whereas others require it to prevent integer conversion errors. */ { /* Not a genuine timeout. Adjust parameters for time remaining. */ - *pxTicksToWait -= ( xConstTickCount - pxTimeOut->xTimeOnEntering ); - vTaskSetTimeOutState( pxTimeOut ); + *pxTicksToWait -= xElapsedTime; + vTaskInternalSetTimeOutState( pxTimeOut ); xReturn = pdFALSE; } else { + *pxTicksToWait = 0; xReturn = pdTRUE; } } @@ -3084,11 +3345,11 @@ void vTaskMissedYield( void ) UBaseType_t uxTaskGetTaskNumber( TaskHandle_t xTask ) { UBaseType_t uxReturn; - TCB_t *pxTCB; + TCB_t const *pxTCB; if( xTask != NULL ) { - pxTCB = ( TCB_t * ) xTask; + pxTCB = xTask; uxReturn = pxTCB->uxTaskNumber; } else @@ -3106,11 +3367,11 @@ void vTaskMissedYield( void ) void vTaskSetTaskNumber( TaskHandle_t xTask, const UBaseType_t uxHandle ) { - TCB_t *pxTCB; + TCB_t * pxTCB; if( xTask != NULL ) { - pxTCB = ( TCB_t * ) xTask; + pxTCB = xTask; pxTCB->uxTaskNumber = uxHandle; } } @@ -3136,6 +3397,11 @@ static portTASK_FUNCTION( prvIdleTask, pvParameters ) /** THIS IS THE RTOS IDLE TASK - WHICH IS CREATED AUTOMATICALLY WHEN THE SCHEDULER IS STARTED. **/ + /* In case a task that has a secure context deletes itself, in which case + the idle task is responsible for deleting the task's secure context, if + any. */ + portALLOCATE_SECURE_CONTEXT( configMINIMAL_SECURE_STACK_SIZE ); + for( ;; ) { /* See if any tasks have deleted themselves - if so then the idle task @@ -3212,6 +3478,11 @@ static portTASK_FUNCTION( prvIdleTask, pvParameters ) configASSERT( xNextTaskUnblockTime >= xTickCount ); xExpectedIdleTime = prvGetExpectedIdleTime(); + /* Define the following macro to set xExpectedIdleTime to 0 + if the application does not want + portSUPPRESS_TICKS_AND_SLEEP() to be called. */ + configPRE_SUPPRESS_TICKS_AND_SLEEP_PROCESSING( xExpectedIdleTime ); + if( xExpectedIdleTime >= configEXPECTED_IDLE_TIME_BEFORE_SLEEP ) { traceLOW_POWER_IDLE_BEGIN(); @@ -3243,6 +3514,8 @@ static portTASK_FUNCTION( prvIdleTask, pvParameters ) const UBaseType_t uxNonApplicationTasks = 1; eSleepModeStatus eReturn = eStandardSleep; + /* This function must be called from a critical section. */ + if( listCURRENT_LIST_LENGTH( &xPendingReadyList ) != 0 ) { /* A task was made ready while the scheduler was suspended. */ @@ -3284,6 +3557,7 @@ static portTASK_FUNCTION( prvIdleTask, pvParameters ) if( xIndex < configNUM_THREAD_LOCAL_STORAGE_POINTERS ) { pxTCB = prvGetTCBFromHandle( xTaskToSet ); + configASSERT( pxTCB != NULL ); pxTCB->pvThreadLocalStoragePointers[ xIndex ] = pvValue; } } @@ -3369,37 +3643,22 @@ static void prvCheckTasksWaitingTermination( void ) #if ( INCLUDE_vTaskDelete == 1 ) { - BaseType_t xListIsEmpty; + TCB_t *pxTCB; - /* ucTasksDeleted is used to prevent vTaskSuspendAll() being called - too often in the idle task. */ + /* uxDeletedTasksWaitingCleanUp is used to prevent taskENTER_CRITICAL() + being called too often in the idle task. */ while( uxDeletedTasksWaitingCleanUp > ( UBaseType_t ) 0U ) { - vTaskSuspendAll(); + taskENTER_CRITICAL(); { - xListIsEmpty = listLIST_IS_EMPTY( &xTasksWaitingTermination ); + pxTCB = listGET_OWNER_OF_HEAD_ENTRY( ( &xTasksWaitingTermination ) ); /*lint !e9079 void * is used as this macro is used with timers and co-routines too. Alignment is known to be fine as the type of the pointer stored and retrieved is the same. */ + ( void ) uxListRemove( &( pxTCB->xStateListItem ) ); + --uxCurrentNumberOfTasks; + --uxDeletedTasksWaitingCleanUp; } - ( void ) xTaskResumeAll(); + taskEXIT_CRITICAL(); - if( xListIsEmpty == pdFALSE ) - { - TCB_t *pxTCB; - - taskENTER_CRITICAL(); - { - pxTCB = ( TCB_t * ) listGET_OWNER_OF_HEAD_ENTRY( ( &xTasksWaitingTermination ) ); - ( void ) uxListRemove( &( pxTCB->xStateListItem ) ); - --uxCurrentNumberOfTasks; - --uxDeletedTasksWaitingCleanUp; - } - taskEXIT_CRITICAL(); - - prvDeleteTCB( pxTCB ); - } - else - { - mtCOVERAGE_TEST_MARKER(); - } + prvDeleteTCB( pxTCB ); } } #endif /* INCLUDE_vTaskDelete */ @@ -3421,25 +3680,6 @@ static void prvCheckTasksWaitingTermination( void ) pxTaskStatus->pxStackBase = pxTCB->pxStack; pxTaskStatus->xTaskNumber = pxTCB->uxTCBNumber; - #if ( INCLUDE_vTaskSuspend == 1 ) - { - /* If the task is in the suspended list then there is a chance it is - actually just blocked indefinitely - so really it should be reported as - being in the Blocked state. */ - if( pxTaskStatus->eCurrentState == eSuspended ) - { - vTaskSuspendAll(); - { - if( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) != NULL ) - { - pxTaskStatus->eCurrentState = eBlocked; - } - } - xTaskResumeAll(); - } - } - #endif /* INCLUDE_vTaskSuspend */ - #if ( configUSE_MUTEXES == 1 ) { pxTaskStatus->uxBasePriority = pxTCB->uxBasePriority; @@ -3460,16 +3700,42 @@ static void prvCheckTasksWaitingTermination( void ) } #endif - /* Obtaining the task state is a little fiddly, so is only done if the value - of eState passed into this function is eInvalid - otherwise the state is - just set to whatever is passed in. */ + /* Obtaining the task state is a little fiddly, so is only done if the + value of eState passed into this function is eInvalid - otherwise the + state is just set to whatever is passed in. */ if( eState != eInvalid ) { - pxTaskStatus->eCurrentState = eState; + if( pxTCB == pxCurrentTCB ) + { + pxTaskStatus->eCurrentState = eRunning; + } + else + { + pxTaskStatus->eCurrentState = eState; + + #if ( INCLUDE_vTaskSuspend == 1 ) + { + /* If the task is in the suspended list then there is a + chance it is actually just blocked indefinitely - so really + it should be reported as being in the Blocked state. */ + if( eState == eSuspended ) + { + vTaskSuspendAll(); + { + if( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) != NULL ) + { + pxTaskStatus->eCurrentState = eBlocked; + } + } + ( void ) xTaskResumeAll(); + } + } + #endif /* INCLUDE_vTaskSuspend */ + } } else { - pxTaskStatus->eCurrentState = eTaskGetState( xTask ); + pxTaskStatus->eCurrentState = eTaskGetState( pxTCB ); } /* Obtaining the stack space takes some time, so the xGetFreeStackSpace @@ -3499,12 +3765,12 @@ static void prvCheckTasksWaitingTermination( void ) static UBaseType_t prvListTasksWithinSingleList( TaskStatus_t *pxTaskStatusArray, List_t *pxList, eTaskState eState ) { - volatile TCB_t *pxNextTCB, *pxFirstTCB; + configLIST_VOLATILE TCB_t *pxNextTCB, *pxFirstTCB; UBaseType_t uxTask = 0; if( listCURRENT_LIST_LENGTH( pxList ) > ( UBaseType_t ) 0 ) { - listGET_OWNER_OF_NEXT_ENTRY( pxFirstTCB, pxList ); + listGET_OWNER_OF_NEXT_ENTRY( pxFirstTCB, pxList ); /*lint !e9079 void * is used as this macro is used with timers and co-routines too. Alignment is known to be fine as the type of the pointer stored and retrieved is the same. */ /* Populate an TaskStatus_t structure within the pxTaskStatusArray array for each task that is referenced from @@ -3512,7 +3778,7 @@ static void prvCheckTasksWaitingTermination( void ) meaning of each TaskStatus_t structure member. */ do { - listGET_OWNER_OF_NEXT_ENTRY( pxNextTCB, pxList ); + listGET_OWNER_OF_NEXT_ENTRY( pxNextTCB, pxList ); /*lint !e9079 void * is used as this macro is used with timers and co-routines too. Alignment is known to be fine as the type of the pointer stored and retrieved is the same. */ vTaskGetInfo( ( TaskHandle_t ) pxNextTCB, &( pxTaskStatusArray[ uxTask ] ), pdTRUE, eState ); uxTask++; } while( pxNextTCB != pxFirstTCB ); @@ -3528,9 +3794,9 @@ static void prvCheckTasksWaitingTermination( void ) #endif /* configUSE_TRACE_FACILITY */ /*-----------------------------------------------------------*/ -#if ( ( configUSE_TRACE_FACILITY == 1 ) || ( INCLUDE_uxTaskGetStackHighWaterMark == 1 ) ) +#if ( ( configUSE_TRACE_FACILITY == 1 ) || ( INCLUDE_uxTaskGetStackHighWaterMark == 1 ) || ( INCLUDE_uxTaskGetStackHighWaterMark2 == 1 ) ) - static uint16_t prvTaskCheckFreeStackSpace( const uint8_t * pucStackByte ) + static configSTACK_DEPTH_TYPE prvTaskCheckFreeStackSpace( const uint8_t * pucStackByte ) { uint32_t ulCount = 0U; @@ -3542,10 +3808,50 @@ static void prvCheckTasksWaitingTermination( void ) ulCount /= ( uint32_t ) sizeof( StackType_t ); /*lint !e961 Casting is not redundant on smaller architectures. */ - return ( uint16_t ) ulCount; + return ( configSTACK_DEPTH_TYPE ) ulCount; } -#endif /* ( ( configUSE_TRACE_FACILITY == 1 ) || ( INCLUDE_uxTaskGetStackHighWaterMark == 1 ) ) */ +#endif /* ( ( configUSE_TRACE_FACILITY == 1 ) || ( INCLUDE_uxTaskGetStackHighWaterMark == 1 ) || ( INCLUDE_uxTaskGetStackHighWaterMark2 == 1 ) ) */ +/*-----------------------------------------------------------*/ + +#if ( INCLUDE_uxTaskGetStackHighWaterMark2 == 1 ) + + /* uxTaskGetStackHighWaterMark() and uxTaskGetStackHighWaterMark2() are the + same except for their return type. Using configSTACK_DEPTH_TYPE allows the + user to determine the return type. It gets around the problem of the value + overflowing on 8-bit types without breaking backward compatibility for + applications that expect an 8-bit return type. */ + configSTACK_DEPTH_TYPE uxTaskGetStackHighWaterMark2( TaskHandle_t xTask ) + { + TCB_t *pxTCB; + uint8_t *pucEndOfStack; + configSTACK_DEPTH_TYPE uxReturn; + + /* uxTaskGetStackHighWaterMark() and uxTaskGetStackHighWaterMark2() are + the same except for their return type. Using configSTACK_DEPTH_TYPE + allows the user to determine the return type. It gets around the + problem of the value overflowing on 8-bit types without breaking + backward compatibility for applications that expect an 8-bit return + type. */ + + pxTCB = prvGetTCBFromHandle( xTask ); + + #if portSTACK_GROWTH < 0 + { + pucEndOfStack = ( uint8_t * ) pxTCB->pxStack; + } + #else + { + pucEndOfStack = ( uint8_t * ) pxTCB->pxEndOfStack; + } + #endif + + uxReturn = prvTaskCheckFreeStackSpace( pucEndOfStack ); + + return uxReturn; + } + +#endif /* INCLUDE_uxTaskGetStackHighWaterMark2 */ /*-----------------------------------------------------------*/ #if ( INCLUDE_uxTaskGetStackHighWaterMark == 1 ) @@ -3586,7 +3892,9 @@ static void prvCheckTasksWaitingTermination( void ) portCLEAN_UP_TCB( pxTCB ); /* Free up the memory allocated by the scheduler for the task. It is up - to the task to free any memory allocated at the application level. */ + to the task to free any memory allocated at the application level. + See the third party link http://www.nadler.com/embedded/newlibAndFreeRTOS.html + for additional information. */ #if ( configUSE_NEWLIB_REENTRANT == 1 ) { _reclaim_reent( &( pxTCB->xNewLib_reent ) ); @@ -3600,7 +3908,7 @@ static void prvCheckTasksWaitingTermination( void ) vPortFree( pxTCB->pxStack ); vPortFree( pxTCB ); } - #elif( tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE == 1 ) + #elif( tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE != 0 ) /*lint !e731 !e9029 Macro has been consolidated for readability reasons. */ { /* The task could have been allocated statically or dynamically, so check what was statically allocated before trying to free the @@ -3622,7 +3930,7 @@ static void prvCheckTasksWaitingTermination( void ) { /* Neither the stack nor the TCB were allocated dynamically, so nothing needs to be freed. */ - configASSERT( pxTCB->ucStaticallyAllocated == tskSTATICALLY_ALLOCATED_STACK_AND_TCB ) + configASSERT( pxTCB->ucStaticallyAllocated == tskSTATICALLY_ALLOCATED_STACK_AND_TCB ); mtCOVERAGE_TEST_MARKER(); } } @@ -3650,7 +3958,7 @@ TCB_t *pxTCB; the item at the head of the delayed list. This is the time at which the task at the head of the delayed list should be removed from the Blocked state. */ - ( pxTCB ) = ( TCB_t * ) listGET_OWNER_OF_HEAD_ENTRY( pxDelayedTaskList ); + ( pxTCB ) = listGET_OWNER_OF_HEAD_ENTRY( pxDelayedTaskList ); /*lint !e9079 void * is used as this macro is used with timers and co-routines too. Alignment is known to be fine as the type of the pointer stored and retrieved is the same. */ xNextTaskUnblockTime = listGET_LIST_ITEM_VALUE( &( ( pxTCB )->xStateListItem ) ); } } @@ -3703,25 +4011,27 @@ TCB_t *pxTCB; #if ( configUSE_MUTEXES == 1 ) - void vTaskPriorityInherit( TaskHandle_t const pxMutexHolder ) + BaseType_t xTaskPriorityInherit( TaskHandle_t const pxMutexHolder ) { - TCB_t * const pxTCB = ( TCB_t * ) pxMutexHolder; + TCB_t * const pxMutexHolderTCB = pxMutexHolder; + BaseType_t xReturn = pdFALSE; /* If the mutex was given back by an interrupt while the queue was - locked then the mutex holder might now be NULL. */ + locked then the mutex holder might now be NULL. _RB_ Is this still + needed as interrupts can no longer use mutexes? */ if( pxMutexHolder != NULL ) { /* If the holder of the mutex has a priority below the priority of the task attempting to obtain the mutex then it will temporarily inherit the priority of the task attempting to obtain the mutex. */ - if( pxTCB->uxPriority < pxCurrentTCB->uxPriority ) + if( pxMutexHolderTCB->uxPriority < pxCurrentTCB->uxPriority ) { /* Adjust the mutex holder state to account for its new priority. Only reset the event list item value if the value is - not being used for anything else. */ - if( ( listGET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ) ) & taskEVENT_LIST_ITEM_VALUE_IN_USE ) == 0UL ) + not being used for anything else. */ + if( ( listGET_LIST_ITEM_VALUE( &( pxMutexHolderTCB->xEventListItem ) ) & taskEVENT_LIST_ITEM_VALUE_IN_USE ) == 0UL ) { - listSET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ), ( TickType_t ) configMAX_PRIORITIES - ( TickType_t ) pxCurrentTCB->uxPriority ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */ + listSET_LIST_ITEM_VALUE( &( pxMutexHolderTCB->xEventListItem ), ( TickType_t ) configMAX_PRIORITIES - ( TickType_t ) pxCurrentTCB->uxPriority ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */ } else { @@ -3730,11 +4040,14 @@ TCB_t *pxTCB; /* If the task being modified is in the ready state it will need to be moved into a new list. */ - if( listIS_CONTAINED_WITHIN( &( pxReadyTasksLists[ pxTCB->uxPriority ] ), &( pxTCB->xStateListItem ) ) != pdFALSE ) + if( listIS_CONTAINED_WITHIN( &( pxReadyTasksLists[ pxMutexHolderTCB->uxPriority ] ), &( pxMutexHolderTCB->xStateListItem ) ) != pdFALSE ) { - if( uxListRemove( &( pxTCB->xStateListItem ) ) == ( UBaseType_t ) 0 ) + if( uxListRemove( &( pxMutexHolderTCB->xStateListItem ) ) == ( UBaseType_t ) 0 ) { - taskRESET_READY_PRIORITY( pxTCB->uxPriority ); + /* It is known that the task is in its ready list so + there is no need to check again and the port level + reset macro can be called directly. */ + portRESET_READY_PRIORITY( pxMutexHolderTCB->uxPriority, uxTopReadyPriority ); } else { @@ -3742,26 +4055,45 @@ TCB_t *pxTCB; } /* Inherit the priority before being moved into the new list. */ - pxTCB->uxPriority = pxCurrentTCB->uxPriority; - prvAddTaskToReadyList( pxTCB ); + pxMutexHolderTCB->uxPriority = pxCurrentTCB->uxPriority; + prvAddTaskToReadyList( pxMutexHolderTCB ); } else { /* Just inherit the priority. */ - pxTCB->uxPriority = pxCurrentTCB->uxPriority; + pxMutexHolderTCB->uxPriority = pxCurrentTCB->uxPriority; } - traceTASK_PRIORITY_INHERIT( pxTCB, pxCurrentTCB->uxPriority ); + traceTASK_PRIORITY_INHERIT( pxMutexHolderTCB, pxCurrentTCB->uxPriority ); + + /* Inheritance occurred. */ + xReturn = pdTRUE; } else { - mtCOVERAGE_TEST_MARKER(); + if( pxMutexHolderTCB->uxBasePriority < pxCurrentTCB->uxPriority ) + { + /* The base priority of the mutex holder is lower than the + priority of the task attempting to take the mutex, but the + current priority of the mutex holder is not lower than the + priority of the task attempting to take the mutex. + Therefore the mutex holder must have already inherited a + priority, but inheritance would have occurred if that had + not been the case. */ + xReturn = pdTRUE; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } } } else { mtCOVERAGE_TEST_MARKER(); } + + return xReturn; } #endif /* configUSE_MUTEXES */ @@ -3771,7 +4103,7 @@ TCB_t *pxTCB; BaseType_t xTaskPriorityDisinherit( TaskHandle_t const pxMutexHolder ) { - TCB_t * const pxTCB = ( TCB_t * ) pxMutexHolder; + TCB_t * const pxTCB = pxMutexHolder; BaseType_t xReturn = pdFALSE; if( pxMutexHolder != NULL ) @@ -3781,7 +4113,6 @@ TCB_t *pxTCB; interrupt, and if a mutex is given by the holding task then it must be the running state task. */ configASSERT( pxTCB == pxCurrentTCB ); - configASSERT( pxTCB->uxMutexesHeld ); ( pxTCB->uxMutexesHeld )--; @@ -3795,8 +4126,8 @@ TCB_t *pxTCB; /* A task can only have an inherited priority if it holds the mutex. If the mutex is held by a task then it cannot be given from an interrupt, and if a mutex is given by the - holding task then it must be the running state task. Remove - the holding task from the ready list. */ + holding task then it must be the running state task. Remove + the holding task from the ready/delayed list. */ if( uxListRemove( &( pxTCB->xStateListItem ) ) == ( UBaseType_t ) 0 ) { taskRESET_READY_PRIORITY( pxTCB->uxPriority ); @@ -3848,6 +4179,111 @@ TCB_t *pxTCB; #endif /* configUSE_MUTEXES */ /*-----------------------------------------------------------*/ +#if ( configUSE_MUTEXES == 1 ) + + void vTaskPriorityDisinheritAfterTimeout( TaskHandle_t const pxMutexHolder, UBaseType_t uxHighestPriorityWaitingTask ) + { + TCB_t * const pxTCB = pxMutexHolder; + UBaseType_t uxPriorityUsedOnEntry, uxPriorityToUse; + const UBaseType_t uxOnlyOneMutexHeld = ( UBaseType_t ) 1; + + if( pxMutexHolder != NULL ) + { + /* If pxMutexHolder is not NULL then the holder must hold at least + one mutex. */ + configASSERT( pxTCB->uxMutexesHeld ); + + /* Determine the priority to which the priority of the task that + holds the mutex should be set. This will be the greater of the + holding task's base priority and the priority of the highest + priority task that is waiting to obtain the mutex. */ + if( pxTCB->uxBasePriority < uxHighestPriorityWaitingTask ) + { + uxPriorityToUse = uxHighestPriorityWaitingTask; + } + else + { + uxPriorityToUse = pxTCB->uxBasePriority; + } + + /* Does the priority need to change? */ + if( pxTCB->uxPriority != uxPriorityToUse ) + { + /* Only disinherit if no other mutexes are held. This is a + simplification in the priority inheritance implementation. If + the task that holds the mutex is also holding other mutexes then + the other mutexes may have caused the priority inheritance. */ + if( pxTCB->uxMutexesHeld == uxOnlyOneMutexHeld ) + { + /* If a task has timed out because it already holds the + mutex it was trying to obtain then it cannot of inherited + its own priority. */ + configASSERT( pxTCB != pxCurrentTCB ); + + /* Disinherit the priority, remembering the previous + priority to facilitate determining the subject task's + state. */ + traceTASK_PRIORITY_DISINHERIT( pxTCB, pxTCB->uxBasePriority ); + uxPriorityUsedOnEntry = pxTCB->uxPriority; + pxTCB->uxPriority = uxPriorityToUse; + + /* Only reset the event list item value if the value is not + being used for anything else. */ + if( ( listGET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ) ) & taskEVENT_LIST_ITEM_VALUE_IN_USE ) == 0UL ) + { + listSET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ), ( TickType_t ) configMAX_PRIORITIES - ( TickType_t ) uxPriorityToUse ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */ + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + + /* If the running task is not the task that holds the mutex + then the task that holds the mutex could be in either the + Ready, Blocked or Suspended states. Only remove the task + from its current state list if it is in the Ready state as + the task's priority is going to change and there is one + Ready list per priority. */ + if( listIS_CONTAINED_WITHIN( &( pxReadyTasksLists[ uxPriorityUsedOnEntry ] ), &( pxTCB->xStateListItem ) ) != pdFALSE ) + { + if( uxListRemove( &( pxTCB->xStateListItem ) ) == ( UBaseType_t ) 0 ) + { + /* It is known that the task is in its ready list so + there is no need to check again and the port level + reset macro can be called directly. */ + portRESET_READY_PRIORITY( pxTCB->uxPriority, uxTopReadyPriority ); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + + prvAddTaskToReadyList( pxTCB ); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + +#endif /* configUSE_MUTEXES */ +/*-----------------------------------------------------------*/ + #if ( portCRITICAL_NESTING_IN_TCB == 1 ) void vTaskEnterCritical( void ) @@ -3928,7 +4364,7 @@ TCB_t *pxTCB; } /* Terminate. */ - pcBuffer[ x ] = 0x00; + pcBuffer[ x ] = ( char ) 0x00; /* Return the new end of string. */ return &( pcBuffer[ x ] ); @@ -3937,12 +4373,12 @@ TCB_t *pxTCB; #endif /* ( configUSE_TRACE_FACILITY == 1 ) && ( configUSE_STATS_FORMATTING_FUNCTIONS > 0 ) */ /*-----------------------------------------------------------*/ -#if ( ( configUSE_TRACE_FACILITY == 1 ) && ( configUSE_STATS_FORMATTING_FUNCTIONS > 0 ) ) +#if ( ( configUSE_TRACE_FACILITY == 1 ) && ( configUSE_STATS_FORMATTING_FUNCTIONS > 0 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) ) void vTaskList( char * pcWriteBuffer ) { TaskStatus_t *pxTaskStatusArray; - volatile UBaseType_t uxArraySize, x; + UBaseType_t uxArraySize, x; char cStatus; /* @@ -3971,7 +4407,7 @@ TCB_t *pxTCB; /* Make sure the write buffer does not contain a string. */ - *pcWriteBuffer = 0x00; + *pcWriteBuffer = ( char ) 0x00; /* Take a snapshot of the number of tasks in case it changes while this function is executing. */ @@ -3980,7 +4416,7 @@ TCB_t *pxTCB; /* Allocate an array index for each task. NOTE! if configSUPPORT_DYNAMIC_ALLOCATION is set to 0 then pvPortMalloc() will equate to NULL. */ - pxTaskStatusArray = pvPortMalloc( uxCurrentNumberOfTasks * sizeof( TaskStatus_t ) ); + pxTaskStatusArray = pvPortMalloc( uxCurrentNumberOfTasks * sizeof( TaskStatus_t ) ); /*lint !e9079 All values returned by pvPortMalloc() have at least the alignment required by the MCU's stack and this allocation allocates a struct that has the alignment requirements of a pointer. */ if( pxTaskStatusArray != NULL ) { @@ -3992,6 +4428,9 @@ TCB_t *pxTCB; { switch( pxTaskStatusArray[ x ].eCurrentState ) { + case eRunning: cStatus = tskRUNNING_CHAR; + break; + case eReady: cStatus = tskREADY_CHAR; break; @@ -4004,9 +4443,10 @@ TCB_t *pxTCB; case eDeleted: cStatus = tskDELETED_CHAR; break; + case eInvalid: /* Fall through. */ default: /* Should not get here, but it is included to prevent static checking errors. */ - cStatus = 0x00; + cStatus = ( char ) 0x00; break; } @@ -4015,8 +4455,8 @@ TCB_t *pxTCB; pcWriteBuffer = prvWriteNameToBuffer( pcWriteBuffer, pxTaskStatusArray[ x ].pcTaskName ); /* Write the rest of the string. */ - sprintf( pcWriteBuffer, "\t%c\t%u\t%u\t%u\r\n", cStatus, ( unsigned int ) pxTaskStatusArray[ x ].uxCurrentPriority, ( unsigned int ) pxTaskStatusArray[ x ].usStackHighWaterMark, ( unsigned int ) pxTaskStatusArray[ x ].xTaskNumber ); - pcWriteBuffer += strlen( pcWriteBuffer ); + sprintf( pcWriteBuffer, "\t%c\t%u\t%u\t%u\r\n", cStatus, ( unsigned int ) pxTaskStatusArray[ x ].uxCurrentPriority, ( unsigned int ) pxTaskStatusArray[ x ].usStackHighWaterMark, ( unsigned int ) pxTaskStatusArray[ x ].xTaskNumber ); /*lint !e586 sprintf() allowed as this is compiled with many compilers and this is a utility function only - not part of the core kernel implementation. */ + pcWriteBuffer += strlen( pcWriteBuffer ); /*lint !e9016 Pointer arithmetic ok on char pointers especially as in this case where it best denotes the intent of the code. */ } /* Free the array again. NOTE! If configSUPPORT_DYNAMIC_ALLOCATION @@ -4029,15 +4469,15 @@ TCB_t *pxTCB; } } -#endif /* ( ( configUSE_TRACE_FACILITY == 1 ) && ( configUSE_STATS_FORMATTING_FUNCTIONS > 0 ) ) */ +#endif /* ( ( configUSE_TRACE_FACILITY == 1 ) && ( configUSE_STATS_FORMATTING_FUNCTIONS > 0 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) ) */ /*----------------------------------------------------------*/ -#if ( ( configGENERATE_RUN_TIME_STATS == 1 ) && ( configUSE_STATS_FORMATTING_FUNCTIONS > 0 ) ) +#if ( ( configGENERATE_RUN_TIME_STATS == 1 ) && ( configUSE_STATS_FORMATTING_FUNCTIONS > 0 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) ) void vTaskGetRunTimeStats( char *pcWriteBuffer ) { TaskStatus_t *pxTaskStatusArray; - volatile UBaseType_t uxArraySize, x; + UBaseType_t uxArraySize, x; uint32_t ulTotalTime, ulStatsAsPercentage; #if( configUSE_TRACE_FACILITY != 1 ) @@ -4072,7 +4512,7 @@ TCB_t *pxTCB; */ /* Make sure the write buffer does not contain a string. */ - *pcWriteBuffer = 0x00; + *pcWriteBuffer = ( char ) 0x00; /* Take a snapshot of the number of tasks in case it changes while this function is executing. */ @@ -4081,7 +4521,7 @@ TCB_t *pxTCB; /* Allocate an array index for each task. NOTE! If configSUPPORT_DYNAMIC_ALLOCATION is set to 0 then pvPortMalloc() will equate to NULL. */ - pxTaskStatusArray = pvPortMalloc( uxCurrentNumberOfTasks * sizeof( TaskStatus_t ) ); + pxTaskStatusArray = pvPortMalloc( uxCurrentNumberOfTasks * sizeof( TaskStatus_t ) ); /*lint !e9079 All values returned by pvPortMalloc() have at least the alignment required by the MCU's stack and this allocation allocates a struct that has the alignment requirements of a pointer. */ if( pxTaskStatusArray != NULL ) { @@ -4092,7 +4532,7 @@ TCB_t *pxTCB; ulTotalTime /= 100UL; /* Avoid divide by zero errors. */ - if( ulTotalTime > 0 ) + if( ulTotalTime > 0UL ) { /* Create a human readable table from the binary data. */ for( x = 0; x < uxArraySize; x++ ) @@ -4117,7 +4557,7 @@ TCB_t *pxTCB; { /* sizeof( int ) == sizeof( long ) so a smaller printf() library can be used. */ - sprintf( pcWriteBuffer, "\t%u\t\t%u%%\r\n", ( unsigned int ) pxTaskStatusArray[ x ].ulRunTimeCounter, ( unsigned int ) ulStatsAsPercentage ); + sprintf( pcWriteBuffer, "\t%u\t\t%u%%\r\n", ( unsigned int ) pxTaskStatusArray[ x ].ulRunTimeCounter, ( unsigned int ) ulStatsAsPercentage ); /*lint !e586 sprintf() allowed as this is compiled with many compilers and this is a utility function only - not part of the core kernel implementation. */ } #endif } @@ -4133,12 +4573,12 @@ TCB_t *pxTCB; { /* sizeof( int ) == sizeof( long ) so a smaller printf() library can be used. */ - sprintf( pcWriteBuffer, "\t%u\t\t<1%%\r\n", ( unsigned int ) pxTaskStatusArray[ x ].ulRunTimeCounter ); + sprintf( pcWriteBuffer, "\t%u\t\t<1%%\r\n", ( unsigned int ) pxTaskStatusArray[ x ].ulRunTimeCounter ); /*lint !e586 sprintf() allowed as this is compiled with many compilers and this is a utility function only - not part of the core kernel implementation. */ } #endif } - pcWriteBuffer += strlen( pcWriteBuffer ); + pcWriteBuffer += strlen( pcWriteBuffer ); /*lint !e9016 Pointer arithmetic ok on char pointers especially as in this case where it best denotes the intent of the code. */ } } else @@ -4156,7 +4596,7 @@ TCB_t *pxTCB; } } -#endif /* ( ( configGENERATE_RUN_TIME_STATS == 1 ) && ( configUSE_STATS_FORMATTING_FUNCTIONS > 0 ) ) */ +#endif /* ( ( configGENERATE_RUN_TIME_STATS == 1 ) && ( configUSE_STATS_FORMATTING_FUNCTIONS > 0 ) && ( configSUPPORT_STATIC_ALLOCATION == 1 ) ) */ /*-----------------------------------------------------------*/ TickType_t uxTaskResetEventItemValue( void ) @@ -4175,7 +4615,7 @@ TickType_t uxReturn; #if ( configUSE_MUTEXES == 1 ) - void *pvTaskIncrementMutexHeldCount( void ) + TaskHandle_t pvTaskIncrementMutexHeldCount( void ) { /* If xSemaphoreCreateMutex() is called before any tasks have been created then pxCurrentTCB will be NULL. */ @@ -4240,7 +4680,7 @@ TickType_t uxReturn; } else { - pxCurrentTCB->ulNotifiedValue = ulReturn - 1; + pxCurrentTCB->ulNotifiedValue = ulReturn - ( uint32_t ) 1; } } else @@ -4315,7 +4755,7 @@ TickType_t uxReturn; blocked state (because a notification was already pending) or the task unblocked because of a notification. Otherwise the task unblocked because of a timeout. */ - if( pxCurrentTCB->ucNotifyState == taskWAITING_NOTIFICATION ) + if( pxCurrentTCB->ucNotifyState != taskNOTIFICATION_RECEIVED ) { /* A notification was not received. */ xReturn = pdFALSE; @@ -4347,7 +4787,7 @@ TickType_t uxReturn; uint8_t ucOriginalNotifyState; configASSERT( xTaskToNotify ); - pxTCB = ( TCB_t * ) xTaskToNotify; + pxTCB = xTaskToNotify; taskENTER_CRITICAL(); { @@ -4390,6 +4830,14 @@ TickType_t uxReturn; /* The task is being notified without its notify value being updated. */ break; + + default: + /* Should not get here if all enums are handled. + Artificially force an assert by testing a value the + compiler can't assume is const. */ + configASSERT( pxTCB->ulNotifiedValue == ~0UL ); + + break; } traceTASK_NOTIFY(); @@ -4473,7 +4921,7 @@ TickType_t uxReturn; http://www.freertos.org/RTOS-Cortex-M3-M4.html */ portASSERT_IF_INTERRUPT_PRIORITY_INVALID(); - pxTCB = ( TCB_t * ) xTaskToNotify; + pxTCB = xTaskToNotify; uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR(); { @@ -4515,6 +4963,13 @@ TickType_t uxReturn; /* The task is being notified without its notify value being updated. */ break; + + default: + /* Should not get here if all enums are handled. + Artificially force an assert by testing a value the + compiler can't assume is const. */ + configASSERT( pxTCB->ulNotifiedValue == ~0UL ); + break; } traceTASK_NOTIFY_FROM_ISR(); @@ -4546,13 +5001,11 @@ TickType_t uxReturn; { *pxHigherPriorityTaskWoken = pdTRUE; } - else - { - /* Mark that a yield is pending in case the user is not - using the "xHigherPriorityTaskWoken" parameter to an ISR - safe FreeRTOS function. */ - xYieldPending = pdTRUE; - } + + /* Mark that a yield is pending in case the user is not + using the "xHigherPriorityTaskWoken" parameter to an ISR + safe FreeRTOS function. */ + xYieldPending = pdTRUE; } else { @@ -4596,7 +5049,7 @@ TickType_t uxReturn; http://www.freertos.org/RTOS-Cortex-M3-M4.html */ portASSERT_IF_INTERRUPT_PRIORITY_INVALID(); - pxTCB = ( TCB_t * ) xTaskToNotify; + pxTCB = xTaskToNotify; uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR(); { @@ -4636,13 +5089,11 @@ TickType_t uxReturn; { *pxHigherPriorityTaskWoken = pdTRUE; } - else - { - /* Mark that a yield is pending in case the user is not - using the "xHigherPriorityTaskWoken" parameter in an ISR - safe FreeRTOS function. */ - xYieldPending = pdTRUE; - } + + /* Mark that a yield is pending in case the user is not + using the "xHigherPriorityTaskWoken" parameter in an ISR + safe FreeRTOS function. */ + xYieldPending = pdTRUE; } else { @@ -4654,7 +5105,6 @@ TickType_t uxReturn; } #endif /* configUSE_TASK_NOTIFICATIONS */ - /*-----------------------------------------------------------*/ #if( configUSE_TASK_NOTIFICATIONS == 1 ) @@ -4688,6 +5138,41 @@ TickType_t uxReturn; #endif /* configUSE_TASK_NOTIFICATIONS */ /*-----------------------------------------------------------*/ +#if( configUSE_TASK_NOTIFICATIONS == 1 ) + + uint32_t ulTaskNotifyValueClear( TaskHandle_t xTask, uint32_t ulBitsToClear ) + { + TCB_t *pxTCB; + uint32_t ulReturn; + + /* If null is passed in here then it is the calling task that is having + its notification state cleared. */ + pxTCB = prvGetTCBFromHandle( xTask ); + + taskENTER_CRITICAL(); + { + /* Return the notification as it was before the bits were cleared, + then clear the bit mask. */ + ulReturn = pxCurrentTCB->ulNotifiedValue; + pxTCB->ulNotifiedValue &= ~ulBitsToClear; + } + taskEXIT_CRITICAL(); + + return ulReturn; + } + +#endif /* configUSE_TASK_NOTIFICATIONS */ +/*-----------------------------------------------------------*/ + +#if( ( configGENERATE_RUN_TIME_STATS == 1 ) && ( INCLUDE_xTaskGetIdleTaskHandle == 1 ) ) + + uint32_t ulTaskGetIdleRunTimeCounter( void ) + { + return xIdleTaskHandle->ulRunTimeCounter; + } + +#endif +/*-----------------------------------------------------------*/ static void prvAddCurrentTaskToDelayedList( TickType_t xTicksToWait, const BaseType_t xCanBlockIndefinitely ) { @@ -4709,7 +5194,7 @@ const TickType_t xConstTickCount = xTickCount; { /* The current task must be in a ready list, so there is no need to check, and the port reset macro can be called directly. */ - portRESET_READY_PRIORITY( pxCurrentTCB->uxPriority, uxTopReadyPriority ); + portRESET_READY_PRIORITY( pxCurrentTCB->uxPriority, uxTopReadyPriority ); /*lint !e931 pxCurrentTCB cannot change as it is the calling task. pxCurrentTCB->uxPriority and uxTopReadyPriority cannot change as called with scheduler suspended or in a critical section. */ } else { @@ -4800,8 +5285,26 @@ const TickType_t xConstTickCount = xTickCount; #endif /* INCLUDE_vTaskSuspend */ } +/* Code below here allows additional code to be inserted into this source file, +especially where access to file scope functions and data is needed (for example +when performing module tests). */ #ifdef FREERTOS_MODULE_TEST #include "tasks_test_access_functions.h" #endif + +#if( configINCLUDE_FREERTOS_TASK_C_ADDITIONS_H == 1 ) + + #include "freertos_tasks_c_additions.h" + + #ifdef FREERTOS_TASKS_C_ADDITIONS_INIT + static void freertos_tasks_c_additions_init( void ) + { + FREERTOS_TASKS_C_ADDITIONS_INIT(); + } + #endif + +#endif + + diff --git a/Firmware/Board/v3/Middlewares/Third_Party/FreeRTOS/Source/timers.c b/Firmware/Board/v3/Middlewares/Third_Party/FreeRTOS/Source/timers.c index 44cb477e..00200b8f 100644 --- a/Firmware/Board/v3/Middlewares/Third_Party/FreeRTOS/Source/timers.c +++ b/Firmware/Board/v3/Middlewares/Third_Party/FreeRTOS/Source/timers.c @@ -1,71 +1,29 @@ /* - FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. - All rights reserved - - VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. - - This file is part of the FreeRTOS distribution. - - FreeRTOS is free software; you can redistribute it and/or modify it under - the terms of the GNU General Public License (version 2) as published by the - Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception. - - *************************************************************************** - >>! NOTE: The modification to the GPL is included to allow you to !<< - >>! distribute a combined work that includes FreeRTOS without being !<< - >>! obliged to provide the source code for proprietary components !<< - >>! outside of the FreeRTOS kernel. !<< - *************************************************************************** - - FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - FOR A PARTICULAR PURPOSE. Full license text is available on the following - link: http://www.freertos.org/a00114.html - - *************************************************************************** - * * - * FreeRTOS provides completely free yet professionally developed, * - * robust, strictly quality controlled, supported, and cross * - * platform software that is more than just the market leader, it * - * is the industry's de facto standard. * - * * - * Help yourself get started quickly while simultaneously helping * - * to support the FreeRTOS project by purchasing a FreeRTOS * - * tutorial book, reference manual, or both: * - * http://www.FreeRTOS.org/Documentation * - * * - *************************************************************************** - - http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading - the FAQ page "My application does not run, what could be wrong?". Have you - defined configASSERT()? - - http://www.FreeRTOS.org/support - In return for receiving this top quality - embedded software for free we request you assist our global community by - participating in the support forum. - - http://www.FreeRTOS.org/training - Investing in training allows your team to - be as productive as possible as early as possible. Now you can receive - FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers - Ltd, and the world's leading authority on the world's leading RTOS. - - http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, - including FreeRTOS+Trace - an indispensable productivity tool, a DOS - compatible FAT file system, and our tiny thread aware UDP/IP stack. - - http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. - Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. - - http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High - Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS - licenses offer ticketed support, indemnification and commercial middleware. - - http://www.SafeRTOS.com - High Integrity Systems also provide a safety - engineered and independently SIL3 certified version for use in safety and - mission critical applications that require provable dependability. - - 1 tab == 4 spaces! -*/ + * FreeRTOS Kernel V10.3.1 + * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * http://www.FreeRTOS.org + * http://aws.amazon.com/freertos + * + * 1 tab == 4 spaces! + */ /* Standard includes. */ #include @@ -84,11 +42,11 @@ task.h is included from an application file. */ #error configUSE_TIMERS must be set to 1 to make the xTimerPendFunctionCall() function available. #endif -/* Lint e961 and e750 are suppressed as a MISRA exception justified because the -MPU ports require MPU_WRAPPERS_INCLUDED_FROM_API_FILE to be defined for the -header files above, but not in this file, in order to generate the correct -privileged Vs unprivileged linkage and placement. */ -#undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE /*lint !e961 !e750. */ +/* Lint e9021, e961 and e750 are suppressed as a MISRA exception justified +because the MPU ports require MPU_WRAPPERS_INCLUDED_FROM_API_FILE to be defined +for the header files above, but not in this file, in order to generate the +correct privileged Vs unprivileged linkage and placement. */ +#undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE /*lint !e9021 !e961 !e750. */ /* This entire source file will be skipped if the application is not configured @@ -100,22 +58,29 @@ configUSE_TIMERS is set to 1 in FreeRTOSConfig.h. */ /* Misc definitions. */ #define tmrNO_DELAY ( TickType_t ) 0U +/* The name assigned to the timer service task. This can be overridden by +defining trmTIMER_SERVICE_TASK_NAME in FreeRTOSConfig.h. */ +#ifndef configTIMER_SERVICE_TASK_NAME + #define configTIMER_SERVICE_TASK_NAME "Tmr Svc" +#endif + +/* Bit definitions used in the ucStatus member of a timer structure. */ +#define tmrSTATUS_IS_ACTIVE ( ( uint8_t ) 0x01 ) +#define tmrSTATUS_IS_STATICALLY_ALLOCATED ( ( uint8_t ) 0x02 ) +#define tmrSTATUS_IS_AUTORELOAD ( ( uint8_t ) 0x04 ) + /* The definition of the timers themselves. */ -typedef struct tmrTimerControl +typedef struct tmrTimerControl /* The old naming convention is used to prevent breaking kernel aware debuggers. */ { const char *pcTimerName; /*<< Text name. This is not used by the kernel, it is included simply to make debugging easier. */ /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ ListItem_t xTimerListItem; /*<< Standard linked list item as used by all kernel features for event management. */ TickType_t xTimerPeriodInTicks;/*<< How quickly and often the timer expires. */ - UBaseType_t uxAutoReload; /*<< Set to pdTRUE if the timer should be automatically restarted once expired. Set to pdFALSE if the timer is, in effect, a one-shot timer. */ void *pvTimerID; /*<< An ID to identify the timer. This allows the timer to be identified when the same callback is used for multiple timers. */ TimerCallbackFunction_t pxCallbackFunction; /*<< The function that will be called when the timer expires. */ #if( configUSE_TRACE_FACILITY == 1 ) UBaseType_t uxTimerNumber; /*<< An ID assigned by trace tools such as FreeRTOS+Trace */ #endif - - #if( ( configSUPPORT_STATIC_ALLOCATION == 1 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) ) - uint8_t ucStaticallyAllocated; /*<< Set to pdTRUE if the timer was created statically so no attempt is made to free the memory again if the timer is later deleted. */ - #endif + uint8_t ucStatus; /*<< Holds bits to say if the timer was statically allocated or not, and if it is active or not. */ } xTIMER; /* The old xTIMER name is maintained above then typedefed to the new Timer_t @@ -158,22 +123,25 @@ typedef struct tmrTimerQueueMessage } u; } DaemonTaskMessage_t; -/*lint -e956 A manual analysis and inspection has been used to determine which -static variables must be declared volatile. */ +/*lint -save -e956 A manual analysis and inspection has been used to determine +which static variables must be declared volatile. */ /* The list in which active timers are stored. Timers are referenced in expire time order, with the nearest expiry time at the front of the list. Only the -timer service task is allowed to access these lists. */ +timer service task is allowed to access these lists. +xActiveTimerList1 and xActiveTimerList2 could be at function scope but that +breaks some kernel aware debuggers, and debuggers that reply on removing the +static qualifier. */ PRIVILEGED_DATA static List_t xActiveTimerList1; PRIVILEGED_DATA static List_t xActiveTimerList2; PRIVILEGED_DATA static List_t *pxCurrentTimerList; PRIVILEGED_DATA static List_t *pxOverflowTimerList; /* A queue that is used to send commands to the timer service task. */ -PRIVILEGED_INITIALIZED_DATA static QueueHandle_t xTimerQueue = NULL; -PRIVILEGED_INITIALIZED_DATA static TaskHandle_t xTimerTaskHandle = NULL; +PRIVILEGED_DATA static QueueHandle_t xTimerQueue = NULL; +PRIVILEGED_DATA static TaskHandle_t xTimerTaskHandle = NULL; -/*lint +e956 */ +/*lint -restore */ /*-----------------------------------------------------------*/ @@ -191,44 +159,44 @@ PRIVILEGED_INITIALIZED_DATA static TaskHandle_t xTimerTaskHandle = NULL; * Initialise the infrastructure used by the timer service task if it has not * been initialised already. */ -PRIVILEGED_FUNCTION static void prvCheckForValidListAndQueue( void ); +static void prvCheckForValidListAndQueue( void ) PRIVILEGED_FUNCTION; /* * The timer service task (daemon). Timer functionality is controlled by this * task. Other tasks communicate with the timer service task using the * xTimerQueue queue. */ -PRIVILEGED_FUNCTION static void prvTimerTask( void *pvParameters ); +static portTASK_FUNCTION_PROTO( prvTimerTask, pvParameters ) PRIVILEGED_FUNCTION; /* * Called by the timer service task to interpret and process a command it * received on the timer queue. */ -PRIVILEGED_FUNCTION static void prvProcessReceivedCommands( void ); +static void prvProcessReceivedCommands( void ) PRIVILEGED_FUNCTION; /* * Insert the timer into either xActiveTimerList1, or xActiveTimerList2, * depending on if the expire time causes a timer counter overflow. */ -PRIVILEGED_FUNCTION static BaseType_t prvInsertTimerInActiveList( Timer_t * const pxTimer, const TickType_t xNextExpiryTime, const TickType_t xTimeNow, const TickType_t xCommandTime ); +static BaseType_t prvInsertTimerInActiveList( Timer_t * const pxTimer, const TickType_t xNextExpiryTime, const TickType_t xTimeNow, const TickType_t xCommandTime ) PRIVILEGED_FUNCTION; /* * An active timer has reached its expire time. Reload the timer if it is an - * auto reload timer, then call its callback. + * auto-reload timer, then call its callback. */ -PRIVILEGED_FUNCTION static void prvProcessExpiredTimer( const TickType_t xNextExpireTime, const TickType_t xTimeNow ); +static void prvProcessExpiredTimer( const TickType_t xNextExpireTime, const TickType_t xTimeNow ) PRIVILEGED_FUNCTION; /* * The tick count has overflowed. Switch the timer lists after ensuring the * current timer list does not still reference some timers. */ -PRIVILEGED_FUNCTION static void prvSwitchTimerLists( void ); +static void prvSwitchTimerLists( void ) PRIVILEGED_FUNCTION; /* * Obtain the current tick count, setting *pxTimerListsWereSwitched to pdTRUE * if a tick count overflow occurred since prvSampleTimeNow() was last called. */ -PRIVILEGED_FUNCTION static TickType_t prvSampleTimeNow( BaseType_t * const pxTimerListsWereSwitched ); +static TickType_t prvSampleTimeNow( BaseType_t * const pxTimerListsWereSwitched ) PRIVILEGED_FUNCTION; /* * If the timer list contains any active timers then return the expire time of @@ -236,24 +204,24 @@ PRIVILEGED_FUNCTION static TickType_t prvSampleTimeNow( BaseType_t * const pxTim * timer list does not contain any timers then return 0 and set *pxListWasEmpty * to pdTRUE. */ -PRIVILEGED_FUNCTION static TickType_t prvGetNextExpireTime( BaseType_t * const pxListWasEmpty ); +static TickType_t prvGetNextExpireTime( BaseType_t * const pxListWasEmpty ) PRIVILEGED_FUNCTION; /* * If a timer has expired, process it. Otherwise, block the timer service task * until either a timer does expire or a command is received. */ -PRIVILEGED_FUNCTION static void prvProcessTimerOrBlockTask( const TickType_t xNextExpireTime, BaseType_t xListWasEmpty ); +static void prvProcessTimerOrBlockTask( const TickType_t xNextExpireTime, BaseType_t xListWasEmpty ) PRIVILEGED_FUNCTION; /* * Called after a Timer_t structure has been allocated either statically or * dynamically to fill in the structure's members. */ -PRIVILEGED_FUNCTION static void prvInitialiseNewTimer( const char * const pcTimerName, +static void prvInitialiseNewTimer( const char * const pcTimerName, /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ const TickType_t xTimerPeriodInTicks, const UBaseType_t uxAutoReload, void * const pvTimerID, TimerCallbackFunction_t pxCallbackFunction, - Timer_t *pxNewTimer ); /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ + Timer_t *pxNewTimer ) PRIVILEGED_FUNCTION; /*-----------------------------------------------------------*/ BaseType_t xTimerCreateTimerTask( void ) @@ -276,7 +244,7 @@ BaseType_t xReturn = pdFAIL; vApplicationGetTimerTaskMemory( &pxTimerTaskTCBBuffer, &pxTimerTaskStackBuffer, &ulTimerTaskStackSize ); xTimerTaskHandle = xTaskCreateStatic( prvTimerTask, - "Tmr Svc", + configTIMER_SERVICE_TASK_NAME, ulTimerTaskStackSize, NULL, ( ( UBaseType_t ) configTIMER_TASK_PRIORITY ) | portPRIVILEGE_BIT, @@ -291,7 +259,7 @@ BaseType_t xReturn = pdFAIL; #else { xReturn = xTaskCreate( prvTimerTask, - "Tmr Svc", + configTIMER_SERVICE_TASK_NAME, configTIMER_TASK_STACK_DEPTH, NULL, ( ( UBaseType_t ) configTIMER_TASK_PRIORITY ) | portPRIVILEGE_BIT, @@ -311,44 +279,39 @@ BaseType_t xReturn = pdFAIL; #if( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) - TimerHandle_t xTimerCreate( const char * const pcTimerName, + TimerHandle_t xTimerCreate( const char * const pcTimerName, /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ const TickType_t xTimerPeriodInTicks, const UBaseType_t uxAutoReload, void * const pvTimerID, - TimerCallbackFunction_t pxCallbackFunction ) /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ + TimerCallbackFunction_t pxCallbackFunction ) { Timer_t *pxNewTimer; - pxNewTimer = ( Timer_t * ) pvPortMalloc( sizeof( Timer_t ) ); + pxNewTimer = ( Timer_t * ) pvPortMalloc( sizeof( Timer_t ) ); /*lint !e9087 !e9079 All values returned by pvPortMalloc() have at least the alignment required by the MCU's stack, and the first member of Timer_t is always a pointer to the timer's mame. */ if( pxNewTimer != NULL ) { + /* Status is thus far zero as the timer is not created statically + and has not been started. The auto-reload bit may get set in + prvInitialiseNewTimer. */ + pxNewTimer->ucStatus = 0x00; prvInitialiseNewTimer( pcTimerName, xTimerPeriodInTicks, uxAutoReload, pvTimerID, pxCallbackFunction, pxNewTimer ); - - #if( configSUPPORT_STATIC_ALLOCATION == 1 ) - { - /* Timers can be created statically or dynamically, so note this - timer was created dynamically in case the timer is later - deleted. */ - pxNewTimer->ucStaticallyAllocated = pdFALSE; - } - #endif /* configSUPPORT_STATIC_ALLOCATION */ } return pxNewTimer; } -#endif /* configSUPPORT_STATIC_ALLOCATION */ +#endif /* configSUPPORT_DYNAMIC_ALLOCATION */ /*-----------------------------------------------------------*/ #if( configSUPPORT_STATIC_ALLOCATION == 1 ) - TimerHandle_t xTimerCreateStatic( const char * const pcTimerName, + TimerHandle_t xTimerCreateStatic( const char * const pcTimerName, /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ const TickType_t xTimerPeriodInTicks, const UBaseType_t uxAutoReload, void * const pvTimerID, TimerCallbackFunction_t pxCallbackFunction, - StaticTimer_t *pxTimerBuffer ) /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ + StaticTimer_t *pxTimerBuffer ) { Timer_t *pxNewTimer; @@ -356,27 +319,25 @@ BaseType_t xReturn = pdFAIL; { /* Sanity check that the size of the structure used to declare a variable of type StaticTimer_t equals the size of the real timer - structures. */ + structure. */ volatile size_t xSize = sizeof( StaticTimer_t ); configASSERT( xSize == sizeof( Timer_t ) ); + ( void ) xSize; /* Keeps lint quiet when configASSERT() is not defined. */ } #endif /* configASSERT_DEFINED */ /* A pointer to a StaticTimer_t structure MUST be provided, use it. */ configASSERT( pxTimerBuffer ); - pxNewTimer = ( Timer_t * ) pxTimerBuffer; /*lint !e740 Unusual cast is ok as the structures are designed to have the same alignment, and the size is checked by an assert. */ + pxNewTimer = ( Timer_t * ) pxTimerBuffer; /*lint !e740 !e9087 StaticTimer_t is a pointer to a Timer_t, so guaranteed to be aligned and sized correctly (checked by an assert()), so this is safe. */ if( pxNewTimer != NULL ) { - prvInitialiseNewTimer( pcTimerName, xTimerPeriodInTicks, uxAutoReload, pvTimerID, pxCallbackFunction, pxNewTimer ); + /* Timers can be created statically or dynamically so note this + timer was created statically in case it is later deleted. The + auto-reload bit may get set in prvInitialiseNewTimer(). */ + pxNewTimer->ucStatus = tmrSTATUS_IS_STATICALLY_ALLOCATED; - #if( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) - { - /* Timers can be created statically or dynamically so note this - timer was created statically in case it is later deleted. */ - pxNewTimer->ucStaticallyAllocated = pdTRUE; - } - #endif /* configSUPPORT_DYNAMIC_ALLOCATION */ + prvInitialiseNewTimer( pcTimerName, xTimerPeriodInTicks, uxAutoReload, pvTimerID, pxCallbackFunction, pxNewTimer ); } return pxNewTimer; @@ -385,12 +346,12 @@ BaseType_t xReturn = pdFAIL; #endif /* configSUPPORT_STATIC_ALLOCATION */ /*-----------------------------------------------------------*/ -static void prvInitialiseNewTimer( const char * const pcTimerName, +static void prvInitialiseNewTimer( const char * const pcTimerName, /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ const TickType_t xTimerPeriodInTicks, const UBaseType_t uxAutoReload, void * const pvTimerID, TimerCallbackFunction_t pxCallbackFunction, - Timer_t *pxNewTimer ) /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ + Timer_t *pxNewTimer ) { /* 0 is not a valid value for xTimerPeriodInTicks. */ configASSERT( ( xTimerPeriodInTicks > 0 ) ); @@ -405,10 +366,13 @@ static void prvInitialiseNewTimer( const char * const pcTimerName, parameters. */ pxNewTimer->pcTimerName = pcTimerName; pxNewTimer->xTimerPeriodInTicks = xTimerPeriodInTicks; - pxNewTimer->uxAutoReload = uxAutoReload; pxNewTimer->pvTimerID = pvTimerID; pxNewTimer->pxCallbackFunction = pxCallbackFunction; vListInitialiseItem( &( pxNewTimer->xTimerListItem ) ); + if( uxAutoReload != pdFALSE ) + { + pxNewTimer->ucStatus |= tmrSTATUS_IS_AUTORELOAD; + } traceTIMER_CREATE( pxNewTimer ); } } @@ -428,7 +392,7 @@ DaemonTaskMessage_t xMessage; /* Send a command to the timer service task to start the xTimer timer. */ xMessage.xMessageID = xCommandID; xMessage.u.xTimerParameters.xMessageValue = xOptionalValue; - xMessage.u.xTimerParameters.pxTimer = ( Timer_t * ) xTimer; + xMessage.u.xTimerParameters.pxTimer = xTimer; if( xCommandID < tmrFIRST_FROM_ISR_COMMAND ) { @@ -468,16 +432,61 @@ TaskHandle_t xTimerGetTimerDaemonTaskHandle( void ) TickType_t xTimerGetPeriod( TimerHandle_t xTimer ) { -Timer_t *pxTimer = ( Timer_t * ) xTimer; +Timer_t *pxTimer = xTimer; configASSERT( xTimer ); return pxTimer->xTimerPeriodInTicks; } /*-----------------------------------------------------------*/ +void vTimerSetReloadMode( TimerHandle_t xTimer, const UBaseType_t uxAutoReload ) +{ +Timer_t * pxTimer = xTimer; + + configASSERT( xTimer ); + taskENTER_CRITICAL(); + { + if( uxAutoReload != pdFALSE ) + { + pxTimer->ucStatus |= tmrSTATUS_IS_AUTORELOAD; + } + else + { + pxTimer->ucStatus &= ~tmrSTATUS_IS_AUTORELOAD; + } + } + taskEXIT_CRITICAL(); +} +/*-----------------------------------------------------------*/ + +UBaseType_t uxTimerGetReloadMode( TimerHandle_t xTimer ) +{ +Timer_t * pxTimer = xTimer; +UBaseType_t uxReturn; + + configASSERT( xTimer ); + taskENTER_CRITICAL(); + { + if( ( pxTimer->ucStatus & tmrSTATUS_IS_AUTORELOAD ) == 0 ) + { + /* Not an auto-reload timer. */ + uxReturn = ( UBaseType_t ) pdFALSE; + } + else + { + /* Is an auto-reload timer. */ + uxReturn = ( UBaseType_t ) pdTRUE; + } + } + taskEXIT_CRITICAL(); + + return uxReturn; +} +/*-----------------------------------------------------------*/ + TickType_t xTimerGetExpiryTime( TimerHandle_t xTimer ) { -Timer_t * pxTimer = ( Timer_t * ) xTimer; +Timer_t * pxTimer = xTimer; TickType_t xReturn; configASSERT( xTimer ); @@ -488,7 +497,7 @@ TickType_t xReturn; const char * pcTimerGetName( TimerHandle_t xTimer ) /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ { -Timer_t *pxTimer = ( Timer_t * ) xTimer; +Timer_t *pxTimer = xTimer; configASSERT( xTimer ); return pxTimer->pcTimerName; @@ -498,16 +507,16 @@ Timer_t *pxTimer = ( Timer_t * ) xTimer; static void prvProcessExpiredTimer( const TickType_t xNextExpireTime, const TickType_t xTimeNow ) { BaseType_t xResult; -Timer_t * const pxTimer = ( Timer_t * ) listGET_OWNER_OF_HEAD_ENTRY( pxCurrentTimerList ); +Timer_t * const pxTimer = ( Timer_t * ) listGET_OWNER_OF_HEAD_ENTRY( pxCurrentTimerList ); /*lint !e9087 !e9079 void * is used as this macro is used with tasks and co-routines too. Alignment is known to be fine as the type of the pointer stored and retrieved is the same. */ /* Remove the timer from the list of active timers. A check has already been performed to ensure the list is not empty. */ ( void ) uxListRemove( &( pxTimer->xTimerListItem ) ); traceTIMER_EXPIRED( pxTimer ); - /* If the timer is an auto reload timer then calculate the next + /* If the timer is an auto-reload timer then calculate the next expiry time and re-insert the timer in the list of active timers. */ - if( pxTimer->uxAutoReload == ( UBaseType_t ) pdTRUE ) + if( ( pxTimer->ucStatus & tmrSTATUS_IS_AUTORELOAD ) != 0 ) { /* The timer is inserted into a list using a time relative to anything other than the current time. It will therefore be inserted into the @@ -527,6 +536,7 @@ Timer_t * const pxTimer = ( Timer_t * ) listGET_OWNER_OF_HEAD_ENTRY( pxCurrentTi } else { + pxTimer->ucStatus &= ~tmrSTATUS_IS_ACTIVE; mtCOVERAGE_TEST_MARKER(); } @@ -535,7 +545,7 @@ Timer_t * const pxTimer = ( Timer_t * ) listGET_OWNER_OF_HEAD_ENTRY( pxCurrentTi } /*-----------------------------------------------------------*/ -static void prvTimerTask( void *pvParameters ) +static portTASK_FUNCTION( prvTimerTask, pvParameters ) { TickType_t xNextExpireTime; BaseType_t xListWasEmpty; @@ -660,7 +670,7 @@ TickType_t xNextExpireTime; static TickType_t prvSampleTimeNow( BaseType_t * const pxTimerListsWereSwitched ) { TickType_t xTimeNow; -PRIVILEGED_INITIALIZED_DATA static TickType_t xLastTime = ( TickType_t ) 0U; /*lint !e956 Variable is only accessible to one task. */ +PRIVILEGED_DATA static TickType_t xLastTime = ( TickType_t ) 0U; /*lint !e956 Variable is only accessible to one task. */ xTimeNow = xTaskGetTickCount(); @@ -760,7 +770,7 @@ TickType_t xTimeNow; software timer. */ pxTimer = xMessage.u.xTimerParameters.pxTimer; - if( listIS_CONTAINED_WITHIN( NULL, &( pxTimer->xTimerListItem ) ) == pdFALSE ) + if( listIS_CONTAINED_WITHIN( NULL, &( pxTimer->xTimerListItem ) ) == pdFALSE ) /*lint !e961. The cast is only redundant when NULL is passed into the macro. */ { /* The timer is in a list, remove it. */ ( void ) uxListRemove( &( pxTimer->xTimerListItem ) ); @@ -783,11 +793,12 @@ TickType_t xTimeNow; switch( xMessage.xMessageID ) { case tmrCOMMAND_START : - case tmrCOMMAND_START_FROM_ISR : - case tmrCOMMAND_RESET : - case tmrCOMMAND_RESET_FROM_ISR : + case tmrCOMMAND_START_FROM_ISR : + case tmrCOMMAND_RESET : + case tmrCOMMAND_RESET_FROM_ISR : case tmrCOMMAND_START_DONT_TRACE : /* Start or restart a timer. */ + pxTimer->ucStatus |= tmrSTATUS_IS_ACTIVE; if( prvInsertTimerInActiveList( pxTimer, xMessage.u.xTimerParameters.xMessageValue + pxTimer->xTimerPeriodInTicks, xTimeNow, xMessage.u.xTimerParameters.xMessageValue ) != pdFALSE ) { /* The timer expired before it was added to the active @@ -795,7 +806,7 @@ TickType_t xTimeNow; pxTimer->pxCallbackFunction( ( TimerHandle_t ) pxTimer ); traceTIMER_EXPIRED( pxTimer ); - if( pxTimer->uxAutoReload == ( UBaseType_t ) pdTRUE ) + if( ( pxTimer->ucStatus & tmrSTATUS_IS_AUTORELOAD ) != 0 ) { xResult = xTimerGenericCommand( pxTimer, tmrCOMMAND_START_DONT_TRACE, xMessage.u.xTimerParameters.xMessageValue + pxTimer->xTimerPeriodInTicks, NULL, tmrNO_DELAY ); configASSERT( xResult ); @@ -814,12 +825,13 @@ TickType_t xTimeNow; case tmrCOMMAND_STOP : case tmrCOMMAND_STOP_FROM_ISR : - /* The timer has already been removed from the active list. - There is nothing to do here. */ + /* The timer has already been removed from the active list. */ + pxTimer->ucStatus &= ~tmrSTATUS_IS_ACTIVE; break; case tmrCOMMAND_CHANGE_PERIOD : case tmrCOMMAND_CHANGE_PERIOD_FROM_ISR : + pxTimer->ucStatus |= tmrSTATUS_IS_ACTIVE; pxTimer->xTimerPeriodInTicks = xMessage.u.xTimerParameters.xMessageValue; configASSERT( ( pxTimer->xTimerPeriodInTicks > 0 ) ); @@ -833,29 +845,28 @@ TickType_t xTimeNow; break; case tmrCOMMAND_DELETE : - /* The timer has already been removed from the active list, - just free up the memory if the memory was dynamically - allocated. */ - #if( ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) && ( configSUPPORT_STATIC_ALLOCATION == 0 ) ) + #if ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) { - /* The timer can only have been allocated dynamically - - free it again. */ - vPortFree( pxTimer ); - } - #elif( ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) && ( configSUPPORT_STATIC_ALLOCATION == 1 ) ) - { - /* The timer could have been allocated statically or - dynamically, so check before attempting to free the - memory. */ - if( pxTimer->ucStaticallyAllocated == ( uint8_t ) pdFALSE ) + /* The timer has already been removed from the active list, + just free up the memory if the memory was dynamically + allocated. */ + if( ( pxTimer->ucStatus & tmrSTATUS_IS_STATICALLY_ALLOCATED ) == ( uint8_t ) 0 ) { vPortFree( pxTimer ); } else { - mtCOVERAGE_TEST_MARKER(); + pxTimer->ucStatus &= ~tmrSTATUS_IS_ACTIVE; } } + #else + { + /* If dynamic allocation is not enabled, the memory + could not have been dynamically allocated. So there is + no need to free the memory - just mark the timer as + "not active". */ + pxTimer->ucStatus &= ~tmrSTATUS_IS_ACTIVE; + } #endif /* configSUPPORT_DYNAMIC_ALLOCATION */ break; @@ -884,7 +895,7 @@ BaseType_t xResult; xNextExpireTime = listGET_ITEM_VALUE_OF_HEAD_ENTRY( pxCurrentTimerList ); /* Remove the timer from the list. */ - pxTimer = ( Timer_t * ) listGET_OWNER_OF_HEAD_ENTRY( pxCurrentTimerList ); + pxTimer = ( Timer_t * ) listGET_OWNER_OF_HEAD_ENTRY( pxCurrentTimerList ); /*lint !e9087 !e9079 void * is used as this macro is used with tasks and co-routines too. Alignment is known to be fine as the type of the pointer stored and retrieved is the same. */ ( void ) uxListRemove( &( pxTimer->xTimerListItem ) ); traceTIMER_EXPIRED( pxTimer ); @@ -893,7 +904,7 @@ BaseType_t xResult; have not yet been switched. */ pxTimer->pxCallbackFunction( ( TimerHandle_t ) pxTimer ); - if( pxTimer->uxAutoReload == ( UBaseType_t ) pdTRUE ) + if( ( pxTimer->ucStatus & tmrSTATUS_IS_AUTORELOAD ) != 0 ) { /* Calculate the reload value, and if the reload value results in the timer going into the same timer list then it has already expired @@ -945,10 +956,10 @@ static void prvCheckForValidListAndQueue( void ) { /* The timer queue is allocated statically in case configSUPPORT_DYNAMIC_ALLOCATION is 0. */ - static StaticQueue_t xStaticTimerQueue; - static uint8_t ucStaticTimerQueueStorage[ configTIMER_QUEUE_LENGTH * sizeof( DaemonTaskMessage_t ) ]; + static StaticQueue_t xStaticTimerQueue; /*lint !e956 Ok to declare in this manner to prevent additional conditional compilation guards in other locations. */ + static uint8_t ucStaticTimerQueueStorage[ ( size_t ) configTIMER_QUEUE_LENGTH * sizeof( DaemonTaskMessage_t ) ]; /*lint !e956 Ok to declare in this manner to prevent additional conditional compilation guards in other locations. */ - xTimerQueue = xQueueCreateStatic( ( UBaseType_t ) configTIMER_QUEUE_LENGTH, sizeof( DaemonTaskMessage_t ), &( ucStaticTimerQueueStorage[ 0 ] ), &xStaticTimerQueue ); + xTimerQueue = xQueueCreateStatic( ( UBaseType_t ) configTIMER_QUEUE_LENGTH, ( UBaseType_t ) sizeof( DaemonTaskMessage_t ), &( ucStaticTimerQueueStorage[ 0 ] ), &xStaticTimerQueue ); } #else { @@ -980,28 +991,32 @@ static void prvCheckForValidListAndQueue( void ) BaseType_t xTimerIsTimerActive( TimerHandle_t xTimer ) { -BaseType_t xTimerIsInActiveList; -Timer_t *pxTimer = ( Timer_t * ) xTimer; +BaseType_t xReturn; +Timer_t *pxTimer = xTimer; configASSERT( xTimer ); /* Is the timer in the list of active timers? */ taskENTER_CRITICAL(); { - /* Checking to see if it is in the NULL list in effect checks to see if - it is referenced from either the current or the overflow timer lists in - one go, but the logic has to be reversed, hence the '!'. */ - xTimerIsInActiveList = ( BaseType_t ) !( listIS_CONTAINED_WITHIN( NULL, &( pxTimer->xTimerListItem ) ) ); + if( ( pxTimer->ucStatus & tmrSTATUS_IS_ACTIVE ) == 0 ) + { + xReturn = pdFALSE; + } + else + { + xReturn = pdTRUE; + } } taskEXIT_CRITICAL(); - return xTimerIsInActiveList; + return xReturn; } /*lint !e818 Can't be pointer to const due to the typedef. */ /*-----------------------------------------------------------*/ void *pvTimerGetTimerID( const TimerHandle_t xTimer ) { -Timer_t * const pxTimer = ( Timer_t * ) xTimer; +Timer_t * const pxTimer = xTimer; void *pvReturn; configASSERT( xTimer ); @@ -1018,7 +1033,7 @@ void *pvReturn; void vTimerSetTimerID( TimerHandle_t xTimer, void *pvNewID ) { -Timer_t * const pxTimer = ( Timer_t * ) xTimer; +Timer_t * const pxTimer = xTimer; configASSERT( xTimer ); @@ -1083,6 +1098,26 @@ Timer_t * const pxTimer = ( Timer_t * ) xTimer; #endif /* INCLUDE_xTimerPendFunctionCall */ /*-----------------------------------------------------------*/ +#if ( configUSE_TRACE_FACILITY == 1 ) + + UBaseType_t uxTimerGetTimerNumber( TimerHandle_t xTimer ) + { + return ( ( Timer_t * ) xTimer )->uxTimerNumber; + } + +#endif /* configUSE_TRACE_FACILITY */ +/*-----------------------------------------------------------*/ + +#if ( configUSE_TRACE_FACILITY == 1 ) + + void vTimerSetTimerNumber( TimerHandle_t xTimer, UBaseType_t uxTimerNumber ) + { + ( ( Timer_t * ) xTimer )->uxTimerNumber = uxTimerNumber; + } + +#endif /* configUSE_TRACE_FACILITY */ +/*-----------------------------------------------------------*/ + /* This entire source file will be skipped if the application is not configured to include software timer functionality. If you want to include software timer functionality then ensure configUSE_TIMERS is set to 1 in FreeRTOSConfig.h. */ From f6f0cf9cd3874c1feaf931e427a62b14fa0e8c67 Mon Sep 17 00:00:00 2001 From: Unknown Date: Wed, 2 Sep 2020 23:12:05 -0400 Subject: [PATCH 09/41] Compile with -flto --- .../FreeRTOS/Source/portable/GCC/ARM_CM4F/port.c | 4 +++- Firmware/Tupfile.lua | 6 +++--- Firmware/communication/communication.cpp | 2 +- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/Firmware/Board/v3/Middlewares/Third_Party/FreeRTOS/Source/portable/GCC/ARM_CM4F/port.c b/Firmware/Board/v3/Middlewares/Third_Party/FreeRTOS/Source/portable/GCC/ARM_CM4F/port.c index d5feca9e..cc8bbe09 100644 --- a/Firmware/Board/v3/Middlewares/Third_Party/FreeRTOS/Source/portable/GCC/ARM_CM4F/port.c +++ b/Firmware/Board/v3/Middlewares/Third_Party/FreeRTOS/Source/portable/GCC/ARM_CM4F/port.c @@ -302,6 +302,7 @@ static void prvPortStartFirstTask( void ) " isb \n" " svc 0 \n" /* System call to start first task. */ " nop \n" + " .ltorg \n" ); } /*-----------------------------------------------------------*/ @@ -695,7 +696,8 @@ static void vPortEnableVFP( void ) " \n" " orr r1, r1, #( 0xf << 20 ) \n" /* Enable CP10 and CP11 coprocessors, then save back. */ " str r1, [r0] \n" - " bx r14 " + " bx r14 \n" + " .ltorg " ); } /*-----------------------------------------------------------*/ diff --git a/Firmware/Tupfile.lua b/Firmware/Tupfile.lua index 040db512..77ce8389 100644 --- a/Firmware/Tupfile.lua +++ b/Firmware/Tupfile.lua @@ -136,16 +136,16 @@ FLAGS += { '-Wall', '-Wdouble-promotion', '-Wfloat-conversion', '-fdata-sections -- linker flags LDFLAGS += board.ldflags -LDFLAGS += '-lc -lm -lnosys' -- libs +LDFLAGS += '-flto -lc -lm -lnosys' -- libs LDFLAGS += '-mthumb -mfloat-abi=hard -specs=nosys.specs -specs=nano.specs -u _printf_float -u _scanf_float -Wl,--cref -Wl,--gc-sections' -LDFLAGS += '-Wl,--undefined=uxTopUsedPriority' +LDFLAGS += '-Wl,--undefined=uxTopUsedPriority ' -- debug build if tup.getconfig("DEBUG") == "true" then FLAGS += '-g -gdwarf-2' OPT += '-Og' else - OPT += '-O2' + OPT += '-O2 -flto' end -- common flags for ASM, C and C++ diff --git a/Firmware/communication/communication.cpp b/Firmware/communication/communication.cpp index faac6f59..7845fd6f 100644 --- a/Firmware/communication/communication.cpp +++ b/Firmware/communication/communication.cpp @@ -57,7 +57,7 @@ void init_communication(void) { } extern "C" { -int _write(int file, const char* data, int len); +int _write(int file, const char* data, int len) __attribute__((used)); } // @brief This is what printf calls internally From 72f7d51b0740ec31e179872587c0b4b48bc1d399 Mon Sep 17 00:00:00 2001 From: Unknown Date: Thu, 3 Sep 2020 00:11:00 -0400 Subject: [PATCH 10/41] Responding on USB --- .../Board/v3/Middlewares/Third_Party/FreeRTOS/Source/tasks.c | 3 ++- Firmware/Board/v3/Src/stm32f4xx_it.c | 1 + Firmware/Tupfile.lua | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Firmware/Board/v3/Middlewares/Third_Party/FreeRTOS/Source/tasks.c b/Firmware/Board/v3/Middlewares/Third_Party/FreeRTOS/Source/tasks.c index 5c68c6a2..32c83890 100644 --- a/Firmware/Board/v3/Middlewares/Third_Party/FreeRTOS/Source/tasks.c +++ b/Firmware/Board/v3/Middlewares/Third_Party/FreeRTOS/Source/tasks.c @@ -369,7 +369,7 @@ typedef tskTCB TCB_t; /*lint -e956 A manual analysis and inspection has been used to determine which static variables must be declared volatile. */ -PRIVILEGED_INITIALIZED_DATA TCB_t * volatile pxCurrentTCB = NULL; +PRIVILEGED_INITIALIZED_DATA TCB_t * volatile pxCurrentTCB __attribute__((used)) = NULL; /* Lists for ready and blocked tasks. --------------------*/ PRIVILEGED_DATA static List_t pxReadyTasksLists[ configMAX_PRIORITIES ];/*< Prioritised ready tasks. */ @@ -2758,6 +2758,7 @@ BaseType_t xSwitchRequired = pdFALSE; #endif /* configUSE_APPLICATION_TASK_TAG */ /*-----------------------------------------------------------*/ +__attribute__((used)) void vTaskSwitchContext( void ) { if( uxSchedulerSuspended != ( UBaseType_t ) pdFALSE ) diff --git a/Firmware/Board/v3/Src/stm32f4xx_it.c b/Firmware/Board/v3/Src/stm32f4xx_it.c index 1e69bcb9..032a25a0 100644 --- a/Firmware/Board/v3/Src/stm32f4xx_it.c +++ b/Firmware/Board/v3/Src/stm32f4xx_it.c @@ -74,6 +74,7 @@ void NMI_Handler(void) /* USER CODE END NonMaskableInt_IRQn 1 */ } +__attribute__((used)) void get_regs(void** stack_ptr) { void* volatile r0 __attribute__((unused)) = stack_ptr[0]; void* volatile r1 __attribute__((unused)) = stack_ptr[1]; diff --git a/Firmware/Tupfile.lua b/Firmware/Tupfile.lua index 77ce8389..ff0cf41e 100644 --- a/Firmware/Tupfile.lua +++ b/Firmware/Tupfile.lua @@ -158,7 +158,7 @@ toolchain = GCCToolchain('arm-none-eabi-', 'build', FLAGS, LDFLAGS) -- Load list of source files Makefile that was autogenerated by CubeMX vars = parse_makefile_vars(board.dir..'/Makefile') -all_stm_sources = (vars['C_SOURCES'] or '')..' '..(vars['CPP_SOURCES'] or '')..' '..(vars['ASM_SOURCES'] or '') +all_stm_sources = (vars['ASM_SOURCES'] or '')..' '..(vars['CPP_SOURCES'] or '')..' '..(vars['C_SOURCES'] or '') for src in string.gmatch(all_stm_sources, "%S+") do stm_sources += board.dir..'/'..src end From d628fdb35caf810073b2bf6f57ab79b08090d1dd Mon Sep 17 00:00:00 2001 From: Unknown Date: Thu, 3 Sep 2020 00:18:26 -0400 Subject: [PATCH 11/41] Minor cleanup, add comment to tupfile --- .../Board/v3/Middlewares/Third_Party/FreeRTOS/Source/tasks.c | 2 +- Firmware/Tupfile.lua | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/Firmware/Board/v3/Middlewares/Third_Party/FreeRTOS/Source/tasks.c b/Firmware/Board/v3/Middlewares/Third_Party/FreeRTOS/Source/tasks.c index 32c83890..220b867b 100644 --- a/Firmware/Board/v3/Middlewares/Third_Party/FreeRTOS/Source/tasks.c +++ b/Firmware/Board/v3/Middlewares/Third_Party/FreeRTOS/Source/tasks.c @@ -369,7 +369,7 @@ typedef tskTCB TCB_t; /*lint -e956 A manual analysis and inspection has been used to determine which static variables must be declared volatile. */ -PRIVILEGED_INITIALIZED_DATA TCB_t * volatile pxCurrentTCB __attribute__((used)) = NULL; +__attribute__((used)) PRIVILEGED_INITIALIZED_DATA TCB_t * volatile pxCurrentTCB = NULL; /* Lists for ready and blocked tasks. --------------------*/ PRIVILEGED_DATA static List_t pxReadyTasksLists[ configMAX_PRIORITIES ];/*< Prioritised ready tasks. */ diff --git a/Firmware/Tupfile.lua b/Firmware/Tupfile.lua index ff0cf41e..bd59d526 100644 --- a/Firmware/Tupfile.lua +++ b/Firmware/Tupfile.lua @@ -158,6 +158,9 @@ toolchain = GCCToolchain('arm-none-eabi-', 'build', FLAGS, LDFLAGS) -- Load list of source files Makefile that was autogenerated by CubeMX vars = parse_makefile_vars(board.dir..'/Makefile') + +-- ASM sources must precede C sources due to LTO removing weak symbols which appear after strong symbols +-- in the call to the linker: https://bugs.launchpad.net/gcc-arm-embedded/+bug/1747966 all_stm_sources = (vars['ASM_SOURCES'] or '')..' '..(vars['CPP_SOURCES'] or '')..' '..(vars['C_SOURCES'] or '') for src in string.gmatch(all_stm_sources, "%S+") do stm_sources += board.dir..'/'..src From cfb5523001ebe1482375616c316bf2c5fff5ca17 Mon Sep 17 00:00:00 2001 From: Unknown Date: Thu, 3 Sep 2020 00:33:31 -0400 Subject: [PATCH 12/41] Fix dump_errors on this branch(?) --- tools/odrive/utils.py | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/tools/odrive/utils.py b/tools/odrive/utils.py index 505bba79..329cda81 100755 --- a/tools/odrive/utils.py +++ b/tools/odrive/utils.py @@ -78,18 +78,20 @@ def dump_errors(odrv, clear=False): # Flatten axis and submodules # (name, remote_obj, errorcode) module_decode_map = [ - ('axis', axis, {k: v for k, v in odrive.enums.__dict__ .items() if k.startswith("AXIS_ERROR_")}), - ('motor', axis.motor, {k: v for k, v in odrive.enums.__dict__ .items() if k.startswith("MOTOR_ERROR_")}), - ('fet_thermistor', axis.fet_thermistor, {k: v for k, v in odrive.enums.__dict__ .items() if k.startswith("THERMISTOR_CURRENT_LIMITER_ERROR")}), - ('motor_thermistor', axis.motor_thermistor, {k: v for k, v in odrive.enums.__dict__ .items() if k.startswith("THERMISTOR_CURRENT_LIMITER_ERROR")}), - ('encoder', axis.encoder, {k: v for k, v in odrive.enums.__dict__ .items() if k.startswith("ENCODER_ERROR_")}), - ('controller', axis.controller, {k: v for k, v in odrive.enums.__dict__ .items() if k.startswith("CONTROLLER_ERROR_")}), + (name, odrv, {k: v for k, v in odrive.enums.__dict__ .items() if k.startswith("AXIS_ERROR_")}), + ('motor', axis, {k: v for k, v in odrive.enums.__dict__ .items() if k.startswith("MOTOR_ERROR_")}), + ('fet_thermistor', axis, {k: v for k, v in odrive.enums.__dict__ .items() if k.startswith("THERMISTOR_CURRENT_LIMITER_ERROR")}), + ('motor_thermistor', axis, {k: v for k, v in odrive.enums.__dict__ .items() if k.startswith("THERMISTOR_CURRENT_LIMITER_ERROR")}), + ('encoder', axis, {k: v for k, v in odrive.enums.__dict__ .items() if k.startswith("ENCODER_ERROR_")}), + ('controller', axis, {k: v for k, v in odrive.enums.__dict__ .items() if k.startswith("CONTROLLER_ERROR_")}), ] # Module error decode for name, remote_obj, errorcodes in module_decode_map: - prefix = ' '*2 + name + ": " - if (remote_obj.error != 0): + prefix = ' '*2 + name.strip('0123456789') + ": " + if not hasattr(remote_obj, name): + print(prefix + _VT100Colors['yellow'] + "not found" + _VT100Colors['default']) + elif getattr(remote_obj, name).error != 0: foundError = False print(prefix + _VT100Colors['red'] + "Error(s):" + _VT100Colors['default']) errorcodes_dict = {val: name for name, val in errorcodes.items() if 'ERROR_' in name} From a530de4fa9c4ea52257e41ab4c5665553fb00f75 Mon Sep 17 00:00:00 2001 From: Unknown Date: Thu, 3 Sep 2020 01:15:07 -0400 Subject: [PATCH 13/41] Add tup.config var for LTO and enable by default --- Firmware/Tupfile.lua | 9 +++++++-- Firmware/tup.config.default | 1 + 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/Firmware/Tupfile.lua b/Firmware/Tupfile.lua index bd59d526..cd959137 100644 --- a/Firmware/Tupfile.lua +++ b/Firmware/Tupfile.lua @@ -138,14 +138,19 @@ FLAGS += { '-Wall', '-Wdouble-promotion', '-Wfloat-conversion', '-fdata-sections LDFLAGS += board.ldflags LDFLAGS += '-flto -lc -lm -lnosys' -- libs LDFLAGS += '-mthumb -mfloat-abi=hard -specs=nosys.specs -specs=nano.specs -u _printf_float -u _scanf_float -Wl,--cref -Wl,--gc-sections' -LDFLAGS += '-Wl,--undefined=uxTopUsedPriority ' +LDFLAGS += '-Wl,--undefined=uxTopUsedPriority' -- debug build if tup.getconfig("DEBUG") == "true" then FLAGS += '-g -gdwarf-2' OPT += '-Og' else - OPT += '-O2 -flto' + OPT += '-O2' +end + +if tup.getconfig("USE_LTO") == "true" then + OPT += '-flto' + LDFLAGS += '-flto' end -- common flags for ASM, C and C++ diff --git a/Firmware/tup.config.default b/Firmware/tup.config.default index b2d49106..e348cedb 100644 --- a/Firmware/tup.config.default +++ b/Firmware/tup.config.default @@ -5,6 +5,7 @@ CONFIG_USB_PROTOCOL=native CONFIG_UART_PROTOCOL=ascii CONFIG_DEBUG=false CONFIG_DOCTEST=false +CONFIG_USE_LTO=true # Uncomment this to error on compilation warnings #CONFIG_STRICT=true From 54636c764f423d3acb049a489329df2a2b90e992 Mon Sep 17 00:00:00 2001 From: Oskar Weigl Date: Thu, 3 Sep 2020 20:03:10 -0700 Subject: [PATCH 14/41] implement faster fmodf related functions --- Firmware/MotorControl/controller.cpp | 2 +- Firmware/MotorControl/encoder.cpp | 4 ++-- Firmware/MotorControl/utils.hpp | 30 +++++++++++++--------------- 3 files changed, 17 insertions(+), 19 deletions(-) diff --git a/Firmware/MotorControl/controller.cpp b/Firmware/MotorControl/controller.cpp index 1524dce6..ecea3c9c 100644 --- a/Firmware/MotorControl/controller.cpp +++ b/Firmware/MotorControl/controller.cpp @@ -233,7 +233,7 @@ bool Controller::update(float* torque_setpoint_output) { pos_setpoint_ = fmodf_pos(pos_setpoint_, *pos_wrap_src_); // Circular delta pos_err = pos_setpoint_ - *pos_estimate_circular; - pos_err = wrap_pm(pos_err, 0.5f * *pos_wrap_src_); + pos_err = wrap_pm(pos_err, *pos_wrap_src_); } else { if(!pos_estimate_linear) { set_error(ERROR_INVALID_ESTIMATE); diff --git a/Firmware/MotorControl/encoder.cpp b/Firmware/MotorControl/encoder.cpp index d2ce992b..f0c65445 100644 --- a/Firmware/MotorControl/encoder.cpp +++ b/Firmware/MotorControl/encoder.cpp @@ -546,7 +546,7 @@ bool Encoder::update() { // discrete phase detector float delta_pos_counts = (float)(shadow_count_ - (int32_t)std::floor(pos_estimate_counts_)); float delta_pos_cpr_counts = (float)(count_in_cpr_ - (int32_t)std::floor(pos_cpr_counts_)); - delta_pos_cpr_counts = wrap_pm(delta_pos_cpr_counts, 0.5f * (float)(config_.cpr)); + delta_pos_cpr_counts = wrap_pm(delta_pos_cpr_counts, (float)(config_.cpr)); // pll feedback pos_estimate_counts_ += current_meas_period * pll_kp_ * delta_pos_counts; pos_cpr_counts_ += current_meas_period * pll_kp_ * delta_pos_cpr_counts; @@ -561,7 +561,7 @@ bool Encoder::update() { // Outputs from Encoder for Controller pos_estimate_ = pos_estimate_counts_ / (float)config_.cpr; vel_estimate_ = vel_estimate_counts_ / (float)config_.cpr; - pos_circular_ += wrap_pm((pos_cpr_counts_ - pos_cpr_counts_last) / (float)config_.cpr, 0.5f); + pos_circular_ += wrap_pm((pos_cpr_counts_ - pos_cpr_counts_last) / (float)config_.cpr, 1.0f); pos_circular_ = fmodf_pos(pos_circular_, axis_->controller_.config_.circular_setpoint_range); //// run encoder count interpolation diff --git a/Firmware/MotorControl/utils.hpp b/Firmware/MotorControl/utils.hpp index 49f9434d..70bd73be 100644 --- a/Firmware/MotorControl/utils.hpp +++ b/Firmware/MotorControl/utils.hpp @@ -84,25 +84,23 @@ static const float one_by_sqrt3 = 0.57735026919f; static const float two_by_sqrt3 = 1.15470053838f; static const float sqrt3_by_2 = 0.86602540378f; -// like fmodf, but always positive +// Result depends on rounding mode +// With default rounding (round to nearest), +// the result will be in range -y/2 to y/2 +static inline float wrap_pm(float x, float y) { + int q = (int)(x/y); + return x - (float)q * y; +} + +// Same as fmodf but result is positive and y must be positive static inline float fmodf_pos(float x, float y) { - float out = fmodf(x, y); - if (out < 0.0f) - out += y; - return out; + float res = wrap_pm(x, y); + if (res < 0) res += y; + return res; } -/** - * @brief Similar to modulo operator, except that the output range is centered - * around zero. - * The returned value is always in the range [-pm_range, pm_range). - */ -static inline float wrap_pm(float x, float pm_range) { - return fmodf_pos(x + pm_range, 2.0f * pm_range) - pm_range; -} - -static inline float wrap_pm_pi(float theta) { - return wrap_pm(theta, M_PI); +static inline float wrap_pm_pi(float x) { + return wrap_pm(x, 2*M_PI); } // Compute rising edge timings (0.0 - 1.0) as a function of alpha-beta From 805b308a869cbb0a892d52b250d87176f2af529c Mon Sep 17 00:00:00 2001 From: Oskar Weigl Date: Fri, 4 Sep 2020 14:27:22 -0700 Subject: [PATCH 15/41] fix rounding mode, use vcvtr --- Firmware/.vscode/c_cpp_properties.json | 6 ++++-- Firmware/MotorControl/utils.hpp | 20 ++++++++++++++++---- 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/Firmware/.vscode/c_cpp_properties.json b/Firmware/.vscode/c_cpp_properties.json index 1d5ab7cf..be9f826f 100644 --- a/Firmware/.vscode/c_cpp_properties.json +++ b/Firmware/.vscode/c_cpp_properties.json @@ -6,12 +6,12 @@ "${workspaceFolder}/**" ], "defines": [ + "__arm__", "STM32F405xx", "USE_HAL_DRIVER", "HW_VERSION_MAJOR=3", "HW_VERSION_MINOR=6", "HW_VERSION_VOLTAGE=56", - "USB_PROTOCOL_NATIVE", "__weak=\"__attribute__((weak))\"", "__packed=\"__attribute__((__packed__))\"", "__GNUC__" @@ -27,6 +27,7 @@ "${workspaceFolder}/**" ], "defines": [ + "__arm__", "STM32F405xx", "USE_HAL_DRIVER", "HW_VERSION_MAJOR=3", @@ -47,11 +48,12 @@ "${workspaceFolder}/**" ], "defines": [ + "__arm__", "STM32F405xx", "USE_HAL_DRIVER", "HW_VERSION_MAJOR=3", "HW_VERSION_MINOR=4", - "HW_VERSION_VOLTAGE=24", + "HW_VERSION_VOLTAGE=56", "__weak=\"__attribute__((weak))\"", "__packed=\"__attribute__((__packed__))\"", "__GNUC__" diff --git a/Firmware/MotorControl/utils.hpp b/Firmware/MotorControl/utils.hpp index 70bd73be..42e03c8f 100644 --- a/Firmware/MotorControl/utils.hpp +++ b/Firmware/MotorControl/utils.hpp @@ -84,12 +84,24 @@ static const float one_by_sqrt3 = 0.57735026919f; static const float two_by_sqrt3 = 1.15470053838f; static const float sqrt3_by_2 = 0.86602540378f; -// Result depends on rounding mode -// With default rounding (round to nearest), +// Round to integer +// Default rounding mode: round to nearest +static inline int round_int(float x) { +#ifdef __arm__ + int res; + asm("vcvtr.s32.f32 %[res], %[x]" : [res] "=X" (res) : [x] "w" (x)); + return res; +#else + return (int)rint(x); +#endif +} + +// Wrap value to range. +// With default rounding mode (round to nearest), // the result will be in range -y/2 to y/2 static inline float wrap_pm(float x, float y) { - int q = (int)(x/y); - return x - (float)q * y; + int intval = round_int(x/y); + return x - (float)intval * y; } // Same as fmodf but result is positive and y must be positive From fc726dfa3615bb2935965fe12552637be9447bbc Mon Sep 17 00:00:00 2001 From: Oskar Weigl Date: Fri, 4 Sep 2020 16:09:17 -0700 Subject: [PATCH 16/41] use nearbyint on VFPv5 as it is single instruction --- Firmware/.vscode/c_cpp_properties.json | 3 +++ Firmware/MotorControl/utils.hpp | 10 +++++++--- Firmware/Tests/test_trap_traj.cpp | 2 +- Firmware/Tupfile.lua | 2 +- Firmware/fibre/cpp/include/fibre/protocol.hpp | 2 +- 5 files changed, 13 insertions(+), 6 deletions(-) diff --git a/Firmware/.vscode/c_cpp_properties.json b/Firmware/.vscode/c_cpp_properties.json index be9f826f..3a82cf12 100644 --- a/Firmware/.vscode/c_cpp_properties.json +++ b/Firmware/.vscode/c_cpp_properties.json @@ -8,6 +8,7 @@ "defines": [ "__arm__", "STM32F405xx", + "FPU_FPV4", "USE_HAL_DRIVER", "HW_VERSION_MAJOR=3", "HW_VERSION_MINOR=6", @@ -29,6 +30,7 @@ "defines": [ "__arm__", "STM32F405xx", + "FPU_FPV4", "USE_HAL_DRIVER", "HW_VERSION_MAJOR=3", "HW_VERSION_MINOR=6", @@ -50,6 +52,7 @@ "defines": [ "__arm__", "STM32F405xx", + "FPU_FPV4", "USE_HAL_DRIVER", "HW_VERSION_MAJOR=3", "HW_VERSION_MINOR=4", diff --git a/Firmware/MotorControl/utils.hpp b/Firmware/MotorControl/utils.hpp index 42e03c8f..e70a9ccc 100644 --- a/Firmware/MotorControl/utils.hpp +++ b/Firmware/MotorControl/utils.hpp @@ -92,7 +92,7 @@ static inline int round_int(float x) { asm("vcvtr.s32.f32 %[res], %[x]" : [res] "=X" (res) : [x] "w" (x)); return res; #else - return (int)rint(x); + return (int)nearbyint(x); #endif } @@ -100,8 +100,12 @@ static inline int round_int(float x) { // With default rounding mode (round to nearest), // the result will be in range -y/2 to y/2 static inline float wrap_pm(float x, float y) { - int intval = round_int(x/y); - return x - (float)intval * y; +#ifdef FPU_FPV4 + float intval = (float)round_int(x/y); +#else + float intval = nearbyint(x/y); +#endif + return x - intval * y; } // Same as fmodf but result is positive and y must be positive diff --git a/Firmware/Tests/test_trap_traj.cpp b/Firmware/Tests/test_trap_traj.cpp index b5d30014..d95328dd 100644 --- a/Firmware/Tests/test_trap_traj.cpp +++ b/Firmware/Tests/test_trap_traj.cpp @@ -1,7 +1,7 @@ #include #include -#include +#include #include #include diff --git a/Firmware/Tupfile.lua b/Firmware/Tupfile.lua index 040db512..d2cf3cbf 100644 --- a/Firmware/Tupfile.lua +++ b/Firmware/Tupfile.lua @@ -35,7 +35,7 @@ tup.frule{ board_v3 = { dir = 'Board/v3', sources = {'Drivers/DRV8301/drv8301.cpp', 'Board/v3/board.cpp'}, - flags = {'-DSTM32F405xx', '-DARM_MATH_CM4', '-mcpu=cortex-m4', '-mfpu=fpv4-sp-d16'}, + flags = {'-DSTM32F405xx', '-DARM_MATH_CM4', '-mcpu=cortex-m4', '-mfpu=fpv4-sp-d16', '-DFPU_FPV4'}, ldflags = {'-TBoard/v3/STM32F405RGTx_FLASH.ld', '-LBoard/v3/Drivers/CMSIS/Lib', '-larm_cortexM4lf_math', '-mcpu=cortex-m4', '-mfpu=fpv4-sp-d16'} } diff --git a/Firmware/fibre/cpp/include/fibre/protocol.hpp b/Firmware/fibre/cpp/include/fibre/protocol.hpp index 2a01e220..5d529c39 100644 --- a/Firmware/fibre/cpp/include/fibre/protocol.hpp +++ b/Firmware/fibre/cpp/include/fibre/protocol.hpp @@ -10,7 +10,7 @@ see protocol.md for the protocol specification #include #include -#include +#include //#include #include #include From 711111e6fb76594fbebf3cb641ea7cd837b28f00 Mon Sep 17 00:00:00 2001 From: Oskar Weigl Date: Fri, 4 Sep 2020 18:23:33 -0700 Subject: [PATCH 17/41] change fmaxf to std max --- Firmware/MotorControl/low_level.cpp | 2 +- Firmware/MotorControl/motor.cpp | 2 +- Firmware/MotorControl/trapTraj.cpp | 2 +- Firmware/Tests/test_trap_traj.cpp | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Firmware/MotorControl/low_level.cpp b/Firmware/MotorControl/low_level.cpp index a40d2ac6..af258c29 100644 --- a/Firmware/MotorControl/low_level.cpp +++ b/Firmware/MotorControl/low_level.cpp @@ -494,7 +494,7 @@ void update_brake_current() { float brake_duty = brake_current * odrv.config_.brake_resistance / vbus_voltage; if (odrv.config_.enable_dc_bus_overvoltage_ramp && (odrv.config_.brake_resistance > 0.0f) && (odrv.config_.dc_bus_overvoltage_ramp_start < odrv.config_.dc_bus_overvoltage_ramp_end)) { - brake_duty += std::fmax((vbus_voltage - odrv.config_.dc_bus_overvoltage_ramp_start) / (odrv.config_.dc_bus_overvoltage_ramp_end - odrv.config_.dc_bus_overvoltage_ramp_start), 0.0f); + brake_duty += std::max((vbus_voltage - odrv.config_.dc_bus_overvoltage_ramp_start) / (odrv.config_.dc_bus_overvoltage_ramp_end - odrv.config_.dc_bus_overvoltage_ramp_start), 0.0f); } if (std::isnan(brake_duty)) { diff --git a/Firmware/MotorControl/motor.cpp b/Firmware/MotorControl/motor.cpp index 9bdbaa75..0b0a2a31 100644 --- a/Firmware/MotorControl/motor.cpp +++ b/Firmware/MotorControl/motor.cpp @@ -416,7 +416,7 @@ bool Motor::update(float torque_setpoint, float phase, float phase_vel) { phase_vel *= config_.direction; if (config_.motor_type == MOTOR_TYPE_ACIM) { - current_setpoint = torque_setpoint / (config_.torque_constant * fmax(current_control_.acim_rotor_flux, config_.acim_gain_min_flux)); + current_setpoint = torque_setpoint / (config_.torque_constant * std::max(current_control_.acim_rotor_flux, config_.acim_gain_min_flux)); } else { current_setpoint = torque_setpoint / config_.torque_constant; diff --git a/Firmware/MotorControl/trapTraj.cpp b/Firmware/MotorControl/trapTraj.cpp index b3afd946..cb271fcd 100644 --- a/Firmware/MotorControl/trapTraj.cpp +++ b/Firmware/MotorControl/trapTraj.cpp @@ -42,7 +42,7 @@ bool TrapezoidalTrajectory::planTrapezoidal(float Xf, float Xi, float Vi, // Are we displacing enough to reach cruising speed? if (s*dX < s*dXmin) { // Short move (triangle profile) - Vr_ = s * sqrtf(std::fmax((Dr_*SQ(Vi) + 2*Ar_*Dr_*dX) / (Dr_ - Ar_), 0.0f)); + Vr_ = s * sqrtf(std::max((Dr_*SQ(Vi) + 2*Ar_*Dr_*dX) / (Dr_ - Ar_), 0.0f)); Ta_ = std::max(0.0f, (Vr_ - Vi) / Ar_); Td_ = std::max(0.0f, -Vr_ / Dr_); Tv_ = 0.0f; diff --git a/Firmware/Tests/test_trap_traj.cpp b/Firmware/Tests/test_trap_traj.cpp index d95328dd..90d8275f 100644 --- a/Firmware/Tests/test_trap_traj.cpp +++ b/Firmware/Tests/test_trap_traj.cpp @@ -85,7 +85,7 @@ bool TrapezoidalTrajectory::planTrapezoidal(float Xf, float Xi, float Vi, // Are we displacing enough to reach cruising speed? if (s*dX < s*dXmin) { // Short move (triangle profile) - Vr_ = s * sqrtf(std::fmax((Dr_*SQ(Vi) + 2*Ar_*Dr_*dX) / (Dr_ - Ar_), 0.0f)); + Vr_ = s * sqrtf(std::max((Dr_*SQ(Vi) + 2*Ar_*Dr_*dX) / (Dr_ - Ar_), 0.0f)); //Vr_ = s * sqrtf((Dr_*SQ(Vi) + 2*Ar_*Dr_*dX) / (Dr_ - Ar_)); Ta_ = std::max(0.0f, (Vr_ - Vi) / Ar_); Td_ = std::max(0.0f, -Vr_ / Dr_); From fb7d1d2961bba82e4ede5f32a07b5ca0b4b54967 Mon Sep 17 00:00:00 2001 From: Oskar Weigl Date: Fri, 4 Sep 2020 18:27:14 -0700 Subject: [PATCH 18/41] change fabsf to std abs --- Firmware/MotorControl/controller.cpp | 2 +- Firmware/MotorControl/motor.cpp | 4 ++-- Firmware/MotorControl/utils.cpp | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Firmware/MotorControl/controller.cpp b/Firmware/MotorControl/controller.cpp index ecea3c9c..88906cf5 100644 --- a/Firmware/MotorControl/controller.cpp +++ b/Firmware/MotorControl/controller.cpp @@ -275,7 +275,7 @@ bool Controller::update(float* torque_setpoint_output) { if (axis_->motor_.config_.motor_type == Motor::MOTOR_TYPE_ACIM) { float effective_flux = axis_->motor_.current_control_.acim_rotor_flux; float minflux = axis_->motor_.config_.acim_gain_min_flux; - if (fabsf(effective_flux) < minflux) + if (std::abs(effective_flux) < minflux) effective_flux = std::copysignf(minflux, effective_flux); vel_gain /= effective_flux; vel_integrator_gain /= effective_flux; diff --git a/Firmware/MotorControl/motor.cpp b/Firmware/MotorControl/motor.cpp index 0b0a2a31..b148ea7c 100644 --- a/Firmware/MotorControl/motor.cpp +++ b/Firmware/MotorControl/motor.cpp @@ -434,7 +434,7 @@ bool Motor::update(float torque_setpoint, float phase, float phase_vel) { // So we elect to write it as if the effect is immediate, to have cleaner code if (config_.acim_autoflux_enable) { - float abs_iq = fabsf(iq); + float abs_iq = std::abs(iq); float gain = abs_iq > id ? config_.acim_autoflux_attack_gain : config_.acim_autoflux_decay_gain; id += gain * (abs_iq - id) * current_meas_period; id = std::clamp(id, config_.acim_autoflux_min_Id, ilim); @@ -446,7 +446,7 @@ bool Motor::update(float torque_setpoint, float phase, float phase_vel) { current_control_.acim_rotor_flux += dflux_by_dt * current_meas_period; float slip_velocity = config_.acim_slip_velocity * (iq / current_control_.acim_rotor_flux); // Check for issues with small denominator. Polarity of check to catch NaN too - bool acceptable_vel = fabsf(slip_velocity) <= 0.1f * (float)current_meas_hz; + bool acceptable_vel = std::abs(slip_velocity) <= 0.1f * (float)current_meas_hz; if (!acceptable_vel) slip_velocity = 0.0f; phase_vel += slip_velocity; diff --git a/Firmware/MotorControl/utils.cpp b/Firmware/MotorControl/utils.cpp index f4dc212d..3bf30baf 100644 --- a/Firmware/MotorControl/utils.cpp +++ b/Firmware/MotorControl/utils.cpp @@ -124,8 +124,8 @@ int SVM(float alpha, float beta, float* tA, float* tB, float* tC) { // based on https://math.stackexchange.com/a/1105038/81278 float fast_atan2(float y, float x) { // a := min (|x|, |y|) / max (|x|, |y|) - float abs_y = fabsf(y); - float abs_x = fabsf(x); + float abs_y = std::abs(y); + float abs_x = std::abs(x); // inject FLT_MIN in denominator to avoid division by zero float a = MACRO_MIN(abs_x, abs_y) / (MACRO_MAX(abs_x, abs_y) + FLT_MIN); // s := a * a From 412329d71a6eb7a42a93f804e783be5361f9cc62 Mon Sep 17 00:00:00 2001 From: Oskar Weigl Date: Fri, 4 Sep 2020 19:46:12 -0700 Subject: [PATCH 19/41] change to cmath by default --- Firmware/Drivers/DRV8301/drv8301.cpp | 2 +- Firmware/MotorControl/low_level.cpp | 2 +- Firmware/MotorControl/trapTraj.cpp | 2 +- Firmware/MotorControl/utils.cpp | 2 +- Firmware/MotorControl/utils.hpp | 2 +- Firmware/Tests/test_trap_traj.cpp | 2 +- Firmware/fibre/cpp/include/fibre/protocol.hpp | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Firmware/Drivers/DRV8301/drv8301.cpp b/Firmware/Drivers/DRV8301/drv8301.cpp index e2fb20c2..3e1cbf91 100644 --- a/Firmware/Drivers/DRV8301/drv8301.cpp +++ b/Firmware/Drivers/DRV8301/drv8301.cpp @@ -41,7 +41,7 @@ #include "utils.hpp" #include "cmsis_os.h" -#include +#include #include #include diff --git a/Firmware/MotorControl/low_level.cpp b/Firmware/MotorControl/low_level.cpp index af258c29..ea6b879b 100644 --- a/Firmware/MotorControl/low_level.cpp +++ b/Firmware/MotorControl/low_level.cpp @@ -3,7 +3,7 @@ #include #include -#include +#include #include #include diff --git a/Firmware/MotorControl/trapTraj.cpp b/Firmware/MotorControl/trapTraj.cpp index cb271fcd..6bc73e18 100644 --- a/Firmware/MotorControl/trapTraj.cpp +++ b/Firmware/MotorControl/trapTraj.cpp @@ -1,4 +1,4 @@ -#include +#include #include "odrive_main.h" #include "utils.hpp" diff --git a/Firmware/MotorControl/utils.cpp b/Firmware/MotorControl/utils.cpp index 3bf30baf..313b5da0 100644 --- a/Firmware/MotorControl/utils.cpp +++ b/Firmware/MotorControl/utils.cpp @@ -1,6 +1,6 @@ #include -#include +#include #include #include #include diff --git a/Firmware/MotorControl/utils.hpp b/Firmware/MotorControl/utils.hpp index e70a9ccc..8c9143fa 100644 --- a/Firmware/MotorControl/utils.hpp +++ b/Firmware/MotorControl/utils.hpp @@ -3,7 +3,7 @@ #define __UTILS_H #include -#include +#include /** * @brief Flash size register address diff --git a/Firmware/Tests/test_trap_traj.cpp b/Firmware/Tests/test_trap_traj.cpp index 90d8275f..8d5399ff 100644 --- a/Firmware/Tests/test_trap_traj.cpp +++ b/Firmware/Tests/test_trap_traj.cpp @@ -1,7 +1,7 @@ #include #include -#include +#include #include #include diff --git a/Firmware/fibre/cpp/include/fibre/protocol.hpp b/Firmware/fibre/cpp/include/fibre/protocol.hpp index 5d529c39..2a01e220 100644 --- a/Firmware/fibre/cpp/include/fibre/protocol.hpp +++ b/Firmware/fibre/cpp/include/fibre/protocol.hpp @@ -10,7 +10,7 @@ see protocol.md for the protocol specification #include #include -#include +#include //#include #include #include From ec63f956f98efe7087d4dbd423de28d8c6f550e3 Mon Sep 17 00:00:00 2001 From: Oskar Weigl Date: Fri, 4 Sep 2020 20:17:35 -0700 Subject: [PATCH 20/41] no need for special fma function, the compiler knows --- Firmware/MotorControl/utils.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Firmware/MotorControl/utils.cpp b/Firmware/MotorControl/utils.cpp index 313b5da0..d518fa56 100644 --- a/Firmware/MotorControl/utils.cpp +++ b/Firmware/MotorControl/utils.cpp @@ -151,7 +151,7 @@ float fast_atan2(float y, float x) { float horner_fma(float x, const float *coeffs, size_t count) { float result = 0.0f; for (size_t idx = 0; idx < count; ++idx) - result = fmaf(result, x, coeffs[idx]); + result = (result * x) + coeffs[idx]; return result; } From 600832f8cff4394ecec00899d791684e7fb0e957 Mon Sep 17 00:00:00 2001 From: Oskar Weigl Date: Fri, 4 Sep 2020 20:31:58 -0700 Subject: [PATCH 21/41] drop flag fno-finite-math-only, and implement explicit nan check function --- Firmware/MotorControl/low_level.cpp | 14 ++++++++------ Firmware/MotorControl/motor.cpp | 9 ++++----- Firmware/MotorControl/thermistor.cpp | 2 +- Firmware/MotorControl/utils.cpp | 5 ++--- Firmware/MotorControl/utils.hpp | 11 +++++++++-- Firmware/Tupfile.lua | 2 +- 6 files changed, 25 insertions(+), 18 deletions(-) diff --git a/Firmware/MotorControl/low_level.cpp b/Firmware/MotorControl/low_level.cpp index ea6b879b..9a6f9ca2 100644 --- a/Firmware/MotorControl/low_level.cpp +++ b/Firmware/MotorControl/low_level.cpp @@ -296,7 +296,7 @@ void start_general_purpose_adc() { // @brief Returns the ADC voltage associated with the specified pin. // This only works if the GPIO was not used for anything else since bootup, otherwise // it must be put to analog mode first. -// Returns NaN if the pin has no associated ADC1 channel. +// Returns -1.0f if the pin has no associated ADC1 channel. // // On ODrive 3.3 and 3.4 the following pins can be used with this function: // GPIO_1, GPIO_2, GPIO_3, GPIO_4 and some pins that are connected to @@ -359,13 +359,13 @@ uint16_t channel_from_gpio(Stm32Gpio gpio) { } // @brief Given an adc channel return the measured voltage. -// returns NaN if the channel is not valid. +// returns -1.0f if the channel is not valid. float get_adc_voltage_channel(uint16_t channel) { if (channel < ADC_CHANNEL_COUNT) return ((float)adc_measurements_[channel]) * (adc_ref_voltage / adc_full_scale); else - return 0.0f / 0.0f; // NaN + return -1.0f; } //-------------------------------- @@ -497,7 +497,7 @@ void update_brake_current() { brake_duty += std::max((vbus_voltage - odrv.config_.dc_bus_overvoltage_ramp_start) / (odrv.config_.dc_bus_overvoltage_ramp_end - odrv.config_.dc_bus_overvoltage_ramp_start), 0.0f); } - if (std::isnan(brake_duty)) { + if (is_nan(brake_duty)) { // Shuts off all motors AND brake resistor, sets error code on all motors. low_level_fault(Motor::ERROR_BRAKE_DUTY_CYCLE_NAN); return; @@ -510,8 +510,10 @@ void update_brake_current() { // Duty limit at 95% to allow bootstrap caps to charge brake_duty = std::clamp(brake_duty, 0.0f, 0.95f); - // Special handling to avoid the case 0.0/0.0 == NaN. - Ibus_sum += brake_duty ? (brake_duty * vbus_voltage / odrv.config_.brake_resistance) : 0.0f; + // Special handling to avoid the case 0.0/0.0 == NaN, or divide by 0. + if (odrv.config_.brake_resistance > 0.0f) { + Ibus_sum += brake_duty * vbus_voltage / odrv.config_.brake_resistance; + } ibus_ += odrv.ibus_report_filter_k_ * (Ibus_sum - ibus_); diff --git a/Firmware/MotorControl/motor.cpp b/Firmware/MotorControl/motor.cpp index b148ea7c..3e160dee 100644 --- a/Firmware/MotorControl/motor.cpp +++ b/Firmware/MotorControl/motor.cpp @@ -260,10 +260,10 @@ bool Motor::run_calibration() { } bool Motor::enqueue_modulation_timings(float mod_alpha, float mod_beta) { - if (std::isnan(mod_alpha) || std::isnan(mod_alpha)) + if (is_nan(mod_alpha) || is_nan(mod_beta)) return set_error(ERROR_MODULATION_IS_NAN), false; float tA, tB, tC; - if (SVM(mod_alpha, mod_beta, &tA, &tB, &tC) != 0) + if (!SVM(mod_alpha, mod_beta, &tA, &tB, &tC)) return set_error(ERROR_MODULATION_MAGNITUDE), false; next_timings_[0] = (uint16_t)(tA * (float)TIM_1_8_PERIOD_CLOCKS); next_timings_[1] = (uint16_t)(tB * (float)TIM_1_8_PERIOD_CLOCKS); @@ -445,9 +445,8 @@ bool Motor::update(float torque_setpoint, float phase, float phase_vel) { float dflux_by_dt = config_.acim_slip_velocity * (id - current_control_.acim_rotor_flux); current_control_.acim_rotor_flux += dflux_by_dt * current_meas_period; float slip_velocity = config_.acim_slip_velocity * (iq / current_control_.acim_rotor_flux); - // Check for issues with small denominator. Polarity of check to catch NaN too - bool acceptable_vel = std::abs(slip_velocity) <= 0.1f * (float)current_meas_hz; - if (!acceptable_vel) + // Check for issues with small denominator. + if (is_nan(slip_velocity) || std::abs(slip_velocity) > 0.1f * (float)current_meas_hz) slip_velocity = 0.0f; phase_vel += slip_velocity; // reporting only: diff --git a/Firmware/MotorControl/thermistor.cpp b/Firmware/MotorControl/thermistor.cpp index 3baf78a0..617dee75 100644 --- a/Firmware/MotorControl/thermistor.cpp +++ b/Firmware/MotorControl/thermistor.cpp @@ -42,7 +42,7 @@ float ThermistorCurrentLimiter::get_current_limit(float base_current_lim) const const float temp_margin = temp_limit_upper_ - temperature_; const float derating_range = temp_limit_upper_ - temp_limit_lower_; float thermal_current_lim = base_current_lim * (temp_margin / derating_range); - if (!(thermal_current_lim >= 0.0f)) { // Funny polarity to also catch NaN + if (thermal_current_lim < 0.0f || is_nan(thermal_current_lim)) { thermal_current_lim = 0.0f; } diff --git a/Firmware/MotorControl/utils.cpp b/Firmware/MotorControl/utils.cpp index d518fa56..24aa9569 100644 --- a/Firmware/MotorControl/utils.cpp +++ b/Firmware/MotorControl/utils.cpp @@ -5,7 +5,7 @@ #include #include -int SVM(float alpha, float beta, float* tA, float* tB, float* tC) { +bool SVM(float alpha, float beta, float* tA, float* tB, float* tC) { int Sextant; if (beta >= 0.0f) { @@ -113,12 +113,11 @@ int SVM(float alpha, float beta, float* tA, float* tB, float* tC) { } break; } - // if any of the results becomes NaN, result_valid will evaluate to false int result_valid = *tA >= 0.0f && *tA <= 1.0f && *tB >= 0.0f && *tB <= 1.0f && *tC >= 0.0f && *tC <= 1.0f; - return result_valid ? 0 : -1; + return result_valid; } // based on https://math.stackexchange.com/a/1105038/81278 diff --git a/Firmware/MotorControl/utils.hpp b/Firmware/MotorControl/utils.hpp index 8c9143fa..e31f27cf 100644 --- a/Firmware/MotorControl/utils.hpp +++ b/Firmware/MotorControl/utils.hpp @@ -77,6 +77,13 @@ std::array make_array(T head, Tail... tail) return std::array({ head, tail ... }); } +// To allow use of -ffast-math we need to have a special check for nan +// that bypasses the "ignore nan" flag +__attribute__((optimize("-fno-finite-math-only"))) +static inline bool is_nan(float x) { + return __builtin_isnan(x);; +} + extern "C" { #endif @@ -122,8 +129,8 @@ static inline float wrap_pm_pi(float x) { // Compute rising edge timings (0.0 - 1.0) as a function of alpha-beta // as per the magnitude invariant clarke transform // The magnitude of the alpha-beta vector may not be larger than sqrt(3)/2 -// Returns 0 on success, and -1 if the input was out of range -int SVM(float alpha, float beta, float* tA, float* tB, float* tC); +// Returns true on success, and false if the input was out of range +bool SVM(float alpha, float beta, float* tA, float* tB, float* tC); float fast_atan2(float y, float x); float horner_fma(float x, const float *coeffs, size_t count); diff --git a/Firmware/Tupfile.lua b/Firmware/Tupfile.lua index d2cf3cbf..f5a78ad8 100644 --- a/Firmware/Tupfile.lua +++ b/Firmware/Tupfile.lua @@ -149,7 +149,7 @@ else end -- common flags for ASM, C and C++ -OPT += '-ffast-math -fno-finite-math-only' +OPT += '-ffast-math' tup.append_table(FLAGS, OPT) tup.append_table(LDFLAGS, OPT) From 4815e5ed19a6d99df8930a2bf15be1386a9b955b Mon Sep 17 00:00:00 2001 From: Unknown Date: Sat, 5 Sep 2020 00:23:58 -0400 Subject: [PATCH 22/41] Change sqrtf to std::sqrt --- Firmware/MotorControl/motor.cpp | 2 +- Firmware/MotorControl/trapTraj.cpp | 2 +- Firmware/Tests/test_trap_traj.cpp | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Firmware/MotorControl/motor.cpp b/Firmware/MotorControl/motor.cpp index 3e160dee..bfee0047 100644 --- a/Firmware/MotorControl/motor.cpp +++ b/Firmware/MotorControl/motor.cpp @@ -349,7 +349,7 @@ bool Motor::FOC_current(float Id_des, float Iq_des, float I_phase, float pwm_pha // Vector modulation saturation, lock integrator if saturated // TODO make maximum modulation configurable - float mod_scalefactor = 0.80f * sqrt3_by_2 * 1.0f / sqrtf(mod_d * mod_d + mod_q * mod_q); + float mod_scalefactor = 0.80f * sqrt3_by_2 * 1.0f / std::sqrt(mod_d * mod_d + mod_q * mod_q); if (mod_scalefactor < 1.0f) { mod_d *= mod_scalefactor; mod_q *= mod_scalefactor; diff --git a/Firmware/MotorControl/trapTraj.cpp b/Firmware/MotorControl/trapTraj.cpp index 6bc73e18..b4f94a37 100644 --- a/Firmware/MotorControl/trapTraj.cpp +++ b/Firmware/MotorControl/trapTraj.cpp @@ -42,7 +42,7 @@ bool TrapezoidalTrajectory::planTrapezoidal(float Xf, float Xi, float Vi, // Are we displacing enough to reach cruising speed? if (s*dX < s*dXmin) { // Short move (triangle profile) - Vr_ = s * sqrtf(std::max((Dr_*SQ(Vi) + 2*Ar_*Dr_*dX) / (Dr_ - Ar_), 0.0f)); + Vr_ = s * std::sqrt(std::max((Dr_*SQ(Vi) + 2*Ar_*Dr_*dX) / (Dr_ - Ar_), 0.0f)); Ta_ = std::max(0.0f, (Vr_ - Vi) / Ar_); Td_ = std::max(0.0f, -Vr_ / Dr_); Tv_ = 0.0f; diff --git a/Firmware/Tests/test_trap_traj.cpp b/Firmware/Tests/test_trap_traj.cpp index 8d5399ff..8d5aad2d 100644 --- a/Firmware/Tests/test_trap_traj.cpp +++ b/Firmware/Tests/test_trap_traj.cpp @@ -85,8 +85,8 @@ bool TrapezoidalTrajectory::planTrapezoidal(float Xf, float Xi, float Vi, // Are we displacing enough to reach cruising speed? if (s*dX < s*dXmin) { // Short move (triangle profile) - Vr_ = s * sqrtf(std::max((Dr_*SQ(Vi) + 2*Ar_*Dr_*dX) / (Dr_ - Ar_), 0.0f)); - //Vr_ = s * sqrtf((Dr_*SQ(Vi) + 2*Ar_*Dr_*dX) / (Dr_ - Ar_)); + Vr_ = s * std::sqrt(std::max((Dr_*SQ(Vi) + 2*Ar_*Dr_*dX) / (Dr_ - Ar_), 0.0f)); + //Vr_ = s * std::sqrt((Dr_*SQ(Vi) + 2*Ar_*Dr_*dX) / (Dr_ - Ar_)); Ta_ = std::max(0.0f, (Vr_ - Vi) / Ar_); Td_ = std::max(0.0f, -Vr_ / Dr_); Tv_ = 0.0f; From 9e1e054f0a741efd7282ad1e981e07fd9b36a8f0 Mon Sep 17 00:00:00 2001 From: Unknown Date: Sat, 5 Sep 2020 00:30:12 -0400 Subject: [PATCH 23/41] Bring several functions from utils.cpp into utils.hpp for inlining --- Firmware/MotorControl/utils.cpp | 157 ------------------------ Firmware/MotorControl/utils.hpp | 209 ++++++++++++++++++++++++++------ 2 files changed, 175 insertions(+), 191 deletions(-) diff --git a/Firmware/MotorControl/utils.cpp b/Firmware/MotorControl/utils.cpp index 24aa9569..8c041d55 100644 --- a/Firmware/MotorControl/utils.cpp +++ b/Firmware/MotorControl/utils.cpp @@ -1,164 +1,7 @@ #include -#include -#include -#include #include -bool SVM(float alpha, float beta, float* tA, float* tB, float* tC) { - int Sextant; - - if (beta >= 0.0f) { - if (alpha >= 0.0f) { - //quadrant I - if (one_by_sqrt3 * beta > alpha) - Sextant = 2; //sextant v2-v3 - else - Sextant = 1; //sextant v1-v2 - - } else { - //quadrant II - if (-one_by_sqrt3 * beta > alpha) - Sextant = 3; //sextant v3-v4 - else - Sextant = 2; //sextant v2-v3 - } - } else { - if (alpha >= 0.0f) { - //quadrant IV - if (-one_by_sqrt3 * beta > alpha) - Sextant = 5; //sextant v5-v6 - else - Sextant = 6; //sextant v6-v1 - } else { - //quadrant III - if (one_by_sqrt3 * beta > alpha) - Sextant = 4; //sextant v4-v5 - else - Sextant = 5; //sextant v5-v6 - } - } - - switch (Sextant) { - // sextant v1-v2 - case 1: { - // Vector on-times - float t1 = alpha - one_by_sqrt3 * beta; - float t2 = two_by_sqrt3 * beta; - - // PWM timings - *tA = (1.0f - t1 - t2) * 0.5f; - *tB = *tA + t1; - *tC = *tB + t2; - } break; - - // sextant v2-v3 - case 2: { - // Vector on-times - float t2 = alpha + one_by_sqrt3 * beta; - float t3 = -alpha + one_by_sqrt3 * beta; - - // PWM timings - *tB = (1.0f - t2 - t3) * 0.5f; - *tA = *tB + t3; - *tC = *tA + t2; - } break; - - // sextant v3-v4 - case 3: { - // Vector on-times - float t3 = two_by_sqrt3 * beta; - float t4 = -alpha - one_by_sqrt3 * beta; - - // PWM timings - *tB = (1.0f - t3 - t4) * 0.5f; - *tC = *tB + t3; - *tA = *tC + t4; - } break; - - // sextant v4-v5 - case 4: { - // Vector on-times - float t4 = -alpha + one_by_sqrt3 * beta; - float t5 = -two_by_sqrt3 * beta; - - // PWM timings - *tC = (1.0f - t4 - t5) * 0.5f; - *tB = *tC + t5; - *tA = *tB + t4; - } break; - - // sextant v5-v6 - case 5: { - // Vector on-times - float t5 = -alpha - one_by_sqrt3 * beta; - float t6 = alpha - one_by_sqrt3 * beta; - - // PWM timings - *tC = (1.0f - t5 - t6) * 0.5f; - *tA = *tC + t5; - *tB = *tA + t6; - } break; - - // sextant v6-v1 - case 6: { - // Vector on-times - float t6 = -two_by_sqrt3 * beta; - float t1 = alpha + one_by_sqrt3 * beta; - - // PWM timings - *tA = (1.0f - t6 - t1) * 0.5f; - *tC = *tA + t1; - *tB = *tC + t6; - } break; - } - - int result_valid = - *tA >= 0.0f && *tA <= 1.0f - && *tB >= 0.0f && *tB <= 1.0f - && *tC >= 0.0f && *tC <= 1.0f; - return result_valid; -} - -// based on https://math.stackexchange.com/a/1105038/81278 -float fast_atan2(float y, float x) { - // a := min (|x|, |y|) / max (|x|, |y|) - float abs_y = std::abs(y); - float abs_x = std::abs(x); - // inject FLT_MIN in denominator to avoid division by zero - float a = MACRO_MIN(abs_x, abs_y) / (MACRO_MAX(abs_x, abs_y) + FLT_MIN); - // s := a * a - float s = a * a; - // r := ((-0.0464964749 * s + 0.15931422) * s - 0.327622764) * s * a + a - float r = ((-0.0464964749f * s + 0.15931422f) * s - 0.327622764f) * s * a + a; - // if |y| > |x| then r := 1.57079637 - r - if (abs_y > abs_x) - r = 1.57079637f - r; - // if x < 0 then r := 3.14159274 - r - if (x < 0.0f) - r = 3.14159274f - r; - // if y < 0 then r := -r - if (y < 0.0f) - r = -r; - - return r; -} - -// Evaluate polynomials using Fused Multiply Add intrisic instruction. -// coeffs[0] is highest order, as per numpy.polyfit -// p(x) = coeffs[0] * x^deg + ... + coeffs[deg], for some degree "deg" -float horner_fma(float x, const float *coeffs, size_t count) { - float result = 0.0f; - for (size_t idx = 0; idx < count; ++idx) - result = (result * x) + coeffs[idx]; - return result; -} - -// Modulo (as opposed to remainder), per https://stackoverflow.com/a/19288271 -int mod(int dividend, int divisor){ - int r = dividend % divisor; - return (r < 0) ? (r + divisor) : r; -} // @brief: Returns how much time is left until the deadline is reached. // If the deadline has already passed, the return value is 0 (except if diff --git a/Firmware/MotorControl/utils.hpp b/Firmware/MotorControl/utils.hpp index e31f27cf..9e978d3a 100644 --- a/Firmware/MotorControl/utils.hpp +++ b/Firmware/MotorControl/utils.hpp @@ -1,9 +1,8 @@ - -#ifndef __UTILS_H -#define __UTILS_H +#pragma once #include -#include +#include +#include /** * @brief Flash size register address @@ -61,8 +60,6 @@ #define SQ(x) ((x) * (x)) -#ifdef __cplusplus - #include /** @@ -71,32 +68,30 @@ * has to match exactly. Whereas initializer lists allow * less arguments. */ -template -std::array make_array(T head, Tail... tail) -{ - return std::array({ head, tail ... }); +template +std::array make_array(T head, Tail... tail) { + return std::array({head, tail...}); } // To allow use of -ffast-math we need to have a special check for nan // that bypasses the "ignore nan" flag -__attribute__((optimize("-fno-finite-math-only"))) -static inline bool is_nan(float x) { - return __builtin_isnan(x);; +__attribute__((optimize("-fno-finite-math-only"))) static inline bool is_nan(float x) { + return __builtin_isnan(x); + ; } -extern "C" { -#endif - static const float one_by_sqrt3 = 0.57735026919f; static const float two_by_sqrt3 = 1.15470053838f; static const float sqrt3_by_2 = 0.86602540378f; // Round to integer // Default rounding mode: round to nearest -static inline int round_int(float x) { +inline int round_int(float x) { #ifdef __arm__ int res; - asm("vcvtr.s32.f32 %[res], %[x]" : [res] "=X" (res) : [x] "w" (x)); + asm("vcvtr.s32.f32 %[res], %[x]" + : [ res ] "=X"(res) + : [ x ] "w"(x)); return res; #else return (int)nearbyint(x); @@ -106,35 +101,185 @@ static inline int round_int(float x) { // Wrap value to range. // With default rounding mode (round to nearest), // the result will be in range -y/2 to y/2 -static inline float wrap_pm(float x, float y) { +inline float wrap_pm(float x, float y) { #ifdef FPU_FPV4 - float intval = (float)round_int(x/y); + float intval = (float)round_int(x / y); #else - float intval = nearbyint(x/y); + float intval = nearbyint(x / y); #endif return x - intval * y; } // Same as fmodf but result is positive and y must be positive -static inline float fmodf_pos(float x, float y) { +inline float fmodf_pos(float x, float y) { float res = wrap_pm(x, y); if (res < 0) res += y; return res; } -static inline float wrap_pm_pi(float x) { - return wrap_pm(x, 2*M_PI); +inline float wrap_pm_pi(float x) { + return wrap_pm(x, 2 * M_PI); } // Compute rising edge timings (0.0 - 1.0) as a function of alpha-beta // as per the magnitude invariant clarke transform // The magnitude of the alpha-beta vector may not be larger than sqrt(3)/2 // Returns true on success, and false if the input was out of range -bool SVM(float alpha, float beta, float* tA, float* tB, float* tC); +inline bool SVM(float alpha, float beta, float* tA, float* tB, float* tC) { + int Sextant; -float fast_atan2(float y, float x); -float horner_fma(float x, const float *coeffs, size_t count); -int mod(int dividend, int divisor); + if (beta >= 0.0f) { + if (alpha >= 0.0f) { + //quadrant I + if (one_by_sqrt3 * beta > alpha) + Sextant = 2; //sextant v2-v3 + else + Sextant = 1; //sextant v1-v2 + + } else { + //quadrant II + if (-one_by_sqrt3 * beta > alpha) + Sextant = 3; //sextant v3-v4 + else + Sextant = 2; //sextant v2-v3 + } + } else { + if (alpha >= 0.0f) { + //quadrant IV + if (-one_by_sqrt3 * beta > alpha) + Sextant = 5; //sextant v5-v6 + else + Sextant = 6; //sextant v6-v1 + } else { + //quadrant III + if (one_by_sqrt3 * beta > alpha) + Sextant = 4; //sextant v4-v5 + else + Sextant = 5; //sextant v5-v6 + } + } + + switch (Sextant) { + // sextant v1-v2 + case 1: { + // Vector on-times + float t1 = alpha - one_by_sqrt3 * beta; + float t2 = two_by_sqrt3 * beta; + + // PWM timings + *tA = (1.0f - t1 - t2) * 0.5f; + *tB = *tA + t1; + *tC = *tB + t2; + } break; + + // sextant v2-v3 + case 2: { + // Vector on-times + float t2 = alpha + one_by_sqrt3 * beta; + float t3 = -alpha + one_by_sqrt3 * beta; + + // PWM timings + *tB = (1.0f - t2 - t3) * 0.5f; + *tA = *tB + t3; + *tC = *tA + t2; + } break; + + // sextant v3-v4 + case 3: { + // Vector on-times + float t3 = two_by_sqrt3 * beta; + float t4 = -alpha - one_by_sqrt3 * beta; + + // PWM timings + *tB = (1.0f - t3 - t4) * 0.5f; + *tC = *tB + t3; + *tA = *tC + t4; + } break; + + // sextant v4-v5 + case 4: { + // Vector on-times + float t4 = -alpha + one_by_sqrt3 * beta; + float t5 = -two_by_sqrt3 * beta; + + // PWM timings + *tC = (1.0f - t4 - t5) * 0.5f; + *tB = *tC + t5; + *tA = *tB + t4; + } break; + + // sextant v5-v6 + case 5: { + // Vector on-times + float t5 = -alpha - one_by_sqrt3 * beta; + float t6 = alpha - one_by_sqrt3 * beta; + + // PWM timings + *tC = (1.0f - t5 - t6) * 0.5f; + *tA = *tC + t5; + *tB = *tA + t6; + } break; + + // sextant v6-v1 + case 6: { + // Vector on-times + float t6 = -two_by_sqrt3 * beta; + float t1 = alpha + one_by_sqrt3 * beta; + + // PWM timings + *tA = (1.0f - t6 - t1) * 0.5f; + *tC = *tA + t1; + *tB = *tC + t6; + } break; + } + + int result_valid = + *tA >= 0.0f && *tA <= 1.0f + && *tB >= 0.0f && *tB <= 1.0f + && *tC >= 0.0f && *tC <= 1.0f; + return result_valid; +} + + +// based on https://math.stackexchange.com/a/1105038/81278 +inline float fast_atan2(const float y, const float x) { + // a := min (|x|, |y|) / max (|x|, |y|) + float abs_y = std::abs(y); + float abs_x = std::abs(x); + // inject FLT_MIN in denominator to avoid division by zero + float a = std::min(abs_x, abs_y) / (std::max(abs_x, abs_y) + std::numeric_limits::min()); + // s := a * a + float s = a * a; + // r := ((-0.0464964749 * s + 0.15931422) * s - 0.327622764) * s * a + a + float r = ((-0.0464964749f * s + 0.15931422f) * s - 0.327622764f) * s * a + a; + // if |y| > |x| then r := 1.57079637 - r + if (abs_y > abs_x) + r = 1.57079637f - r; + // if x < 0 then r := 3.14159274 - r + if (x < 0.0f) + r = 3.14159274f - r; + // if y < 0 then r := -r + if (y < 0.0f) + r = -r; + + return r; +} + +// Evaluate polynomials using Fused Multiply Add intrisic instruction. +// coeffs[0] is highest order, as per numpy.polyfit +// p(x) = coeffs[0] * x^deg + ... + coeffs[deg], for some degree "deg" +inline float horner_fma(float x, const float *coeffs, size_t count) { + float result = 0.0f; + for (size_t idx = 0; idx < count; ++idx) + result = (result * x) + coeffs[idx]; + return result; +} + +// Modulo (as opposed to remainder), per https://stackoverflow.com/a/19288271 +inline int mod(const int dividend, const int divisor){ + int r = dividend % divisor; + return (r < 0) ? (r + divisor) : r; +} uint32_t deadline_to_timeout(uint32_t deadline_ms); uint32_t timeout_to_deadline(uint32_t timeout_ms); @@ -143,11 +288,7 @@ int is_in_the_future(uint32_t time_ms); uint32_t micros(void); void delay_us(uint32_t us); +extern "C" { float our_arm_sin_f32(float x); float our_arm_cos_f32(float x); - -#ifdef __cplusplus -} -#endif - -#endif //__UTILS_H +} \ No newline at end of file From fc5707a1a701cdd7969f5a21d73e80ccd142e57a Mon Sep 17 00:00:00 2001 From: Unknown Date: Sat, 5 Sep 2020 00:34:46 -0400 Subject: [PATCH 24/41] Remove unused macros --- Firmware/MotorControl/utils.hpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Firmware/MotorControl/utils.hpp b/Firmware/MotorControl/utils.hpp index 9e978d3a..e01afb7f 100644 --- a/Firmware/MotorControl/utils.hpp +++ b/Firmware/MotorControl/utils.hpp @@ -55,8 +55,7 @@ #endif #define M_PI (3.14159265358979323846f) -#define MACRO_MAX(x, y) (((x) > (y)) ? (x) : (y)) -#define MACRO_MIN(x, y) (((x) < (y)) ? (x) : (y)) +#include #define SQ(x) ((x) * (x)) From 9d5e8614eb8323b8bfe8cc1f80cf6ab99013e714 Mon Sep 17 00:00:00 2001 From: Unknown Date: Sat, 5 Sep 2020 00:36:06 -0400 Subject: [PATCH 25/41] Change SQ macro to a constexpr function --- Firmware/MotorControl/utils.hpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Firmware/MotorControl/utils.hpp b/Firmware/MotorControl/utils.hpp index e01afb7f..d02c9fa6 100644 --- a/Firmware/MotorControl/utils.hpp +++ b/Firmware/MotorControl/utils.hpp @@ -3,6 +3,7 @@ #include #include #include +#include /** * @brief Flash size register address @@ -55,11 +56,10 @@ #endif #define M_PI (3.14159265358979323846f) -#include - -#define SQ(x) ((x) * (x)) - -#include +template +constexpr T SQ(const T& x){ + return x * x; +} /** * @brief Small helper to make array with known size From ea08c1fe77c35042f54edab26069b35ee5541af2 Mon Sep 17 00:00:00 2001 From: Unknown Date: Sat, 5 Sep 2020 00:43:40 -0400 Subject: [PATCH 26/41] Constexpr math constants --- Firmware/MotorControl/utils.hpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Firmware/MotorControl/utils.hpp b/Firmware/MotorControl/utils.hpp index d02c9fa6..7a663406 100644 --- a/Firmware/MotorControl/utils.hpp +++ b/Firmware/MotorControl/utils.hpp @@ -54,7 +54,12 @@ #ifdef M_PI #undef M_PI #endif -#define M_PI (3.14159265358979323846f) + +// Math Constants +constexpr float M_PI = 3.14159265358979323846f; +constexpr float one_by_sqrt3 = 0.57735026919f; +constexpr float two_by_sqrt3 = 1.15470053838f; +constexpr float sqrt3_by_2 = 0.86602540378f; template constexpr T SQ(const T& x){ @@ -76,13 +81,8 @@ std::array make_array(T head, Tail... tail) { // that bypasses the "ignore nan" flag __attribute__((optimize("-fno-finite-math-only"))) static inline bool is_nan(float x) { return __builtin_isnan(x); - ; } -static const float one_by_sqrt3 = 0.57735026919f; -static const float two_by_sqrt3 = 1.15470053838f; -static const float sqrt3_by_2 = 0.86602540378f; - // Round to integer // Default rounding mode: round to nearest inline int round_int(float x) { From 29332281be14e85a4d0e9ff8a8022e451225ff6f Mon Sep 17 00:00:00 2001 From: Unknown Date: Sat, 5 Sep 2020 00:56:59 -0400 Subject: [PATCH 27/41] Convert SVM to not use out parameters --- Firmware/MotorControl/motor.cpp | 4 +-- Firmware/MotorControl/utils.hpp | 48 +++++++++++++++++---------------- 2 files changed, 27 insertions(+), 25 deletions(-) diff --git a/Firmware/MotorControl/motor.cpp b/Firmware/MotorControl/motor.cpp index bfee0047..06493cd4 100644 --- a/Firmware/MotorControl/motor.cpp +++ b/Firmware/MotorControl/motor.cpp @@ -262,8 +262,8 @@ bool Motor::run_calibration() { bool Motor::enqueue_modulation_timings(float mod_alpha, float mod_beta) { if (is_nan(mod_alpha) || is_nan(mod_beta)) return set_error(ERROR_MODULATION_IS_NAN), false; - float tA, tB, tC; - if (!SVM(mod_alpha, mod_beta, &tA, &tB, &tC)) + auto [tA, tB, tC, success] = SVM(mod_alpha, mod_beta); + if(!success) return set_error(ERROR_MODULATION_MAGNITUDE), false; next_timings_[0] = (uint16_t)(tA * (float)TIM_1_8_PERIOD_CLOCKS); next_timings_[1] = (uint16_t)(tB * (float)TIM_1_8_PERIOD_CLOCKS); diff --git a/Firmware/MotorControl/utils.hpp b/Firmware/MotorControl/utils.hpp index 7a663406..251e2cbc 100644 --- a/Firmware/MotorControl/utils.hpp +++ b/Firmware/MotorControl/utils.hpp @@ -4,6 +4,7 @@ #include #include #include +#include /** * @brief Flash size register address @@ -124,7 +125,8 @@ inline float wrap_pm_pi(float x) { // as per the magnitude invariant clarke transform // The magnitude of the alpha-beta vector may not be larger than sqrt(3)/2 // Returns true on success, and false if the input was out of range -inline bool SVM(float alpha, float beta, float* tA, float* tB, float* tC) { +inline auto SVM(float alpha, float beta) { + float tA, tB, tC; int Sextant; if (beta >= 0.0f) { @@ -166,9 +168,9 @@ inline bool SVM(float alpha, float beta, float* tA, float* tB, float* tC) { float t2 = two_by_sqrt3 * beta; // PWM timings - *tA = (1.0f - t1 - t2) * 0.5f; - *tB = *tA + t1; - *tC = *tB + t2; + tA = (1.0f - t1 - t2) * 0.5f; + tB = tA + t1; + tC = tB + t2; } break; // sextant v2-v3 @@ -178,9 +180,9 @@ inline bool SVM(float alpha, float beta, float* tA, float* tB, float* tC) { float t3 = -alpha + one_by_sqrt3 * beta; // PWM timings - *tB = (1.0f - t2 - t3) * 0.5f; - *tA = *tB + t3; - *tC = *tA + t2; + tB = (1.0f - t2 - t3) * 0.5f; + tA = tB + t3; + tC = tA + t2; } break; // sextant v3-v4 @@ -190,9 +192,9 @@ inline bool SVM(float alpha, float beta, float* tA, float* tB, float* tC) { float t4 = -alpha - one_by_sqrt3 * beta; // PWM timings - *tB = (1.0f - t3 - t4) * 0.5f; - *tC = *tB + t3; - *tA = *tC + t4; + tB = (1.0f - t3 - t4) * 0.5f; + tC = tB + t3; + tA = tC + t4; } break; // sextant v4-v5 @@ -202,9 +204,9 @@ inline bool SVM(float alpha, float beta, float* tA, float* tB, float* tC) { float t5 = -two_by_sqrt3 * beta; // PWM timings - *tC = (1.0f - t4 - t5) * 0.5f; - *tB = *tC + t5; - *tA = *tB + t4; + tC = (1.0f - t4 - t5) * 0.5f; + tB = tC + t5; + tA = tB + t4; } break; // sextant v5-v6 @@ -214,9 +216,9 @@ inline bool SVM(float alpha, float beta, float* tA, float* tB, float* tC) { float t6 = alpha - one_by_sqrt3 * beta; // PWM timings - *tC = (1.0f - t5 - t6) * 0.5f; - *tA = *tC + t5; - *tB = *tA + t6; + tC = (1.0f - t5 - t6) * 0.5f; + tA = tC + t5; + tB = tA + t6; } break; // sextant v6-v1 @@ -226,17 +228,17 @@ inline bool SVM(float alpha, float beta, float* tA, float* tB, float* tC) { float t1 = alpha + one_by_sqrt3 * beta; // PWM timings - *tA = (1.0f - t6 - t1) * 0.5f; - *tC = *tA + t1; - *tB = *tC + t6; + tA = (1.0f - t6 - t1) * 0.5f; + tC = tA + t1; + tB = tC + t6; } break; } int result_valid = - *tA >= 0.0f && *tA <= 1.0f - && *tB >= 0.0f && *tB <= 1.0f - && *tC >= 0.0f && *tC <= 1.0f; - return result_valid; + tA >= 0.0f && tA <= 1.0f + && tB >= 0.0f && tB <= 1.0f + && tC >= 0.0f && tC <= 1.0f; + return std::make_tuple(tA, tB, tC, result_valid); } From b38fd2be9c87eb16bb08d5ddd4968d2796497fb4 Mon Sep 17 00:00:00 2001 From: Oskar Weigl Date: Sat, 5 Sep 2020 15:25:32 -0700 Subject: [PATCH 28/41] Only inline short functions --- Firmware/MotorControl/thermistor.cpp | 2 +- Firmware/MotorControl/utils.cpp | 146 ++++++++++++++++- Firmware/MotorControl/utils.hpp | 188 +++------------------- Firmware/communication/interface_uart.cpp | 5 - 4 files changed, 171 insertions(+), 170 deletions(-) diff --git a/Firmware/MotorControl/thermistor.cpp b/Firmware/MotorControl/thermistor.cpp index 617dee75..df3b1d0d 100644 --- a/Firmware/MotorControl/thermistor.cpp +++ b/Firmware/MotorControl/thermistor.cpp @@ -22,7 +22,7 @@ ThermistorCurrentLimiter::ThermistorCurrentLimiter(uint16_t adc_channel, void ThermistorCurrentLimiter::update() { const float voltage = get_adc_voltage_channel(adc_channel_); const float normalized_voltage = voltage / adc_ref_voltage; - temperature_ = horner_fma(normalized_voltage, coefficients_, num_coeffs_); + temperature_ = horner_poly_eval(normalized_voltage, coefficients_, num_coeffs_); } bool ThermistorCurrentLimiter::do_checks() { diff --git a/Firmware/MotorControl/utils.cpp b/Firmware/MotorControl/utils.cpp index 8c041d55..dad400fb 100644 --- a/Firmware/MotorControl/utils.cpp +++ b/Firmware/MotorControl/utils.cpp @@ -3,6 +3,150 @@ #include +// Compute rising edge timings (0.0 - 1.0) as a function of alpha-beta +// as per the magnitude invariant clarke transform +// The magnitude of the alpha-beta vector may not be larger than sqrt(3)/2 +// Returns true on success, and false if the input was out of range +std::tuple SVM(float alpha, float beta) { + float tA, tB, tC; + int Sextant; + + if (beta >= 0.0f) { + if (alpha >= 0.0f) { + //quadrant I + if (one_by_sqrt3 * beta > alpha) + Sextant = 2; //sextant v2-v3 + else + Sextant = 1; //sextant v1-v2 + + } else { + //quadrant II + if (-one_by_sqrt3 * beta > alpha) + Sextant = 3; //sextant v3-v4 + else + Sextant = 2; //sextant v2-v3 + } + } else { + if (alpha >= 0.0f) { + //quadrant IV + if (-one_by_sqrt3 * beta > alpha) + Sextant = 5; //sextant v5-v6 + else + Sextant = 6; //sextant v6-v1 + } else { + //quadrant III + if (one_by_sqrt3 * beta > alpha) + Sextant = 4; //sextant v4-v5 + else + Sextant = 5; //sextant v5-v6 + } + } + + switch (Sextant) { + // sextant v1-v2 + case 1: { + // Vector on-times + float t1 = alpha - one_by_sqrt3 * beta; + float t2 = two_by_sqrt3 * beta; + + // PWM timings + tA = (1.0f - t1 - t2) * 0.5f; + tB = tA + t1; + tC = tB + t2; + } break; + + // sextant v2-v3 + case 2: { + // Vector on-times + float t2 = alpha + one_by_sqrt3 * beta; + float t3 = -alpha + one_by_sqrt3 * beta; + + // PWM timings + tB = (1.0f - t2 - t3) * 0.5f; + tA = tB + t3; + tC = tA + t2; + } break; + + // sextant v3-v4 + case 3: { + // Vector on-times + float t3 = two_by_sqrt3 * beta; + float t4 = -alpha - one_by_sqrt3 * beta; + + // PWM timings + tB = (1.0f - t3 - t4) * 0.5f; + tC = tB + t3; + tA = tC + t4; + } break; + + // sextant v4-v5 + case 4: { + // Vector on-times + float t4 = -alpha + one_by_sqrt3 * beta; + float t5 = -two_by_sqrt3 * beta; + + // PWM timings + tC = (1.0f - t4 - t5) * 0.5f; + tB = tC + t5; + tA = tB + t4; + } break; + + // sextant v5-v6 + case 5: { + // Vector on-times + float t5 = -alpha - one_by_sqrt3 * beta; + float t6 = alpha - one_by_sqrt3 * beta; + + // PWM timings + tC = (1.0f - t5 - t6) * 0.5f; + tA = tC + t5; + tB = tA + t6; + } break; + + // sextant v6-v1 + case 6: { + // Vector on-times + float t6 = -two_by_sqrt3 * beta; + float t1 = alpha + one_by_sqrt3 * beta; + + // PWM timings + tA = (1.0f - t6 - t1) * 0.5f; + tC = tA + t1; + tB = tC + t6; + } break; + } + + int result_valid = + tA >= 0.0f && tA <= 1.0f + && tB >= 0.0f && tB <= 1.0f + && tC >= 0.0f && tC <= 1.0f; + return {tA, tB, tC, result_valid}; +} + +// based on https://math.stackexchange.com/a/1105038/81278 +float fast_atan2(float y, float x) { + // a := min (|x|, |y|) / max (|x|, |y|) + float abs_y = std::abs(y); + float abs_x = std::abs(x); + // inject FLT_MIN in denominator to avoid division by zero + float a = std::min(abs_x, abs_y) / (std::max(abs_x, abs_y) + std::numeric_limits::min()); + // s := a * a + float s = a * a; + // r := ((-0.0464964749 * s + 0.15931422) * s - 0.327622764) * s * a + a + float r = ((-0.0464964749f * s + 0.15931422f) * s - 0.327622764f) * s * a + a; + // if |y| > |x| then r := 1.57079637 - r + if (abs_y > abs_x) + r = 1.57079637f - r; + // if x < 0 then r := 3.14159274 - r + if (x < 0.0f) + r = 3.14159274f - r; + // if y < 0 then r := -r + if (y < 0.0f) + r = -r; + + return r; +} + // @brief: Returns how much time is left until the deadline is reached. // If the deadline has already passed, the return value is 0 (except if // the deadline is very far in the past) @@ -41,6 +185,6 @@ void delay_us(uint32_t us) { uint32_t start = micros(); while (micros() - start < (uint32_t) us) { - __ASM("nop"); + asm volatile ("nop"); } } diff --git a/Firmware/MotorControl/utils.hpp b/Firmware/MotorControl/utils.hpp index 251e2cbc..8eb044f9 100644 --- a/Firmware/MotorControl/utils.hpp +++ b/Firmware/MotorControl/utils.hpp @@ -62,6 +62,23 @@ constexpr float one_by_sqrt3 = 0.57735026919f; constexpr float two_by_sqrt3 = 1.15470053838f; constexpr float sqrt3_by_2 = 0.86602540378f; +// Function prototypes for implementations in utils.cpp +std::tuple SVM(float alpha, float beta); +float fast_atan2(float y, float x); +uint32_t deadline_to_timeout(uint32_t deadline_ms); +uint32_t timeout_to_deadline(uint32_t timeout_ms); +int is_in_the_future(uint32_t time_ms); +uint32_t micros(void); +void delay_us(uint32_t us); + +extern "C" { +float our_arm_sin_f32(float x); +float our_arm_cos_f32(float x); +} + +// ---------------- +// Inline functions + template constexpr T SQ(const T& x){ return x * x; @@ -80,7 +97,8 @@ std::array make_array(T head, Tail... tail) { // To allow use of -ffast-math we need to have a special check for nan // that bypasses the "ignore nan" flag -__attribute__((optimize("-fno-finite-math-only"))) static inline bool is_nan(float x) { +__attribute__((optimize("-fno-finite-math-only"))) +inline bool is_nan(float x) { return __builtin_isnan(x); } @@ -90,8 +108,8 @@ inline int round_int(float x) { #ifdef __arm__ int res; asm("vcvtr.s32.f32 %[res], %[x]" - : [ res ] "=X"(res) - : [ x ] "w"(x)); + : [res] "=X" (res) + : [x] "w" (x) ); return res; #else return (int)nearbyint(x); @@ -121,155 +139,10 @@ inline float wrap_pm_pi(float x) { return wrap_pm(x, 2 * M_PI); } -// Compute rising edge timings (0.0 - 1.0) as a function of alpha-beta -// as per the magnitude invariant clarke transform -// The magnitude of the alpha-beta vector may not be larger than sqrt(3)/2 -// Returns true on success, and false if the input was out of range -inline auto SVM(float alpha, float beta) { - float tA, tB, tC; - int Sextant; - - if (beta >= 0.0f) { - if (alpha >= 0.0f) { - //quadrant I - if (one_by_sqrt3 * beta > alpha) - Sextant = 2; //sextant v2-v3 - else - Sextant = 1; //sextant v1-v2 - - } else { - //quadrant II - if (-one_by_sqrt3 * beta > alpha) - Sextant = 3; //sextant v3-v4 - else - Sextant = 2; //sextant v2-v3 - } - } else { - if (alpha >= 0.0f) { - //quadrant IV - if (-one_by_sqrt3 * beta > alpha) - Sextant = 5; //sextant v5-v6 - else - Sextant = 6; //sextant v6-v1 - } else { - //quadrant III - if (one_by_sqrt3 * beta > alpha) - Sextant = 4; //sextant v4-v5 - else - Sextant = 5; //sextant v5-v6 - } - } - - switch (Sextant) { - // sextant v1-v2 - case 1: { - // Vector on-times - float t1 = alpha - one_by_sqrt3 * beta; - float t2 = two_by_sqrt3 * beta; - - // PWM timings - tA = (1.0f - t1 - t2) * 0.5f; - tB = tA + t1; - tC = tB + t2; - } break; - - // sextant v2-v3 - case 2: { - // Vector on-times - float t2 = alpha + one_by_sqrt3 * beta; - float t3 = -alpha + one_by_sqrt3 * beta; - - // PWM timings - tB = (1.0f - t2 - t3) * 0.5f; - tA = tB + t3; - tC = tA + t2; - } break; - - // sextant v3-v4 - case 3: { - // Vector on-times - float t3 = two_by_sqrt3 * beta; - float t4 = -alpha - one_by_sqrt3 * beta; - - // PWM timings - tB = (1.0f - t3 - t4) * 0.5f; - tC = tB + t3; - tA = tC + t4; - } break; - - // sextant v4-v5 - case 4: { - // Vector on-times - float t4 = -alpha + one_by_sqrt3 * beta; - float t5 = -two_by_sqrt3 * beta; - - // PWM timings - tC = (1.0f - t4 - t5) * 0.5f; - tB = tC + t5; - tA = tB + t4; - } break; - - // sextant v5-v6 - case 5: { - // Vector on-times - float t5 = -alpha - one_by_sqrt3 * beta; - float t6 = alpha - one_by_sqrt3 * beta; - - // PWM timings - tC = (1.0f - t5 - t6) * 0.5f; - tA = tC + t5; - tB = tA + t6; - } break; - - // sextant v6-v1 - case 6: { - // Vector on-times - float t6 = -two_by_sqrt3 * beta; - float t1 = alpha + one_by_sqrt3 * beta; - - // PWM timings - tA = (1.0f - t6 - t1) * 0.5f; - tC = tA + t1; - tB = tC + t6; - } break; - } - - int result_valid = - tA >= 0.0f && tA <= 1.0f - && tB >= 0.0f && tB <= 1.0f - && tC >= 0.0f && tC <= 1.0f; - return std::make_tuple(tA, tB, tC, result_valid); -} - - -// based on https://math.stackexchange.com/a/1105038/81278 -inline float fast_atan2(const float y, const float x) { - // a := min (|x|, |y|) / max (|x|, |y|) - float abs_y = std::abs(y); - float abs_x = std::abs(x); - // inject FLT_MIN in denominator to avoid division by zero - float a = std::min(abs_x, abs_y) / (std::max(abs_x, abs_y) + std::numeric_limits::min()); - // s := a * a - float s = a * a; - // r := ((-0.0464964749 * s + 0.15931422) * s - 0.327622764) * s * a + a - float r = ((-0.0464964749f * s + 0.15931422f) * s - 0.327622764f) * s * a + a; - // if |y| > |x| then r := 1.57079637 - r - if (abs_y > abs_x) - r = 1.57079637f - r; - // if x < 0 then r := 3.14159274 - r - if (x < 0.0f) - r = 3.14159274f - r; - // if y < 0 then r := -r - if (y < 0.0f) - r = -r; - - return r; -} - -// Evaluate polynomials using Fused Multiply Add intrisic instruction. +// Evaluate polynomials in an efficient way // coeffs[0] is highest order, as per numpy.polyfit // p(x) = coeffs[0] * x^deg + ... + coeffs[deg], for some degree "deg" -inline float horner_fma(float x, const float *coeffs, size_t count) { +inline float horner_poly_eval(float x, const float *coeffs, size_t count) { float result = 0.0f; for (size_t idx = 0; idx < count; ++idx) result = (result * x) + coeffs[idx]; @@ -279,17 +152,6 @@ inline float horner_fma(float x, const float *coeffs, size_t count) { // Modulo (as opposed to remainder), per https://stackoverflow.com/a/19288271 inline int mod(const int dividend, const int divisor){ int r = dividend % divisor; - return (r < 0) ? (r + divisor) : r; + if (r < 0) r += divisor; + return r; } - -uint32_t deadline_to_timeout(uint32_t deadline_ms); -uint32_t timeout_to_deadline(uint32_t timeout_ms); -int is_in_the_future(uint32_t time_ms); - -uint32_t micros(void); -void delay_us(uint32_t us); - -extern "C" { -float our_arm_sin_f32(float x); -float our_arm_cos_f32(float x); -} \ No newline at end of file diff --git a/Firmware/communication/interface_uart.cpp b/Firmware/communication/interface_uart.cpp index 74fa02c0..6450eb50 100644 --- a/Firmware/communication/interface_uart.cpp +++ b/Firmware/communication/interface_uart.cpp @@ -18,9 +18,6 @@ static uint8_t dma_rx_buffer[UART_RX_BUFFER_SIZE]; static uint32_t dma_last_rcv_idx; -// FIXME: the stdlib doesn't know about CMSIS threads, so this is just a global variable -// static thread_local uint32_t deadline_ms = 0; - osThreadId uart_thread = 0; extern UART_HandleTypeDef* uart0; static UART_HandleTypeDef* huart_ = uart0; // defined in board.cpp. @@ -35,7 +32,6 @@ public: size_t chunk = length < UART_TX_BUFFER_SIZE ? length : UART_TX_BUFFER_SIZE; // wait for USB interface to become ready // TODO: implement ring buffer to get a more continuous stream of data - // if (osSemaphoreWait(sem_uart_dma, deadline_to_timeout(deadline_ms)) != osOK) if (osSemaphoreWait(sem_uart_dma, PROTOCOL_SERVER_TIMEOUT_MS) != osOK) return -1; // transmit chunk @@ -76,7 +72,6 @@ static void uart_server_thread(void * ctx) { continue; } - // deadline_ms = timeout_to_deadline(PROTOCOL_SERVER_TIMEOUT_MS); // Process bytes in one or two chunks (two in case there was a wrap) if (new_rcv_idx < dma_last_rcv_idx) { uart_stream_input.process_bytes(dma_rx_buffer + dma_last_rcv_idx, From 33987df7e1335f2deada3eb39d9c42f529fd40c1 Mon Sep 17 00:00:00 2001 From: Oskar Weigl Date: Sat, 5 Sep 2020 16:15:11 -0700 Subject: [PATCH 29/41] Avoid redundant normalizing of adc voltage --- Firmware/MotorControl/encoder.cpp | 4 ++-- Firmware/MotorControl/low_level.cpp | 13 ++++++++----- Firmware/MotorControl/low_level.h | 9 ++++++--- Firmware/MotorControl/thermistor.cpp | 3 +-- 4 files changed, 17 insertions(+), 12 deletions(-) diff --git a/Firmware/MotorControl/encoder.cpp b/Firmware/MotorControl/encoder.cpp index f0c65445..4fe75689 100644 --- a/Firmware/MotorControl/encoder.cpp +++ b/Firmware/MotorControl/encoder.cpp @@ -330,8 +330,8 @@ void Encoder::sample_now() { } break; case MODE_SINCOS: { - sincos_sample_s_ = (get_adc_voltage(get_gpio(config_.sincos_gpio_pin_sin)) / 3.3f) - 0.5f; - sincos_sample_c_ = (get_adc_voltage(get_gpio(config_.sincos_gpio_pin_cos)) / 3.3f) - 0.5f; + sincos_sample_s_ = get_adc_relative_voltage(get_gpio(config_.sincos_gpio_pin_sin)) - 0.5f; + sincos_sample_c_ = get_adc_relative_voltage(get_gpio(config_.sincos_gpio_pin_cos)) - 0.5f; } break; case MODE_SPI_ABS_AMS: diff --git a/Firmware/MotorControl/low_level.cpp b/Firmware/MotorControl/low_level.cpp index 9a6f9ca2..abd5fc09 100644 --- a/Firmware/MotorControl/low_level.cpp +++ b/Firmware/MotorControl/low_level.cpp @@ -311,8 +311,12 @@ void start_general_purpose_adc() { // The true frequency is slightly lower because of the injected vbus // measurements float get_adc_voltage(Stm32Gpio gpio) { + return get_adc_relative_voltage(gpio) * adc_ref_voltage; +} + +float get_adc_relative_voltage(Stm32Gpio gpio) { const uint16_t channel = channel_from_gpio(gpio); - return get_adc_voltage_channel(channel); + return get_adc_relative_voltage_ch(channel); } // @brief Given a GPIO_port and pin return the associated adc_channel. @@ -358,12 +362,11 @@ uint16_t channel_from_gpio(Stm32Gpio gpio) { return channel; } -// @brief Given an adc channel return the measured voltage. +// @brief Given an adc channel return the voltage as a ratio of adc_ref_voltage // returns -1.0f if the channel is not valid. -float get_adc_voltage_channel(uint16_t channel) -{ +float get_adc_relative_voltage_ch(uint16_t channel) { if (channel < ADC_CHANNEL_COUNT) - return ((float)adc_measurements_[channel]) * (adc_ref_voltage / adc_full_scale); + return (float)adc_measurements_[channel] / adc_full_scale; else return -1.0f; } diff --git a/Firmware/MotorControl/low_level.h b/Firmware/MotorControl/low_level.h index e02ef5c2..fdae02a1 100644 --- a/Firmware/MotorControl/low_level.h +++ b/Firmware/MotorControl/low_level.h @@ -46,12 +46,15 @@ void sync_timers(TIM_HandleTypeDef* htim_a, TIM_HandleTypeDef* htim_b, uint16_t TIM_CLOCKSOURCE_ITRx, uint16_t count_offset, TIM_HandleTypeDef* htim_refbase = nullptr); void start_general_purpose_adc(); -float get_adc_voltage(Stm32Gpio gpio); -uint16_t channel_from_gpio(Stm32Gpio gpio); -float get_adc_voltage_channel(uint16_t channel); void pwm_in_init(); void start_analog_thread(); +// ADC getters +uint16_t channel_from_gpio(Stm32Gpio gpio); +float get_adc_voltage(Stm32Gpio gpio); +float get_adc_relative_voltage(Stm32Gpio gpio); +float get_adc_relative_voltage_ch(uint16_t channel); + void update_brake_current(); #ifdef __cplusplus diff --git a/Firmware/MotorControl/thermistor.cpp b/Firmware/MotorControl/thermistor.cpp index df3b1d0d..4d16ae61 100644 --- a/Firmware/MotorControl/thermistor.cpp +++ b/Firmware/MotorControl/thermistor.cpp @@ -20,8 +20,7 @@ ThermistorCurrentLimiter::ThermistorCurrentLimiter(uint16_t adc_channel, } void ThermistorCurrentLimiter::update() { - const float voltage = get_adc_voltage_channel(adc_channel_); - const float normalized_voltage = voltage / adc_ref_voltage; + const float normalized_voltage = get_adc_relative_voltage_ch(adc_channel_); temperature_ = horner_poly_eval(normalized_voltage, coefficients_, num_coeffs_); } From 1e48a2b0e06d89f69a7a6af7573f8a270e0e78fd Mon Sep 17 00:00:00 2001 From: Oskar Weigl Date: Sat, 5 Sep 2020 16:40:59 -0700 Subject: [PATCH 30/41] fix result valid type --- Firmware/MotorControl/utils.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Firmware/MotorControl/utils.cpp b/Firmware/MotorControl/utils.cpp index dad400fb..cb1866db 100644 --- a/Firmware/MotorControl/utils.cpp +++ b/Firmware/MotorControl/utils.cpp @@ -18,7 +18,6 @@ std::tuple SVM(float alpha, float beta) { Sextant = 2; //sextant v2-v3 else Sextant = 1; //sextant v1-v2 - } else { //quadrant II if (-one_by_sqrt3 * beta > alpha) @@ -116,7 +115,7 @@ std::tuple SVM(float alpha, float beta) { } break; } - int result_valid = + bool result_valid = tA >= 0.0f && tA <= 1.0f && tB >= 0.0f && tB <= 1.0f && tC >= 0.0f && tC <= 1.0f; From 8419e0ab1705ba6f6f12372f5e93842288d0e850 Mon Sep 17 00:00:00 2001 From: Oskar Weigl Date: Sat, 5 Sep 2020 17:30:07 -0700 Subject: [PATCH 31/41] decode functions using nm with name demangling --- Firmware/sampler.py | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/Firmware/sampler.py b/Firmware/sampler.py index a51e4c7e..6f032b32 100644 --- a/Firmware/sampler.py +++ b/Firmware/sampler.py @@ -45,17 +45,22 @@ class OpenOCDCMSampler(object): return 0 - def initSymbols(self, elf, readelf='arm-none-eabi-readelf'): - proc = subprocess.Popen([readelf, '-s', elf], stdout=subprocess.PIPE) + def initSymbols(self, elf, symbol_dump_cmd='arm-none-eabi-nm'): + proc = subprocess.Popen([symbol_dump_cmd, '-CS', elf], stdout=subprocess.PIPE) for line in proc.stdout.readlines(): field = line.split() - # for i,txt in enumerate(field): - # print("{}, {}".format(i, txt)) + try: - if field[3] == b'FUNC': - addr = int(field[1], 16) - 1 # For some reason readelf dumps the func addr off by 1 - func = field[7] - size = int(field[2]) + # For using nm -CS + if field[2] in ('t', 'T', 'w', 'W'): + addr = int(field[0], 16) + func = field[3] + size = int(field[1], 16) + # # For using readelf -s + # if field[3] == b'FUNC': + # addr = int(field[1], 16) - 1 # For some reason readelf dumps the func addr off by 1 + # func = field[7] + # size = int(field[2]) if addr not in self.indexes: self.table.append((addr, func, size)) self.indexes.add(addr) From d788fa71488871fc0638786b4d81e1356dea4c6f Mon Sep 17 00:00:00 2001 From: Oskar Weigl Date: Sat, 5 Sep 2020 17:38:31 -0700 Subject: [PATCH 32/41] use --size-sort to force always print a size --- Firmware/sampler.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Firmware/sampler.py b/Firmware/sampler.py index 6f032b32..694b783c 100644 --- a/Firmware/sampler.py +++ b/Firmware/sampler.py @@ -46,7 +46,7 @@ class OpenOCDCMSampler(object): def initSymbols(self, elf, symbol_dump_cmd='arm-none-eabi-nm'): - proc = subprocess.Popen([symbol_dump_cmd, '-CS', elf], stdout=subprocess.PIPE) + proc = subprocess.Popen([symbol_dump_cmd, '-CS', '--size-sort', elf], stdout=subprocess.PIPE) for line in proc.stdout.readlines(): field = line.split() From 7d92018ee8952998ef8d19ec342c4a898c633687 Mon Sep 17 00:00:00 2001 From: Unknown Date: Sat, 5 Sep 2020 20:44:10 -0400 Subject: [PATCH 33/41] Fix character matching --- Firmware/sampler.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Firmware/sampler.py b/Firmware/sampler.py index 694b783c..a033f66f 100644 --- a/Firmware/sampler.py +++ b/Firmware/sampler.py @@ -52,7 +52,7 @@ class OpenOCDCMSampler(object): try: # For using nm -CS - if field[2] in ('t', 'T', 'w', 'W'): + if field[2] in (b't', b'T', b'w', b'W'): addr = int(field[0], 16) func = field[3] size = int(field[1], 16) From 682f8bfada7b5ae2778584617456744a2af4915d Mon Sep 17 00:00:00 2001 From: Unknown Date: Sat, 5 Sep 2020 20:45:48 -0400 Subject: [PATCH 34/41] Decode function name as UTF-8 --- Firmware/sampler.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Firmware/sampler.py b/Firmware/sampler.py index a033f66f..3c97617c 100644 --- a/Firmware/sampler.py +++ b/Firmware/sampler.py @@ -129,7 +129,7 @@ if __name__ == '__main__': tmp = sorted(countmap.items(), key=operator.itemgetter(1)) #, reverse=True) for k, v in tmp: - print('{:05.2f}% {}'.format((v * 100.) / total, k)) + print('{:05.2f}% {}'.format((v * 100.) / total, k.decode('UTF-8'))) # print('{:06.2f} clocks : {}'.format((v * 10500) / total, k)) start = cur print('{} Samples'.format(total)) From 4a45314c978dc3d18259e209dff2273bb806e4ed Mon Sep 17 00:00:00 2001 From: Oskar Weigl Date: Sat, 5 Sep 2020 18:09:14 -0700 Subject: [PATCH 35/41] all words in function names --- Firmware/sampler.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Firmware/sampler.py b/Firmware/sampler.py index 3c97617c..7ad9392d 100644 --- a/Firmware/sampler.py +++ b/Firmware/sampler.py @@ -54,7 +54,7 @@ class OpenOCDCMSampler(object): # For using nm -CS if field[2] in (b't', b'T', b'w', b'W'): addr = int(field[0], 16) - func = field[3] + func = ' '.join(field[3:-1]) size = int(field[1], 16) # # For using readelf -s # if field[3] == b'FUNC': From f9fa06c86fe1720568c6e57f4bd93fecaec4fc8b Mon Sep 17 00:00:00 2001 From: Unknown Date: Sat, 5 Sep 2020 21:15:45 -0400 Subject: [PATCH 36/41] Fix all words in func names --- Firmware/sampler.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Firmware/sampler.py b/Firmware/sampler.py index 7ad9392d..4fc25a97 100644 --- a/Firmware/sampler.py +++ b/Firmware/sampler.py @@ -54,7 +54,7 @@ class OpenOCDCMSampler(object): # For using nm -CS if field[2] in (b't', b'T', b'w', b'W'): addr = int(field[0], 16) - func = ' '.join(field[3:-1]) + func = b' '.join(field[3:]) size = int(field[1], 16) # # For using readelf -s # if field[3] == b'FUNC': From 062c3978474b2d46ca9f210913c20feebc1c3912 Mon Sep 17 00:00:00 2001 From: Samuel Sadok Date: Mon, 7 Sep 2020 20:54:12 +0200 Subject: [PATCH 37/41] implement CI check against std::isnan --- .github/workflows/compile.yaml | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/.github/workflows/compile.yaml b/.github/workflows/compile.yaml index a433132f..f8468433 100644 --- a/.github/workflows/compile.yaml +++ b/.github/workflows/compile.yaml @@ -108,9 +108,22 @@ jobs: mv tup_build.sh tup_build.bat # in reality this is a .bat script on windows .\tup_build.bat - #code-checks: - # runs-on: ubuntu-latest - # steps: + code-checks: + strategy: + fail-fast: false + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + + - name: Check that we're not using std::isnan + run: | + cd ${{ github.workspace }}/Firmware + + if grep 'std::isnan' -R .; then + echo "Don't use std::isnan because it's not compatible with '-ffast-math'. Use is_nan() instead." + return 1; + fi + # TODO: # - check if enums.py is consistent with yaml # - clang-format check From 29742a1392f2a578fdcf54582eccddab40ebfad0 Mon Sep 17 00:00:00 2001 From: PAJohnson Date: Sat, 26 Sep 2020 23:17:30 -0400 Subject: [PATCH 38/41] Update top level gitignore for gui artifacts --- .gitignore | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.gitignore b/.gitignore index 66a8990f..c94fc787 100644 --- a/.gitignore +++ b/.gitignore @@ -61,3 +61,8 @@ ODrive\.files ODrive\.includes Firmware/Tests/bin/ + +# GUI +GUI/dist_electron +GUI/node_modules +GUI/build \ No newline at end of file From 7851d20e2ba3e1558c1dff1f851c78aff38e59e8 Mon Sep 17 00:00:00 2001 From: PAJohnson Date: Sat, 26 Sep 2020 23:17:30 -0400 Subject: [PATCH 39/41] Update top level gitignore for gui artifacts --- .gitignore | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.gitignore b/.gitignore index 66a8990f..c94fc787 100644 --- a/.gitignore +++ b/.gitignore @@ -61,3 +61,8 @@ ODrive\.files ODrive\.includes Firmware/Tests/bin/ + +# GUI +GUI/dist_electron +GUI/node_modules +GUI/build \ No newline at end of file From 074b017ab260d47fba20f1fb8d14083f1c59f181 Mon Sep 17 00:00:00 2001 From: PAJohnson Date: Sat, 26 Sep 2020 23:17:30 -0400 Subject: [PATCH 40/41] Update top level gitignore for gui artifacts --- .gitignore | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.gitignore b/.gitignore index 66a8990f..c94fc787 100644 --- a/.gitignore +++ b/.gitignore @@ -61,3 +61,8 @@ ODrive\.files ODrive\.includes Firmware/Tests/bin/ + +# GUI +GUI/dist_electron +GUI/node_modules +GUI/build \ No newline at end of file From 746212191c53505ef7f9793828994d62ed4e7ce7 Mon Sep 17 00:00:00 2001 From: Paul Guenette Date: Fri, 30 Oct 2020 21:41:28 -0400 Subject: [PATCH 41/41] Fix thermistor sampling --- Firmware/MotorControl/axis.cpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/Firmware/MotorControl/axis.cpp b/Firmware/MotorControl/axis.cpp index 79af1d3d..5f354acc 100644 --- a/Firmware/MotorControl/axis.cpp +++ b/Firmware/MotorControl/axis.cpp @@ -186,11 +186,7 @@ bool Axis::do_checks() { // @brief Update all esitmators bool Axis::do_updates() { // Sub-components should use set_error which will propegate to this error_ - task_times_.thermistor_update.beginTimer(); - for (ThermistorCurrentLimiter* thermistor : thermistors_) { - thermistor->update(); - } - task_times_.thermistor_update.stopTimer(); + task_times_.encoder_update.beginTimer(); encoder_.update(); @@ -200,9 +196,12 @@ bool Axis::do_updates() { sensorless_estimator_.update(); task_times_.sensorless_update.stopTimer(); - task_times_.min_endstop_update.beginTimer(); + task_times_.thermistor_update.beginTimer(); motor_.fet_thermistor_.update(); motor_.motor_thermistor_.update(); + task_times_.thermistor_update.stopTimer(); + + task_times_.min_endstop_update.beginTimer(); min_endstop_.update(); task_times_.min_endstop_update.stopTimer();