Thomas Chef vor 5 Jahren
Commit
5fd4c7da57

+ 74 - 0
.gitignore

@@ -0,0 +1,74 @@
+# Prerequisites
+*.d
+
+# Object files
+*.o
+*.ko
+*.obj
+*.elf
+
+# Linker output
+*.ilk
+*.map
+*.exp
+
+# Precompiled Headers
+*.gch
+*.pch
+
+# Libraries
+*.lib
+*.a
+*.la
+*.lo
+
+# Shared objects (inc. Windows DLLs)
+*.dll
+*.so
+*.so.*
+*.dylib
+
+# Executables
+*.exe
+*.out
+*.app
+*.i*86
+*.x86_64
+*.hex
+
+# Debug files
+*.dSYM/
+*.su
+*.idb
+*.pdb
+
+# Kernel Module Compile Results
+*.mod*
+*.cmd
+.tmp_versions/
+modules.order
+Module.symvers
+Mkfile.old
+dkms.conf
+
+# Eclipse
+.metadata/
+RemoteSystemsTempFiles/.project
+.settings/
+*.a
+*.o
+*.d
+wifi_manager/.cproject
+wifi_manager/.project
+sdkconfig
+sdkconfig.old
+**/build/
+#doxygen
+Doxyfile
+wifi_manager/doc/
+.project
+.cproject
+
+# Visual Studio Code
+.vscode/
+.DS_Store

+ 7 - 0
CMakeLists.txt

@@ -0,0 +1,7 @@
+# The following four lines of boilerplate have to be in your project's CMakeLists
+# in this exact order for cmake to work correctly
+cmake_minimum_required(VERSION 3.5)
+
+set(SUPPORTED_TARGETS esp32)
+include($ENV{IDF_PATH}/tools/cmake/project.cmake)
+project(WiFi_433_Transceiver)

+ 9 - 0
Makefile

@@ -0,0 +1,9 @@
+#
+# This is a project Makefile. It is assumed the directory this Makefile resides in is a
+# project subdirectory.
+#
+
+PROJECT_NAME := WiFi_433_Transceiver
+
+include $(IDF_PATH)/make/project.mk
+

+ 5 - 0
README.md

@@ -0,0 +1,5 @@
+# Description
+
+ESP32 and Aurel based 433MHz sensor/NEXA transceiver with WiFi-UDP communication to backend.
+
+This project communicates with the "remote" application running on the Debian-server.

+ 5 - 0
main/CMakeLists.txt

@@ -0,0 +1,5 @@
+idf_component_register(SRCS "main.c" "led.c" "rxTimer.c" "transceiver.c" "receiver.c"
+                        "Sensors/ClasOSensor.c" "Sensors/proovesmartSensor.c" "Sensors/nexa.c"
+                        "nexaTransmit.c"
+                        "wifi.c" "udp_client.c"
+                    INCLUDE_DIRS ".")

+ 15 - 0
main/Kconfig.projbuild

@@ -0,0 +1,15 @@
+menu "WIFI_433_Transceiver Application Configuration"
+
+    config ESP_WIFI_SSID
+        string "WiFi SSID"
+        default "Hemnet3"
+        help
+            SSID (network name) to connect to.
+
+    config ESP_WIFI_PASSWORD
+        string "WiFi Password"
+        default "mypassword"
+        help
+            WiFi password (WPA or WPA2) to use.
+
+endmenu

+ 134 - 0
main/Sensors/ClasOSensor.c

@@ -0,0 +1,134 @@
+#include "ClasOSensor.h"
+#include <stdint.h>
+#include <stdio.h>
+#include "../rxTimer.h"
+#include "../led.h"
+
+enum
+{
+    UNKNOWN,
+    T0,
+    T1,
+    T2,
+    T3,
+    TEMP1_OK,
+    DONE
+};
+
+static uint8_t rx_state = UNKNOWN;
+
+static uint64_t sensor_data;
+static uint32_t rx_numBits;
+
+void ClasO_ResetDecoder()
+{
+    sensor_data = 0;
+    rx_numBits = 0;
+    rx_state = UNKNOWN;
+}
+
+static void addBit(uint8_t value)
+{
+
+    rx_numBits++;
+    sensor_data = (sensor_data << 1) + (value & 0x01);
+
+    rx_state = TEMP1_OK;
+}
+
+static int32_t rx_decode(uint32_t width)
+{
+    switch (rx_state) {
+        case UNKNOWN: // Start of frame
+            if (3700 <= width && width <= 4150)
+            {
+                rx_state = T0;
+            }
+            else
+            {
+                return -1; // error, reset
+            }
+            break;
+
+        case T0: // First half of pulse : HIGH around 230us
+
+            if (rx_numBits == 32)
+            { // end of frame
+                rx_state = DONE;
+                //printf("c");
+                sensor_data = (sensor_data >> 8); // Mask away some bits at the end
+                return 1;
+            }
+            else if (420 <= width && width <= 560)
+            {
+                rx_state = T1;
+            }
+            else
+            {
+                if (rx_numBits == 0 && 3700 <= width && width <= 4150 )
+                {
+                    rx_state = T0;
+                }
+                else
+                {
+                    return -1; // error, reset
+                }
+            }
+            break;
+
+        case T1:
+            if (880 <= width && width <= 1080)
+            {
+                addBit(0);
+            }
+            else if (1800 <= width && width <= 2100)
+            {
+                //debug_width = width;
+                addBit(1);
+            }
+            else
+            {
+                return -1; // error, reset
+            }
+            rx_state = T0;
+            break;
+    }
+    return 0;
+}
+
+int64_t nextPulseClasOSensor(uint32_t width)
+{
+    static int64_t previous_data = 0;
+    static uint32_t old_time=0;
+    static uint32_t now;
+    int64_t retVal = -1;
+
+    if (width > 0)
+    {
+        if (rx_state != DONE)
+        {
+            switch (rx_decode(width))
+            {
+            case -1:
+                ClasO_ResetDecoder();
+                break;
+            case 1:
+                rx_state = DONE;
+                //printf("%d\n",debug_width);
+                break;
+            }
+        }
+    }
+    if (rx_state == DONE) {
+        now = millis();
+        if( sensor_data != previous_data || (now > (old_time+1000)) ) {
+            previous_data = sensor_data;
+            retVal = sensor_data;
+            blinkTheLED();
+        }
+        old_time = now;
+        ClasO_ResetDecoder();
+    }
+    
+    return retVal;
+}

+ 11 - 0
main/Sensors/ClasOSensor.h

@@ -0,0 +1,11 @@
+#ifndef __CLASO__
+#define __CLASO__
+
+#include <stdbool.h>
+#include <stdint.h>
+
+void ClasO_ResetDecoder ();
+
+int64_t nextPulseClasOSensor(uint32_t width);
+
+#endif

+ 141 - 0
main/Sensors/nexa.c

@@ -0,0 +1,141 @@
+#include "nexa.h"
+#include <stdint.h>
+#include <stdio.h>
+#include "../rxTimer.h"
+#include "../led.h"
+
+#define FACTOR 9
+#define CONV(a) ((((a)*FACTOR) / 100) + (a))
+
+struct nexaData_t {
+  unsigned char bitNo;
+  unsigned short width;
+} ;
+
+enum { UNKNOWN, T0, T1, T2, T3, OK_Sensor, DONE };
+
+static uint8_t rx_state = UNKNOWN;
+
+static uint64_t sensor_data;
+static uint32_t rx_numBits;
+static uint8_t x_2ndbit;
+
+void NEXA_resetDecoder () {
+	sensor_data = 0;
+	rx_numBits = 0;
+	x_2ndbit = false;
+	rx_state = UNKNOWN;
+}
+
+static void addBit (uint8_t value) {
+
+	// X
+	rx_numBits++;
+	sensor_data = (sensor_data << 1) + (value & 0x01);
+	if( x_2ndbit == false ) {
+		x_2ndbit = true;
+	}
+	else {
+		x_2ndbit = false;
+		unsigned int bits = (sensor_data & 0x03);
+		if( bits == 2 ) {
+			// Bit is 1
+			sensor_data = (sensor_data >> 1) | 0x00000001;
+		}
+		else {
+			// Bit is 0
+			sensor_data = (sensor_data >> 1) & 0xFFFFFFFE;
+		}
+	}
+
+	rx_state = OK_Sensor;
+}
+
+static int rx_decode(uint32_t width) {
+  
+    if( rx_numBits == 3 ) {	// end of frame
+          //state = DONE;
+          //return 1;
+	}
+        
+	switch (rx_state) {
+        case UNKNOWN: // Start of frame
+            if ( 2240 <= width && width <= 3540 ) {
+                rx_state = T0;
+            }
+            else {
+                return -1;	// error, reset
+            }
+            break;
+
+        case T0: // First half of pulse
+
+            if ( 155 <= width && width <= 305 ) {
+                rx_state = T1;
+            }
+            else {
+                if( rx_numBits == 0 && 2240 <= width && width <= 3540 ) {
+                    rx_state = T0;
+                }
+                else {
+                    return -1;	// error, reset
+                }
+            }
+            break;
+
+        case T1:
+            if ( 240 <= width && width <= 440 ) {
+                addBit(0);
+            } else if ( (1410-300) <= width && width <= (1410+300) ) {
+                //debug_width = width;
+                addBit(1);
+            } else if( rx_numBits == 64 ) {	// end of frame
+                rx_state = DONE;
+                return 1;
+            } else  {
+                return -1;	// error, reset
+            }
+            rx_state = T0;
+            break;
+	}
+	return 0;
+}
+
+#define TOO_SHORT 100
+
+int64_t nextPulseNEXA(uint32_t width)
+{
+    static int64_t previous_data = 0;
+    static uint32_t old_time=0;
+    static uint32_t now;
+    int64_t retVal = -1;
+
+    if (width > 0)
+    {
+        if (rx_state != DONE)
+        {
+            switch (rx_decode(width))
+            {
+            case -1:
+                NEXA_resetDecoder();
+                break;
+            case 1:
+                rx_state = DONE;
+                //printf("%d\n",debug_width);
+                break;
+            }
+        }
+    }
+    if (rx_state == DONE) {
+        now = millis();
+        if( sensor_data != previous_data || (now > (old_time+1000)) ) {
+            previous_data = sensor_data;
+            retVal = sensor_data;
+            blinkTheLED();
+        }
+        old_time = now;
+        NEXA_resetDecoder();
+    }
+    
+    return retVal;
+}

+ 11 - 0
main/Sensors/nexa.h

@@ -0,0 +1,11 @@
+#ifndef __NEXA__
+#define __NEXA__
+
+#include <stdbool.h>
+#include <stdint.h>
+
+void NEXA_resetDecoder ();
+
+int64_t nextPulseNEXA(uint32_t width);
+
+#endif

+ 137 - 0
main/Sensors/proovesmartSensor.c

@@ -0,0 +1,137 @@
+#include "proovesmartSensor.h"
+#include <stdint.h>
+#include <stdio.h>
+#include "../rxTimer.h"
+#include "../led.h"
+#include <string.h>
+#include "esp_log.h"
+
+enum { UNKNOWN, T0, T1, T2, T3, OK_Sensor, DONE };
+
+static unsigned char rx_state = T0;
+
+static uint64_t sensor_data;
+static uint32_t rx_numBits;
+
+static unsigned char isTrigged = 0;
+static uint32_t trigDataBuff[4] = {0,0,0,0};
+
+void ProovesmartSensor_ResetDecoder () {
+	sensor_data = 0;
+	rx_numBits = 0;
+	rx_state = T0;
+    isTrigged = 0;
+    memset(trigDataBuff,0,sizeof(trigDataBuff));
+}
+
+static void addBit (uint8_t value) {
+
+	rx_numBits++;
+	sensor_data = (sensor_data << 1) + (value & 0x01);
+
+	rx_state = OK_Sensor;
+}
+
+#define MARG 55
+
+static int rx_decode (uint32_t width) {
+        
+	switch (rx_state) {
+
+        uint32_t bitData;
+
+        case T0: // First ON-half of pulse : HIGH around 910
+
+            if ( (1010-MARG) <= width && width <= (1080) ) {
+                rx_state = T1;
+            }
+            else {
+                if( isTrigged ) {
+                    //ESP_LOGE("PROOVE", "T0 Un-Trig B:%u W:%u",rx_numBits,width);
+                }
+                return -1;	// error, reset
+            }
+            break;
+
+        case T1:
+            if ( (445-MARG) <= width && width <= (445+MARG)) {
+                bitData = 1;
+            } else if ( (1420-MARG) <= width && width <= (1420+MARG) ) {
+                bitData = 0;
+            } else  {
+                if( isTrigged ) {
+                    //ESP_LOGE("PROOVE", "T1 Un-Trig B:%u W:%u",rx_numBits,width);
+                }
+                return -1;	// error, reset
+            }
+
+            if( isTrigged == 0 ) {
+
+                trigDataBuff[3] = trigDataBuff[2];
+                trigDataBuff[2] = trigDataBuff[1];
+                trigDataBuff[1] = trigDataBuff[0];
+                trigDataBuff[0] = bitData;
+
+                if( trigDataBuff[3] == 0 &&
+                    trigDataBuff[2] == 1 &&
+                    trigDataBuff[1] == 0 &&
+                    trigDataBuff[0] == 0) {
+
+                        isTrigged = 1;
+                        // ESP_LOGI("PROOVE", "Trig %u",width);
+                }
+
+            }
+            else {
+                addBit(bitData);
+
+                if( rx_numBits == 36-8 ) {	// end of frame (We skip the last 8 bits)
+                    rx_state = DONE;
+                    return 1;
+                }
+            }
+              
+            rx_state = T0;
+
+            break;
+    }
+    return 0;
+}
+
+int64_t nextPulseProovesmartSensor(uint32_t width)
+{
+    static int64_t previous_data = 0;
+    static uint32_t old_time=0;
+    static uint32_t now;
+    int64_t retVal = -1;
+
+    if (width > 0)
+    {
+        if (rx_state != DONE)
+        {
+            switch (rx_decode(width))
+            {
+            case -1:
+                ProovesmartSensor_ResetDecoder();
+                break;
+            case 1:
+                rx_state = DONE;
+                break;
+            }
+        }
+    }
+    if (rx_state == DONE) {
+        now = millis();
+        sensor_data <<= 8;
+        if( sensor_data != previous_data || (now > (old_time+1000)) ) {
+            previous_data = sensor_data;
+            retVal = sensor_data;
+            blinkTheLED();
+            //printf("%d\n",debug_width);
+        }
+        old_time = now;
+        ProovesmartSensor_ResetDecoder();
+    }
+    
+    return retVal;
+}

+ 11 - 0
main/Sensors/proovesmartSensor.h

@@ -0,0 +1,11 @@
+#ifndef __PROOVE__
+#define __PROOVE__
+
+#include <stdbool.h>
+#include <stdint.h>
+
+void ProovesmartSensor_ResetDecoder ();
+
+int64_t nextPulseProovesmartSensor(uint32_t width);
+
+#endif

+ 3 - 0
main/component.mk

@@ -0,0 +1,3 @@
+#
+# Main Makefile. This is basically the same as a component makefile.
+#

+ 82 - 0
main/led.c

@@ -0,0 +1,82 @@
+#include "led.h"
+#include "driver/gpio.h"
+#include "freertos/FreeRTOS.h"
+#include "freertos/task.h"
+#include "esp_log.h"
+
+unsigned int blinkLed = 0;
+
+#define BLINK_GPIO 2
+
+// Interface function to blink the green LED
+void blinkTheLED()
+{
+  blinkLed++;
+}
+
+enum
+{
+  MODE_INACTIVE,
+  MODE_ON,
+  MODE_OFF,
+  MODE_SWITCH, // Just have been off
+};
+
+void rxLed()
+{
+  static unsigned long timer = 0;
+  static int mode = MODE_INACTIVE;
+
+  switch (mode)
+  {
+
+  case MODE_INACTIVE:
+    if (blinkLed > 0)
+    {
+      blinkLed--;
+      mode = MODE_ON;
+      timer = 1;
+      gpio_set_level(BLINK_GPIO, 0); // On
+    }
+    break;
+
+  case MODE_ON:
+    timer--;
+    if (timer == 0)
+    {
+      mode = MODE_OFF;
+      gpio_set_level(BLINK_GPIO, 1);
+      timer = 1;
+    }
+    break;
+
+  case MODE_OFF:
+    timer--;
+    if (timer == 0)
+    {
+      mode = MODE_INACTIVE;
+      gpio_set_level(BLINK_GPIO, 1);
+      break;
+    }
+  }
+}
+
+static void led_task(void *pvParameter)
+{
+    ESP_LOGI("LED", "Task started.");
+    while (1)
+    {
+        rxLed();
+        vTaskDelay(200 / portTICK_PERIOD_MS);
+    }
+    vTaskDelete(NULL);
+}
+
+void initLed()
+{
+    gpio_set_level(BLINK_GPIO, 0);
+    gpio_pad_select_gpio(BLINK_GPIO);
+    gpio_set_direction(BLINK_GPIO, GPIO_MODE_OUTPUT);
+
+    xTaskCreatePinnedToCore(&led_task, "Led_Task", 8192, NULL, tskIDLE_PRIORITY + 1, NULL, 0);
+}

+ 10 - 0
main/led.h

@@ -0,0 +1,10 @@
+#ifndef __BLINK_LED__
+#define __BLINK_LED__
+
+void led_interrupt();
+void initLed();
+
+void blinkTheLED();
+
+
+#endif

+ 85 - 0
main/main.c

@@ -0,0 +1,85 @@
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <time.h>
+#include <sys/time.h>
+#include "freertos/FreeRTOS.h"
+#include "freertos/task.h"
+#include "esp_sleep.h"
+#include "esp_log.h"
+#include "driver/uart.h"
+#include "driver/rtc_io.h"
+#include "esp_intr_alloc.h"
+#include "esp_attr.h"
+#include "driver/timer.h"
+#include <stddef.h>
+#include "esp_intr_alloc.h"
+
+#include "led.h"
+#include "rxTimer.h"
+#include "transceiver.h"
+#include "receiver.h"
+#include "nexaTransmit.h"
+#include "wifi.h"
+#include "udp_client.h"
+
+
+void app_main(void)
+{
+    //volatile uint32_t counter = 0;
+
+    // Init stuff
+    disableRx = true;
+    rxTimerInit();          // First we start the Timer (which samples Rx and handles uS-delays)
+#ifdef WIFI_ENABLED
+    initWifi();             // Init WIFI
+    udpClientInit();
+#endif
+    initTransceiver();      // Init the 433-transceiver-HW
+    initLed();              // Init LED-Blink
+    initReceiver();         // Init receiver-task
+    initNexaTransmit();     // Init NEXA Transmit task
+    disableRx = false;
+  
+    while (true)
+    {
+        vTaskDelay(100 / portTICK_PERIOD_MS);
+
+        int c;
+        c=getchar();
+
+        if( c == 't') {
+            ESP_LOGI("MAIN", "Time: %10d mS",millis());
+        }
+        if( c == '?' ) {
+            char buff[40*15];
+            vTaskList(buff);
+            printf(buff);
+        }
+        if( c == 'p' ) {
+            int idx=dataArrIdx;
+            for(int i=0;i<500;i++) {
+                
+                if( dataArr[idx] > 200 && dataArr[idx] < 5000 ) 
+                    printf("%u\n",dataArr[idx]);
+                else
+                    printf("-\n");
+
+                idx--;
+                if( idx == -1 ) idx = 999;
+            }
+        }
+        if( c == 'w' ) {
+            char buff[40*10];
+            vTaskGetRunTimeStats(buff);
+            printf(buff);
+        }
+
+        if( c == '0' ) {
+            sendNexaCode(0x4C90AD81);
+        }
+        if( c == '1' ) {
+            sendNexaCode(0x4C90AD91);
+        }
+    }
+}

+ 138 - 0
main/nexaTransmit.c

@@ -0,0 +1,138 @@
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <time.h>
+#include <sys/time.h>
+#include "freertos/FreeRTOS.h"
+#include "freertos/task.h"
+#include "esp_sleep.h"
+#include "esp_log.h"
+#include "driver/uart.h"
+#include "driver/rtc_io.h"
+#include "esp_intr_alloc.h"
+#include "esp_attr.h"
+#include "driver/timer.h"
+#include <stddef.h>
+#include "esp_intr_alloc.h"
+
+#include "transceiver.h"
+#include "rxTimer.h"
+#include "led.h"
+
+QueueHandle_t nexaTxQueue = NULL;
+
+// Nexa : http://elektronikforumet.com/wiki/index.php/RF_Protokoll_-_Nexa_sj%C3%A4lvl%C3%A4rande
+// "1" = 295 µs hög och 170 µs låg
+// "0" = 295 µs hög och 920 µs låg
+// 
+// Etta skickas som 10 och Nolla som 01
+//
+// Dessa siffror från web-sidan stämmer inte med den Nexa-kontroll som jag har.
+// Jag har rättat dessa med siffror från verkligheten. Finns i define's nedan.
+
+// <NT01995080>
+// <NT01995090>
+
+// Timing for NEXA Remote controls
+#define HIGH_PULSE     230
+#define LOW_PULSE_0    340
+#define LOW_PULSE_1   1410
+#define SYNC_PULSE    2890
+#define STOP_PULSE   10000
+
+static void send1() {
+
+  trcvSendHighLowPulse( HIGH_PULSE, LOW_PULSE_1);    // 1
+  trcvSendHighLowPulse( HIGH_PULSE, LOW_PULSE_0 );   // 0
+}
+
+static void send0() {
+
+  trcvSendHighLowPulse( HIGH_PULSE, LOW_PULSE_0 );   // 0
+  trcvSendHighLowPulse( HIGH_PULSE, LOW_PULSE_1);    // 1  
+}
+
+static void sendSync() {
+  trcvSendHighLowPulse( HIGH_PULSE, SYNC_PULSE );  
+}
+
+static void sendStop() {
+  trcvSendHighLowPulse( HIGH_PULSE, STOP_PULSE );
+}
+
+static void sendNexaCodeNo(uint32_t orig_code) {
+
+  uint32_t code=0;
+  int32_t i;
+  int32_t loop;
+  
+  ESP_LOGI("NEXA TX", "<NT%08lX>",(unsigned long int)orig_code);
+  blinkTheLED();
+
+  if( 1 ) {
+
+    trcvSwitch2transmit();
+
+    for( loop=4; loop>0; loop--) {
+      
+      code = orig_code;
+      
+      sendSync();
+
+      for(i=0; i < 32; i++) {
+
+        if( code & 0x80000000 ) {
+          send1();
+        }
+        else {
+          send0();
+        }
+        code = (code << 1);
+      }
+      
+      sendStop();    
+      
+    }
+
+    trcvSwitch2receive();
+  }
+}
+
+// Public interface for sending a NEXA Code
+void sendNexaCode(uint32_t data) {
+
+    if( nexaTxQueue != NULL ) xQueueSend( nexaTxQueue, &data, 0 );
+}
+
+// Public interface for sending a NEXA Code in string format. For example: <NT4C90AD91>
+void sendNexaCodeStr(char *str) {
+
+    if( str[0] == '<' && str[11] == '>' ) {
+
+        uint32_t code;
+	
+	      sscanf((const char *)str,"<NT%08lX>",(long unsigned int *)&code);
+
+        sendNexaCode(code);
+    }
+}
+
+static void nexaTxTask(void *pvParameter)
+{
+    ESP_LOGI("NEXA TX", "Task started.");
+    uint32_t data;
+    while (1)
+    {
+        while( xQueueReceive( nexaTxQueue, &data, portMAX_DELAY ) == pdTRUE ) {
+          sendNexaCodeNo(data);
+        }
+    }
+    vTaskDelete(NULL);
+}
+
+void initNexaTransmit() {
+
+  nexaTxQueue = xQueueCreate( 20, sizeof( uint32_t ) );
+
+  xTaskCreatePinnedToCore(&nexaTxTask, "nexaTxTask", 8192, NULL, tskIDLE_PRIORITY + 2, NULL, 0);
+}

+ 14 - 0
main/nexaTransmit.h

@@ -0,0 +1,14 @@
+#ifndef __NEXATX__
+#define __NEXATX__
+
+#include <stdint.h>
+
+
+
+void sendNexaCode(uint32_t data);
+void sendNexaCodeStr(char *str);
+
+void initNexaTransmit();
+
+
+#endif

+ 104 - 0
main/receiver.c

@@ -0,0 +1,104 @@
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <time.h>
+#include <sys/time.h>
+#include "freertos/FreeRTOS.h"
+#include "freertos/task.h"
+#include "esp_sleep.h"
+#include "esp_log.h"
+#include "driver/uart.h"
+#include "driver/rtc_io.h"
+#include "esp_intr_alloc.h"
+#include "esp_attr.h"
+#include "driver/timer.h"
+#include <stddef.h>
+#include "esp_intr_alloc.h"
+
+#include "receiver.h"
+#include "transceiver.h"
+#include "rxTimer.h"
+#include "Sensors/ClasOSensor.h"
+#include "Sensors/proovesmartSensor.h"
+#include "Sensors/nexa.h"
+#include "led.h"
+#include "udp_client.h"
+#include "wifi.h"
+
+uint32_t dataArr[1000];
+uint32_t dataArrIdx = 0;
+
+static int convertToSignedTemp(unsigned int value)
+{
+
+	//int signValue;
+
+	return ( (value >> 11) == 0 )? value : ((-1 ^ 0xFFF) | value);
+}
+
+
+void receiverTask(void *pvParameter)
+{
+    ESP_LOGI("RX", "Receiver task starting.");
+    uint32_t width;
+
+    char dataStr[UDP_QUEUE_OBJ_LENGTH];
+
+    while (1) {
+
+        while( xQueueReceive( rxQueue, &width, portMAX_DELAY ) == pdTRUE ) {
+
+            dataArr[dataArrIdx++] = width;
+            if( dataArrIdx == 1000 ) dataArrIdx=0;
+
+            // Receive the Clas Ohlsson Sensors
+            int64_t data = nextPulseClasOSensor(width);
+            if( data != -1 ) {
+
+                int value      = convertToSignedTemp( data & 0xFFF );
+
+                ESP_LOGI("RX", "ClasO:  <TR%08llX> %d",data,value);
+
+                sprintf(dataStr,"<TR%08llX>\n",data);
+#ifdef WIFI_ENABLED
+                sendUDPMessage(dataStr);
+#endif
+            }
+
+            // Receive the Telldus / Proovesmart Sensors
+            data = nextPulseProovesmartSensor(width);
+            if( data != -1 ) {
+
+                const int value = (data & 0x00FFF0000) >> 16;
+                const int id = (data & 0xFF0000000) >> 28;
+
+                ESP_LOGI("RX", "Proove: <Tr%016llX> ID:%d  %d",data,id,value);
+
+                sprintf(dataStr,"<Tr%016llX>\n",data);
+#ifdef WIFI_ENABLED
+                sendUDPMessage(dataStr);
+#endif
+            }
+
+            // Receive the NEXA Sensors
+            data = nextPulseNEXA(width);
+            if( data != -1 ) {
+
+                ESP_LOGI("RX", "NEXA: <NR%08llX>",data);
+
+                sprintf(dataStr,"<NR%08llX>\n",data);
+#ifdef WIFI_ENABLED
+                sendUDPMessage(dataStr);
+#endif
+            }
+        }
+    }
+    vTaskDelete(NULL);
+}
+
+void initReceiver() {
+            
+    ESP_LOGI("RX", "Receiver has been initialized.");
+
+    xTaskCreatePinnedToCore(&receiverTask, "receiverTask", 8192, NULL, tskIDLE_PRIORITY + 5, NULL, 0);
+}

+ 13 - 0
main/receiver.h

@@ -0,0 +1,13 @@
+#ifndef __RECEIVER__
+#define __RECEIVER__
+
+
+
+void initReceiver();
+
+extern uint32_t dataArr[1000];
+extern uint32_t dataArrIdx;
+
+
+
+#endif

+ 121 - 0
main/rxTimer.c

@@ -0,0 +1,121 @@
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <time.h>
+#include <sys/time.h>
+#include "freertos/FreeRTOS.h"
+#include "freertos/task.h"
+#include "esp_sleep.h"
+#include "esp_log.h"
+#include "driver/uart.h"
+#include "driver/rtc_io.h"
+#include "esp_intr_alloc.h"
+#include "esp_attr.h"
+#include "driver/timer.h"
+#include <stddef.h>
+#include "esp_intr_alloc.h"
+
+#include "transceiver.h"
+
+static intr_handle_t s_timer_handle;
+
+static bool timerTaskIsDone = false;
+
+static volatile uint32_t tenUsCounter = 0;  
+
+QueueHandle_t rxQueue = NULL;
+
+static uint32_t millisCnt=0;
+
+uint32_t millis() { return millisCnt; }
+
+
+static void timer_tg0_isr(void* arg)
+{
+    static uint32_t subMillisCounter=100;
+
+    if( subMillisCounter-- == 0 ) {
+        millisCnt++;
+        subMillisCounter=100;
+    }
+
+    tenUsCounter++;
+
+    static uint8_t currValue = 0;
+  
+    static uint16_t samples = 0;
+    static uint16_t newSamples = 0;
+    
+    // Sample the pin value
+    uint8_t value = (uint8_t)gpio_get_level(GPIO_RX_DATA);
+
+    if( value == currValue ) {
+        samples++;
+        samples+=newSamples;
+        newSamples=0;
+    }
+    else {
+        newSamples++;
+    }
+    
+    if( newSamples == 6 ) {
+
+        const uint32_t dataToSend = samples * 10;
+
+        if( disableRx == false ) {
+            xQueueSend( rxQueue, &dataToSend, 0 );
+        }
+        
+        samples = newSamples;
+        newSamples = 0;
+        currValue = value;    
+    }
+
+    //Reset irq and set for next time
+    TIMERG1.int_clr_timers.t1 = 1;
+    TIMERG1.hw_timer[1].config.alarm_en = 1;
+}
+
+static void timerSetupTask(void *pvParameter)
+{
+    rxQueue = xQueueCreate( 1000, sizeof( uint32_t ) );
+
+    timer_config_t config = {
+        .alarm_en = true,				//Alarm Enable
+        .counter_en = false,			//If the counter is enabled it will start incrementing / decrementing immediately after calling timer_init()
+        .intr_type = TIMER_INTR_LEVEL,	//Is interrupt is triggered on timer’s alarm (timer_intr_mode_t)
+        .counter_dir = TIMER_COUNT_UP,	//Does counter increment or decrement (timer_count_dir_t)
+        .auto_reload = true,			//If counter should auto_reload a specific initial value on the timer’s alarm, or continue incrementing or decrementing.
+        .divider = 8   				//Divisor of the incoming 160 MHz (12.5nS) APB_CLK clock. E.g. 800 = 10uS per timer tick
+    };
+
+    timer_init(TIMER_GROUP_1, TIMER_1, &config);
+    timer_set_counter_value(TIMER_GROUP_1, TIMER_1, 0);
+    timer_set_alarm_value(TIMER_GROUP_1, TIMER_1, 100);     // Here we set the ISR-Value
+    timer_enable_intr(TIMER_GROUP_1, TIMER_1);
+    timer_isr_register(TIMER_GROUP_1, TIMER_1, &timer_tg0_isr, NULL, 0, &s_timer_handle);
+
+    timer_start(TIMER_GROUP_1, TIMER_1);
+
+    
+
+    timerTaskIsDone = true;
+    vTaskDelete(NULL);
+}
+
+void rxTimerInit()
+{
+    xTaskCreatePinnedToCore(&timerSetupTask, "timerSetupTask", 8192, NULL, tskIDLE_PRIORITY + 2, NULL, 1);
+
+    // Wait until task has finished
+    while(timerTaskIsDone == false) vTaskDelay( 50 / portTICK_PERIOD_MS );
+
+    ESP_LOGI("rxTimer", "10uS Timer has been started.");
+}
+
+void delayMicroseconds(uint32_t delay)
+{
+	volatile uint32_t endtime = tenUsCounter + ((uint32_t)delay / 10);
+
+	while( tenUsCounter < endtime ) taskYIELD();
+}

+ 18 - 0
main/rxTimer.h

@@ -0,0 +1,18 @@
+#ifndef __RX_TIMER__
+#define __RX_TIMER__
+
+#include "freertos/FreeRTOS.h"
+#include "freertos/queue.h"
+#include <stdint.h>
+
+void rxTimerInit();
+
+void delayMicroseconds(uint32_t delay);
+
+extern QueueHandle_t rxQueue;
+
+uint32_t millis();
+
+
+
+#endif

+ 87 - 0
main/transceiver.c

@@ -0,0 +1,87 @@
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <time.h>
+#include <sys/time.h>
+#include "freertos/FreeRTOS.h"
+#include "freertos/task.h"
+#include "esp_sleep.h"
+#include "esp_log.h"
+#include "driver/uart.h"
+#include "driver/rtc_io.h"
+#include "esp_intr_alloc.h"
+#include "esp_attr.h"
+#include "driver/timer.h"
+#include <stddef.h>
+#include "esp_intr_alloc.h"
+
+#include "transceiver.h"
+#include "rxTimer.h"
+
+
+bool disableRx = true; // Controls if trcv is in RX or TX-mode
+
+void trcvSendHighLowPulse(uint32_t high, uint32_t low) {
+
+  if( disableRx == false ) return;
+  
+  gpio_set_level(GPIO_TX_DATA, 1);
+  delayMicroseconds( high ); 
+  gpio_set_level(GPIO_TX_DATA, 0);
+  delayMicroseconds( low );  
+}
+
+void initTransceiver() {
+
+    gpio_set_level(GPIO_ENABLE, 0);
+    gpio_set_level(GPIO_TX_ENABLE, 0);
+    gpio_set_level(GPIO_TX_DATA, 0);
+
+    gpio_pad_select_gpio(GPIO_ENABLE);
+    gpio_pad_select_gpio(GPIO_TX_ENABLE);
+    gpio_pad_select_gpio(GPIO_TX_DATA);
+    gpio_pad_select_gpio(GPIO_RX_DATA);
+
+    gpio_set_direction(GPIO_ENABLE, GPIO_MODE_OUTPUT);
+    gpio_set_direction(GPIO_TX_ENABLE, GPIO_MODE_OUTPUT);
+    gpio_set_direction(GPIO_TX_DATA, GPIO_MODE_OUTPUT);
+    gpio_set_direction(GPIO_RX_DATA, GPIO_MODE_INPUT);
+
+    // ------------------ INIT THE TRANCEIVER -------------------------
+    // From powerdown mode (pin 4-5-6 low), 
+    // 1. Drive high pin 6 (ENABLE)
+    // 2. After 20us drive high pin 5 (RX/TX)200us, hold on 40us 
+    // 3. Drive down 20us pin 6 (ENABLE).  
+    gpio_set_level(GPIO_ENABLE, 1); delayMicroseconds( 20 ); 
+    gpio_set_level(GPIO_TX_ENABLE, 1); delayMicroseconds( 200 ); gpio_set_level(GPIO_TX_ENABLE, 0);
+    delayMicroseconds( 40 ); 
+    gpio_set_level(GPIO_ENABLE, 0); delayMicroseconds( 20 ); gpio_set_level(GPIO_ENABLE, 1);  
+    delayMicroseconds( 200 );
+    // ------------------ INIT THE TRANCEIVER -------------------------  
+            
+    ESP_LOGI("TRCV", "Transceiver has been initialized.");
+}
+
+void trcvSwitch2transmit() {
+
+  disableRx = true;
+  // ------------------ GO TO TRANSMIT STATE -------------------------
+  gpio_set_level(GPIO_TX_ENABLE, 1);
+  delayMicroseconds( 400 );
+  // ------------------ GO TO TRANSMIT STATE -------------------------
+}
+
+void trcvSwitch2receive() {
+  // ------------------ GO TO RECEIVE STATE -------------------------
+  // From Transmission Mode to Receiver Mode follow the procedure:
+  // Drive down pin 5 (RX/TX), after 40us drive down pin 6 (ENABLE) 20us long.
+  //After 200 us the device is ready for reception.
+  gpio_set_level(GPIO_TX_ENABLE, 0); 
+  delayMicroseconds( 40 ); 
+  gpio_set_level(GPIO_ENABLE, 0); 
+  delayMicroseconds( 20 ); 
+  gpio_set_level(GPIO_ENABLE, 1);  
+  delayMicroseconds( 200 );
+  // ------------------ GO TO RECEIVE STATE -------------------------
+  disableRx = false;
+}

+ 30 - 0
main/transceiver.h

@@ -0,0 +1,30 @@
+#ifndef __TRANSCEIVER__
+#define __TRANSCEIVER__
+
+/****************************************************************************************************
+ * The following I/O-Pins are used in the transceiver app:
+ * 
+ * 19	Output ENABLE
+ * 18	Output TX_ENABLE
+ * 17	Output TX_DATA
+ * 16	Input  RX_DATA
+ ****************************************************************************************************/
+
+ #define GPIO_ENABLE        19
+ #define GPIO_TX_ENABLE     18
+ #define GPIO_TX_DATA       17
+ #define GPIO_RX_DATA       16
+
+
+ extern bool disableRx;
+
+
+void initTransceiver();
+
+void trcvSwitch2transmit();
+void trcvSwitch2receive();
+
+void trcvSendHighLowPulse(uint32_t high, uint32_t low);
+
+
+#endif

+ 116 - 0
main/udp_client.c

@@ -0,0 +1,116 @@
+#include <string.h>
+#include <sys/param.h>
+#include "freertos/FreeRTOS.h"
+#include "freertos/task.h"
+#include "freertos/event_groups.h"
+#include "esp_system.h"
+#include "esp_wifi.h"
+#include "esp_event.h"
+#include "esp_log.h"
+#include "nvs_flash.h"
+#include "esp_netif.h"
+
+#include "lwip/err.h"
+#include "lwip/sockets.h"
+#include "lwip/sys.h"
+#include <lwip/netdb.h>
+
+#include "udp_client.h"
+#include "wifi.h"
+#include "nexaTransmit.h"
+
+/**********************************************************************************
+ * For sending and receiving UDP-Data from the Debian-server use these commands:
+ * echo "<NT4C90AD91>" | nc -uv 192.168.1.164 53000
+ * nc -lu -p 53000
+ **********************************************************************************/
+
+#ifdef WIFI_ENABLED
+
+#define HOST_IP_ADDR "192.168.1.110"
+#define PORT 53000
+
+static QueueHandle_t udpTxQueue = NULL; // Queue for transmitting UDP-Data to back-end server
+
+static void setupConnection(int *socket_fd, struct sockaddr_in *backEndAddress) {
+
+    struct sockaddr_in recvFromAddress;
+
+    closesocket(*socket_fd);
+
+    backEndAddress->sin_addr.s_addr = inet_addr(HOST_IP_ADDR);
+    backEndAddress->sin_family = AF_INET;
+    backEndAddress->sin_port = htons(PORT);
+
+    // Wait for WiFi to be connected first
+    while( commIsUpAndRunning == 0 ) vTaskDelay(500 / portTICK_PERIOD_MS);
+
+    *socket_fd = socket(AF_INET, SOCK_DGRAM, 0);
+    if (*socket_fd < 0) ESP_LOGE("UDP","Socket error");
+
+    // Bind our server socket to a port.
+    recvFromAddress.sin_family = AF_INET;
+    recvFromAddress.sin_addr.s_addr = htonl(INADDR_ANY);
+    recvFromAddress.sin_port = htons(PORT);
+    if( (bind(*socket_fd, (const struct sockaddr *)&recvFromAddress, sizeof(struct sockaddr_in))) == -1 )
+        ESP_LOGE("UDP","Bind error");
+    else
+        ESP_LOGI("UDP","UDP Rx Bind.");
+}
+
+
+void udp_client_task(void *pvParameter)
+{
+    struct sockaddr_in backEndAddress;
+    int recv_len;
+    char dataBuff[UDP_QUEUE_OBJ_LENGTH];
+    int socket_fd;
+
+    setupConnection(&socket_fd, &backEndAddress);
+
+    while(1)
+    {
+        memset(dataBuff,0,UDP_QUEUE_OBJ_LENGTH);
+
+        // Receive
+        if( (recv_len = recvfrom(socket_fd, dataBuff, UDP_QUEUE_OBJ_LENGTH,MSG_DONTWAIT, NULL, NULL)) > 0 ) {
+
+            if( dataBuff[recv_len-1] == '\n' ) dataBuff[recv_len-1] = '\0';
+            sendNexaCodeStr(dataBuff);
+            ESP_LOGI("UDP","UDP Task: Data: %s -- %d" , dataBuff, recv_len);
+        }
+        else if( recv_len == -1 && errno != 11 ) {
+            ESP_LOGE("UDP", "Error occurred during recvfrom: errno %d", errno);
+        }
+
+        // Transmit
+        while( xQueueReceive( udpTxQueue, &dataBuff, 0 ) == pdTRUE ) {
+
+            //ESP_LOGI("UDP","Send data:%s",dataBuff);
+            sendto(socket_fd, dataBuff, strlen(dataBuff), 0, (struct sockaddr *)&backEndAddress, sizeof(backEndAddress));
+        }
+
+        vTaskDelay(50 / portTICK_RATE_MS);
+    }
+
+    vTaskDelete(NULL);
+}
+
+// Public interface for sending a UDP Message to the back-end server.
+// Argument #1 must be UDP_QUEUE_OBJ_LENGTH chars in length.
+void sendUDPMessage(char *p) {
+
+  if( udpTxQueue != NULL ) xQueueSend( udpTxQueue, p, 0 );
+}
+
+void udpClientInit()
+{
+    ESP_ERROR_CHECK(esp_netif_init());
+    ESP_ERROR_CHECK(esp_event_loop_create_default());
+
+    udpTxQueue = xQueueCreate( 5, UDP_QUEUE_OBJ_LENGTH );
+
+    xTaskCreate(udp_client_task, "udp_client", 4096, NULL, 5, NULL);
+}
+
+#endif

+ 10 - 0
main/udp_client.h

@@ -0,0 +1,10 @@
+#ifndef __UDP_CLIENT__
+#define __UDP_CLIENT__
+
+#define UDP_QUEUE_OBJ_LENGTH 25
+
+void udpClientInit();
+
+void sendUDPMessage(char *p);
+
+#endif

+ 182 - 0
main/wifi.c

@@ -0,0 +1,182 @@
+/* WiFi station Example
+
+   This example code is in the Public Domain (or CC0 licensed, at your option.)
+
+   Unless required by applicable law or agreed to in writing, this
+   software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+   CONDITIONS OF ANY KIND, either express or implied.
+*/
+
+
+#include <string.h>
+#include "freertos/FreeRTOS.h"
+#include "freertos/task.h"
+#include "freertos/event_groups.h"
+#include "esp_system.h"
+#include "esp_log.h"
+#include "driver/gpio.h"
+
+#include "wifi.h"
+
+
+#ifdef WIFI_ENABLED
+
+#include "nvs_flash.h"
+#include "esp_wifi.h"
+#include "esp_event.h"
+#include "lwip/err.h"
+#include "lwip/sys.h"
+
+
+// These are configured in idf.py menuconfig
+#define DEFAULT_SSID CONFIG_ESP_WIFI_SSID
+#define DEFAULT_PWD CONFIG_ESP_WIFI_PASSWORD
+
+
+static const char *TAG = "wifi";
+
+
+int latestRSSIValue = 0;
+int latestWiFiChannel = -1;
+
+/*******
+ * 0: Not initialized
+ * 5: Waiting for a connection, or other event
+ * 10: WIFI_EVENT_STA_START
+ * 15: Waiting for a connection
+ * 20: WIFI_EVENT_STA_DISCONNECTED
+ * 30: IP_EVENT_STA_GOT_IP
+ * 35: All is up and running
+ */
+
+static int wifiState = 0; // Local wifi-state
+
+int commIsUpAndRunning = 0; // Global info
+
+static void event_handler(void* arg, esp_event_base_t event_base,int32_t event_id, void* event_data)
+{
+    ESP_LOGI(TAG, "Got event: %s ID:%d",event_base, event_id);
+    if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) {
+        wifiState = 10;
+    }
+    else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) {
+        wifiState = 20;
+
+    }
+    else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) {
+        wifiState = 30;
+    }
+}
+
+static void setupAndConfigureWiFi(void)
+{
+    ESP_ERROR_CHECK(esp_netif_init());
+    ESP_ERROR_CHECK(esp_event_loop_create_default());
+
+    wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
+    ESP_ERROR_CHECK(esp_wifi_init(&cfg));
+
+    ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &event_handler, NULL));
+    ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &event_handler, NULL));
+
+    // Initialize default station as network interface instance (esp-netif)
+    esp_netif_t *sta_netif = esp_netif_create_default_wifi_sta();
+    assert(sta_netif);
+
+    // Initialize and start WiFi
+    wifi_config_t wifi_config = {
+        .sta = {
+            .ssid = DEFAULT_SSID,
+            .password = DEFAULT_PWD,
+            .scan_method = WIFI_ALL_CHANNEL_SCAN,
+            .sort_method = WIFI_CONNECT_AP_BY_SIGNAL,
+            .threshold.rssi = -127,
+            .threshold.authmode = WIFI_AUTH_OPEN,
+        },
+    };
+    ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
+    ESP_ERROR_CHECK(esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config));
+    ESP_ERROR_CHECK(esp_wifi_start());
+}
+
+void    wifiTask(void *pvParameters)
+{
+    static TickType_t lastLogTime = 0;
+
+    while(1) {
+
+        switch (wifiState)
+        {
+        case 0:
+            // Time to setup everything
+            ESP_LOGI(TAG, "wifiTask state 0. Init-phase");
+            wifiState = 5;
+            setupAndConfigureWiFi();
+            break;
+        
+        case 10:
+            // Try to connect
+            ESP_LOGI(TAG, "wifiTask state 10: Try to scan and connect");
+            wifiState = 15;
+            esp_wifi_connect();
+            break;          
+        
+        case 20:
+            // We got disconnected ??
+            commIsUpAndRunning = 0;
+            ESP_LOGI(TAG, "wifiTask state 20: Disconnected");
+            wifiState = 15;
+            esp_wifi_connect();
+            break;          
+       
+        case 30:
+            // We got IP
+            commIsUpAndRunning = 1;
+            wifiState = 35;
+            ESP_LOGI(TAG, "wifiTask state 30. We got IP");
+            break;
+        
+        case 35:
+            // Everything is fine !
+
+            if( (xTaskGetTickCount()*portTICK_PERIOD_MS) > (lastLogTime + 500) ) {
+                static int logCounter = 5;
+                lastLogTime = xTaskGetTickCount() * portTICK_PERIOD_MS;
+                wifi_ap_record_t wifidata;
+                if (esp_wifi_sta_get_ap_info(&wifidata)==0){
+                    if( --logCounter == 0 ) {
+                        //ESP_LOGI(TAG, "WiFi RSSI:%d  Ch:%d",wifidata.rssi, wifidata.primary);
+                        logCounter=60;
+                    }
+                    latestRSSIValue = wifidata.rssi;
+                    latestWiFiChannel = wifidata.primary;
+                }
+            }
+            break;
+
+        case 5:
+        case 15:
+        default:
+            break;
+        }
+
+        vTaskDelay(250 / portTICK_PERIOD_MS);
+    }
+
+    vTaskDelete(NULL);
+}
+
+void initWifi(void)
+{
+  //Initialize NVS
+  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(ret);
+
+  xTaskCreate(wifiTask, "WiFi-Task", 1024*10, NULL, 2, NULL);
+}
+
+#endif

+ 13 - 0
main/wifi.h

@@ -0,0 +1,13 @@
+#ifndef __WIFI__
+#define __WIFI__
+
+void initWifi(void);
+
+extern int latestRSSIValue;
+extern int commIsUpAndRunning; // Global info
+extern int latestWiFiChannel;
+
+#define WIFI_ENABLED
+
+
+#endif

+ 10 - 0
sdkconfig.defaults

@@ -0,0 +1,10 @@
+CONFIG_ESP32_DEFAULT_CPU_FREQ_160=y
+
+CONFIG_FREERTOS_USE_TRACE_FACILITY=y
+CONFIG_FREERTOS_USE_STATS_FORMATTING_FUNCTIONS=y
+CONFIG_FREERTOS_VTASKLIST_INCLUDE_COREID=y
+
+CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS=y
+
+# CONFIG_FREERTOS_RUN_TIME_STATS_USING_ESP_TIMER=y
+CONFIG_FREERTOS_RUN_TIME_STATS_USING_CPU_CLK=y