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