blob: 12dc0e9a2d0f46411110c0e7d5528302f38c6a2a [file] [log] [blame]
/*
*
* Copyright (c) 2021 Project CHIP Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include "esp_event.h"
#include "esp_log.h"
#include "esp_netif.h"
#include "esp_system.h"
#include "esp_wifi.h"
#include "freertos/FreeRTOS.h"
#include "freertos/semphr.h"
#include "pw_status/status.h"
#include "pw_status/try.h"
#include "wifi_service/wifi_service.rpc.pb.h"
namespace chip {
namespace rpc {
class WiFi final : public pw_rpc::nanopb::WiFi::Service<WiFi>
{
public:
// Singleton
static WiFi & Instance() { return instance_; }
// Initalize the wifi station
pw::Status Init();
// Blocks the calling thread until wifi connection is completed successfully.
// NOTE: Currently only supports blocking a single thread.
void BlockUntilWiFiConnected() { xSemaphoreTake(wifi_connected_semaphore_, portMAX_DELAY); }
// The following functions are the RPC handlers
pw::Status GetChannel(const pw_protobuf_Empty & request, chip_rpc_Channel & response)
{
uint8_t channel = 0;
wifi_second_chan_t second;
PW_TRY(EspToPwStatus(esp_wifi_get_channel(&channel, &second)));
response.channel = channel;
return pw::OkStatus();
}
pw::Status GetSsid(const pw_protobuf_Empty & request, chip_rpc_Ssid & response)
{
wifi_config_t config;
PW_TRY(EspToPwStatus(esp_wifi_get_config(WIFI_IF_STA, &config)));
size_t size = std::min(sizeof(response.ssid.bytes), sizeof(config.sta.ssid));
memcpy(response.ssid.bytes, config.sta.ssid, sizeof(response.ssid.bytes));
response.ssid.size = size;
return pw::OkStatus();
}
pw::Status GetState(const pw_protobuf_Empty & request, chip_rpc_State & response)
{
wifi_ap_record_t ap_info;
esp_err_t err = esp_wifi_sta_get_ap_info(&ap_info);
PW_TRY(EspToPwStatus(err));
response.connected = (err != ESP_ERR_WIFI_NOT_CONNECT);
return pw::OkStatus();
}
pw::Status GetMacAddress(const pw_protobuf_Empty & request, chip_rpc_MacAddress & response)
{
uint8_t mac[6];
PW_TRY(EspToPwStatus(esp_wifi_get_mac(WIFI_IF_STA, mac)));
sprintf(response.mac_address, "%02x:%02x:%02x:%02x:%02x:%02x", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
return pw::OkStatus();
}
pw::Status GetWiFiInterface(const pw_protobuf_Empty & request, chip_rpc_WiFiInterface & response)
{
wifi_ap_record_t ap_info;
PW_TRY(EspToPwStatus(esp_wifi_sta_get_ap_info(&ap_info)));
sprintf(response.interface, "STA");
return pw::OkStatus();
}
pw::Status GetIP4Address(const pw_protobuf_Empty & request, chip_rpc_IP4Address & response)
{
esp_netif_ip_info_t ip_info;
PW_TRY(EspToPwStatus(esp_netif_get_ip_info(esp_netif_, &ip_info)));
sprintf(response.address, IPSTR, IP2STR(&ip_info.ip));
return pw::OkStatus();
}
pw::Status GetIP6Address(const pw_protobuf_Empty & request, chip_rpc_IP6Address & response)
{
esp_ip6_addr_t ip6{ 0 };
PW_TRY(EspToPwStatus(esp_netif_get_ip6_linklocal(esp_netif_, &ip6)));
sprintf(response.address, IPV6STR, IPV62STR(ip6));
return pw::OkStatus();
}
// NOTE: Currently this is blocking, it can be made non-blocking if needed
// but would require another worker thread to handle the scanning.
void StartScan(const chip_rpc_ScanConfig & request, ServerWriter<chip_rpc_ScanResults> & writer);
pw::Status StopScan(const pw_protobuf_Empty & request, pw_protobuf_Empty & response)
{
esp_wifi_scan_stop();
return pw::OkStatus();
}
pw::Status Connect(const chip_rpc_ConnectionData & request, chip_rpc_ConnectionResult & response);
pw::Status Disconnect(const pw_protobuf_Empty & request, pw_protobuf_Empty & response)
{
PW_TRY(EspToPwStatus(esp_wifi_disconnect()));
return pw::OkStatus();
}
private:
static WiFi instance_;
esp_netif_t * esp_netif_ = nullptr;
SemaphoreHandle_t wifi_connected_semaphore_;
static constexpr pw::Status EspToPwStatus(esp_err_t err)
{
switch (err)
{
case ESP_OK:
return pw::OkStatus();
case ESP_ERR_WIFI_NOT_INIT:
return pw::Status::FailedPrecondition();
case ESP_ERR_INVALID_ARG:
return pw::Status::InvalidArgument();
case ESP_ERR_ESP_NETIF_INVALID_PARAMS:
return pw::Status::InvalidArgument();
case ESP_ERR_WIFI_IF:
return pw::Status::NotFound();
case ESP_ERR_WIFI_NOT_CONNECT:
return pw::Status::FailedPrecondition();
case ESP_ERR_WIFI_NOT_STARTED:
return pw::Status::FailedPrecondition();
case ESP_ERR_WIFI_CONN:
return pw::Status::Internal();
case ESP_FAIL:
return pw::Status::Internal();
default:
return pw::Status::Unknown();
}
}
static void WiFiEventHandler(void * arg, esp_event_base_t event_base, int32_t event_id, void * event_data);
};
} // namespace rpc
} // namespace chip