参照乐鑫官方教程,在ESP32C3上实现了CoAP服务器,代码如下(基于IDF):
/*CoAP*/
#include <stdio.h>
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_wifi.h"
#include "esp_netif.h"
#include "nvs_flash.h"
#include "wifi_provisioning/manager.h"
#include "wifi_provisioning/scheme_softap.h"
#include "socket.h"
#include "esp_http_server.h"
#include "coap3/coap.h"
/*宏定义*/
#define ERASE_NVS 0
// 清除储存的wifi密码->0: 沿用上次的WIFI信息进行连接; 1: 清除WIFI信息,使用SOFTAP一键配网进行新链接
/*函数声明*/
void WIFI_CALLBACK_FUN(void *event_handler_arg, esp_event_base_t event_base, int32_t event_id, void *event_data); // 事件队列回调函数
void wifi_connect(void); // WIFI连接处理函数
void uri_get_req(coap_resource_t *resource, coap_session_t *session,
const coap_pdu_t *request, const coap_string_t *str_t,
coap_pdu_t *response); //相应客户端的GET请求
void uri_post_req(coap_resource_t *resource, coap_session_t *session,
const coap_pdu_t *request, const coap_string_t *str_t,
coap_pdu_t *response); //相应客户端的POST请求
/*全局变量*/
int LINK_WIFI_SUCCESS = 255;
/***************************************************************************************************************/
/*MAIN函数*/
void app_main(void)
{
wifi_connect(); // 连接wifi
/*1. 创建coap套接字*/
coap_address_t addr;
coap_address_init(&addr); //仅执行了addr.size=28
addr.addr.sin.sin_family = AF_INET;
int set_ip = 0;
inet_aton("0.0.0.0", &set_ip);
addr.addr.sin.sin_addr.s_addr = set_ip;
addr.addr.sin.sin_port = htons(5683);
/*2. 创建coap ctx*/
coap_context_t *ctx = NULL; //ctx结构体包含coap状态和属性
ctx = coap_new_context(&addr); //创建ctx对象
/*3. 给资源提供URI*/
coap_resource_t * resource = NULL;
coap_str_const_t uri_path =
{
.length = strlen("ok"),
.s = (const uint8_t *)"ok"
};
resource = coap_resource_init(&uri_path, 0);
/*4. 注册URI*/
coap_register_request_handler(resource, COAP_REQUEST_CODE_GET, uri_get_req);
//coap_register_handler(resource, COAP_REQUEST_CODE_GET, uri_get_req); //OLD
//coap_register_handler(resource, COAP_REQUEST_CODE_POST, uri_post_req);//OLD
coap_register_request_handler(resource, COAP_REQUEST_CODE_POST, uri_post_req);
/*5. 设置COAP GET资源可见-订阅模式*/
coap_resource_set_get_observable(resource, 1);
/*6. 将资源添加进(注册)ctx*/
coap_add_resource(ctx, resource);
/*7.监听,等待接收数据*/
while(1)
{
int ret = coap_io_process(ctx, 1000);
if(ret == -1)
{
printf("ret=-1, 出错!\n");
goto error_line;
}
vTaskDelay(1);
}
error_line:
/*end: 释放ctx资源*/
coap_free_context(ctx);
while(1)
{
printf("错误,空闲线程!\n");
vTaskDelay(500);
}
}
/*响应客户端的POST请求回调函数*/
void uri_post_req(coap_resource_t *resource, coap_session_t *session,
const coap_pdu_t *request, const coap_string_t *str_t,
coap_pdu_t *response)
{
const uint8_t *recv_dat = NULL;
size_t dt_len = 0;
char recv_buf[100] = {0};
coap_resource_notify_observers(resource, NULL); //
int ret = coap_get_data(request, &dt_len, &recv_dat);
if(ret == 1)
{
strncpy(recv_buf, (char *)recv_dat, dt_len);
recv_buf[dt_len] = 'dependencies:
espressif/coap: "^4.3.0"
'; //字符串结尾标志
printf("CoAP收到的POST数据为:%s\n", recv_buf);
//coap_send_ack(session, response);
//response->code = COAP_RESPONSE_CODE_CHANGED; //COAP_RESPONSE_CODE(204);
}
else
{
printf("CoAP接收POST错误!\n");
}
}
/*响应客户端的GET请求回调函数*/
int cnt = 0;
void uri_get_req(coap_resource_t *resource, coap_session_t *session,
const coap_pdu_t *request, const coap_string_t *str_t,
coap_pdu_t *response)
{
char get_buf[15] = "Hello CoAP!";
cnt ++;
itoa(cnt, &get_buf[11], 10);
coap_add_data_blocked_response(request, response, COAP_MEDIATYPE_TEXT_PLAIN, 0, sizeof(get_buf), (const uint8_t *)get_buf);
//COAP_MEDIATYPE_TEXT_PLAIN->0-TEXT格式
printf("CoAP回应GET数据为:%s\n", get_buf);
}
/**********************************************************************************************/
/*回调函数*/
int dis_cnt = 0;
void WIFI_CALLBACK_FUN(void *event_handler_arg, esp_event_base_t eb, int32_t ei, void *event_data)
{
if (eb == WIFI_EVENT)
{
if (ei == WIFI_EVENT_STA_START)
{
esp_wifi_connect(); // 开始连接WIFI
printf("正在连接WIFI!\n");
}
if (ei == WIFI_EVENT_STA_DISCONNECTED)
{
dis_cnt ++;
if(dis_cnt < 10)
{
vTaskDelay(100);
esp_wifi_connect();
printf("正在进行第%d次重新连接...\n", dis_cnt);
}
else
{
nvs_flash_erase(); //清除旧密码
nvs_flash_init();
printf("自动连接失败,正在启动SOFTAP配网服务!\n");
const char *pop = "abcd1234";
const char *wifi_name = "SOFTAP_PROV_MGR_PROB";
const char *wifi_key = "12345678";
wifi_prov_mgr_start_provisioning(WIFI_PROV_SECURITY_1, pop, wifi_name, wifi_key);
wifi_prov_mgr_wait();
wifi_prov_mgr_deinit();
printf("Provisioning服务结束,连接WIFI成功!\n");
}
}
}
if(eb == WIFI_PROV_EVENT && ei == WIFI_PROV_CRED_FAIL)
{
printf("配网失败,正在重试!\n");
nvs_flash_erase(); //清除旧密码
nvs_flash_init();
printf("自动连接失败,正在启动SOFTAP配网服务!\n");
const char *pop = "abcd1234";
const char *wifi_name = "SOFTAP_PROV_MGR_PROB";
const char *wifi_key = "12345678";
wifi_prov_mgr_start_provisioning(WIFI_PROV_SECURITY_1, pop, wifi_name, wifi_key);
wifi_prov_mgr_wait();
wifi_prov_mgr_deinit();
printf("Provisioning服务结束,连接WIFI成功!\n");
}
if (eb == IP_EVENT && ei == IP_EVENT_STA_GOT_IP)
{
printf("WIFI连接成功!\n");
ip_event_got_ip_t *sta_ip = (ip_event_got_ip_t *)event_data;
printf("本机IP地址为: " IPSTR "\n", IP2STR(&sta_ip->ip_info.ip));
LINK_WIFI_SUCCESS = 0; //已经连接成功标识清零
}
}
/*连接WIFI*/
void wifi_connect(void)
{
nvs_flash_init();
#if ERASE_NVS != 0
nvs_flash_erase();
nvs_flash_init();
#endif
esp_event_loop_create_default(); // 创建默认事件队列
esp_event_handler_instance_register(IP_EVENT, IP_EVENT_STA_GOT_IP, WIFI_CALLBACK_FUN, NULL, NULL);
esp_event_handler_instance_register(WIFI_PROV_EVENT, WIFI_PROV_CRED_FAIL, WIFI_CALLBACK_FUN, NULL, NULL);
esp_netif_init(); // 初始化网卡
esp_netif_create_default_wifi_ap(); // 创建默认网卡ap
esp_netif_create_default_wifi_sta(); // 创建默认网卡sta
wifi_init_config_t esp_wifi_init_config = WIFI_INIT_CONFIG_DEFAULT();
esp_wifi_init(&esp_wifi_init_config); // 初始化WIFI功能
/*softAP配网*/
wifi_prov_mgr_config_t wifi_prov_mgr_config_t =
{
.scheme = wifi_prov_scheme_softap,
.app_event_handler = WIFI_PROV_EVENT_HANDLER_NONE
};
wifi_prov_mgr_init(wifi_prov_mgr_config_t);
bool wifi_prov_mgr_diag = false;
wifi_prov_mgr_is_provisioned(&wifi_prov_mgr_diag);
if (wifi_prov_mgr_diag == false)
{
const char *pop = "abcd1234";
const char *wifi_name = "SOFTAP_PROV_MGR_PROB";
const char *wifi_key = "12345678";
wifi_prov_mgr_start_provisioning(WIFI_PROV_SECURITY_1, pop, wifi_name, wifi_key);
wifi_prov_mgr_wait();
wifi_prov_mgr_deinit();
printf("Provisioning服务结束,连接WIFI成功!\n");
}
else
{
esp_event_handler_instance_register(WIFI_EVENT, WIFI_EVENT_STA_START, WIFI_CALLBACK_FUN, NULL, NULL); // 注册WIFI开启事件
esp_event_handler_instance_register(WIFI_EVENT, WIFI_EVENT_STA_CONNECTED, WIFI_CALLBACK_FUN, NULL, NULL); // 注册WIFI连接事件
esp_event_handler_instance_register(WIFI_EVENT, WIFI_EVENT_STA_DISCONNECTED, WIFI_CALLBACK_FUN, NULL, NULL); // 注册WIFI连接失败事件
esp_wifi_start();
}
esp_wifi_set_ps(WIFI_PS_NONE); // 关闭WIFI的省电模式
while(LINK_WIFI_SUCCESS) //等到WIFIF连接成功
{
vTaskDelay(1); //防止看门狗复位
}
}
但是注意:创建项目后包含头文件"coap3/coap.h"会出现错误,是因为Coap相关库文件未引入,引入方法是在项目main文件夹下面创建文件"idf_component.yml",并在文件中添加以下代码:
https://libcoap.net/doc/reference/4.2.0/resource_8c.html#a44d6a5ed6425069699a01f7e8ed72579
调试:使用谷歌浏览器,在谷歌浏览器中安装Cooper插件,使用插件可以进行调试。
下载地址:https://github.com/mkovatsc/Copper4Cr.git
或者在本页附件也能下载。
最后,附上coap函数库学习地址: