blob: 608350a38ad053d634c0c0c20bb48bdb7cdc2d5b [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.
*/
#include "PigweedLoggerMutex.h"
#include "RpcService.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "nvs_flash.h"
#include "pw_rpc/server.h"
#include "wifi_service.h"
#include "lwip/err.h"
#include "lwip/sockets.h"
#include "lwip/sys.h"
namespace {
const char * TAG = "ipv6only";
constexpr size_t kUdpBufferSize = 512;
constexpr size_t kRpcStackSizeBytes = (6 * 1024);
constexpr uint8_t kRpcTaskPriority = 5;
constexpr size_t kTestStackSizeBytes = (8 * 1024);
constexpr uint8_t kTestTaskPriority = 5;
TaskHandle_t rpcTaskHandle;
TaskHandle_t testTaskHandle;
void UdpReceiver(void * pvParameters)
{
int portno; // port to listen on
struct sockaddr_in6 serveraddr; // server's addr
char buf[kUdpBufferSize]; // rx message buf
char * hostaddrp; // dotted decimal host addr string
int optval; // flag value for setsockopt
int n; // message byte size
int sockfd = 0;
socklen_t clientlen; // byte size of client's address
struct sockaddr_in6 clientaddr; // client addr
while (1)
{
// Start the udp server after the wifi is connectd.
chip::rpc::WiFi::Instance().BlockUntilWiFiConnected();
ESP_LOGI(TAG, "UDP server starting");
portno = 8765;
// socket: create the parent socket
sockfd = socket(AF_INET6, SOCK_DGRAM, 0);
if (sockfd < 0)
{
ESP_LOGE(TAG, "ERROR opening socket");
assert(0);
return;
}
// setsockopt: Handy debugging trick that lets
// us rerun the server immediately after we kill it;
// otherwise we have to wait about 20 secs.
// Eliminates "ERROR on binding: Address already in use" error.
optval = 1;
setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, static_cast<const void *>(&optval), sizeof(int));
// build the server's Internet address
memset(&serveraddr, 0, sizeof(serveraddr));
serveraddr.sin6_len = sizeof(serveraddr);
serveraddr.sin6_family = AF_INET6;
serveraddr.sin6_addr = in6addr_any;
serveraddr.sin6_port = htons((unsigned short) portno);
// bind: associate the parent socket with a port
if (bind(sockfd, reinterpret_cast<struct sockaddr *>(&serveraddr), sizeof(serveraddr)) < 0)
{
ESP_LOGE(TAG, "ERROR on binding");
assert(0);
vTaskDelete(NULL);
}
ESP_LOGI(TAG, "UDP server bound to port %d", portno);
// main loop: wait for a datagram, then respond
clientlen = sizeof(clientaddr);
wifi_ap_record_t ap_info;
fd_set readset;
while (ESP_OK == esp_wifi_sta_get_ap_info(&ap_info))
{
// recvfrom: receive a UDP datagram from a client
memset(buf, 0, sizeof(buf));
FD_ZERO(&readset);
FD_SET(sockfd, &readset);
int select_err = select(sockfd + 1, &readset, nullptr, nullptr, nullptr);
if (select_err < 0)
continue;
n = recvfrom(sockfd, buf, kUdpBufferSize, 0, reinterpret_cast<struct sockaddr *>(&clientaddr), &clientlen);
if (n < 0)
continue;
// Echo back
n = sendto(sockfd, buf, n, 0, reinterpret_cast<struct sockaddr *>(&clientaddr), clientlen);
}
}
// Never returns
}
void RegisterServices(pw::rpc::Server & server)
{
server.RegisterService(chip::rpc::WiFi::Instance());
}
void RunRpcService(void *)
{
::chip::rpc::Start(RegisterServices, &::chip::rpc::logger_mutex);
}
} // namespace
extern "C" void app_main()
{
PigweedLogger::init();
// 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);
ESP_LOGI(TAG, "WiFi Init: %s", pw_StatusString(chip::rpc::WiFi::Instance().Init()));
ESP_LOGI(TAG, "----------- chip-esp32-ipv6-example starting -----------");
xTaskCreate(RunRpcService, "RPC", kRpcStackSizeBytes / sizeof(StackType_t), nullptr, kRpcTaskPriority, &rpcTaskHandle);
xTaskCreate(UdpReceiver, "TestTask", kTestStackSizeBytes / sizeof(StackType_t), nullptr, kTestTaskPriority, &testTaskHandle);
}