1 概述
终于再次看到引子博客了,兴奋~
匿名广播的英文是Anonymous Broad Cast,简称abc。匿名广播是Rime协议栈最基础的协议,它会向节点覆盖范围内的所有节点发送消息,并接收从其它节点发送过来的匿名广播消息。
相关代码位于contiki/core/net/rime/abc.[ch]。
2 相关定义
attributes
static const struct packetbuf_attrlist attributes[] =
{ ABC_ATTRIBUTES PACKETBUF_ATTR_LAST };
定义了包属性链表attributes,且用ABC_ATTRIBUTES
、PACKETBUF_ATTR_LAST
对其进行赋初值。
#define ABC_ATTRIBUTES
#define PACKETBUF_ATTR_LAST { PACKETBUF_ATTR_NONE, 0 }
ABC_ATTRIBUTES
的定义为空,PACKETBUF_ATTR_LAST
的属性类型是PACKETBUF_ATTR_NONE
,它用于判断一个属性链表是否到达结尾。
struct abc_callbacks
struct abc_callbacks {
/** Called when a packet has been received by the abc module. */
void (* recv)(struct abc_conn *ptr);
void (* sent)(struct abc_conn *ptr, int status, int num_tx);
};
定义了abc的回调函数结构体。当节点接收到另一个节点发送的匿名广播时,会调用结构体中的recv函数。
struct abc_conn
struct abc_conn {
struct channel channel;
const struct abc_callbacks *u;
};
定义一个abc连接的结构体,其中:
channel:所绑定的通道
u:所绑定的回调函数的结构体
3 相关函数
abc_open
void abc_open(struct abc_conn *c, uint16_t channelno, const struct abc_callbacks *callbacks)
{
channel_open(&c->channel, channelno);
c->u = callbacks;
channel_set_attributes(channelno, attributes);
}
打开一个abc连接,其实就是打开一个通道,并设置通道的属性。
abc_close
void abc_close(struct abc_conn *c)
{
channel_close(&c->channel);
}
关闭abc连接,其实就是关闭打开的通道
abc_send
int abc_send(struct abc_conn *c)
{
return rime_output(&c->channel);
}
发送一个abc消息。
需要注意两点:
第一,发送消息前,我们需要将待发送的消息存放到packetbuf中。
第二,参数c必须指向一个之前进行abc_open()时所设置的abc连接。
rime_output()是Rime协议栈的一个接口,我们今后会讲到,可以先简单看一下其实现内容。
int rime_output(struct channel *c)
{
RIMESTATS_ADD(tx); //将发送统计状态+1
if(chameleon_create(c)) { // 创建包头
packetbuf_compact(); // 发送前对包进行紧凑处理
NETSTACK_LLSEC.send(packet_sent, c); //发送
return 1;
}
return 0;
}
abc_input
void abc_input(struct channel *channel)
{
struct abc_conn *c = (struct abc_conn *)channel;
if(c->u->recv) {
c->u->recv(c);
}
}
当本节点接收到其它节点的匿名广播时,会调用abc_input()函数,而该函数内部又会调用abc结构体中绑定的回调函数结构体中的recv函数。
这里有一点很奇怪,为啥可以将struct channel *
类型的channel转变为struct abc_conn *
类型的c,并调用c->u->recv
呢?这个咋一眼看上去访问越界了呀,访问到未知的内存了。这涉及到MAC的回调机制,我们将在今后讲解。我们目前只需要知道,其实传入的channel
指针所指向的地址存放了一个struct abc_conn
的变量。
abc_sent
void abc_sent(struct channel *channel, int status, int num_tx)
{
struct abc_conn *c = (struct abc_conn *)channel;
if(c->u->sent) {
c->u->sent(c, status, num_tx);
}
}
当本节点发送了一个匿名广播消息时,无论发送成功或者失败,都会回调本函数。关于struct channel 到struct abc_conn 的转换的原因,与abc_input相同。
4 小结
关于如何编写程序,发送一个abc匿名广播消息,其实很简单,参考引子博客。