From 3722b0af74c0715394eecd6e96665fb891e8dbad Mon Sep 17 00:00:00 2001 From: jonny_jr9 Date: Tue, 29 Aug 2023 11:11:29 +0200 Subject: [PATCH] Add uart templates, send and receive tasks with templates work both boards compile and send/receive example data using new templates in common uart code common/uart_common.hpp --- board_control/main/main.cpp | 363 ++++++++++++++------------- board_control/main/uart.cpp | 73 +----- board_control/main/uart.hpp | 5 - board_motorctl/main/main.cpp | 71 ++---- board_motorctl/main/motordrivers.cpp | 3 - board_motorctl/main/uart.cpp | 44 ++++ board_motorctl/main/uart.hpp | 9 + common/CMakeLists.txt | 10 + common/buzzer.cpp | 94 +++++++ common/buzzer.hpp | 56 +++++ common/types.hpp | 55 ++++ common/uart_common.cpp | 29 +++ common/uart_common.hpp | 60 +++++ common/wifi.c | 265 +++++++++++++++++++ common/wifi.h | 22 ++ 15 files changed, 854 insertions(+), 305 deletions(-) create mode 100644 board_motorctl/main/uart.cpp create mode 100644 board_motorctl/main/uart.hpp create mode 100644 common/CMakeLists.txt create mode 100644 common/buzzer.cpp create mode 100644 common/buzzer.hpp create mode 100644 common/types.hpp create mode 100644 common/uart_common.cpp create mode 100644 common/uart_common.hpp create mode 100644 common/wifi.c create mode 100644 common/wifi.h diff --git a/board_control/main/main.cpp b/board_control/main/main.cpp index a54e30e..86aa88f 100644 --- a/board_control/main/main.cpp +++ b/board_control/main/main.cpp @@ -12,127 +12,138 @@ extern "C" #include "esp_spiffs.h" -//custom C files -//#include "wifi.h" + //custom C files + //#include "wifi.h" } -//custom C++ files -//#include "config.hpp" -//#include "control.hpp" -//#include "button.hpp" -//#include "http.hpp" #include "uart.hpp" + +//========================= +//======= UART TEST ======= +//========================= +//only run uart test code at the end +//disables other functionality +#define UART_TEST_ONLY + + //tag for logging static const char * TAG = "main"; +#ifndef UART_TEST_ONLY +//custom C++ files +#include "config.hpp" +#include "control.hpp" +#include "button.hpp" +#include "http.hpp" -// //====================================== -// //============ buzzer task ============= -// //====================================== -// //TODO: move the task creation to buzzer class (buzzer.cpp) -// //e.g. only have function buzzer.createTask() in app_main -// void task_buzzer( void * pvParameters ){ -// ESP_LOGI("task_buzzer", "Start of buzzer task..."); -// //run function that waits for a beep events to arrive in the queue -// //and processes them -// buzzer.processQueue(); -// } -// -// -// -// //======================================= -// //============ control task ============= -// //======================================= -// //task that controls the armchair modes and initiates commands generation and applies them to driver -// void task_control( void * pvParameters ){ -// ESP_LOGI(TAG, "Initializing controlledArmchair and starting handle loop"); -// //start handle loop (control object declared in config.hpp) -// control.startHandleLoop(); -// } -// -// -// -// //====================================== -// //============ button task ============= -// //====================================== -// //task that handles the button interface/commands -// void task_button( void * pvParameters ){ -// ESP_LOGI(TAG, "Initializing command-button and starting handle loop"); -// //create button instance -// buttonCommands commandButton(&buttonJoystick, &joystick, &control, &buzzer, &motorLeft, &motorRight); -// //start handle loop -// commandButton.startHandleLoop(); -// } -// -// -// -// //======================================= -// //============== fan task =============== -// //======================================= -// //task that controlls fans for cooling the drivers -// void task_fans( void * pvParameters ){ -// ESP_LOGI(TAG, "Initializing fans and starting fan handle loop"); -// //create fan instances with config defined in config.cpp -// controlledFan fan(configCooling, &motorLeft, &motorRight); -// //repeatedly run fan handle function in a slow loop -// while(1){ -// fan.handle(); -// vTaskDelay(500 / portTICK_PERIOD_MS); -// } -// } -// -// -// -// //================================= -// //========== init spiffs ========== -// //================================= -// //initialize spi flash filesystem (used for webserver) -// void init_spiffs(){ -// ESP_LOGI(TAG, "init spiffs"); -// esp_vfs_spiffs_conf_t esp_vfs_spiffs_conf = { -// .base_path = "/spiffs", -// .partition_label = NULL, -// .max_files = 5, -// .format_if_mount_failed = true}; -// esp_vfs_spiffs_register(&esp_vfs_spiffs_conf); -// -// size_t total = 0; -// size_t used = 0; -// esp_spiffs_info(NULL, &total, &used); -// -// ESP_LOGI(TAG, "SPIFFS: total %d, used %d", total, used); -// esp_vfs_spiffs_unregister(NULL); -// } -// -// -// -// //================================== -// //======== define loglevels ======== -// //================================== -// void setLoglevels(void){ -// //set loglevel for all tags: -// esp_log_level_set("*", ESP_LOG_WARN); -// -// //--- set loglevel for individual tags --- -// esp_log_level_set("main", ESP_LOG_INFO); -// esp_log_level_set("buzzer", ESP_LOG_ERROR); -// //esp_log_level_set("motordriver", ESP_LOG_INFO); -// //esp_log_level_set("motor-control", ESP_LOG_DEBUG); -// //esp_log_level_set("evaluatedJoystick", ESP_LOG_DEBUG); -// //esp_log_level_set("joystickCommands", ESP_LOG_DEBUG); -// esp_log_level_set("button", ESP_LOG_INFO); -// esp_log_level_set("control", ESP_LOG_INFO); -// esp_log_level_set("fan-control", ESP_LOG_INFO); -// esp_log_level_set("wifi", ESP_LOG_INFO); -// esp_log_level_set("http", ESP_LOG_INFO); -// esp_log_level_set("automatedArmchair", ESP_LOG_DEBUG); -// //esp_log_level_set("current-sensors", ESP_LOG_INFO); -// } +//====================================== +//============ buzzer task ============= +//====================================== +//TODO: move the task creation to buzzer class (buzzer.cpp) +//e.g. only have function buzzer.createTask() in app_main +void task_buzzer( void * pvParameters ){ + ESP_LOGI("task_buzzer", "Start of buzzer task..."); + //run function that waits for a beep events to arrive in the queue + //and processes them + buzzer.processQueue(); +} + + + +//======================================= +//============ control task ============= +//======================================= +//task that controls the armchair modes and initiates commands generation and applies them to driver +void task_control( void * pvParameters ){ + ESP_LOGI(TAG, "Initializing controlledArmchair and starting handle loop"); + //start handle loop (control object declared in config.hpp) + control.startHandleLoop(); +} + + + +//====================================== +//============ button task ============= +//====================================== +//task that handles the button interface/commands +void task_button( void * pvParameters ){ + ESP_LOGI(TAG, "Initializing command-button and starting handle loop"); + //create button instance + buttonCommands commandButton(&buttonJoystick, &joystick, &control, &buzzer, &motorLeft, &motorRight); + //start handle loop + commandButton.startHandleLoop(); +} + + + +//======================================= +//============== fan task =============== +//======================================= +//task that controlls fans for cooling the drivers +void task_fans( void * pvParameters ){ + ESP_LOGI(TAG, "Initializing fans and starting fan handle loop"); + //create fan instances with config defined in config.cpp + controlledFan fan(configCooling, &motorLeft, &motorRight); + //repeatedly run fan handle function in a slow loop + while(1){ + fan.handle(); + vTaskDelay(500 / portTICK_PERIOD_MS); + } +} + + + +//================================= +//========== init spiffs ========== +//================================= +//initialize spi flash filesystem (used for webserver) +void init_spiffs(){ + ESP_LOGI(TAG, "init spiffs"); + esp_vfs_spiffs_conf_t esp_vfs_spiffs_conf = { + .base_path = "/spiffs", + .partition_label = NULL, + .max_files = 5, + .format_if_mount_failed = true}; + esp_vfs_spiffs_register(&esp_vfs_spiffs_conf); + + size_t total = 0; + size_t used = 0; + esp_spiffs_info(NULL, &total, &used); + + ESP_LOGI(TAG, "SPIFFS: total %d, used %d", total, used); + esp_vfs_spiffs_unregister(NULL); +} +#endif + + + +//================================== +//======== define loglevels ======== +//================================== +void setLoglevels(void){ + //set loglevel for all tags: + esp_log_level_set("*", ESP_LOG_WARN); + + //--- set loglevel for individual tags --- + esp_log_level_set("main", ESP_LOG_INFO); + esp_log_level_set("buzzer", ESP_LOG_ERROR); + //esp_log_level_set("motordriver", ESP_LOG_INFO); + //esp_log_level_set("motor-control", ESP_LOG_DEBUG); + //esp_log_level_set("evaluatedJoystick", ESP_LOG_DEBUG); + //esp_log_level_set("joystickCommands", ESP_LOG_DEBUG); + esp_log_level_set("button", ESP_LOG_INFO); + esp_log_level_set("control", ESP_LOG_INFO); + esp_log_level_set("fan-control", ESP_LOG_INFO); + esp_log_level_set("wifi", ESP_LOG_INFO); + esp_log_level_set("http", ESP_LOG_INFO); + esp_log_level_set("automatedArmchair", ESP_LOG_DEBUG); + //esp_log_level_set("current-sensors", ESP_LOG_INFO); +} @@ -143,81 +154,77 @@ static const char * TAG = "main"; //=========== app_main ============ //================================= extern "C" void app_main(void) { -// //enable 5V volate regulator -// gpio_pad_select_gpio(GPIO_NUM_17); -// gpio_set_direction(GPIO_NUM_17, GPIO_MODE_OUTPUT); -// gpio_set_level(GPIO_NUM_17, 1); -// -// //---- define log levels ---- -// setLoglevels(); -// -// //------------------------------ -// //--- create task for buzzer --- -// //------------------------------ -// xTaskCreate(&task_buzzer, "task_buzzer", 2048, NULL, 2, NULL); -// -// //------------------------------- -// //--- create task for control --- -// //------------------------------- -// //task that generates motor commands depending on the current mode and sends those to motorctl task -// xTaskCreate(&task_control, "task_control", 4096, NULL, 5, NULL); -// -// //------------------------------ -// //--- create task for button --- -// //------------------------------ -// //task that evaluates and processes the button input and runs the configured commands -// xTaskCreate(&task_button, "task_button", 4096, NULL, 4, NULL); -// -// //----------------------------------- -// //--- create task for fan control --- -// //----------------------------------- -// //task that evaluates and processes the button input and runs the configured commands -// xTaskCreate(&task_fans, "task_fans", 2048, NULL, 1, NULL); -// -// -// //beep at startup -// buzzer.beep(3, 70, 50); -// -// //--- initialize nvs-flash and netif (needed for wifi) --- -// wifi_initNvs_initNetif(); -// -// //--- initialize spiffs --- -// init_spiffs(); -// -// //--- initialize and start wifi --- -// //FIXME: run wifi_init_client or wifi_init_ap as intended from control.cpp when switching state -// //currently commented out because of error "assert failed: xQueueSemaphoreTake queue.c:1549 (pxQueue->uxItemSize == 0)" when calling control->changeMode from button.cpp -// //when calling control.changeMode(http) from main.cpp it worked without error for some reason? -// ESP_LOGI(TAG,"starting wifi..."); -// //wifi_init_client(); //connect to existing wifi -// wifi_init_ap(); //start access point -// ESP_LOGI(TAG,"done starting wifi"); -// -// -// //--- testing http server --- -// // wifi_init_client(); //connect to existing wifi -// // vTaskDelay(2000 / portTICK_PERIOD_MS); -// // ESP_LOGI(TAG, "initializing http server"); -// // http_init_server(); -// -// -// //--- testing force http mode after startup --- -// //control.changeMode(controlMode_t::HTTP); -// -// -// //--- main loop --- -// //does nothing except for testing things +#ifndef UART_TEST_ONLY + //enable 5V volate regulator + gpio_pad_select_gpio(GPIO_NUM_17); + gpio_set_direction(GPIO_NUM_17, GPIO_MODE_OUTPUT); + gpio_set_level(GPIO_NUM_17, 1); + + //---- define log levels ---- + setLoglevels(); + + //------------------------------ + //--- create task for buzzer --- + //------------------------------ + xTaskCreate(&task_buzzer, "task_buzzer", 2048, NULL, 2, NULL); + + //------------------------------- + //--- create task for control --- + //------------------------------- + //task that generates motor commands depending on the current mode and sends those to motorctl task + xTaskCreate(&task_control, "task_control", 4096, NULL, 5, NULL); + + //------------------------------ + //--- create task for button --- + //------------------------------ + //task that evaluates and processes the button input and runs the configured commands + xTaskCreate(&task_button, "task_button", 4096, NULL, 4, NULL); + + //----------------------------------- + //--- create task for fan control --- + //----------------------------------- + //task that evaluates and processes the button input and runs the configured commands + xTaskCreate(&task_fans, "task_fans", 2048, NULL, 1, NULL); - //TESTING UART - //xTaskCreate(uart_task_testing, "uart_task", 4096, NULL, 10, NULL); + //beep at startup + buzzer.beep(3, 70, 50); + + //--- initialize nvs-flash and netif (needed for wifi) --- + wifi_initNvs_initNetif(); + + //--- initialize spiffs --- + init_spiffs(); + + //--- initialize and start wifi --- + //FIXME: run wifi_init_client or wifi_init_ap as intended from control.cpp when switching state + //currently commented out because of error "assert failed: xQueueSemaphoreTake queue.c:1549 (pxQueue->uxItemSize == 0)" when calling control->changeMode from button.cpp + //when calling control.changeMode(http) from main.cpp it worked without error for some reason? + ESP_LOGI(TAG,"starting wifi..."); + //wifi_init_client(); //connect to existing wifi + wifi_init_ap(); //start access point + ESP_LOGI(TAG,"done starting wifi"); + + + //--- testing http server --- + // wifi_init_client(); //connect to existing wifi + // vTaskDelay(2000 / portTICK_PERIOD_MS); + // ESP_LOGI(TAG, "initializing http server"); + // http_init_server(); + + + //--- testing force http mode after startup --- + //control.changeMode(controlMode_t::HTTP); +#endif + uart_init(); - xTaskCreate(task_uartReceive, "task_uartReceive", 4096, NULL, 10, NULL); - xTaskCreate(task_uartSend, "task_uartSend", 5*4096, NULL, 10, NULL); + xTaskCreate(task_uartReceive, "task_uartReceive", 4096, NULL, 10, NULL); + xTaskCreate(task_uartSend, "task_uartSend", 4096, NULL, 10, NULL); + //--- main loop --- + //does nothing except for testing things while(1){ vTaskDelay(1000 / portTICK_PERIOD_MS); - //--------------------------------- //-------- TESTING section -------- //--------------------------------- diff --git a/board_control/main/uart.cpp b/board_control/main/uart.cpp index bdd821c..14aacaa 100644 --- a/board_control/main/uart.cpp +++ b/board_control/main/uart.cpp @@ -21,43 +21,11 @@ static const char * TAG = "uart"; -void uart_task_testing(void *arg){ - //repeatedly send 8 bit count and log received 1 byte - uint8_t *data = (uint8_t *) malloc(1024); - uint8_t count = 0; - ESP_LOGW(TAG, "startloop..."); - while (1) { - vTaskDelay(500 / portTICK_PERIOD_MS); - int len = uart_read_bytes(UART_NUM_1, data, (1024 - 1), 20 / portTICK_PERIOD_MS); - //uart_flush_input(UART_NUM_1); - //uart_flush(UART_NUM_1); - ESP_LOGW(TAG, "received len=%d data=%d", len, *data); - *data = 99; //set to 99 (indicates no new data received) - uart_write_bytes(UART_NUM_1, (const char *) &count, 1); - ESP_LOGW(TAG, "sent data %d", count); - count++; - } -} - - - +//============================== +//====== task_uartReceive ====== +//============================== +//TODO copy receive task from board_motorctl/uart.cpp void task_uartReceive(void *arg){ - static const char * TAG = "uart-receive"; - //repeatedly send 8 bit count and log received 1 byte - char *data = (char *) malloc(1024); - char count = 0; - ESP_LOGW(TAG, "startloop..."); - while (1) { - vTaskDelay(200 / portTICK_PERIOD_MS); - int len = uart_read_bytes(UART_NUM_1, data, (1024 - 1), 20 / portTICK_PERIOD_MS); - if (len>0) ESP_LOGW(TAG, "received len=%d data=%d", len, *data); - } -} - - - -void task_uartReceiveQueue(void *arg){ - static const char * TAG = "uart-receive"; while (1) { vTaskDelay(200 / portTICK_PERIOD_MS); } @@ -65,38 +33,17 @@ void task_uartReceiveQueue(void *arg){ - -// //send incrementing count -// void task_uartSend(void *arg){ -// static const char * TAG = "uart-send"; -// //repeatedly send 8 bit count and log received 1 byte -// char *data = (char *) malloc(1024); -// char count = 0; -// ESP_LOGW(TAG, "startloop..."); -// while (1) { -// vTaskDelay(200 / portTICK_PERIOD_MS); -// uart_write_bytes(UART_NUM_1, (const char *) &count, 1); -// ESP_LOGW(TAG, "sent data %d", (int)count); -// count++; -// } -// ESP_LOGE(TAG, "loop exit..."); -// } - - - -//send struct +//============================= +//======= task_uartSend ======= +//============================= +//repeatedly send structs to uart void task_uartSend(void *arg){ static const char * TAG = "uart-send"; - uartDataStruct data = {123, 0, 1.1}; - uint8_t serialData[sizeof(uartDataStruct)]; - char count = 0; + uartData_test_t data = {123, 0, 1.1}; ESP_LOGW(TAG, "startloop..."); while (1) { vTaskDelay(500 / portTICK_PERIOD_MS); - memcpy(serialData, &data, sizeof(uartDataStruct)); - uart_write_bytes(UART_NUM_1, (const char *)serialData, sizeof(uartDataStruct)); - ESP_LOGW(TAG, "sent data struct with len %d", sizeof(uartDataStruct)); - ESP_LOGW(TAG, "sent DATA: timestamp=%d, id=%d, value=%.1f", data.timestamp, data.id, data.value); + uart_sendStruct(data); //change data values data.timestamp = esp_log_timestamp(); diff --git a/board_control/main/uart.hpp b/board_control/main/uart.hpp index 2ec926d..ef8ea55 100644 --- a/board_control/main/uart.hpp +++ b/board_control/main/uart.hpp @@ -8,8 +8,3 @@ void task_uartSend(void *arg); -typedef struct { - uint32_t timestamp; - int id; - float value; -} uartDataStruct; diff --git a/board_motorctl/main/main.cpp b/board_motorctl/main/main.cpp index e608a52..d0c051c 100644 --- a/board_motorctl/main/main.cpp +++ b/board_motorctl/main/main.cpp @@ -13,11 +13,13 @@ extern "C" #include #include "driver/ledc.h" -#include "driver/uart.h" - //custom C files +//custom C files #include "wifi.h" } +//custom C++ files +#include "config.hpp" +#include "uart.hpp" //========================= //======= UART TEST ======= @@ -30,13 +32,10 @@ extern "C" //tag for logging static const char * TAG = "main"; + + #ifndef UART_TEST_ONLY -//custom C++ files -#include "config.hpp" #include "control.hpp" - - - //==================================== //========== motorctl task =========== //==================================== @@ -109,33 +108,6 @@ void setLoglevels(void){ #endif - -#ifdef UART_TEST_ONLY -void uart_init(void){ - uart_config_t uart1_config = { - .baud_rate = 115198, - .data_bits = UART_DATA_8_BITS, - .parity = UART_PARITY_EVEN, - .stop_bits = UART_STOP_BITS_1, - .flow_ctrl = UART_HW_FLOWCTRL_DISABLE, - }; - ESP_LOGW(TAG, "config..."); - ESP_ERROR_CHECK(uart_param_config(UART_NUM_1, &uart1_config)); - ESP_LOGW(TAG, "setpins..."); - ESP_ERROR_CHECK(uart_set_pin(UART_NUM_1, 23, 22, 0, 0)); - ESP_LOGW(TAG, "init..."); - ESP_ERROR_CHECK(uart_driver_install(UART_NUM_1, 1024, 1024, 10, NULL, 0)); - -} - -//struct for testing uart -typedef struct { - uint32_t timestamp; - int id; - float value; -} uartDataStruct; -#endif - //================================= //=========== app_main ============ //================================= @@ -170,36 +142,22 @@ extern "C" void app_main(void) { //beep at startup buzzer.beep(3, 70, 50); - - - //--- main loop --- - //does nothing except for testing things - while(1){ - vTaskDelay(5000 / portTICK_PERIOD_MS); - } - #endif #ifdef UART_TEST_ONLY uart_init(); - uint8_t receivedData[sizeof(uartDataStruct)]; - uartDataStruct data; - - ESP_LOGW(TAG, "startloop..."); - while(1){ - vTaskDelay(500 / portTICK_PERIOD_MS); - int len = uart_read_bytes(UART_NUM_1, receivedData, sizeof(uartDataStruct), 20 / portTICK_PERIOD_MS); - uart_flush_input(UART_NUM_1); - if (len > 0){ - memcpy(&data, receivedData, sizeof(uartDataStruct)); - //uart_write_bytes(UART_NUM_1, (const char *) data, 1); - //ESP_LOGW(TAG, "sent data back %d", *data); - ESP_LOGW(TAG, "received len=%d DATA: timestamp=%d, id=%d, value=%.1f", len, data.timestamp, data.id, data.value); - } + xTaskCreate(task_uartReceive, "task_uartReceive", 4096, NULL, 10, NULL); + xTaskCreate(task_uartSend, "task_uartSend", 4096, NULL, 10, NULL); #endif + + //--- main loop --- + //does nothing except for testing things + while(1){ + vTaskDelay(5000 / portTICK_PERIOD_MS); + //--- test controlledMotor --- (ramp) // //brake for 1 s // motorLeft.setTarget(motorstate_t::BRAKE); @@ -210,5 +168,6 @@ extern "C" void app_main(void) { // //command 100% - forward // motorLeft.setTarget(motorstate_t::FWD, 100); // vTaskDelay(1000 / portTICK_PERIOD_MS); + } } diff --git a/board_motorctl/main/motordrivers.cpp b/board_motorctl/main/motordrivers.cpp index e15b4e6..387bda3 100644 --- a/board_motorctl/main/motordrivers.cpp +++ b/board_motorctl/main/motordrivers.cpp @@ -7,9 +7,6 @@ //Note fade functionality provided by LEDC would be very useful but unfortunately is not usable here because: //"Due to hardware limitations, there is no way to stop a fade before it reaches its target duty." -//definition of string array to be able to convert state enum to readable string -const char* motorstateStr[4] = {"IDLE", "FWD", "REV", "BRAKE"}; - //tag for logging static const char * TAG = "motordriver"; diff --git a/board_motorctl/main/uart.cpp b/board_motorctl/main/uart.cpp new file mode 100644 index 0000000..2121422 --- /dev/null +++ b/board_motorctl/main/uart.cpp @@ -0,0 +1,44 @@ +#include "uart.hpp" +//===== uart board MOTORCTL ===== + +static const char * TAG = "uart"; + + +//============================== +//====== task_uartReceive ====== +//============================== +void task_uartReceive(void *arg){ + //receive data from uart, detect associated struct and copy/handle the data + //TODO use queue instead of check interval? + uartData_test_t testData; + uint8_t receivedData[1024-1]; + while(1){ + //note: check has to be more frequent than pause time between sending + vTaskDelay(200 / portTICK_PERIOD_MS); + int len = uart_read_bytes(UART_NUM_1, receivedData, sizeof(uartData_test_t), 20 / portTICK_PERIOD_MS); + uart_flush_input(UART_NUM_1); + if (len < 1) continue; + switch (len){ + case sizeof(uartData_test_t): + testData = serialData2Struct(receivedData); + ESP_LOGW(TAG, "received uartDataStruct len=%d DATA: timestamp=%d, id=%d, value=%.1f", len, testData.timestamp, testData.id, testData.value); + break; + //TODO add other received structs here + default: + ESP_LOGW(TAG, "received data len=%d cant be associated with configures struct", len); + break; + } + } +} + + + +//============================= +//======= task_uartSend ======= +//============================= +//TODO copy send task from board_control/uart.cpp +void task_uartSend(void *arg){ + while (1) { + vTaskDelay(500 / portTICK_PERIOD_MS); + } +} diff --git a/board_motorctl/main/uart.hpp b/board_motorctl/main/uart.hpp new file mode 100644 index 0000000..402b35d --- /dev/null +++ b/board_motorctl/main/uart.hpp @@ -0,0 +1,9 @@ +#pragma once +#include "uart_common.hpp" + + +//===== uart board MOTORCTL ===== + +void task_uartReceive(void *arg); +void task_uartSend(void *arg); + diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt new file mode 100644 index 0000000..a47af70 --- /dev/null +++ b/common/CMakeLists.txt @@ -0,0 +1,10 @@ +idf_component_register( + SRCS + "wifi.c" + "buzzer.cpp" + "uart_common.cpp" + INCLUDE_DIRS + "." + PRIV_REQUIRES nvs_flash + ) + diff --git a/common/buzzer.cpp b/common/buzzer.cpp new file mode 100644 index 0000000..0850116 --- /dev/null +++ b/common/buzzer.cpp @@ -0,0 +1,94 @@ +#include "buzzer.hpp" + +static const char *TAG_BUZZER = "buzzer"; + +//============================ +//========== init ============ +//============================ +//define gpio pin as output, initialize queue +void buzzer_t::init(){ + //define buzzer pin as output + gpio_pad_select_gpio(gpio_pin); + gpio_set_direction(gpio_pin, GPIO_MODE_OUTPUT); + //create queue + beepQueue = xQueueCreate( 20, sizeof( struct beepEntry ) ); +} + + +//============================= +//======== constructor ======== +//============================= +//copy provided config parameters to private variables, run init function +buzzer_t::buzzer_t(gpio_num_t gpio_pin_f, uint16_t msGap_f){ + ESP_LOGI(TAG_BUZZER, "Initializing buzzer"); + //copy configuration parameters to variables + gpio_pin = gpio_pin_f; + msGap = msGap_f; + //run init function to initialize gpio and queue + init(); +}; + + +//============================ +//=========== beep =========== +//============================ +//function to add a beep command to the queue +void buzzer_t::beep(uint8_t count, uint16_t msOn, uint16_t msOff){ + //create entry struct with provided data + struct beepEntry entryInsert = { + count = count, + msOn = msOn, + msOff = msOff + }; + + // Send a pointer to a struct AMessage object. Don't block if the + // queue is already full. + //struct beepEntry *entryInsertPointer; + //entryInsertPointer = &entryInsertData; + ESP_LOGW(TAG_BUZZER, "Inserted object to queue - count=%d, msOn=%d, msOff=%d", entryInsert.count, entryInsert.msOn, entryInsert.msOff); + //xQueueGenericSend( beepQueue, ( void * ) &entryInsertPointer, ( TickType_t ) 0, queueSEND_TO_BACK ); + xQueueSend( beepQueue, ( void * )&entryInsert, ( TickType_t ) 0 ); +} + + +//============================== +//======== processQueue ======== +//============================== +void buzzer_t::processQueue(){ + //struct for receiving incomming events + struct beepEntry entryRead = { }; + + //loop forever + while(1){ + ESP_LOGD(TAG_BUZZER, "processQueue: waiting for beep command"); + + //if queue is ready + if( beepQueue != 0 ) + { + // wait for a queue entry to be available indefinetely if INCLUDE_vTaskSuspend is enabled in the FreeRTOS config + // otherwise waits for at least 7 weeks + if( xQueueReceive( beepQueue, &entryRead, portMAX_DELAY ) ) + { + ESP_LOGW(TAG_BUZZER, "Read entry from queue: count=%d, msOn=%d, msOff=%d", entryRead.count, entryRead.msOn, entryRead.msOff); + + //beep requested count with requested delays + for (int i = entryRead.count; i--;){ + //turn on + ESP_LOGD(TAG_BUZZER, "turning buzzer on"); + gpio_set_level(gpio_pin, 1); + vTaskDelay(entryRead.msOn / portTICK_PERIOD_MS); + //turn off + ESP_LOGD(TAG_BUZZER, "turning buzzer off"); + gpio_set_level(gpio_pin, 0); + vTaskDelay(entryRead.msOff / portTICK_PERIOD_MS); + } + //wait for minimum gap between beep events + vTaskDelay(msGap / portTICK_PERIOD_MS); + } + }else{ //wait for queue to become available + vTaskDelay(50 / portTICK_PERIOD_MS); + } + } +} + + diff --git a/common/buzzer.hpp b/common/buzzer.hpp new file mode 100644 index 0000000..ce6c2c6 --- /dev/null +++ b/common/buzzer.hpp @@ -0,0 +1,56 @@ +#pragma once + +#include + +extern "C" +{ +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "driver/gpio.h" +#include "esp_log.h" +} + +#include "freertos/queue.h" + + + +//=================================== +//========= buzzer_t class ========== +//=================================== +//class which blinks a gpio pin for the provided count and durations. +//- 'processQueue' has to be run in a separate task +//- uses a queue to queue up multiple beep commands +class buzzer_t { + public: + //--- constructor --- + buzzer_t(gpio_num_t gpio_pin_f, uint16_t msGap_f = 200); + + //--- functions --- + void processQueue(); //has to be run once in a separate task, waits for and processes queued events + void beep(uint8_t count, uint16_t msOn, uint16_t msOff); + //void clear(); (TODO - not implemented yet) + //void createTask(); (TODO - not implemented yet) + + //--- variables --- + uint16_t msGap; //gap between beep entries (when multiple queued) + + private: + //--- functions --- + void init(); + + //--- variables --- + gpio_num_t gpio_pin; + + struct beepEntry { + uint8_t count; + uint16_t msOn; + uint16_t msOff; + }; + + //queue for queueing up multiple events while one is still processing + QueueHandle_t beepQueue = NULL; + +}; + + + diff --git a/common/types.hpp b/common/types.hpp new file mode 100644 index 0000000..e7986c4 --- /dev/null +++ b/common/types.hpp @@ -0,0 +1,55 @@ +#pragma once + +extern "C" +{ +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/queue.h" +#include "esp_timer.h" +#include +} +//======================================= +//====== struct/type declarations ====== +//======================================= +//global structs and types that need to be available for all boards + + +//=============================== +//==== from motordrivers.hpp ==== +//=============================== +enum class motorstate_t {IDLE, FWD, REV, BRAKE}; +//definition of string array to be able to convert state enum to readable string (defined in motordrivers.cpp) +const char* motorstateStr[] = {"IDLE", "FWD", "REV", "BRAKE"}; + + + +//=========================== +//==== from motorctl.hpp ==== +//=========================== +//struct for sending command for one motor in the queue +struct motorCommand_t { + motorstate_t state; + float duty; +}; + +//struct containing commands for two motors +typedef struct motorCommands_t { + motorCommand_t left; + motorCommand_t right; +} motorCommands_t; + +//struct with all config parameters for a motor regarding ramp and current limit +typedef struct motorctl_config_t { + uint32_t msFadeAccel; //acceleration of the motor (ms it takes from 0% to 100%) + uint32_t msFadeDecel; //deceleration of the motor (ms it takes from 100% to 0%) + bool currentLimitEnabled; + adc1_channel_t currentSensor_adc; + float currentSensor_ratedCurrent; + float currentMax; + uint32_t deadTimeMs; //time motor stays in IDLE before direction change +} motorctl_config_t; + +//enum fade type (acceleration, deceleration) +//e.g. used for specifying which fading should be modified with setFade, togleFade functions +enum class fadeType_t {ACCEL, DECEL}; + diff --git a/common/uart_common.cpp b/common/uart_common.cpp new file mode 100644 index 0000000..fd013e6 --- /dev/null +++ b/common/uart_common.cpp @@ -0,0 +1,29 @@ +#include "uart_common.hpp" + +static const char * TAG = "uart-common"; + + +//=========================== +//======== uart_init ======= +//=========================== +//initial struct on given pins +//TODO add pins and baud rate to config? +void uart_init(void){ + uart_config_t uart1_config = { + .baud_rate = 115198, + .data_bits = UART_DATA_8_BITS, + .parity = UART_PARITY_EVEN, + .stop_bits = UART_STOP_BITS_1, + .flow_ctrl = UART_HW_FLOWCTRL_DISABLE, + }; + ESP_LOGI(TAG, "configure..."); + ESP_ERROR_CHECK(uart_param_config(UART_NUM_1, &uart1_config)); + ESP_LOGI(TAG, "setpins..."); + ESP_ERROR_CHECK(uart_set_pin(UART_NUM_1, 23, 22, 0, 0)); + ESP_LOGI(TAG, "init..."); + ESP_ERROR_CHECK(uart_driver_install(UART_NUM_1, 1024, 1024, 10, NULL, 0)); +} + + + + diff --git a/common/uart_common.hpp b/common/uart_common.hpp new file mode 100644 index 0000000..6858c1f --- /dev/null +++ b/common/uart_common.hpp @@ -0,0 +1,60 @@ +#pragma once +extern "C" +{ +#include +#include +#include +#include +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "driver/gpio.h" +#include "esp_log.h" +#include "sdkconfig.h" +#include + +#include "freertos/queue.h" +#include "driver/uart.h" +} + +//struct for testin uart +typedef struct { + uint32_t timestamp; + int id; + float value; +} uartData_test_t; + + +//===== uart_init ===== +//should be run once at startup +void uart_init(void); + + +//============================ +//====== uart_sendStruct ===== +//============================ +//send and struct via uart +template void uart_sendStruct(T dataStruct) { + static const char * TAG = "uart-common"; + //TODO check if initialized? + uint8_t dataSerial[sizeof(T)]; + memcpy(dataSerial, &dataStruct, sizeof(T)); + uart_write_bytes(UART_NUM_1, (const char *)dataSerial, sizeof(T)); + ESP_LOGW(TAG, "sent data struct with len %d", sizeof(T)); + //ESP_LOGW(TAG, "sent DATA: timestamp=%d, id=%d, value=%.1f", data.timestamp, data.id, data.value); +} + + + +//============================== +//====== serialData2Struct ===== +//============================== +//convert serial data (byte array) to given struct and return it +//note check whether serial data length actually matches size of struct is necessary before +template T serialData2Struct(uint8_t *dataSerial){ + static const char * TAG = "uart-common"; + T dataStruct; + memcpy(&dataStruct, dataSerial, sizeof(T)); + ESP_LOGW(TAG, "converted serial data len=%d to struct", sizeof(T)); + return dataStruct; +} + diff --git a/common/wifi.c b/common/wifi.c new file mode 100644 index 0000000..27eb3db --- /dev/null +++ b/common/wifi.c @@ -0,0 +1,265 @@ +#include +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/event_groups.h" +#include "esp_system.h" +#include "esp_mac.h" +#include "esp_wifi.h" +#include "esp_event.h" +#include "esp_log.h" +#include "nvs_flash.h" + +#include "lwip/err.h" +#include "lwip/sys.h" + +#include "wifi.h" + + + +//--- variables used for ap and wifi --- +static const char *TAG = "wifi"; +static esp_event_handler_instance_t instance_any_id; + + +//============================================ +//============ init nvs and netif ============ +//============================================ +//initialize nvs-flash and netif (needed for both AP and CLIENT) +//has to be run once at startup +void wifi_initNvs_initNetif(){ + //Initialize NVS (needed for wifi) + esp_err_t ret = nvs_flash_init(); + if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) { + ESP_ERROR_CHECK(nvs_flash_erase()); + ret = nvs_flash_init(); + } + ESP_ERROR_CHECK(esp_netif_init()); + ESP_ERROR_CHECK(esp_event_loop_create_default()); +} + + +//=========================================== +//============ init access point ============ +//=========================================== + +//-------------------------------------------- +//------ configuration / declarations -------- +//-------------------------------------------- +#define EXAMPLE_ESP_WIFI_SSID_AP "armchair" +#define EXAMPLE_ESP_WIFI_PASS_AP "" +#define EXAMPLE_ESP_WIFI_CHANNEL_AP 1 +#define EXAMPLE_MAX_STA_CONN_AP 4 + +static esp_netif_t *ap; + +static void wifi_event_handler_ap(void* arg, esp_event_base_t event_base, + int32_t event_id, void* event_data) +{ + if (event_id == WIFI_EVENT_AP_STACONNECTED) { + wifi_event_ap_staconnected_t* event = (wifi_event_ap_staconnected_t*) event_data; + ESP_LOGI(TAG, "station "MACSTR" join, AID=%d", + MAC2STR(event->mac), event->aid); + } else if (event_id == WIFI_EVENT_AP_STADISCONNECTED) { + wifi_event_ap_stadisconnected_t* event = (wifi_event_ap_stadisconnected_t*) event_data; + ESP_LOGI(TAG, "station "MACSTR" leave, AID=%d", + MAC2STR(event->mac), event->aid); + } +} + +//----------------------- +//------ init ap -------- +//----------------------- +void wifi_init_ap(void) +{ + ap = esp_netif_create_default_wifi_ap(); + + wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); + ESP_ERROR_CHECK(esp_wifi_init(&cfg)); + + ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT, + ESP_EVENT_ANY_ID, + &wifi_event_handler_ap, + NULL, + &instance_any_id)); + + wifi_config_t wifi_config = { + .ap = { + .ssid = EXAMPLE_ESP_WIFI_SSID_AP, + .ssid_len = strlen(EXAMPLE_ESP_WIFI_SSID_AP), + .channel = EXAMPLE_ESP_WIFI_CHANNEL_AP, + .password = EXAMPLE_ESP_WIFI_PASS_AP, + .max_connection = EXAMPLE_MAX_STA_CONN_AP, + .authmode = WIFI_AUTH_WPA_WPA2_PSK + }, + }; + if (strlen(EXAMPLE_ESP_WIFI_PASS_AP) == 0) { + wifi_config.ap.authmode = WIFI_AUTH_OPEN; + } + + ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_AP)); + ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_AP, &wifi_config)); + ESP_ERROR_CHECK(esp_wifi_start()); + + ESP_LOGI(TAG, "wifi_init_softap finished. SSID:%s password:%s channel:%d", + EXAMPLE_ESP_WIFI_SSID_AP, EXAMPLE_ESP_WIFI_PASS_AP, EXAMPLE_ESP_WIFI_CHANNEL_AP); +} + + + +//============================= +//========= deinit AP ========= +//============================= +void wifi_deinit_ap(void) +{ + ESP_ERROR_CHECK(esp_event_handler_instance_unregister(WIFI_EVENT, ESP_EVENT_ANY_ID, instance_any_id)); + ESP_ERROR_CHECK(esp_event_handler_instance_unregister(WIFI_EVENT, ESP_EVENT_ANY_ID, instance_any_id)); + esp_wifi_stop(); + esp_wifi_deinit(); + esp_netif_destroy_default_wifi(ap); + +} + + + + + +//=========================================== +//=============== init client =============== +//=========================================== + +//-------------------------------------------- +//------ configuration / declarations -------- +//-------------------------------------------- +#define EXAMPLE_ESP_WIFI_SSID_CLIENT "BKA-network" +#define EXAMPLE_ESP_WIFI_PASS_CLIENT "airwaveslogitech410" +#define EXAMPLE_ESP_MAXIMUM_RETRY_CLIENT 10 + +static esp_netif_t *sta; +static esp_event_handler_instance_t instance_got_ip; + +/* FreeRTOS event group to signal when we are connected*/ +static EventGroupHandle_t s_wifi_event_group; + +/* The event group allows multiple bits for each event, but we only care about two events: + * - we are connected to the AP with an IP + * - we failed to connect after the maximum amount of retries */ +#define WIFI_CONNECTED_BIT BIT0 +#define WIFI_FAIL_BIT BIT1 + +static int s_retry_num = 0; +static void event_handler(void* arg, esp_event_base_t event_base, + int32_t event_id, void* event_data) +{ + if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) { + esp_wifi_connect(); + } else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) { + if (s_retry_num < EXAMPLE_ESP_MAXIMUM_RETRY_CLIENT) { + esp_wifi_connect(); + s_retry_num++; + ESP_LOGI(TAG, "retry to connect to the AP"); + } else { + xEventGroupSetBits(s_wifi_event_group, WIFI_FAIL_BIT); + } + ESP_LOGI(TAG,"connect to the AP fail"); + } else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) { + ip_event_got_ip_t* event = (ip_event_got_ip_t*) event_data; + ESP_LOGI(TAG, "got ip:" IPSTR, IP2STR(&event->ip_info.ip)); + s_retry_num = 0; + xEventGroupSetBits(s_wifi_event_group, WIFI_CONNECTED_BIT); + } +} +//--------------------------- +//------ init client -------- +//--------------------------- +void wifi_init_client(void) +{ + s_wifi_event_group = xEventGroupCreate(); + sta = esp_netif_create_default_wifi_sta(); + + + + //set static ip + esp_netif_dhcpc_stop(sta); + + esp_netif_ip_info_t ip_info; + IP4_ADDR(&ip_info.ip, 10, 0, 0, 66); + IP4_ADDR(&ip_info.gw, 10, 0, 0, 1); + IP4_ADDR(&ip_info.netmask, 255, 255, 0, 0); + + esp_netif_set_ip_info(sta, &ip_info); + + + + + wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); + ESP_ERROR_CHECK(esp_wifi_init(&cfg)); + + ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT, + ESP_EVENT_ANY_ID, + &event_handler, + NULL, + &instance_any_id)); + ESP_ERROR_CHECK(esp_event_handler_instance_register(IP_EVENT, + IP_EVENT_STA_GOT_IP, + &event_handler, + NULL, + &instance_got_ip)); + + wifi_config_t wifi_config = { + .sta = { + .ssid = EXAMPLE_ESP_WIFI_SSID_CLIENT, + .password = EXAMPLE_ESP_WIFI_PASS_CLIENT, + /* Setting a password implies station will connect to all security modes including WEP/WPA. + * However these modes are deprecated and not advisable to be used. Incase your Access point + * doesn't support WPA2, these mode can be enabled by commenting below line */ + .threshold.authmode = WIFI_AUTH_WPA2_PSK, + }, + }; + ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA) ); + ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config) ); + ESP_ERROR_CHECK(esp_wifi_start() ); + + ESP_LOGI(TAG, "wifi_init_sta finished."); + + /* Waiting until either the connection is established (WIFI_CONNECTED_BIT) or connection failed for the maximum + * number of re-tries (WIFI_FAIL_BIT). The bits are set by event_handler() (see above) */ + EventBits_t bits = xEventGroupWaitBits(s_wifi_event_group, + WIFI_CONNECTED_BIT | WIFI_FAIL_BIT, + pdFALSE, + pdFALSE, + portMAX_DELAY); + + /* xEventGroupWaitBits() returns the bits before the call returned, hence we can test which event actually + * happened. */ + if (bits & WIFI_CONNECTED_BIT) { + ESP_LOGI(TAG, "connected to ap SSID:%s password:%s", + EXAMPLE_ESP_WIFI_SSID_CLIENT, EXAMPLE_ESP_WIFI_PASS_CLIENT); + } else if (bits & WIFI_FAIL_BIT) { + ESP_LOGI(TAG, "Failed to connect to SSID:%s, password:%s", + EXAMPLE_ESP_WIFI_SSID_CLIENT, EXAMPLE_ESP_WIFI_PASS_CLIENT); + } else { + ESP_LOGE(TAG, "UNEXPECTED EVENT"); + } + + // /* The event will not be processed after unregister */ + // ESP_ERROR_CHECK(esp_event_handler_instance_unregister(IP_EVENT, IP_EVENT_STA_GOT_IP, instance_got_ip)); + // ESP_ERROR_CHECK(esp_event_handler_instance_unregister(WIFI_EVENT, ESP_EVENT_ANY_ID, instance_any_id)); + // vEventGroupDelete(s_wifi_event_group); +} + + + +//================================= +//========= deinit client ========= +//================================= +void wifi_deinit_client(void) +{ + /* The event will not be processed after unregister */ + ESP_ERROR_CHECK(esp_event_handler_instance_unregister(IP_EVENT, IP_EVENT_STA_GOT_IP, instance_got_ip)); + ESP_ERROR_CHECK(esp_event_handler_instance_unregister(WIFI_EVENT, ESP_EVENT_ANY_ID, instance_any_id)); + vEventGroupDelete(s_wifi_event_group); + esp_wifi_stop(); + esp_wifi_deinit(); + esp_netif_destroy_default_wifi(sta); +} + diff --git a/common/wifi.h b/common/wifi.h new file mode 100644 index 0000000..39eecee --- /dev/null +++ b/common/wifi.h @@ -0,0 +1,22 @@ +#pragma once + +//TODO: currently wifi names and passwords are configured in wifi.c -> move this to config? + +//initialize nvs-flash and netif (needed for both AP and CLIENT) +//has to be run once at startup +//Note: this cant be put in wifi_init functions because this may not be in deinit functions +void wifi_initNvs_initNetif(); + + +//function to start an access point +void wifi_init_ap(void); +//function to disable/deinit access point +void wifi_deinit_ap(void); + +//function to connect to existing wifi network +void wifi_init_client(void); +//function to disable/deinit client +void wifi_deinit_client(void); + + +