前言
最近在调试ESP8266的mesh功能,盯了几天的代码和调试信息,终于发现了mesh在使用上十分简单(遗憾的是对它的工作原理一无所知),个人感觉其他的发包程序基本上都是按照这个流程来的,因此决定把这个mesh的json发包函数的流程记录下来,以供日后参考。
程序源码
void ICACHE_FLASH_ATTR mesh_json_bcast_test()
{
char buf[32];
uint8_t src[6];
uint8_t dst[6];
struct mesh_header_format *header = NULL;
/** 获取mac地址 */
if (!wifi_get_macaddr(STATION_IF, src))
{
MESH_PARSER_PRINT("bcast get sta mac fail\n");
return;
}
os_memset(buf, 0, sizeof(buf));
os_sprintf(buf, "%s", "{\"bcast\":\"");
os_sprintf(buf + os_strlen(buf), MACSTR, MAC2STR(src));
os_sprintf(buf + os_strlen(buf), "%s", "\"}\r\n");
os_memset(dst, 0, sizeof(dst));
/** 创建一个数据包 */
header = (struct mesh_header_format *)espconn_mesh_create_packet(
dst,
src,
false,
true,
M_PROTO_JSON,
os_strlen(buf),
false,
0,
false,
0,
false,
0,
0);
/** 进行数据包地址正确性检查 */
if (!header)
{
MESH_PARSER_PRINT("bcast create packet fail\n");
return;
}
/** 设置用户数据 */
if (!espconn_mesh_set_usr_data(header, buf, os_strlen(buf)))
{
MESH_DEMO_PRINT("bcast set user data fail\n");
MESH_DEMO_FREE(header);
return;
}
/** 发送数据 */
if (espconn_mesh_sent(&g_ser_conn, (uint8_t *)header, header->len))
{
MESH_DEMO_PRINT("bcast mesh is busy\n");
espconn_mesh_connect(&g_ser_conn);
MESH_DEMO_FREE(header);
return;
}
MESH_DEMO_FREE(header);
}
流程介绍
- 首先通过wifi_get_macaddr来获取模块的mac地址。
- 配置用户数据包(buf)的内容。
- 初始化目标mac地址(MAC地址为零的话视为向网络中所有设备发送数据包)。
- 通过调用espconn_mesh_create_packet函数创建一个数据包(由指针header指向这个数据包)。
- 通过调用espconn_mesh_set_usr_data函数将用户数据包中的内容添加进将要发送的数据包中。
- 通过调用espconn_mesh_sent函数发送数据(数据发送完成后需要用户手动释放这个数据包的内存)。
从上述流程图可以看出json发包首先需要创建并配置数据包,然后设置该数据包的用户数据,最后在通过发包程序发送数据。
相关API介绍
一、wifi_get_macaddr
功能 |
查询MAC地址 |
- |
函数原型 |
bool wifi_get_macaddr(uint8 if_index,uint8 *macaddr) |
- |
参数 |
if_index |
获取到的soft-ap当前的配置 |
参数枚举 |
STATION_IF |
0x00 |
- |
SOFTAP_IF |
0x01 |
参数 |
*macaddr |
获取到的mac地址 |
返回值 |
true |
获取mac地址成功 |
- |
false |
获取mac地址失败 |
二、espconn_mesh_create_packet
功能 |
创建mesh数据包 |
- |
函数原型 |
void * espconn_mesh_create_packet ( uint8_t* dst_addr, uint8_t* src_addr, bool p2p, bool piggyback_cr, enum mesh_usr_proto_type proto, uint16_t data_len, bool option, uint16_t ot_len, bool frag, enum mesh_option_type frag_type, bool mf, uint16_t frag_idx, uint16_t frag_id ) |
- |
参数 |
*dst_addr |
接收方的mac地址(为零的话表示接收方为网内的所有设备) |
参数 |
*src_addr |
发送方的mac地址 |
参数 |
p2p |
是否为节点到节点的数据包(bool类型) |
参数 |
piggyback_cr |
piggyback流请求(bool类型) |
参数 |
proto |
获取到的soft-ap当前的配置 |
参数枚举 |
M_PROTO_NONE |
用户数据为网络管理包 |
- |
M_PROTO_HTTP |
用户数据风格为HTTP风格 |
- |
M_PROTO_JSON |
用户数据风格为JSON风格 |
- |
M_PROTO_MQTT |
用户数据风格为MQTT风格 |
- |
M_PROTO_BIN |
用户数据风格为二进制风格 |
参数 |
data_len |
用户数据的长度 |
参数 |
option |
操作选项使能(bool类型) |
参数 |
ot_len |
操作选项数据长度 |
参数 |
frag |
fragmentation使能标志(bool类型) |
参数 |
frag_type |
fragmentation类型 |
参数枚举 |
M_O_CONGEST_REQ |
堵塞请求 |
- |
M_O_CONGEST_RESP |
响应堵塞请求 |
- |
M_O_ROUTER_SPREAD |
路由器信息拓展选项 |
- |
M_O_ROUTE_ADD |
节点加入选项 |
- |
M_O_ROUTE_DEL |
节点推出选项 |
- |
M_O_TOPO_REQ |
拓扑请求选项 |
- |
M_O_TOPO_RESP |
拓扑响应选项 |
- |
M_O_MCAST_GRP |
组列表的群播 |
- |
M_O_MESH_FRAG |
mesh管理片段选项 |
- |
M_O_USR_FRAG |
用户数据片段 |
- |
M_O_USR_OPTION |
用户选项 |
参数 |
mf |
更多的fragmentation |
参数 |
frag_idx |
fragmentation首 |
参数 |
frag_id |
fragmentation id |
返回值 |
void * |
返回一个由系统创建的数据包的地址(该地址空间需要用户手动释放) |
三、 espconn_mesh_set_usr_data
功能 |
设置mesh发送包的用户数据 |
- |
函数原型 |
bool espconn_mesh_set_usr_data ( struct mesh_header_format* head, uint8_t* usr_data, uint16_t data_len ) |
- |
参数 |
*head |
发送包的地址 |
参数 |
*usr_data |
用户数据缓存区 |
参数 |
data_len |
数据长度 |
返回值 |
true |
设置成功 |
- |
false |
设置失败 |
四、 espconn_mesh_sent
功能 |
mesh发送数据包 |
- |
函数原型 |
int8_t espconn_mesh_sent ( struct espconn* usr_esp, uint8* pdata, uint16 len ) |
- |
参数 |
*usr_esp |
网络连接结构体 |
参数 |
*pdata |
数据包的地址 |
参数 |
len |
数据包的长度 |
返回值 |
ESPCONN_OK(0) |
发送成功 |
- |
ESPCONN_MEM(-1) |
内存不足 |
- |
ESPCONN_MAXNUM(-7) |
发送数据缓存区已满 |
- |
ESPCONN_ARG(-12) |
非法参数 |
- |
ESPCONN_IF(-14) |
发送UDP数据失败 |
参考资料
[1]. ESP8266 Mesh 用户手册
[2]. ESP8266 ESP-MESH API 参考
[3]. ESP8266Non-OS SDK API参考