[Rime 协议栈] 匿名广播 abc

概述

终于再次看到引子博客了,兴奋~
匿名广播的英文是Anonymous Broad Cast,简称abc。匿名广播是Rime协议栈最基础的协议,它会向节点覆盖范围内的所有节点发送消息,并接收从其它节点发送过来的匿名广播消息。
相关代码位于contiki/core/net/rime/abc.[ch]。

相关定义

attributes

1
2
static const struct packetbuf_attrlist attributes[] =
{ ABC_ATTRIBUTES PACKETBUF_ATTR_LAST };

定义了包属性链表attributes,且用ABC_ATTRIBUTESPACKETBUF_ATTR_LAST对其进行赋初值。

1
2
#define ABC_ATTRIBUTES
#define PACKETBUF_ATTR_LAST { PACKETBUF_ATTR_NONE, 0 }

ABC_ATTRIBUTES的定义为空,PACKETBUF_ATTR_LAST的属性类型是PACKETBUF_ATTR_NONE,它用于判断一个属性链表是否到达结尾。

struct abc_callbacks

1
2
3
4
5
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

1
2
3
4
struct abc_conn {
struct channel channel;
const struct abc_callbacks *u;
};

定义一个abc连接的结构体,其中:
channel:所绑定的通道
u:所绑定的回调函数的结构体

相关函数

abc_open

1
2
3
4
5
6
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

1
2
3
4
void abc_close(struct abc_conn *c)
{
channel_close(&c->channel);
}

关闭abc连接,其实就是关闭打开的通道

abc_send

1
2
3
4
int abc_send(struct abc_conn *c)
{
return rime_output(&c->channel);
}

发送一个abc消息。
需要注意两点:
第一,发送消息前,我们需要将待发送的消息存放到packetbuf中。
第二,参数c必须指向一个之前进行abc_open()时所设置的abc连接。
rime_output()是Rime协议栈的一个接口,我们今后会讲到,可以先简单看一下其实现内容。

1
2
3
4
5
6
7
8
9
10
11
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

1
2
3
4
5
6
7
8
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

1
2
3
4
5
6
7
8
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相同。

小结

关于如何编写程序,发送一个abc匿名广播消息,其实很简单,参考引子博客。