Add mutex to chairAdjust object - fix potential crashes
This commit is contained in:
parent
c19d053867
commit
e23d37df4c
@ -7,6 +7,7 @@ extern "C"
|
|||||||
#include "chairAdjust.hpp"
|
#include "chairAdjust.hpp"
|
||||||
|
|
||||||
|
|
||||||
|
#define MUTEX_TIMEOUT (10000 / portTICK_PERIOD_MS)
|
||||||
|
|
||||||
//--- gloabl variables ---
|
//--- gloabl variables ---
|
||||||
// strings for logging the rest state
|
// strings for logging the rest state
|
||||||
@ -21,12 +22,12 @@ static const char * TAG = "chair-adjustment";
|
|||||||
//=============================
|
//=============================
|
||||||
//======== constructor ========
|
//======== constructor ========
|
||||||
//=============================
|
//=============================
|
||||||
cControlledRest::cControlledRest(gpio_num_t gpio_up_f, gpio_num_t gpio_down_f, uint32_t travelDurationMs, const char * name_f, float defaultPosition):travelDuration(travelDurationMs){
|
cControlledRest::cControlledRest(gpio_num_t gpio_up_f, gpio_num_t gpio_down_f, uint32_t travelDurationMs, const char * name_f, float defaultPosition): gpio_up(gpio_up_f), gpio_down(gpio_down_f), travelDuration(travelDurationMs){
|
||||||
strcpy(name, name_f);
|
strcpy(name, name_f);
|
||||||
gpio_up = gpio_up_f;
|
|
||||||
gpio_down = gpio_down_f;
|
|
||||||
positionNow = defaultPosition;
|
positionNow = defaultPosition;
|
||||||
positionTarget = positionNow;
|
positionTarget = positionNow;
|
||||||
|
// recursive mutex necessary, because handle() method calls setState() which both have the same mutex
|
||||||
|
mutex = xSemaphoreCreateRecursiveMutex();
|
||||||
init();
|
init();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -95,117 +96,150 @@ void cControlledRest::updatePosition(){
|
|||||||
//============================
|
//============================
|
||||||
void cControlledRest::setState(restState_t targetState)
|
void cControlledRest::setState(restState_t targetState)
|
||||||
{
|
{
|
||||||
// TODO: drop this section?
|
// lock the mutex before accessing shared variables
|
||||||
// check if actually changed
|
if (xSemaphoreTakeRecursive(mutex, MUTEX_TIMEOUT) == pdTRUE)
|
||||||
if (targetState == state)
|
|
||||||
{
|
{
|
||||||
// update anyways when target is 0 or 100, to trigger movement threshold in case of position tracking is out of sync
|
// TODO: drop this section?
|
||||||
if (positionTarget == 0 || positionTarget == 100)
|
// check if actually changed
|
||||||
ESP_LOGD(TAG, "[%s] state already at '%s', but updating anyway to trigger move to limit addition", name, restStateStr[state]);
|
if (targetState == state)
|
||||||
else
|
|
||||||
{
|
{
|
||||||
ESP_LOGV(TAG, "[%s] state already at '%s', nothing to do", name, restStateStr[state]);
|
// update anyways when target is 0 or 100, to trigger movement threshold in case of position tracking is out of sync
|
||||||
return;
|
if (positionTarget == 0 || positionTarget == 100)
|
||||||
|
ESP_LOGD(TAG, "[%s] state already at '%s', but updating anyway to trigger move to limit addition", name, restStateStr[state]);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ESP_LOGV(TAG, "[%s] state already at '%s', nothing to do", name, restStateStr[state]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// when switching direction without stop: update position first
|
||||||
|
if (state != REST_OFF)
|
||||||
|
updatePosition();
|
||||||
|
|
||||||
|
// activate handle task when turning on (previous state is off)
|
||||||
|
if (state == REST_OFF)
|
||||||
|
xTaskNotifyGive(taskHandle); // activate handle task that stops the rest-motor again
|
||||||
|
|
||||||
|
// apply new state
|
||||||
|
ESP_LOGI(TAG, "[%s] switching from state '%s' to '%s'", name, restStateStr[state], restStateStr[targetState]);
|
||||||
|
switch (targetState)
|
||||||
|
{
|
||||||
|
case REST_UP:
|
||||||
|
gpio_set_level(gpio_down, 0);
|
||||||
|
gpio_set_level(gpio_up, 1);
|
||||||
|
timestamp_lastPosUpdate = esp_log_timestamp();
|
||||||
|
break;
|
||||||
|
case REST_DOWN:
|
||||||
|
gpio_set_level(gpio_down, 1);
|
||||||
|
gpio_set_level(gpio_up, 0);
|
||||||
|
timestamp_lastPosUpdate = esp_log_timestamp();
|
||||||
|
break;
|
||||||
|
case REST_OFF:
|
||||||
|
gpio_set_level(gpio_down, 0);
|
||||||
|
gpio_set_level(gpio_up, 0);
|
||||||
|
updatePosition();
|
||||||
|
positionTarget = positionNow; // disable resuming - no unexpected pos when incrementing
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
state = targetState;
|
||||||
|
|
||||||
|
// Release the mutex
|
||||||
|
xSemaphoreGiveRecursive(mutex);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
// when switching direction without stop: update position first
|
|
||||||
if (state != REST_OFF)
|
|
||||||
updatePosition();
|
|
||||||
|
|
||||||
// activate handle task when turning on (previous state is off)
|
|
||||||
if (state == REST_OFF)
|
|
||||||
xTaskNotifyGive(taskHandle); //activate handle task that stops the rest-motor again
|
|
||||||
|
|
||||||
//apply new state
|
|
||||||
ESP_LOGI(TAG, "[%s] switching from state '%s' to '%s'", name, restStateStr[state], restStateStr[targetState]);
|
|
||||||
switch (targetState)
|
|
||||||
{
|
{
|
||||||
case REST_UP:
|
ESP_LOGE(TAG, "mutex timeout in setState() -> RESTART");
|
||||||
gpio_set_level(gpio_down, 0);
|
esp_restart();
|
||||||
gpio_set_level(gpio_up, 1);
|
|
||||||
timestamp_lastPosUpdate = esp_log_timestamp();
|
|
||||||
break;
|
|
||||||
case REST_DOWN:
|
|
||||||
gpio_set_level(gpio_down, 1);
|
|
||||||
gpio_set_level(gpio_up, 0);
|
|
||||||
timestamp_lastPosUpdate = esp_log_timestamp();
|
|
||||||
break;
|
|
||||||
case REST_OFF:
|
|
||||||
gpio_set_level(gpio_down, 0);
|
|
||||||
gpio_set_level(gpio_up, 0);
|
|
||||||
updatePosition();
|
|
||||||
positionTarget = positionNow; //disable resuming - no unexpected pos when incrementing
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
state = targetState;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//==========================
|
//==========================
|
||||||
//==== setTargetPercent ====
|
//==== setTargetPercent ====
|
||||||
//==========================
|
//==========================
|
||||||
void cControlledRest::setTargetPercent(float targetPercent){
|
void cControlledRest::setTargetPercent(float targetPercent)
|
||||||
float positionTargetPrev = positionTarget;
|
{
|
||||||
positionTarget = targetPercent;
|
// lock the mutex before accessing shared variables
|
||||||
|
if (xSemaphoreTakeRecursive(mutex, MUTEX_TIMEOUT) == pdTRUE)
|
||||||
|
{
|
||||||
|
positionTarget = targetPercent;
|
||||||
|
float positionTargetPrev = positionTarget;
|
||||||
|
positionTarget = targetPercent;
|
||||||
|
|
||||||
// limit to 0-100
|
// limit to 0-100
|
||||||
if (positionTarget > 100)
|
if (positionTarget > 100)
|
||||||
positionTarget = 100;
|
positionTarget = 100;
|
||||||
else if (positionTarget < 0)
|
else if (positionTarget < 0)
|
||||||
positionTarget = 0;
|
positionTarget = 0;
|
||||||
|
|
||||||
// ignore if unchanged
|
// ignore if unchanged
|
||||||
//if (positionTarget == positionTargetPrev){
|
// if (positionTarget == positionTargetPrev){
|
||||||
// ESP_LOGI(TAG, "[%s] Target position unchanged at %.2f%%", name, positionTarget);
|
// ESP_LOGI(TAG, "[%s] Target position unchanged at %.2f%%", name, positionTarget);
|
||||||
// return;
|
// return;
|
||||||
//}
|
//}
|
||||||
|
|
||||||
ESP_LOGI(TAG, "[%s] changed Target position from %.2f%% to %.2f%%", name, positionTargetPrev, positionTarget);
|
ESP_LOGI(TAG, "[%s] changed Target position from %.2f%% to %.2f%%", name, positionTargetPrev, positionTarget);
|
||||||
|
|
||||||
// start rest in required direction
|
// start rest in required direction
|
||||||
// TODO always run this check in handle()?
|
// TODO always run this check in handle()?
|
||||||
// note: when already at 0/100 start anyways (runs for certain threshold in case tracked position out of sync)
|
// note: when already at 0/100 start anyways (runs for certain threshold in case tracked position out of sync)
|
||||||
if (positionTarget > positionNow || positionTarget >= 100)
|
if (positionTarget > positionNow || positionTarget >= 100)
|
||||||
setState(REST_UP);
|
setState(REST_UP);
|
||||||
else if (positionTarget < positionNow || positionTarget <= 0)
|
else if (positionTarget < positionNow || positionTarget <= 0)
|
||||||
setState(REST_DOWN);
|
setState(REST_DOWN);
|
||||||
else // already at exact position
|
else // already at exact position
|
||||||
setState(REST_OFF);
|
setState(REST_OFF);
|
||||||
|
|
||||||
|
// Release the mutex
|
||||||
|
xSemaphoreGiveRecursive(mutex);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ESP_LOGE(TAG, "mutex timeout while waiting in setTargetPercent -> RESTART");
|
||||||
|
esp_restart();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//======================
|
//======================
|
||||||
//======= handle =======
|
//======= handle =======
|
||||||
//======================
|
//======================
|
||||||
// handle automatic stop when target position is reached, should be run repeatedly in a task
|
// handle automatic stop when target position is reached, should be run repeatedly in a task
|
||||||
#define TRAVEL_TIME_LIMIT_ADDITION_MS 2000 // traveling longer into limit compensates inaccuracies in time based position tracking
|
#define TRAVEL_TIME_LIMIT_ADDITION_MS 2000 // traveling longer into limit compensates inaccuracies in time based position tracking
|
||||||
void cControlledRest::handle(){
|
void cControlledRest::handle()
|
||||||
|
{
|
||||||
|
// lock the mutex before accessing shared variables
|
||||||
|
if (xSemaphoreTakeRecursive(mutex, MUTEX_TIMEOUT) == pdTRUE)
|
||||||
|
{
|
||||||
|
// nothing to do when not running atm
|
||||||
|
// TODO: turn on automatically when position != target?
|
||||||
|
if (state == REST_OFF)
|
||||||
|
return;
|
||||||
|
|
||||||
// nothing to do when not running atm
|
// calculate time already running and needed time to reach target
|
||||||
// TODO: turn on automatically when position != target?
|
uint32_t timeRan = esp_log_timestamp() - timestamp_lastPosUpdate;
|
||||||
if (state == REST_OFF)
|
uint32_t timeTarget = travelDuration * fabs(positionTarget - positionNow) / 100;
|
||||||
return;
|
|
||||||
|
|
||||||
// calculate time already running and needed time to reach target
|
// intentionally travel longer into limit - compensates inaccuracies in time based position tracking
|
||||||
uint32_t timeRan = esp_log_timestamp() - timestamp_lastPosUpdate;
|
if (positionTarget == 0 || positionTarget == 100)
|
||||||
uint32_t timeTarget = travelDuration * fabs(positionTarget - positionNow) / 100;
|
timeTarget += TRAVEL_TIME_LIMIT_ADDITION_MS;
|
||||||
|
|
||||||
// intentionally travel longer into limit - compensates inaccuracies in time based position tracking
|
// target reached
|
||||||
if (positionTarget == 0 || positionTarget == 100)
|
if (timeRan >= timeTarget)
|
||||||
timeTarget += TRAVEL_TIME_LIMIT_ADDITION_MS;
|
{
|
||||||
|
ESP_LOGW(TAG, "[%s] handle: reached target run-time (%dms/%dms) for position %.2f%% -> stopping", name, timeRan, timeTarget, positionTarget);
|
||||||
|
setState(REST_OFF);
|
||||||
|
}
|
||||||
|
|
||||||
// target reached
|
// Release the mutex
|
||||||
if (timeRan >= timeTarget){
|
xSemaphoreGiveRecursive(mutex);
|
||||||
ESP_LOGW(TAG, "[%s] handle: reached target run-time (%dms/%dms) for position %.2f%% -> stopping", name, timeRan, timeTarget, positionTarget);
|
}
|
||||||
setState(REST_OFF);
|
else
|
||||||
|
{
|
||||||
|
ESP_LOGE(TAG, "mutex timeout while waiting in handle() -> RESTART");
|
||||||
|
esp_restart();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//============================
|
//============================
|
||||||
//===== chairAdjust_task =====
|
//===== chairAdjust_task =====
|
||||||
//============================
|
//============================
|
||||||
|
@ -3,6 +3,7 @@ extern "C"
|
|||||||
{
|
{
|
||||||
#include "freertos/FreeRTOS.h"
|
#include "freertos/FreeRTOS.h"
|
||||||
#include "freertos/task.h"
|
#include "freertos/task.h"
|
||||||
|
#include "freertos/semphr.h"
|
||||||
#include "driver/gpio.h"
|
#include "driver/gpio.h"
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -38,11 +39,14 @@ private:
|
|||||||
void init();
|
void init();
|
||||||
void updatePosition();
|
void updatePosition();
|
||||||
|
|
||||||
|
SemaphoreHandle_t mutex;
|
||||||
|
|
||||||
char name[32];
|
char name[32];
|
||||||
gpio_num_t gpio_up;
|
const gpio_num_t gpio_up;
|
||||||
gpio_num_t gpio_down;
|
const gpio_num_t gpio_down;
|
||||||
restState_t state;
|
|
||||||
const uint32_t travelDuration = 12000;
|
const uint32_t travelDuration = 12000;
|
||||||
|
|
||||||
|
restState_t state;
|
||||||
uint32_t timestamp_lastPosUpdate = 0;
|
uint32_t timestamp_lastPosUpdate = 0;
|
||||||
float positionTarget = 0;
|
float positionTarget = 0;
|
||||||
float positionNow = 0;
|
float positionNow = 0;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user