//#define PICO #ifdef PICO #include #include #include "FreeRTOS.h" #include "task.h" #include "semphr.h" #else #include #include #include #endif #include "gpio.h" #include "jobs.h" #include "log.h" #include "utils.h" #define BUTTON_BUFFETING_SLEEP_DURATION_MS 20 int init_app_state(AppState *s) { s->action = STOP; #ifdef PICO s->lock = xSemaphoreCreateMutex(); #else if (pthread_mutex_init(&s->lock, NULL) != 0) { error("mutex init failed"); return -1; } #endif s->freq_multiplicator = 0; return 0; } int lock(AppState *s) { #ifdef PICO if (xSemaphoreTake(s->lock, (TickType_t)10) != pdTRUE) { error("unable to lock the FreeRTOS task"); return -1; } return 0; #else return pthread_mutex_lock(&s->lock); #endif } int release(AppState *s) { #ifdef PICO xSemaphoreGive(s->lock); return 0; #else return pthread_mutex_unlock(&s->lock); #endif } int cancel_task(AppState *s) { debug("stopping task..."); #ifdef PICO if (s->task != NULL) { vTaskDelete(*s->task); free(s->task); gpio_set_state(GPIOS[2], false); gpio_set_level(GPIOS[4],0); return 0; } #else if (s->task != NULL) { if (pthread_cancel(*s->task) != 0) { error("unable to cancel the thread task"); return -1; } if (pthread_join(*s->task, NULL) != 0) { error("unable to wait for finished task"); return -1; } free(s->task); s->task = NULL; } gpio_set_level(GPIOS[4],0); return 0; #endif } int launch_task(AppState *s, FnJob f) { debug("starting app task..."); #ifdef PICO TaskHandle_t* task = malloc(sizeof(TaskHandle_t)); if (task == NULL) { error("unable allocate memory for the app task"); return -1; } BaseType_t res = xTaskCreateAffinitySet(f, "task", configMINIMAL_STACK_SIZE, s, configMAX_PRIORITIES - 1U, 1 << 1,task); if (res != pdPASS) { error("unable to launch run alarm task task, code error: %d", res); return -1; } s->task = task; #else pthread_t* task = malloc(sizeof(task)); if (task == NULL) { error("unable to allocate memory for task thread"); return -1; } if (pthread_create(task, NULL, f, s) != 0) { error("thread task creation failed"); return -1; } s->task = task; #endif return 0; } /** * */ void check_acd_value(void* args) { AppState* s = (AppState*) args; uint16_t current_freq_multiplicator = 0; for (;;) { double freq_mul = gpio_get_adc(); if (freq_mul != current_freq_multiplicator) { #ifdef PICO gpio_set_level(GPIOS[4], current_freq_multiplicator * DEFAULT_WRAP_LEVEL); #endif if (lock(s) != 0) fatal(stop_app_fallback, "unable to lock app mutex"); s->freq_multiplicator = freq_mul; current_freq_multiplicator = freq_mul; if (release(s) != 0) fatal(stop_app_fallback, "unable to release app mutex"); debug("freq multiplicator updated: %d\n", current_freq_multiplicator); } #ifdef PICO gpio_set_level(GPIOS[4], current_freq_multiplicator * DEFAULT_WRAP_LEVEL); #endif } } /** * Main app loop. * * Check the button state and if the button state is pushed (LOW level) * the app task is launched. * */ void check_btn_state(void* args) { TaskParam* params = (TaskParam*) args; AppState *s = params->s; bool has_proceed = false; for (;;) { if (!gpio_get_input(GPIOS[1])) { #ifdef PICO vTaskDelay(pdMS_TO_TICKS(BUTTON_BUFFETING_SLEEP_DURATION_MS)); #else _sleep_ms(BUTTON_BUFFETING_SLEEP_DURATION_MS); #endif if(!gpio_get_input(GPIOS[1]) && !has_proceed) { if (lock(s) != 0) fatal(stop_app_fallback, "unable to lock app mutex"); if (s->action == START) { s->action = STOP; cancel_task(s); if (release(s) != 0) fatal(stop_app_fallback, "unable to release app mutex"); gpio_set_state(GPIOS[0], false); has_proceed = true; continue; } s->action = START; if (launch_task(s, params->f) != 0) fatal(stop_app_fallback, "unable to launch app task"); if (release(s) != 0) fatal(stop_app_fallback, "unable to release app mutex"); gpio_set_state(GPIOS[0], true); has_proceed = true; } continue; } has_proceed = false; } } #ifdef PICO void vApplicationStackOverflowHook(TaskHandle_t pxTask, char *pcTaskName) { fatal(stop_app_fallback, "a task stack overflow, please fix it"); } #endif