Skip to content

Commit

Permalink
Introduce local network setup
Browse files Browse the repository at this point in the history
- Rework and simplify mDNS components initialization
- Introduce AP WiFi network, which is now a default WiFi network
  • Loading branch information
dshil committed Nov 19, 2024
1 parent ab3d883 commit 98559b1
Show file tree
Hide file tree
Showing 16 changed files with 558 additions and 125 deletions.
1 change: 1 addition & 0 deletions components/ocs_net/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
idf_component_register(
SRCS
"sta_network.cpp"
"ap_network.cpp"
"mdns_provider.cpp"
"netif_builder.cpp"
"ip_addr_to_str.cpp"
Expand Down
27 changes: 15 additions & 12 deletions components/ocs_net/Kconfig
Original file line number Diff line number Diff line change
@@ -1,24 +1,27 @@
menu "OCS Network Configuration"
menu "WiFi Configuration"
menu "STA Configuration"
config OCS_NETWORK_WIFI_STA_SSID
string "WiFi STA SSID"
default "your-ssid"
help
SSID for the WiFi access point, to which ESP32 is connected.

config OCS_NETWORK_WIFI_STA_PASSWORD
string "WiFi STA Password"
default "your-password"
help
Password for the WiFi access point, to which ESP32 is connected.

config OCS_NETWORK_WIFI_STA_RETRY_COUNT
int "WiFi Retry Count"
default 5
help
Maximum number of attempts to establish a WiFi connection.
endmenu

menu "AP Configuration"
config OCS_NETWORK_WIFI_AP_CHANNEL
int "WiFi Channel"
range 1 13
default 1
help
WiFi channel (network channel).

config OCS_NETWORK_WIFI_AP_MAX_CONN
int "Maximum number of STA connections"
default 7
help
Maximum number of the STA connects to AP.
endmenu
endmenu

menu "mDNS Configuration"
Expand Down
190 changes: 190 additions & 0 deletions components/ocs_net/ap_network.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
/*
* Copyright (c) 2024, Open Control Systems authors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/

#include <cstring>

#include "esp_netif.h"

#include "ocs_core/lock_guard.h"
#include "ocs_core/log.h"
#include "ocs_net/ap_network.h"
#include "ocs_net/macros.h"
#include "ocs_status/code_to_str.h"

namespace ocs {
namespace net {

namespace {

const char* log_tag = "ap_network";

} // namespace

ApNetwork::ApNetwork(const Params& params)
: params_(params)
, cond_(mu_) {
ESP_ERROR_CHECK(esp_netif_init());
ESP_ERROR_CHECK(esp_event_loop_create_default());

netif_ = make_netif_shared(esp_netif_create_default_wifi_ap());
configASSERT(netif_);

wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
ESP_ERROR_CHECK(esp_wifi_init(&cfg));

ESP_ERROR_CHECK(esp_event_handler_instance_register(
WIFI_EVENT, ESP_EVENT_ANY_ID, &handle_event_, this, &instance_any_id_));

ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_AP));

wifi_config_t wifi_config;
memset(&wifi_config, 0, sizeof(wifi_config));

strncpy(reinterpret_cast<char*>(wifi_config.ap.ssid), params_.ssid.c_str(),
sizeof(wifi_config.ap.ssid));

strncpy(reinterpret_cast<char*>(wifi_config.ap.password), params_.password.c_str(),
sizeof(wifi_config.ap.password));

wifi_config.ap.channel = params_.channel;
wifi_config.ap.max_connection = params_.max_connection;
wifi_config.ap.authmode = WIFI_AUTH_WPA2_PSK;
wifi_config.ap.pmf_cfg.required = true;

ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_AP, &wifi_config));
}

ApNetwork::~ApNetwork() {
ESP_ERROR_CHECK(esp_event_handler_instance_unregister(WIFI_EVENT, ESP_EVENT_ANY_ID,
&instance_any_id_));

ESP_ERROR_CHECK(esp_wifi_deinit());
ESP_ERROR_CHECK(esp_event_loop_delete_default());

// Note: Deinitialization is not supported yet
// https://docs.espressif.com/projects/esp-idf/en/stable/esp32/api-reference/network/esp_netif.html#_CPPv416esp_netif_deinitv
configASSERT(esp_netif_deinit() == ESP_ERR_NOT_SUPPORTED);
}

status::StatusCode ApNetwork::start() {
const auto err = esp_wifi_start();
if (err != ESP_OK) {
ocs_loge(log_tag, "esp_wifi_start(): %s", esp_err_to_name(err));
return status::StatusCode::Error;
}

return status::StatusCode::OK;
}

status::StatusCode ApNetwork::stop() {
const auto err = esp_wifi_stop();
if (err != ESP_OK) {
ocs_loge(log_tag, "esp_wifi_stop(): %s", esp_err_to_name(err));
return status::StatusCode::Error;
}

return status::StatusCode::OK;
}

status::StatusCode ApNetwork::wait(TickType_t wait) {
core::LockGuard lock(mu_);

while (code_ == status::StatusCode::Last) {
if (const auto code = cond_.wait(wait); code != status::StatusCode::OK) {
return code;
}
}

return code_;
}

std::optional<ip_addr_t> ApNetwork::get_ip_addr() const {
return std::nullopt;
}

void ApNetwork::handle_event_(void* event_arg,
esp_event_base_t event_base,
int32_t event_id,
void* event_data) {
configASSERT(event_base == WIFI_EVENT);
configASSERT(event_arg);

ApNetwork& self = *static_cast<ApNetwork*>(event_arg);

if (event_base == WIFI_EVENT) {
self.handle_wifi_event_(event_id, event_data);
} else {
ocs_loge(log_tag, "unsupported event: event_id=%ld", event_id);
}
}

void ApNetwork::handle_wifi_event_(int32_t event_id, void* event_data) {
switch (event_id) {
case WIFI_EVENT_AP_START:
handle_wifi_event_ap_sta_start_();
break;

case WIFI_EVENT_AP_STOP:
handle_wifi_event_ap_sta_stop_();
break;

case WIFI_EVENT_AP_STACONNECTED:
handle_wifi_event_ap_sta_connected_(event_data);
break;

case WIFI_EVENT_AP_STADISCONNECTED:
handle_wifi_event_ap_sta_disconnected_(event_data);
break;

default:
break;
}
}

void ApNetwork::handle_wifi_event_ap_sta_start_() {
core::LockGuard lock(mu_);
code_ = status::StatusCode::OK;

if (const auto code = cond_.broadcast(); code != status::StatusCode::OK) {
ocs_logw(log_tag, "failed to broadcast on START event: %s",
status::code_to_str(code));
}

handle_connect_();
}

void ApNetwork::handle_wifi_event_ap_sta_stop_() {
core::LockGuard lock(mu_);
code_ = status::StatusCode::Error;

if (const auto code = cond_.broadcast(); code != status::StatusCode::OK) {
ocs_logw(log_tag, "failed to broadcast on STOP event: %s",
status::code_to_str(code));
}

handle_disconnect_();
}

void ApNetwork::handle_wifi_event_ap_sta_connected_(void* event_data) {
wifi_event_ap_staconnected_t event =
*static_cast<wifi_event_ap_staconnected_t*>(event_data);

ocs_logi(log_tag, "station joined: mac=" MACSTR " AID=%d", MAC2STR(event.mac),
event.aid);
}

void ApNetwork::handle_wifi_event_ap_sta_disconnected_(void* event_data) {
wifi_event_ap_staconnected_t event =
*static_cast<wifi_event_ap_staconnected_t*>(event_data);

ocs_logi(log_tag, "station left: mac=" MACSTR " AID=%d", MAC2STR(event.mac),
event.aid);
}

} // namespace net
} // namespace ocs
85 changes: 85 additions & 0 deletions components/ocs_net/ap_network.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
/*
* Copyright (c) 2024, Open Control Systems authors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/

#pragma once

#include <string>

#include "esp_wifi.h"

#include "ocs_core/cond.h"
#include "ocs_core/noncopyable.h"
#include "ocs_core/static_event_group.h"
#include "ocs_core/static_mutex.h"
#include "ocs_net/basic_network.h"
#include "ocs_net/netif_builder.h"
#include "ocs_status/code.h"

namespace ocs {
namespace net {

//! Handle WiFi AP (access-point) mode network operations.
class ApNetwork : public BasicNetwork, public core::NonCopyable<> {
public:
struct Params {
//! WiFi SSID.
std::string ssid;

//! WiFi password.
std::string password;

//! WiFi channel.
int channel { 0 };

//! Maximum number of simultaneous STA connection to the AP.
int max_connection { 0 };
};

//! Initialize.
explicit ApNetwork(const Params& params);

//! Destroy.
~ApNetwork();

//! Start the WiFi connection process.
status::StatusCode start() override;

//! Stop the WiFi connection process.
status::StatusCode stop() override;

//! Wait for the WiFi connection to be established.
status::StatusCode wait(TickType_t wait) override;

//! Return received IP address.
std::optional<ip_addr_t> get_ip_addr() const override;

private:
static void handle_event_(void* event_arg,
esp_event_base_t event_base,
int32_t event_id,
void* event_data);

void handle_wifi_event_(int32_t event_id, void* event_data);
void handle_wifi_event_ap_sta_start_();
void handle_wifi_event_ap_sta_stop_();
void handle_wifi_event_ap_sta_connected_(void* event_data);
void handle_wifi_event_ap_sta_disconnected_(void* event_data);

const Params params_;

NetifSharedPtr netif_;

esp_event_handler_instance_t instance_any_id_ { nullptr };

core::StaticMutex mu_;
core::Cond cond_;
status::StatusCode code_ { status::StatusCode::Last };
};

} // namespace net
} // namespace ocs
4 changes: 2 additions & 2 deletions components/ocs_net/basic_network.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ class BasicNetwork : public core::NonCopyable<BasicNetwork> {
//! Stop the network connection process.
virtual status::StatusCode stop() = 0;

//! Wait for the network connection to be established.
virtual status::StatusCode wait() = 0;
//! Wait for @p wait interval for the network connection to be established.
virtual status::StatusCode wait(TickType_t wait) = 0;

//! Return received IP address.
virtual std::optional<ip_addr_t> get_ip_addr() const = 0;
Expand Down
12 changes: 12 additions & 0 deletions components/ocs_net/macros.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
/*
* Copyright (c) 2024, Open Control Systems authors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/

#pragma once

#define MAC2STR(mac) (mac)[0], (mac)[1], (mac)[2], (mac)[3], (mac)[4], (mac)[5]
#define MACSTR "%02x:%02x:%02x:%02x:%02x:%02x"
Loading

0 comments on commit 98559b1

Please sign in to comment.