Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: examples/repl_esp32 #37

Closed
wants to merge 13 commits into from
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
- [atclient_esp32_static_components](./examples/atclient_esp32_static_components/README.md) is an example of how to use atclient in your ESP-IDF project with static libraries in separated components built from [atclient_espidf](./packages/atclient_espidf/README.md).
- [atclient_esp32_static_no_components](./examples/atclient_esp32_static_no_components/) is an example of how to use atclient in your ESP-IDF project with static libraries without components built from [atclient_espidf](./packages/atclient_espidf/README.md).
- [repl](./examples/repl/README.md) is a command line interface for interacting with the atProtocol. Works on Desktop Linux/MacOS.
- [repl_esp32](./examples/repl_esp32/README.md) is a command line interface for interacting with the atProtocol. Works on ESP32, not tested on other devices that can run the IDF.

## Contributing

Expand Down
6 changes: 0 additions & 6 deletions examples/repl/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,7 @@ project(
)

include(GNUInstallDirs)
include(FetchContent)

# FetchContent_Declare(
# atclient
# SOURCE_DIR ${CMAKE_SOURCE_DIR}/../../atclient
# )
# FetchContent_MakeAvailable(atclient)
find_package(atclient REQUIRED CONFIG)

message(STATUS "atclient was found")
Expand Down
2 changes: 2 additions & 0 deletions examples/repl_esp32/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
include/
lib/
10 changes: 10 additions & 0 deletions examples/repl_esp32/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
cmake_minimum_required(VERSION 3.19)

set(EXTRA_COMPONENT_DIRS
${CMAKE_CURRENT_LIST_DIR}/../../packages/atchops
${CMAKE_CURRENT_LIST_DIR}/../../packages/atclient
)

include($ENV{IDF_PATH}/tools/cmake/project.cmake)

project(repl_esp32)
31 changes: 31 additions & 0 deletions examples/repl_esp32/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# repl_esp32

This example is a command line interface for interacting with the atProtocol. Works on ESP32, not tested on other devices that can run the IDF. You will be able to interact with your atServer through the command-line which will run on your ESP32.

## Running the REPL

You will need the [IDF toolchain](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/build-system.html#idf-py) to build and flash to your device.

1. Get IDF

```
get_idf
```

2. Build

```
idf.py build
```

3. Menuconfig, set your SSID and Password in "repl_esp32 WiFi Configuration"

```
idf.py menuconfig
```

4. Build, Flash and Monitor

```
idf.py build && idf.py flash monitor
```
5 changes: 5 additions & 0 deletions examples/repl_esp32/main/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
idf_component_register(
SRCS "main.c" "event_handlers.c" "wifi.c"
INCLUDE_DIRS "."
REQUIRES atclient atchops mbedtls esp_wifi esp_event nvs_flash freertos
)
13 changes: 13 additions & 0 deletions examples/repl_esp32/main/Kconfig.projbuild
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
menu "repl_esp32 WiFi Configuration"
config ESP_WIFI_SSID
string "WiFi SSID"
default "ssid"
help
SSID (network name) to connect to.

config ESP_WIFI_PASSWORD
string "WiFi Password"
default "pswd"
help
WiFi password (WPA or WPA2) to use.
endmenu
57 changes: 57 additions & 0 deletions examples/repl_esp32/main/event_handlers.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
#include <esp_wifi.h>
#include <esp_event.h>
#include <esp_wifi_types.h>
#include <esp_netif_types.h>
#include <esp_log.h>
#include <freertos/FreeRTOS.h>
#include <freertos/event_groups.h>

#define WIFI_CONNECTED_BIT BIT0
#define WIFI_FAIL_BIT BIT1

const char *TAG_WIFI_EVENT_HANDLER = "repl_esp32 Wifi Event Handler";
const char *TAG_IP_EVENT_HANDLER = "repl_esp32 IP Event Handler";

// arguments should be identical to esp_event_handler_t
void event_handler_wifi(void *event_handler_arg, esp_event_base_t event_base, int32_t event_id, void *event_data)
{
// event_base should always be WIFI_EVENT
if(event_base != WIFI_EVENT)
{
return;
}

EventGroupHandle_t wifi_event_group = *((EventGroupHandle_t *) event_handler_arg);

if(event_id == WIFI_EVENT_STA_START)
{
ESP_LOGI(TAG_WIFI_EVENT_HANDLER, "Connecting to WiFi...");
} else if(event_id == WIFI_EVENT_STA_CONNECTED)
{
ESP_LOGI(TAG_WIFI_EVENT_HANDLER, "Connected to WiFi ! ... SSID:%s", ((wifi_event_sta_connected_t *) event_data)->ssid);
xEventGroupSetBits(wifi_event_group, WIFI_CONNECTED_BIT); // set connected bit
} else if(event_id == WIFI_EVENT_STA_DISCONNECTED)
{
ESP_LOGI(TAG_WIFI_EVENT_HANDLER, "Disconnected from WiFi...");
xEventGroupSetBits(wifi_event_group, WIFI_FAIL_BIT); // set fail bit
}
}

// arguments should be identical to esp_event_handler_t
void event_handler_ip(void *event_handler_arg, esp_event_base_t event_base, int32_t event_id, void *event_data)
{
// event_base should always be IP_EVENT, otherwise this function is being used incorrectly.
if(event_base != IP_EVENT)
{
return;
}

if(event_id == IP_EVENT_STA_GOT_IP)
{
ip_event_got_ip_t *event = (ip_event_got_ip_t *)event_data;
ESP_LOGI(TAG_IP_EVENT_HANDLER, "got ip:" IPSTR, IP2STR(&event->ip_info.ip));
} else if(event_id == IP_EVENT_STA_LOST_IP)
{
ESP_LOGI(TAG_IP_EVENT_HANDLER, "Lost IP...");
}
}
64 changes: 64 additions & 0 deletions examples/repl_esp32/main/main.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
#include <string.h>
#include <stdlib.h>
#include <esp_log.h>
#include <atclient/connection.h>

static const char *TAG = "repl_esp32 main";

extern int wifi_connect(const char *ssid, const char *password);

void app_main(void)
{
int ret = 1;

ret = wifi_connect(CONFIG_ESP_WIFI_SSID, CONFIG_ESP_WIFI_PASSWORD);
if (ret != 0)
{
ESP_LOGE(TAG, "Failed to connect to WiFi.");
goto exit;
}
ESP_LOGI(TAG, "Connected to WiFi.");

ESP_LOGI(TAG, "Connecting to root.atsign.org:64...");
atclient_connection_ctx root_connection;
atclient_connection_init(&root_connection);
ret = atclient_connection_connect(&root_connection, "root.atsign.org", 64);
if (ret != 0)
{
ESP_LOGE(TAG, "Failed to connect to root.atsign.org. at_client_connection_connect: %d", ret);

ESP_LOGI(TAG, "Trying again...");
ret = atclient_connection_connect(&root_connection, "root.atsign.org", 64);
if (ret != 0)
{
ESP_LOGE(TAG, "Failed to connect to root.atsign.org. at_client_connection_connect: %d", ret);
goto exit;
}
}
ESP_LOGI(TAG, "Connected to root.atsign.org");

ESP_LOGI(TAG, "Sending data...");
const unsigned long recvlen = 4096;
unsigned char *recv = malloc(sizeof(unsigned char) * recvlen);
unsigned long olen = 0;
const char *src = "colin\r\n";
const unsigned long srclen = strlen(src);

ret = atclient_connection_send(&root_connection, recv, recvlen, &olen, (const unsigned char *) src, srclen);
if (ret != 0)
{
ESP_LOGE(TAG, "Failed to send data. at_client_connection_send: %d", ret);
goto exit;
}

ESP_LOGI(TAG, "Receiving data...");
ESP_LOGI(TAG, "olen: %lu", olen);
ESP_LOGI(TAG, "recv: \"%s\"", recv);

free(recv);
goto exit;
exit:
{
return;
}
}
175 changes: 175 additions & 0 deletions examples/repl_esp32/main/wifi.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
#include <string.h>
#include <esp_netif.h> //
#include <esp_event.h>
#include <esp_wifi.h>
#include <esp_log.h> // ESP_LOGI and ESP
#include <esp_wifi_types.h>
#include <nvs_flash.h> // NVS "non-volatile storage" (ROM)
#include <freertos/FreeRTOS.h>
#include <freertos/event_groups.h>

#define WIFI_CONNECTED_BIT BIT0
#define WIFI_FAIL_BIT BIT1

static const char *TAG = "repl_esp32 WiFi"; // for logging

extern void event_handler_wifi(void *event_handler_arg, esp_event_base_t event_base, int32_t event_id, void *event_data);

extern void event_handler_ip(void *event_handler_arg, esp_event_base_t event_base, int32_t event_id, void *event_data);

static int init_nvs()
{
int ret = 1;
// intialize NVS "non-volatile storage" (ROM)
ret = nvs_flash_init(); // from nvs_flash.h

// if NVS is not initialized, erase it and try again
if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND)
{
// erase NVS
ESP_ERROR_CHECK(nvs_flash_erase());
// re-initialize NVS
ret = nvs_flash_init();
}

return ret;
}

static int init_net()
{
int ret = 1;

// initialize underlying TCP/IP stack, esp_netif.h
ESP_LOGI(TAG, "Initializing TCP/IP stack...");
ret = esp_netif_init();
ESP_ERROR_CHECK(ret);

return ret;
}

static int init_event_handlers(EventGroupHandle_t *wifi_event_group)
{
int ret = 1;

// create default event loop, esp_event.h
ESP_LOGI(TAG, "Creating default event loop...");
ret = esp_event_loop_create_default();
ESP_ERROR_CHECK(ret);

// create default network interface, esp_wifi.h
esp_netif_create_default_wifi_sta();

// register wifi event handler, esp_event.h
esp_event_base_t wifi_event_base = WIFI_EVENT;
int32_t any_event_id = ESP_EVENT_ANY_ID;
ret = esp_event_handler_instance_register(
wifi_event_base, // esp_event_base_t
any_event_id, // int32_t
&event_handler_wifi, // esp_event_handler_t
wifi_event_group, // void * (event_handler_arg)
NULL // esp_event_handler_instance_t * (instance)
);
ESP_ERROR_CHECK(ret);

// register ip event handler, esp_event.h
esp_event_base_t ip_event_base = IP_EVENT;
ret = esp_event_handler_instance_register(
ip_event_base, // esp_event_base_t
any_event_id, // int32_t
&event_handler_ip, // esp_event_handler_t
NULL, // void * (event_handler_arg)
NULL // esp_event_handler_instance_t * (instance)
);

return ret;
}

static int init_wifi_sta(const unsigned char *wifi_ssid, const unsigned long wifi_ssidlen, const unsigned char *wifi_password, const unsigned long wifi_passwordlen)
{
int ret = 1;

wifi_init_config_t wifi_init_config = WIFI_INIT_CONFIG_DEFAULT();

wifi_sta_config_t wifi_sta_config;
memset(&wifi_sta_config, 0, sizeof(wifi_sta_config));
memcpy(wifi_sta_config.ssid, wifi_ssid, wifi_ssidlen);
memcpy(wifi_sta_config.password, wifi_password, wifi_passwordlen);

wifi_config_t wifi_config = {
.sta = wifi_sta_config};

// init wifi
ret = esp_wifi_init(&wifi_init_config);
ESP_ERROR_CHECK(ret);

// set mode to station
ret = esp_wifi_set_mode(WIFI_MODE_STA);
ESP_ERROR_CHECK(ret);

// configure wifi
ret = esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config);
ESP_ERROR_CHECK(ret);

// start wifi
ret = esp_wifi_start();
ESP_ERROR_CHECK(ret);

return ret;
}

int wifi_connect(const char *ssid, const char *password)
{
int ret = 1;

// initialize NVS "non-volatile storage" (ROM), nvs_flash.h
ESP_LOGI(TAG, "Initializing NVS...");
ret = init_nvs();
ESP_ERROR_CHECK(ret);

// initialie network interface, esp_netif.h
ESP_LOGI(TAG, "Initializing network interface...");
ret = init_net();
ESP_ERROR_CHECK(ret);

// use free rtos to create event group, freertos/FreeRTOS.h
EventGroupHandle_t wifi_event_group = xEventGroupCreate();

// initialize event handlers, esp_event.h
ESP_LOGI(TAG, "Initializing event handlers...");
ret = init_event_handlers(&wifi_event_group);
ESP_ERROR_CHECK(ret);

// initialize wifi, esp_wifi.h
ESP_LOGI(TAG, "Initializing wifi...");
ret = init_wifi_sta((const unsigned char *)ssid, strlen(ssid), (const unsigned char *)password, strlen(password));
ESP_ERROR_CHECK(ret);

// event handler sets bits in event group, attempt connect using esp_wifi_connect()
EventBits_t bits;
do
{
ESP_LOGI(TAG, "Attempting to connect to WiFi...");
ret = esp_wifi_connect();
ESP_LOGI(TAG, "esp_wifi_connect() returned %d", (int)ret);
vTaskDelay(1000 / portTICK_PERIOD_MS);

bits = xEventGroupWaitBits(
wifi_event_group, // EventGroupHandle_t
WIFI_CONNECTED_BIT | WIFI_FAIL_BIT, // bits to wait for
pdFALSE, // clear bits on exit
pdFALSE, // wait for all bits
portMAX_DELAY // wait forever
);
if (bits & WIFI_CONNECTED_BIT)
{
ESP_LOGI(TAG, "Connected to WiFi !");
ret = 0;
}
else if (bits & WIFI_FAIL_BIT)
{
ESP_LOGI(TAG, "Failed to connect to WiFi.");
}
} while (bits & WIFI_FAIL_BIT);

return ret;
}
1 change: 1 addition & 0 deletions packages/atclient/src/connection.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ static void my_debug(void *ctx, int level, const char *file, int line, const cha

void atclient_connection_init(atclient_connection_ctx *ctx)
{
memset(ctx, 0, sizeof(atclient_connection_ctx));
ctx->host = NULL;
ctx->port = NULL;
ctx->cert_pem = ROOT_CERT;
Expand Down