/** * @file Blinky_LED.c * @brief Demo application using the mesh network * @author Hendrik Schutter * @date 20.01.2021 * * Additional Infos: If button "BOOT" on ESP32-Module is pressed, all LED2 (blue) in the network will toggle the state. */ #include "Blinky_LED.h" static const char *LOG_TAG = "blinky_led"; static bool bLEDisOn = false; //set led default off static mesh_addr_t addrParent; //addr of parent node static mesh_addr_t childrenAddr[CONFIG_MESH_ROUTE_TABLE_SIZE]; //array of children attached to this node static uint16_t u16ChildrenSize; //number of children attached to this node xQueueHandle queueBlinkyLEDPackets; //handle for led action queue /** * @fn esp_err_t errBlinkyLEDInitialize() * @brief Starts the demp app * @param void * @return ESP32 error code * @author Hendrik Schutter * @date 20.01.2021 * * Initialize the queue and starts the tasks */ esp_err_t errBlinkyLEDInitialize(void) { esp_err_t err = ESP_OK; BaseType_t xReturned; vGPIOInitialize(); //create queue to store led action created from BTN and mesh network events queueBlinkyLEDPackets = xQueueCreate(5, sizeof(BLINKY_PACKET_t)); if (queueBlinkyLEDPackets == 0) // Queue not created { ESP_LOGE(LOG_TAG, "Unable to create Queue for Application Packets"); err = ESP_FAIL; } //register the receiver handle in mesh network ERROR_CHECK(errMeshNetworkSetAppReceiveHandle(rxHandle)); if(err == ESP_OK) { xReturned = xTaskCreate(vTaskReadUserInput, "vTaskReadUserInput", 4096, NULL, 5, NULL); if(xReturned != pdPASS) { err = ESP_FAIL; } } if(err == ESP_OK) { xReturned = xTaskCreate(vTaskReceiveData, "vTaskReceiveData", 4096, NULL, 5, NULL); if(xReturned != pdPASS) { err = ESP_FAIL; } } return err; } /** * @fn void vGPIOInitialize(void) * @brief sets the GPIO pins to correct modes * @param void * @return void * @author Hendrik Schutter * @date 20.01.2021 * * Initialize GPIO */ void vGPIOInitialize(void) { gpio_config_t gpioConf; //LED as Output gpio_reset_pin(GPIO_LED); gpio_set_direction(GPIO_LED, GPIO_MODE_OUTPUT); //BTN as Input gpioConf.intr_type = GPIO_INTR_DISABLE; gpioConf.mode = GPIO_MODE_INPUT; gpioConf.pin_bit_mask = GPIO_INPUT_PIN_SEL; gpioConf.pull_down_en = 0; gpioConf.pull_up_en = 1; gpio_config(&gpioConf); } /** * @fn void rxHandle(const uint8_t* const pu8Data, const uint8_t* const pu8Sender) * @brief callback handler from mesh network layer * @param pu8Data data received * @param pu8Sender sender node from data * @return void * @author Hendrik Schutter * @date 20.01.2021 * * Adds the data into queue */ void rxHandle(const uint8_t* const pu8Data, const uint8_t* const pu8Sender) { //send payload to app queue BLINKY_PACKET_t bTmpPacket; memcpy(&bTmpPacket, (uint8_t *)pu8Data, sizeof(BLINKY_PACKET_t)); memcpy(&bTmpPacket.meshSenderAddr, (uint8_t *)pu8Sender, 6); //copy MAC from sender into app packet if (xQueueSend(queueBlinkyLEDPackets, &bTmpPacket, portMAX_DELAY) != pdPASS) { ESP_LOGE(LOG_TAG, "Unable to push packet from mesh into Queue"); } } /** * @fn void vTaskReadUserInput(void *arg) * @brief FreeRTOS task reading the user input (button) * @param args parameter for task * @return void * @author Hendrik Schutter * @date 20.01.2021 * * Adds a button press to the queue */ void vTaskReadUserInput(void *arg) { esp_err_t err = ESP_OK; BLINKY_PACKET_t bTmpPacket; MESH_PACKET_t meshPacket; bTmpPacket.type = LED_OFF; //default off meshPacket.type = APP_Data; //this is a app packet while(true) { //check for BTN press if(gpio_get_level(GPIO_BOOT_BTN) == 0) { err = ESP_OK; if(bLEDisOn == false) { bTmpPacket.type = LED_ON; } else { bTmpPacket.type = LED_OFF; } //push led action into queue if (xQueueSend(queueBlinkyLEDPackets, &bTmpPacket, portMAX_DELAY) != pdPASS) { ESP_LOGE(LOG_TAG, "Unable to push packet into queue"); } memcpy(meshPacket.au8Payload, &bTmpPacket, sizeof(BLINKY_PACKET_t)); if(bMeshNetworkIsRootNode() == false) { //this node is not root --> send led action to parent ERROR_CHECK(errMeshNetworkGetParentNode(&addrParent)); ERROR_CHECK(errMeshNetworkSendMeshPacket(&addrParent, &meshPacket)); } else { //this node is root --> send led action to children ERROR_CHECK(errMeshNetworkGetChildren(childrenAddr, &u16ChildrenSize)); for (uint16_t u16Index = 0; u16Index < u16ChildrenSize; u16Index++) { ERROR_CHECK (errMeshNetworkSendMeshPacket(&childrenAddr[u16Index], &meshPacket)); } } vTaskDelay(200 / portTICK_PERIOD_MS); } vTaskDelay(50 / portTICK_PERIOD_MS); } } /** * @fn void vTaskReceiveData(void *arg) * @brief FreeRTOS task reading queue and setting the LED * @param args parameter for task * @return void * @author Hendrik Schutter * @date 20.01.2021 * * Sets the LED off or on based on data in queue */ void vTaskReceiveData(void *arg) { esp_err_t err = ESP_OK; MESH_PACKET_t meshPacket; BLINKY_PACKET_t bTmpPacket; bTmpPacket.type = LED_OFF; //default off meshPacket.type = APP_Data; //this is a app packet while (1) { if (xQueueReceive(queueBlinkyLEDPackets, &bTmpPacket, portMAX_DELAY) != pdTRUE) { ESP_LOGE(LOG_TAG, "Unable to receive packet from Queue"); } else { err = ESP_OK; //Successfully RECEIVED the packet switch (bTmpPacket.type) { case LED_ON: bLEDisOn = true; gpio_set_level(GPIO_LED, 1); //switch on ESP_LOGI(LOG_TAG,"switch LED ON"); break; case LED_OFF: bLEDisOn = false; gpio_set_level(GPIO_LED, 0); //switch off ESP_LOGI(LOG_TAG,"switch LED OFF"); break; default: bLEDisOn = false; gpio_set_level(GPIO_LED, 0); //switch off ESP_LOGI(LOG_TAG,"switch LED OFF"); break; } } ERROR_CHECK(errMeshNetworkGetChildren(childrenAddr, &u16ChildrenSize)); //get all children attached to this node memcpy(meshPacket.au8Payload, &bTmpPacket, sizeof(BLINKY_PACKET_t)); //copy led action in mesh packet payload for (uint16_t u16Index = 0; u16Index < u16ChildrenSize; u16Index++) { //loop through children if(bMeshNetworkCheckMACEquality(bTmpPacket.meshSenderAddr.addr, childrenAddr[u16Index].addr) == false) //exclude the sender node { ERROR_CHECK (errMeshNetworkSendMeshPacket(&childrenAddr[u16Index], &meshPacket)); //send to child } } vTaskDelay(200 / portTICK_PERIOD_MS); } }