diff --git a/examples/protocols/http_request/Makefile b/examples/protocols/http_request/Makefile new file mode 100644 index 00000000..26250750 --- /dev/null +++ b/examples/protocols/http_request/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 := http-request + +include $(IDF_PATH)/make/project.mk + diff --git a/examples/protocols/http_request/README.md b/examples/protocols/http_request/README.md new file mode 100644 index 00000000..1e1bd3d2 --- /dev/null +++ b/examples/protocols/http_request/README.md @@ -0,0 +1,5 @@ +# HTTP Request Example + +Uses a POSIX socket to make a very simple HTTP request. + +See the README.md file in the upper level 'examples' directory for more information about examples. diff --git a/examples/protocols/http_request/main/Kconfig.projbuild b/examples/protocols/http_request/main/Kconfig.projbuild new file mode 100644 index 00000000..92a75195 --- /dev/null +++ b/examples/protocols/http_request/main/Kconfig.projbuild @@ -0,0 +1,17 @@ +menu "Example Configuration" + +config WIFI_SSID + string "WiFi SSID" + default "myssid" + help + SSID (network name) for the example to connect to. + +config WIFI_PASSWORD + string "WiFi Password" + default "mypassword" + help + WiFi password (WPA or WPA2) for the example to use. + + Can be left blank if the network has no security set. + +endmenu diff --git a/examples/protocols/http_request/main/component.mk b/examples/protocols/http_request/main/component.mk new file mode 100644 index 00000000..a98f634e --- /dev/null +++ b/examples/protocols/http_request/main/component.mk @@ -0,0 +1,4 @@ +# +# "main" pseudo-component makefile. +# +# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.) diff --git a/examples/protocols/http_request/main/http_request_example_main.c b/examples/protocols/http_request/main/http_request_example_main.c new file mode 100644 index 00000000..844bfc34 --- /dev/null +++ b/examples/protocols/http_request/main/http_request_example_main.c @@ -0,0 +1,244 @@ +/* HTTP GET Example using plain POSIX sockets + + 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 +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/event_groups.h" +#include "esp_system.h" +#include "esp_wifi.h" +#include "esp_event_loop.h" +#include "esp_log.h" +#include "nvs_flash.h" + +#include "lwip/err.h" +#include "lwip/sockets.h" +#include "lwip/sys.h" +#include "lwip/netdb.h" +#include "lwip/dns.h" + +/* The examples use simple WiFi configuration that you can set via + 'make menuconfig'. + + If you'd rather not, just change the below entries to strings with + the config you want - ie #define EXAMPLE_WIFI_SSID "mywifissid" +*/ +#define EXAMPLE_WIFI_SSID CONFIG_WIFI_SSID +#define EXAMPLE_WIFI_PASS CONFIG_WIFI_PASSWORD + +/* FreeRTOS event group to signal when we are connected & ready to make a request */ +static EventGroupHandle_t wifi_event_group; + +/* The event group allows multiple bits for each event, + but we only care about one event - are we connected + to the AP with an IP? */ +const int CONNECTED_BIT = 1>>0; + +/* Constants that aren't configurable in menuconfig */ +#define WEB_SERVER "example.com" +#define WEB_PORT 80 +#define WEB_URL "http://example.com/" + +static const char *TAG = "example"; + +static const char *REQUEST = "GET " WEB_URL " HTTP/1.0\r\n" + "Host: "WEB_SERVER"\r\n" + "User-Agent: esp-idf/1.0 esp32\r\n" + "\r\n"; + +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: + /* This is a workaround as ESP32 WiFi libs don't currently + auto-reassociate. */ + esp_wifi_connect(); + xEventGroupClearBits(wifi_event_group, CONNECTED_BIT); + break; + default: + break; + } + return ESP_OK; +} + +static void initialise_wifi(void) +{ + 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 = { + .sta = { + .ssid = EXAMPLE_WIFI_SSID, + .password = EXAMPLE_WIFI_PASS, + }, + }; + ESP_LOGI(TAG, "Setting WiFi configuration SSID %s...", wifi_config.sta.ssid); + 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() ); +} + +static void http_get_task(void *pvParameters) +{ + const struct addrinfo hints = { + .ai_family = AF_INET, + .ai_socktype = SOCK_STREAM, + }; + struct addrinfo *res; + struct in_addr *addr; + int s, r; + char recv_buf[64]; + + while(1) { + /* Wait for the callback to set the CONNECTED_BIT in the + event group. + */ + xEventGroupWaitBits(wifi_event_group, CONNECTED_BIT, + false, true, portMAX_DELAY); + ESP_LOGI(TAG, "Connected to AP"); + + int err = getaddrinfo(WEB_SERVER, "80", &hints, &res); + + if(err != 0 || res == NULL) { + ESP_LOGE(TAG, "DNS lookup failed err=%d res=%p", err, res); + vTaskDelay(1000 / portTICK_PERIOD_MS); + continue; + } + + /* Code to print the resolved IP. + + Note: inet_ntoa is non-reentrant, look at ipaddr_ntoa_r for "real" code */ + addr = &((struct sockaddr_in *)res->ai_addr)->sin_addr; + ESP_LOGI(TAG, "DNS lookup succeeded. IP=%s", inet_ntoa(*addr)); + + s = socket(res->ai_family, res->ai_socktype, 0); + if(s < 0) { + ESP_LOGE(TAG, "... Failed to allocate socket."); + freeaddrinfo(res); + vTaskDelay(1000 / portTICK_PERIOD_MS); + continue; + } + ESP_LOGI(TAG, "... allocated socket"); + + if(connect(s, res->ai_addr, res->ai_addrlen) != 0) { + ESP_LOGE(TAG, "... socket connect failed errno=%d", errno); + close(s); + freeaddrinfo(res); + vTaskDelay(4000 / portTICK_PERIOD_MS); + continue; + } + + ESP_LOGI(TAG, "... connected"); + freeaddrinfo(res); + + if (write(s, REQUEST, strlen(REQUEST)) < 0) { + ESP_LOGE(TAG, "... socket send failed"); + close(s); + vTaskDelay(4000 / portTICK_PERIOD_MS); + continue; + } + ESP_LOGI(TAG, "... socket send success"); + + struct timeval receiving_timeout; + receiving_timeout.tv_sec = 5; + receiving_timeout.tv_usec = 0; + if (setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &receiving_timeout, + sizeof(receiving_timeout)) < 0) { + ESP_LOGE(TAG, "... failed to set socket receiving timeout"); + close(s); + vTaskDelay(4000 / portTICK_PERIOD_MS); + continue; + } + ESP_LOGI(TAG, "... set socket receiving timeout success"); + + /* Read HTTP response */ + do { + bzero(recv_buf, sizeof(recv_buf)); + r = read(s, recv_buf, sizeof(recv_buf)-1); + for(int i = 0; i < r; i++) { + putchar(recv_buf[i]); + } + } while(r > 0); + + ESP_LOGI(TAG, "... done reading from socket. Last read return=%d errno=%d\r\n", r, errno); + close(s); + for(int countdown = 10; countdown >= 0; countdown--) { + ESP_LOGI(TAG, "%d... ", countdown); + vTaskDelay(1000 / portTICK_PERIOD_MS); + } + ESP_LOGI(TAG, "Starting again!"); + } +} + +/****************************************************************************** + * FunctionName : user_rf_cal_sector_set + * Description : SDK just reversed 4 sectors, used for rf init data and paramters. + * We add this function to force users to set rf cal sector, since + * we don't know which sector is free in user's application. + * sector map for last several sectors : ABCCC + * A : rf cal + * B : rf init data + * C : sdk parameters + * Parameters : none + * Returns : rf cal sector +*******************************************************************************/ +uint32_t user_rf_cal_sector_set(void) +{ + flash_size_map size_map = system_get_flash_size_map(); + uint32_t rf_cal_sec = 0; + + switch (size_map) { + case FLASH_SIZE_4M_MAP_256_256: + rf_cal_sec = 128 - 5; + break; + + case FLASH_SIZE_8M_MAP_512_512: + rf_cal_sec = 256 - 5; + break; + + case FLASH_SIZE_16M_MAP_512_512: + case FLASH_SIZE_16M_MAP_1024_1024: + rf_cal_sec = 512 - 5; + break; + + case FLASH_SIZE_32M_MAP_512_512: + case FLASH_SIZE_32M_MAP_1024_1024: + rf_cal_sec = 1024 - 5; + break; + + case FLASH_SIZE_64M_MAP_1024_1024: + rf_cal_sec = 2048 - 5; + break; + + case FLASH_SIZE_128M_MAP_1024_1024: + rf_cal_sec = 4096 - 5; + break; + + default: + rf_cal_sec = 0; + break; + } + + return rf_cal_sec; +} + +void user_init() +{ + ESP_ERROR_CHECK( nvs_flash_init() ); + initialise_wifi(); + xTaskCreate(&http_get_task, "http_get_task", 4096, NULL, 5, NULL); +}