From ffeef87257485367718c1916d3f5be9101e9f551 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kelvin=20C=C3=A9sar=20de=20Andrade?= Date: Fri, 30 Oct 2020 00:45:37 -0300 Subject: [PATCH] =?UTF-8?q?Corrigido=20a=20vers=C3=A3o=20de=20firmware=20d?= =?UTF-8?q?o=20ESP32;=20-=20Criado=20fun=C3=A7=C3=A3o=20para=20c=C3=A1lcul?= =?UTF-8?q?o=20do=20RMS=20-=20Fun=C3=A7=C3=A3o=20para=20avaliar=20se=20o?= =?UTF-8?q?=20buffer=20de=20leitura=20est=C3=A1=20cheio;=20-=20Organiza?= =?UTF-8?q?=C3=A7=C3=A3o=20da=20chamada=20das=20fun=C3=A7=C3=B5es=20-=20Or?= =?UTF-8?q?ganiza=C3=A7=C3=A3o=20do=20salvamento=20no=20buffer;=20-=20Adic?= =?UTF-8?q?ionado=20max=20e=20min=20no=20buffer,=20para=20facilitar=20o=20?= =?UTF-8?q?c=C3=A1lculo=20de=20offset=20DC=20que=20deve=20ser=20subtraido?= =?UTF-8?q?=20do=20sinal;=20-=20Criado=20estrutura=20para=20armzenamento?= =?UTF-8?q?=20das=20vari=C3=A1veis=20principais=20do=20Smart=20Meter;=20-?= =?UTF-8?q?=20Criado=20buffer=20do=20tipo=20ring,=20para=20salvar=20os=20d?= =?UTF-8?q?ados=20de=20'time=20series'=20do=20Smart=20MEter;=20-=20Criado?= =?UTF-8?q?=20fun=C3=A7=C3=A3o=20para=20inserir=20no=20vetor=20de=20Smart?= =?UTF-8?q?=20Meter=20time=20series,=20os=20dados=20atuais=20que=20foram?= =?UTF-8?q?=20calculados;=20-=20Altera=C3=A7=C3=A3o=20da=20lib=20de=20wifi?= =?UTF-8?q?;=20-=20Melhorias=20gerais=20do=20c=C3=B3digo?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/buffer/buffer.h | 17 -- .../buffer.c => data_buffers/data_buffers.c} | 46 +++- lib/data_buffers/data_buffers.h | 44 ++++ lib/goertzel/goertzel.c | 21 +- lib/goertzel/goertzel.h | 3 +- lib/smartmeter/smartmeter.h | 7 + lib/wifi/wifi.c | 175 ------------- lib/wireless/wireless.c | 136 ++++++++++ lib/{wifi/wifi.h => wireless/wireless.h} | 26 +- platformio.ini | 2 +- sdkconfig | 3 +- src/smartmeter.c | 234 ++++++++++-------- src/smartmeter.h | 64 +++-- test/tcp-server.py | 4 +- 14 files changed, 416 insertions(+), 366 deletions(-) delete mode 100644 lib/buffer/buffer.h rename lib/{buffer/buffer.c => data_buffers/data_buffers.c} (52%) create mode 100644 lib/data_buffers/data_buffers.h create mode 100644 lib/smartmeter/smartmeter.h delete mode 100644 lib/wifi/wifi.c create mode 100644 lib/wireless/wireless.c rename lib/{wifi/wifi.h => wireless/wireless.h} (64%) diff --git a/lib/buffer/buffer.h b/lib/buffer/buffer.h deleted file mode 100644 index 214d528..0000000 --- a/lib/buffer/buffer.h +++ /dev/null @@ -1,17 +0,0 @@ -// Inclusion guard, to prevent multiple includes of the same header -#ifndef BUFFER_H -#define BUFFER_H - -#include // C standard library - -#define BUFFER_SIZE 2048 // Define buffer size for current and voltage - -typedef struct { - int16_t data[BUFFER_SIZE]; - uint16_t size; -} Buffer; - -int buffer_push (Buffer *buf, int16_t value); -int is_buffer_full(Buffer *buf); -void buffer_clean (Buffer *buf); -#endif diff --git a/lib/buffer/buffer.c b/lib/data_buffers/data_buffers.c similarity index 52% rename from lib/buffer/buffer.c rename to lib/data_buffers/data_buffers.c index 7e94aae..3fa48bf 100644 --- a/lib/buffer/buffer.c +++ b/lib/data_buffers/data_buffers.c @@ -1,4 +1,40 @@ -#include "buffer.h" // Include buffer header +#include "data_buffers.h" // Include buffer header + +TimeSerieSM sm_ts; + +// Function used to insert data into timeseries struct +int sm_push (SmartMeter *data){ + uint16_t pt = sm_ts.pointer; + + // Store data into timeseries data block + sm_ts.data[pt].v_rms = data->v_rms; + sm_ts.data[pt].i_rms = data->i_rms; + sm_ts.data[pt].aparrent_power = data->aparrent_power; + sm_ts.data[pt].active_power = data->active_power; + sm_ts.data[pt].reactive_power = data->reactive_power; + sm_ts.data[pt].frequency = data->frequency; + sm_ts.data[pt].fp = data->fp; + sm_ts.data[pt].THD_V = data->THD_V; + sm_ts.data[pt].THD_I = data->THD_I; + sm_ts.pointer++; + + // Verify if timeserires size is not full + if(sm_ts.pointer >= SM_TIMESERIE_SIZE){ + sm_ts.pointer = 0; + } + return 1; +} + + + + + + + + + + + // Function used to insert data into buffer and contabilize it size; int buffer_push (Buffer *buf, int16_t value){ @@ -8,7 +44,13 @@ int buffer_push (Buffer *buf, int16_t value){ } // Insert data into buffer and increment it counter buf->data[buf->size] = value; + // Compute max and min values + buf->max = (value > buf->max ) ? value : buf->max; + buf->min = (value < buf->min ) ? value : buf->min; + buf->size++; + + return 1; } void buffer_clean (Buffer *buf){ @@ -16,6 +58,8 @@ void buffer_clean (Buffer *buf){ buf->data[i] = 0; } buf->size = 0; + buf->max = 0; + buf->min = 0; } int is_buffer_full(Buffer *buf){ // Verify if buffer size is not full diff --git a/lib/data_buffers/data_buffers.h b/lib/data_buffers/data_buffers.h new file mode 100644 index 0000000..e2c5608 --- /dev/null +++ b/lib/data_buffers/data_buffers.h @@ -0,0 +1,44 @@ +// Inclusion guard, to prevent multiple includes of the same header +#ifndef BUFFER_H +#define BUFFER_H + +#include // C standard library +#define BUFFER_SIZE 2048 // Define buffer size for current and voltage +#define SM_TIMESERIE_SIZE 32 // Define smart meter main measures timeseires size + +// # Buffer struct +typedef struct { + int16_t data[BUFFER_SIZE]; // Array to store values + uint16_t size; // Store array size + uint16_t max; // Store max value in array + uint16_t min; // Store min value in array +} Buffer; + +// # Smart Meter main data block struct +typedef struct { + float v_rms; + float i_rms; + float aparrent_power; + float active_power; + float reactive_power; + float frequency; + float fp; + float THD_V; + float THD_I; + uint32_t timestamp; +} SmartMeter; + +// # Smart Meter timeseries block +typedef struct { + SmartMeter data[SM_TIMESERIE_SIZE]; + uint16_t pointer; +} TimeSerieSM; + +// # Buffer functions +int buffer_push (Buffer *buf, int16_t value); +int is_buffer_full(Buffer *buf); +void buffer_clean (Buffer *buf); + +// # Timeseries functions +int sm_push (SmartMeter *buf); +#endif diff --git a/lib/goertzel/goertzel.c b/lib/goertzel/goertzel.c index 601ed37..3616ffb 100644 --- a/lib/goertzel/goertzel.c +++ b/lib/goertzel/goertzel.c @@ -30,18 +30,18 @@ int goertzel (Buffer *buf, GoertzelState *goertz, uint16_t target_freq, uint16_t uint8_t enable_full_dft = config > 0x1; float w, c_real, c_img, coeff; float hann_const = 1; - float scale_factor = buf->size / 4; + float scale_factor = buf->size / 2; // # Calculate k constant - k = (unsigned int) (0.5 + (buf->size*target_freq/sample_rate)); + k = (unsigned int) floor((0.5 + (buf->size*target_freq/sample_rate))); // # Calculate omega - w = (k * 2.0 * PI_VALUE) / (buf->size); // Omega + w = (float) (k * 2.0 * M_PI) / (buf->size); // Omega // # Goertzel coeffiencts c_real = cosf(w); // Real coeff - coeff = 2 * c_real; // Pre-compute coeff; + coeff = 2 * c_real; // Pre-compute coeff; // Verifica se o cálculo completo da DFT está ativo if(enable_full_dft){ @@ -49,7 +49,8 @@ int goertzel (Buffer *buf, GoertzelState *goertz, uint16_t target_freq, uint16_t } // Cálcula a constante de Hanning para utilizar aplicar no sinal if(enable_hanning){ - hann_const = 2 * PI_VALUE / (buf->size - 1); // Compute hanning constant + hann_const = 2 * M_PI / (buf->size - 1); // Compute hanning constant + //printf(" # Hanning window enabled"); } @@ -61,7 +62,7 @@ int goertzel (Buffer *buf, GoertzelState *goertz, uint16_t target_freq, uint16_t // # Process samples for (uint16_t n = 0; n < buf->size; n++){ if(enable_hanning) - y = (float) buf->data[n] * (0.5 - 0.5*cosf(hann_const*n)); + y = (float) buf->data[n] * (1 - cosf(hann_const*n)) / 2; else y = (float) buf->data[n]; y += coeff*y_1 - y_2; @@ -72,7 +73,7 @@ int goertzel (Buffer *buf, GoertzelState *goertz, uint16_t target_freq, uint16_t if(enable_full_dft){ // # Calculate real, imaginary and amplitude - goertz->DFT_r = (y_1 - y_2 * c_real) / (scale_factor); + goertz->DFT_r = (y_1 * c_real - y_2) / (scale_factor); goertz->DFT_i = (y_2 * c_img) / (scale_factor); goertz->DFT_m = fast_sqrt(goertz->DFT_r*goertz->DFT_r + goertz->DFT_i*goertz->DFT_i); @@ -80,11 +81,11 @@ int goertzel (Buffer *buf, GoertzelState *goertz, uint16_t target_freq, uint16_t if(goertz->DFT_r > 0) { goertz->DFT_arg = atanf(goertz->DFT_i / goertz->DFT_r); } else if(goertz->DFT_r < 0) { - goertz->DFT_arg = PI_VALUE + atanf(goertz->DFT_i/goertz->DFT_r); + goertz->DFT_arg = M_PI + atanf(goertz->DFT_i/goertz->DFT_r); } else if(goertz->DFT_r == 0 && goertz->DFT_i > 0) { - goertz->DFT_arg = PI_2; + goertz->DFT_arg = M_PI_2; } else if(goertz->DFT_r == 0 && goertz->DFT_i < 0) { - goertz->DFT_arg = -PI_2; + goertz->DFT_arg = -M_PI_2; } } else { goertz->DFT_r = 0; diff --git a/lib/goertzel/goertzel.h b/lib/goertzel/goertzel.h index 630281b..4f3a19c 100644 --- a/lib/goertzel/goertzel.h +++ b/lib/goertzel/goertzel.h @@ -4,7 +4,7 @@ #include // C standard library #include -#include "buffer.h" +#include "data_buffers.h" //#include #define PI_VALUE 3.141592653 #define PI_2 1.570796327 @@ -21,4 +21,5 @@ typedef struct { // Functions int goertzel (Buffer *buf, GoertzelState *goertz, uint16_t target_freq, uint16_t sample_rate, uint8_t config); +float fast_sqrt(float x); #endif \ No newline at end of file diff --git a/lib/smartmeter/smartmeter.h b/lib/smartmeter/smartmeter.h new file mode 100644 index 0000000..d707f05 --- /dev/null +++ b/lib/smartmeter/smartmeter.h @@ -0,0 +1,7 @@ +// Inclusion guard, to prevent multiple includes of the same header +#ifndef SMARTMETER_H +#define SMARTMETER_H + +#include // C standard library + +#endif diff --git a/lib/wifi/wifi.c b/lib/wifi/wifi.c deleted file mode 100644 index cea9fc8..0000000 --- a/lib/wifi/wifi.c +++ /dev/null @@ -1,175 +0,0 @@ -/* WiFi connection over AP by Moritz Boesenberg - 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 "wifi.h" -static EventGroupHandle_t s_wifi_event_group; - -static EventGroupHandle_t wifi_event_group; - -const int CONNECTED_BIT = BIT0; - -static const char *TAG = "ESP32_Server"; - - -static RTC_DATA_ATTR char __SSID[32] = SSID; -static RTC_DATA_ATTR char __PWD[64] = PASSPHARSE; -static void wifi_event_handler(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); - } - - ESP_LOGI(TAG, "wifi_event_handler wifi_event_handler wifi_event_handler"); -} - -static esp_err_t event_handler(void *ctx, system_event_t *event) -{ - switch (event->event_id) - { - case SYSTEM_EVENT_STA_START: - esp_wifi_connect(); - break; - case SYSTEM_EVENT_STA_GOT_IP: - ESP_LOGI(TAG, "SYSTEM_EVENT_STA_GOT_IP "); - ESP_LOGI(TAG, "Login Success"); - gpio_set_level(LED_R, 1); - gpio_set_level(LED_G, 1); - gpio_set_level(LED_B, 1); - xEventGroupSetBits(wifi_event_group, CONNECTED_BIT); - break; - case SYSTEM_EVENT_STA_DISCONNECTED: - - ESP_LOGI(TAG, "SYSTEM_EVENT_STA_DISCONNECTED %d ", esp_wifi_connect()); - - gpio_set_level(LED_R, 0); - gpio_set_level(LED_G, 0); - gpio_set_level(LED_B, 0); - - esp_wifi_connect(); - xEventGroupClearBits(wifi_event_group, CONNECTED_BIT); - break; - default: - break; - } - return ESP_OK; -} -void wifi_init_softap() -{ - - if (strlen(__PWD) && strlen(__SSID) != 0) - { - tcpip_adapter_init(); - wifi_event_group = xEventGroupCreate(); - ESP_ERROR_CHECK(esp_event_loop_init(event_handler, NULL)); - wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); - ESP_ERROR_CHECK(esp_wifi_init(&cfg)); - ESP_ERROR_CHECK(esp_wifi_set_storage(WIFI_STORAGE_RAM)); - - wifi_config_t wifi_config = {}; - strcpy((char *)wifi_config.sta.ssid, __SSID); - strcpy((char *)wifi_config.sta.password, __PWD); - - ESP_LOGI(TAG, "WiFi %s ", wifi_config.sta.ssid); - ESP_LOGI(TAG, "PSW %s ", wifi_config.sta.password); - 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()); - - xEventGroupWaitBits(wifi_event_group, CONNECTED_BIT, false, true, portMAX_DELAY); - } - else - { - s_wifi_event_group = xEventGroupCreate(); - - tcpip_adapter_init(); - - ESP_ERROR_CHECK(esp_event_loop_create_default()); - ESP_ERROR_CHECK(esp_event_loop_init(event_handler, NULL)); //-> just here to get rid of startup error - wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); //= WIFI_INIT_CONFIG_DEFAULT(); - ESP_ERROR_CHECK(esp_wifi_init(&cfg)); - - ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &wifi_event_handler, NULL)); - - wifi_config_t wifi_config = { - .ap = { - .ssid = "SM Server", - .ssid_len = strlen("SM Server"), - .password = "", - .max_connection = 1, - .authmode = WIFI_AUTH_OPEN}, - }; - - - - ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_AP)); - ESP_ERROR_CHECK(esp_wifi_set_config(ESP_IF_WIFI_AP, &wifi_config)); - - tcpip_adapter_ip_info_t ip_info; - IP4_ADDR(&ip_info.ip, 192, 168, 1, 1); - IP4_ADDR(&ip_info.gw, 192, 168, 1, 1); - IP4_ADDR(&ip_info.netmask, 255, 255, 255, 0); - - tcpip_adapter_ap_start((uint8_t *)"9C:B6:D0:E7:30:0F", &ip_info); - - ESP_ERROR_CHECK(esp_wifi_start()); - } - - -} -// # Handle TCP socket connection -int socket_tcp_connect(){ - int s; - struct sockaddr_in tcpServerAddr; - tcpServerAddr.sin_addr.s_addr = inet_addr(TCP_SERVER_IP); - tcpServerAddr.sin_family = AF_INET; - tcpServerAddr.sin_port = htons( TCP_SERVER_PORT ); - ESP_LOGI(TAG,"- TCP Connection started. \n"); - - xEventGroupWaitBits(wifi_event_group,CONNECTED_BIT,false,true,portMAX_DELAY); - // # Allocate socket - s = socket(AF_INET, SOCK_STREAM, 0); - if(s < 0) { - ESP_LOGE(TAG, " * Failed to allocate socket.\n"); - return -1; - } - ESP_LOGI(TAG, " * Socket allocated\n"); - if(connect(s, (struct sockaddr *)&tcpServerAddr, sizeof(tcpServerAddr)) != 0) { - ESP_LOGE(TAG, " * Socket connect failed errno=%d \n", errno); - close(s); - return -1; - } - ESP_LOGI(TAG, " * Connected! \n"); - - return s; -} -void socket_tcp_close_connection(int s){ - close(s); - ESP_LOGI(TAG, " * Connection closed! \n"); -} -// # Send data over TCP Socket -uint16_t socket_tcp_send_data(int s, uint8_t data[], uint16_t data_size){ - printf("Size of data : %d", data_size); - if(s >= 0){ - if( write(s, data , data_size) < 0) - { - ESP_LOGE(TAG, " * Send failed \n"); - return 0; - } - //ESP_LOGI(TAG, "... socket send success"); - return 1; - } else return 0; -} \ No newline at end of file diff --git a/lib/wireless/wireless.c b/lib/wireless/wireless.c new file mode 100644 index 0000000..be6089c --- /dev/null +++ b/lib/wireless/wireless.c @@ -0,0 +1,136 @@ + +#include "wireless.h" + +// Event group +static EventGroupHandle_t wifi_event_group; +const int CONNECTED_BIT = BIT0; +static const char *TAG = "WIFI"; + +// Wifi event handler +static esp_err_t event_handler(void *ctx, system_event_t *event) +{ + switch(event->event_id) { + + case SYSTEM_EVENT_STA_START: + esp_wifi_connect(); + break; + + case SYSTEM_EVENT_STA_GOT_IP: + xEventGroupSetBits(wifi_event_group, CONNECTED_BIT); + break; + + case SYSTEM_EVENT_STA_DISCONNECTED: + xEventGroupClearBits(wifi_event_group, CONNECTED_BIT); + break; + + default: + break; + } + + return ESP_OK; +} + + + +// Main application +void setup_wifi() +{ + //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); + + + + // disable the default wifi logging + esp_log_level_set("wifi", ESP_LOG_NONE); + + // initialize NVS + ESP_ERROR_CHECK(nvs_flash_init()); + + // create the event group to handle wifi events + wifi_event_group = xEventGroupCreate(); + + // initialize the tcp stack + tcpip_adapter_init(); + + // initialize the wifi event handler + ESP_ERROR_CHECK(esp_event_loop_init(event_handler, NULL)); + + // initialize the wifi stack in STAtion mode with config in RAM + wifi_init_config_t wifi_init_config = WIFI_INIT_CONFIG_DEFAULT(); + ESP_ERROR_CHECK(esp_wifi_init(&wifi_init_config)); + ESP_ERROR_CHECK(esp_wifi_set_ps(WIFI_PS_NONE)); + ESP_ERROR_CHECK(esp_wifi_set_storage(WIFI_STORAGE_RAM)); + ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA)); + + // configure the wifi connection and start the interface + wifi_config_t wifi_config = { + .sta = { + .ssid = WIFI_SSID, + .password = WIFI_PASS, + }, + }; + ESP_ERROR_CHECK(esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config)); + ESP_ERROR_CHECK(esp_wifi_start()); + printf("Connecting to %s\n", WIFI_SSID); + + // wait for connection + printf("Main task: waiting for connection to the wifi network... "); + xEventGroupWaitBits(wifi_event_group, CONNECTED_BIT, false, true, portMAX_DELAY); + printf("connected!\n"); + + // print the local IP address + tcpip_adapter_ip_info_t ip_info; + ESP_ERROR_CHECK(tcpip_adapter_get_ip_info(TCPIP_ADAPTER_IF_STA, &ip_info)); + printf("IP Address: %s\n", ip4addr_ntoa(&ip_info.ip)); + printf("Subnet mask: %s\n", ip4addr_ntoa(&ip_info.netmask)); + printf("Gateway: %s\n", ip4addr_ntoa(&ip_info.gw)); +} + +// # Handle TCP socket connection +int socket_tcp_connect(){ + int s; + struct sockaddr_in tcpServerAddr; + tcpServerAddr.sin_addr.s_addr = inet_addr(TCP_SERVER_IP); + tcpServerAddr.sin_family = AF_INET; + tcpServerAddr.sin_port = htons( TCP_SERVER_PORT ); + ESP_LOGI(TAG,"- TCP Connection started. \n"); + + xEventGroupWaitBits(wifi_event_group,CONNECTED_BIT,false,true,portMAX_DELAY); + // # Allocate socket + s = socket(AF_INET, SOCK_STREAM, 0); + if(s < 0) { + ESP_LOGE(TAG, " * Failed to allocate socket.\n"); + return -1; + } + ESP_LOGI(TAG, " * Socket allocated\n"); + if(connect(s, (struct sockaddr *)&tcpServerAddr, sizeof(tcpServerAddr)) != 0) { + ESP_LOGE(TAG, " * Socket connect failed errno=%d \n", errno); + close(s); + return -1; + } + ESP_LOGI(TAG, " * Connected! \n"); + + return s; +} +void socket_tcp_close_connection(int s){ + close(s); + ESP_LOGI(TAG, " * Connection closed! \n"); +} +// # Send data over TCP Socket +uint16_t socket_tcp_send_data(int s, uint8_t data[], uint16_t data_size){ + printf("Size of data : %d", data_size); + if(s >= 0){ + if( write(s, data , data_size) < 0) + { + ESP_LOGE(TAG, " * Send failed \n"); + return 0; + } + //ESP_LOGI(TAG, "... socket send success"); + return 1; + } else return 0; +} \ No newline at end of file diff --git a/lib/wifi/wifi.h b/lib/wireless/wireless.h similarity index 64% rename from lib/wifi/wifi.h rename to lib/wireless/wireless.h index a6f3046..5918251 100644 --- a/lib/wifi/wifi.h +++ b/lib/wireless/wireless.h @@ -1,40 +1,36 @@ // Inclusion guard, to prevent multiple includes of the same header #ifndef WIFI_H #define WIFI_H + + +#include #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "freertos/event_groups.h" #include "esp_system.h" +#include "esp_log.h" #include "esp_wifi.h" #include "esp_event.h" #include "esp_log.h" #include "nvs_flash.h" -#include "cJSON.h" -#include "driver/gpio.h" -#include - -#include -#include "tcpip_adapter.h" #include "lwip/err.h" #include "lwip/sys.h" #include "lwip/sockets.h" +#include "tcpip_adapter.h" -#define LED_R 0 -#define LED_G 2 -#define LED_B 4 +#define WIFI_SSID "kelvin_esp" +#define WIFI_PASS "kelvin321" -#define SSID "r3358" -#define PASSPHARSE "kelvin321" -#define MESSAGE "HelloTCPServer" -#define TCP_SERVER_IP "192.168.43.129" +#define TCP_SERVER_IP "192.168.137.1" #define TCP_SERVER_PORT (8090) -void wifi_init_softap(void); +void setup_wifi(void); + int socket_tcp_connect(); void socket_tcp_close_connection(int s); uint16_t socket_tcp_send_data(int s, uint8_t data[], uint16_t data_size); -// End of the inclusion guard + #endif \ No newline at end of file diff --git a/platformio.ini b/platformio.ini index 7db79ec..a7a1f70 100644 --- a/platformio.ini +++ b/platformio.ini @@ -9,7 +9,7 @@ ; https://docs.platformio.org/page/projectconf.html [env:esp32dev] -platform = espressif32 +platform = espressif32@1.12.3 board = esp32dev framework = espidf monitor_speed = 115200 diff --git a/sdkconfig b/sdkconfig index 98e8916..3cdc453 100644 --- a/sdkconfig +++ b/sdkconfig @@ -393,7 +393,8 @@ CONFIG_MBEDTLS_SSL_OUT_CONTENT_LEN=4096 # CONFIG_MBEDTLS_ECP_RESTARTABLE is not set # CONFIG_MBEDTLS_CMAC_C is not set CONFIG_MBEDTLS_HARDWARE_AES=y -# CONFIG_MBEDTLS_HARDWARE_MPI is not set +CONFIG_MBEDTLS_HARDWARE_MPI=y +# CONFIG_MBEDTLS_MPI_USE_INTERRUPT is not set CONFIG_MBEDTLS_HARDWARE_SHA=y CONFIG_MBEDTLS_HAVE_TIME=y # CONFIG_MBEDTLS_HAVE_TIME_DATE is not set diff --git a/src/smartmeter.c b/src/smartmeter.c index 6bff7c0..16b5e1c 100644 --- a/src/smartmeter.c +++ b/src/smartmeter.c @@ -2,43 +2,45 @@ #include "smartmeter.h" // Smartmeter header // Global variable -SmartMeter SM_data[32]; + +SmartMeter sm_data; // Store smart meter main variables data; + static void adc_i2s_init(void) { + static const i2s_config_t i2s_config = { .mode = I2S_MODE_MASTER | I2S_MODE_RX | I2S_MODE_ADC_BUILT_IN, .sample_rate = ADC_SAMPLE_RATE*2, .bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT, - .communication_format = I2S_COMM_FORMAT_I2S | I2S_COMM_FORMAT_I2S_LSB, + .communication_format = I2S_COMM_FORMAT_I2S_MSB, .channel_format = I2S_CHANNEL_FMT_ONLY_LEFT, - .intr_alloc_flags = ESP_INTR_FLAG_LEVEL3, + .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1, .dma_buf_count = ADC_DMA_COUNT, .dma_buf_len = ADC_BUFFER_SIZE, .use_apll = false, }; //install and start i2s driver i2s_driver_install(I2S_NUM, &i2s_config, 0, NULL); - + // ADC-I2S Scanning does not normal start (more badly) after the reset of ESP32. + // It is necessary to add a delay of 5 seconds before switching on the ADC for a reliable start, this is issue. + vTaskDelay(5000/portTICK_RATE_MS); //init ADC pad static const adc_i2s_pattern_t adc_i2s_pattern[] = { { .atten = ADC_ATTEN_DB_11, .bits = ADC_WIDTH_BIT_12, - .channel = ADC1_CHANNEL_6, + .channel = ADC1_CHANNEL_0, }, { .atten = ADC_ATTEN_DB_11, .bits = ADC_WIDTH_BIT_12, - .channel = ADC1_CHANNEL_7 + .channel = ADC1_CHANNEL_3 } }; i2s_set_adc_mode(ADC_UNIT_1, adc_i2s_pattern, sizeof(adc_i2s_pattern)); - - // Delay necessary or reliable start; - vTaskDelay(1000/portTICK_RATE_MS); } // # ---------------------------------------------- // # SIGNAL GENERATOR @@ -84,12 +86,20 @@ void signal_generator_task(void *parameters) } void compute_goertzel(Buffer *buf){ + // Debug + int64_t start_time = 0; // Start time tick [us] + int64_t end_time = 0; // End time tick [us] + float time_spent = 0; // Time spent in the execution [s] + start_time = esp_timer_get_time(); // Debug + + + u16_t i = 0; //u8_t freq_multiple = 1; // Frequency multiple used to compute harmonics u8_t epsilon; float delta, delta_pi, main_freq, main_amp; - // - Goertzel + // Frequecies and amplitudes around 60 Hz where Goertzel algorithm will be applied. float dft[5][2] = { {0, 50}, // {amp, freq} {0, 55}, // {amp, freq} @@ -127,10 +137,10 @@ void compute_goertzel(Buffer *buf){ if(k > 0){ epsilon = (dft[k+1][0] >= dft[k-1][0]) ? 1 : -1; delta = epsilon * (2 * dft[k+epsilon][0] - dft[k][0]) / (dft[k][0] + dft[k+epsilon][0]); - k_m = (u16_t) (0.5 + (buf->size * dft[k][1] / ADC_SAMPLE_RATE)); + k_m = (u16_t) floor((0.5 + (buf->size * dft[k][1] / ADC_SAMPLE_RATE))); main_freq = (k_m + delta)* (1 / SAMPLING_WINDOW_TIME); - delta_pi = PI_VALUE * delta; + delta_pi = M_PI * delta; main_amp = fabs (dft[k][0]); main_amp *= fabs ( (float) (delta_pi) / (float) sinf(delta_pi)); @@ -138,7 +148,7 @@ void compute_goertzel(Buffer *buf){ main_amp *= fabs ( (float) (delta*delta - 1)); // Debug - printf("Maior amplitude = %f, k = %d\n", dft[k][0], k); + printf("\nMaior amplitude = %f, k = %d\n", dft[k][0], k); printf("- Epsilon: %d \n", epsilon); printf("- delta: %f \n", delta); printf("- k_m: %d \n", k_m); @@ -147,7 +157,12 @@ void compute_goertzel(Buffer *buf){ printf("- Main amplitude: %f\n", main_amp); } + // Obtain current time + end_time = esp_timer_get_time(); + // Calculating time spent + time_spent = (float)(end_time - start_time) / 1000000; + printf("compute_goertzel execution time = %f us\n", time_spent); /* // Calculate goertzel for 3rd and 5th hamornics @@ -158,7 +173,7 @@ void compute_goertzel(Buffer *buf){ // Apply goertzel to the frequency found goertzel_handle = goertzel(&buf, &g_state, harmonics[i][1], ADC_SAMPLE_RATE); printf("g_state.DFT_m %f\n", g_state.DFT_m); - harmonics[i][0] = S_VOL_RATIO * g_state.DFT_m; + harmonics[i][0] = SENS_VOLT_RATIO * g_state.DFT_m; // Calculate frequency mutiple to next iteration freq_multiple = freq_multiple+2; @@ -167,6 +182,51 @@ void compute_goertzel(Buffer *buf){ */ } +// Compute rms and remove dc offset +void do_rms(Buffer *voltage, Buffer *current){ + u32_t sum_voltage = 0; + u32_t sum_current = 0; + + // # Calcula o valor de offset do sinal + u16_t voltage_offset = (voltage->max + voltage->min) / 2; + u16_t current_offset = (current->max + current->min) / 2; + + // Remove o offset do sinal e computa o somatório da sua potência + for (u16_t i = 0; i < BUFFER_SIZE; i++){ + // Atualiza o valor do buffer removendo o offset + voltage->data[i] -= voltage_offset; + current->data[i] -= current_offset; + // Remove o offset do valor de tensão e atualiza no buffer + sum_voltage += (uint32_t) (voltage->data[i]*voltage->data[i]); + sum_current += (uint32_t) (current->data[i]*current->data[i]); + } + // Cálculo do RMS + sm_data.v_rms = fast_sqrt(sum_voltage / BUFFER_SIZE); + sm_data.i_rms = fast_sqrt(sum_current / BUFFER_SIZE); + + // # Debug + printf("==================\n"); + printf("v_rms = %f\n", sm_data.v_rms ); + printf("i_rms = %f\n", sm_data.i_rms ); + printf("voltage_offset = %d\n", voltage_offset ); + printf("current_offset = %d\n", current_offset ); + printf("==================\n"); +} + + +// # Verify buffers state +bool buffers_verify(){ + return (buf_voltage.size >= BUFFER_SIZE || buf_current.size >= BUFFER_SIZE || buffer_handle == -1) ? true : false; +} + + +/* + Apply linear equation to convert binary to mV + y = 0.8165x + 143.21 +*/ +uint16_t convert_to_voltage(uint16_t value){ + return (float) (value * 0.8165 + 143.21); +} void sample_read_task(void *parameters) { @@ -181,104 +241,79 @@ void sample_read_task(void *parameters) size_t measures_read; // Receive number of measures read from I2S - ADC // # Declare local variables - int16_t voltage_converted = 0; // Voltage read; - int16_t current_converted = 0; // Current read; - + u16_t sample = 0; // Generic variable to momently store sample value converted to mV + u16_t loop_ctrl = 0; // Used to control while loop - - // # Debug - int64_t start_time = 0; // Start time tick [us] - int64_t end_time = 0; // End time tick [us] - float time_spent = 0; // Time spent in the execution [s] - int16_t max_value = 0; // # Start ADC I2S Setup ESP_LOGI(TAG_SM, "# Starting ADC configuration"); adc_i2s_init(); - ESP_LOGI(TAG_SM, "# ADC setup successfuly"); - - while (true) { - //for (int k = 0; k < 1; ++k) { - // Verify buffer size - if(buf_voltage.size >= BUFFER_SIZE){ - - // Debug - /* - for(uint16_t x = 0; x < buf_voltage.size ; x++){ - printf("Buffer [%d] = %d\n", x, buf_voltage.data[x]); - if((x == 512) || (x == 1024) || (x == 1573)){ - vTaskDelay(10000 / portTICK_PERIOD_MS); - } - } - */ - // # Apply goertzel: - start_time = esp_timer_get_time(); // Debug - printf(" - max_value = %d", max_value); - compute_goertzel(&buf_voltage); - // Obtain current time - end_time = esp_timer_get_time(); - - // Calculating time spent - time_spent = (float)(end_time - start_time) / 1000000; - printf("compute_goertzel execution time = %f us", time_spent); - // Clean buffer - //buffer_clean(&buf_voltage); - break; - } - // # Read data from i2s. - + ESP_LOGI(TAG_SM, "# ADC setup successfuly"); + buffer_clean(&buf_current); + buffer_clean(&buf_voltage); + ESP_LOGI(TAG_SM, "# Buffers cleaned"); + + while (loop_ctrl == 0) { + // # Read data from i2s. esp_err_t err = i2s_read(I2S_NUM, buf, sizeof(buf), &measures_read, portMAX_DELAY); if (err != ESP_OK) { printf("i2s_read: %d\n", err); - } - - measures_read /= sizeof(adc_sample_t); - - - - + } + // # Compute vector size + measures_read /= sizeof(adc_sample_t); - // Loop on measures to convert and save on buffer + // # Loop on measures to convert and save on buffer for (u16_t i = 0; i < measures_read; i ++) { // Get channels offset on buffer switch (buf[i] >> 12){ case ADC_CURRENT_CHANNEL: - current_converted = esp_adc_cal_raw_to_voltage(ADC_GET_MEASURE(buf[i]), &cal) - ADC_V_REF / 2; - buffer_handle = buffer_push(&buf_current, current_converted); - + // Realiza a conversão da amostra para tensão de acordo com calibração + sample = convert_to_voltage(ADC_GET_MEASURE(buf[i])); + + // Salva no buffer de tensão + buffer_handle = buffer_push(&buf_current, sample); break; case ADC_VOLTAGE_CHANNEL: - - //voltage_converted = esp_adc_cal_raw_to_voltage(ADC_GET_MEASURE(buf[i]), &cal) - ADC_V_REF / 2; // - voltage_converted = ADC_GET_MEASURE(buf[i]) - ADC_SIGNAL_OFFSET; - buffer_handle = buffer_push(&buf_voltage, voltage_converted); - //if(voltage_converted > max_value) max_value = voltage_converted; + // Realiza a conversão da amostra para tensão de acordo com calibração + sample = convert_to_voltage(ADC_GET_MEASURE(buf[i])); - //printf("%d\n", buf_voltage.size); + // Salva no buffer de tensão + buffer_handle = buffer_push(&buf_voltage, sample); break; - default: ESP_LOGE(TAG_SM, "# Unknown channel %d", buf[0]>>12); } - - - - - // Insert data into buffers - - - - //sum_voltage += (uint32_t) (voltage_converted*voltage_converted); - //sum_current += (uint32_t) (current_converted*current_converted); - //sum_active_power += (uint32_t) (voltage_converted*current_converted); } + if(buf_voltage.size != buf_current.size){ + ESP_LOGE(TAG_SM, "# Voltage buffer and current doesn't have the same size [%d/%d]", buf_voltage.size, buf_current.size); + } else { + // Verifica se os buffers chegaram ao limite + if(buffers_verify()){ + // # Compute RMS and remove DC offset from signals; + do_rms(&buf_voltage, &buf_current); + // # Apply goertzel to voltage signal + compute_goertzel(&buf_voltage); + for(uint16_t x = 0; x < buf_voltage.size ; x++){ + printf("%u,%d;", x, buf_voltage.data[x]); + } + printf("\n\n"); + buffer_clean(&buf_voltage); + // # Apply goertzel to current signal + compute_goertzel(&buf_current); + buffer_clean(&buf_current); + + // # Debug + loop_ctrl = 1; + } + } + } // Debug @@ -305,9 +340,8 @@ void sample_read_task(void *parameters) } socket_tcp_close_connection(s); - - buffer_clean(&buf_voltage); */ + i2s_adc_disable(I2S_NUM); i2s_stop(I2S_NUM); vTaskDelete(NULL); @@ -317,26 +351,8 @@ void sample_read_task(void *parameters) void app_main(void) { - //set RGB PINs - //gpio_pad_select_gpio(LED_R); - //gpio_pad_select_gpio(LED_G); - //gpio_pad_select_gpio(LED_B); -// - //gpio_set_direction(LED_R, GPIO_MODE_OUTPUT); - //gpio_set_direction(LED_G, GPIO_MODE_OUTPUT); - //gpio_set_direction(LED_B, GPIO_MODE_OUTPUT); - - 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); - //wifi_init_softap(); + //setup_wifi(); @@ -345,7 +361,7 @@ void app_main(void) // Print info to show main task is running ESP_LOGI(TAG_SM, "# Running app_main in core %d", xPortGetCoreID()); - /* + /**/ // Log task creation ESP_LOGI(TAG_SM, "# Creating signal_generator task"); @@ -362,8 +378,8 @@ void app_main(void) // Check task creation error if (task_create_ret != pdPASS){ ESP_LOGE(TAG_SM, "Error creating signal_generator task"); } // Delay - vTaskDelay(1000 / portTICK_PERIOD_MS); - */ + vTaskDelay(10000 / portTICK_PERIOD_MS); + // Log task creation ESP_LOGI(TAG_SM, "# Creating sample_read_task"); @@ -372,7 +388,7 @@ void app_main(void) task_create_ret = xTaskCreatePinnedToCore( sample_read_task, // Function executed in the task "SRT", // Task name (for debug) - 24000, // Stack size in bytes + 32000, // Stack size in bytes NULL, // Parameter to pass to the function 1, // Task priority &sample_read_task_handle, // Used to pass back a handle by which the created task can be referenced diff --git a/src/smartmeter.h b/src/smartmeter.h index ed7c2d0..1a7d168 100644 --- a/src/smartmeter.h +++ b/src/smartmeter.h @@ -35,8 +35,8 @@ #include "soc/syscon_struct.h" // Application lib files -#include "wifi.h" // Wi-fi functions -#include "buffer.h" // Buffer library +#include "wireless.h" // Wi-fi functions +#include "data_buffers.h" // Data buffers library #include "goertzel.h" // Goertzel library // Signal generator library @@ -49,35 +49,39 @@ // ## DEFINES ## // # Current sensor configuration: -#define S_AMP_RATIO 1 // Current sensor ratio; -#define ADC_CURRENT_CHANNEL 6 // Define channel used to measure current +#define SENS_CURR_RATIO (1) // Current sensor ratio; +#define ADC_CURRENT_CHANNEL (0) // Define channel used to measure current // # Voltage sensor configuration: -#define S_VOL_RATIO 0.1884 // Voltage sensor ratio; 3.3/4095 * (2/3.3)*311 -#define ADC_VOLTAGE_CHANNEL 7 // Define channel used to measure voltage +#define SENS_VOLT_RATIO (0.1884) // Voltage sensor ratio; 3.3/4095 * (2/3.3)*311 +#define SENS_DC_OFFSET ((2450 - 180) / 2) // Voltage sensor DC offset value in [mV] +#define ADC_VOLTAGE_CHANNEL (3) // Define channel used to measure voltage // # ADC configuration: -#define MAIN_FREQ 60 // Main signal frequency in Hz; -#define I2S_NUM 0 // I2S drive number; -#define ADC_NUM_OF_CH 2 // Number of channels that are read; -#define ADC_SAMPLE_RATE 10240 // Sampling rate in Hz -#define ADC_BUFFER_SIZE 1024 // I2S Buffer size (limit: 1024) +#define MAIN_FREQ (60) // Main signal frequency in Hz; +#define I2S_NUM (0) // I2S drive number; +#define ADC_NUM_OF_CH (2) // Number of channels that are read; +#define ADC_SAMPLE_RATE (10240) // Sampling rate in Hz +#define ADC_BUFFER_SIZE (1024) // I2S Buffer size (limit: 1024) -#define ADC_DMA_COUNT 32 // Number of DMA buffers +#define ADC_DMA_COUNT (24) // Number of DMA buffers -#define ADC_V_REF 3300 // ADC Voltage reference in mV; -#define ADC_RESOLUTION 4096 // ADC resolution -#define ADC_SIGNAL_IS_AC true // Define that signal read is AC; -#define ADC_SIGNAL_OFFSET 2048 // Define offset for AC signal; -#define ADC_GET_MEASURE(s) (s & 0xFFF) // Macro used to get 12 bit part from adc read; -#define SAMPLING_WINDOW_TIME 0.2 // Define the sampling window time from signal +#define ADC_V_REF (3300) // ADC Voltage reference in mV; +#define ADC_RESOLUTION (4096) // ADC resolution +#define ADC_SIGNAL_IS_AC true // Define that signal read is AC; + +#define ADC_GET_MEASURE(s) (s & 0xFFF) // Macro used to get 12 bit part from adc read; + + + +#define SAMPLING_WINDOW_TIME (0.2) // Define the sampling window time from signal // # Signal generator: -#define SIN_WAVE_NUM 255 // Number of samples per period +#define SIN_WAVE_NUM (255) // Number of samples per period // # Goertzel -#define G_MAIN_FREQ_NUM 5 // Number of frequencies to use on interpolation -#define G_NUM_OF_HARM 2 // Define the number of harmonics +#define G_MAIN_FREQ_NUM (5) // Number of frequencies to use on interpolation +#define G_NUM_OF_HARM (2) // Define the number of harmonics #define ENABLE_DEBUG // Enable debug mode @@ -99,19 +103,7 @@ int16_t buffer_handle = 0; GoertzelState g_state; int16_t goertzel_handle = 0; -// Main data structure -typedef struct { - float v_rms; - float i_rms; - float aparrent_power; - float active_power; - float reactive_power; - float frequency; - float fp; - float THD_V; - float THD_I; - uint16_t pointer; -} SmartMeter; + @@ -135,5 +127,9 @@ void signal_generator_task(void *parameters); // Function to compute goertzel on signal read; void compute_goertzel(); +// Function to convert adc read binary data to mV +uint16_t convert_to_voltage(uint16_t value); + + // End of the inclusion guard #endif \ No newline at end of file diff --git a/test/tcp-server.py b/test/tcp-server.py index 79a77c3..d770c60 100644 --- a/test/tcp-server.py +++ b/test/tcp-server.py @@ -3,7 +3,7 @@ import struct s = socket.socket() -s.bind(('192.168.43.129', 8090 )) +s.bind(('192.168.137.1', 8090 )) s.listen(0) print("Starting server") while True: @@ -15,7 +15,7 @@ if len(content) > 0: try: data_struct = struct.Struct('>8192B') - read_recover = list(data_struct.unpack(received)) + read_recover = list(data_struct.unpack(data_struct)) for x in read_recover: print(x)