实验一 ATOS 点对点通信实验 一 实验目的 1. 了解节点对点通信过程 2. 学会 ATOS 平台通讯模块 (ActiveMessage) 的使用二 实验设备 1. 带有 CC2530 芯片的基站一个 2. 基本节点一个 3. 天线两个 4. 烧录线一根 5. 平行串口线一根 HUST Ke Shi
三 实验原理本实验使用 TinyOS 中的活动消息 (PlatformMacC) 模型实现点对点通信, 活动模型组件 PlatformMacC 包含了网络协议中路由层以下的部分 在 ATOS 平台下,PlatformMacC 包含的主要功能有 :CSMA/CA 链路层重发 重复包判断等机制 其中,CSMA/CA 机制使节点在发送数据之前, 首先去侦听信道状况, 只有在信道空闲的情况下才发送数据, 从而避免了数据碰撞, 保证了节点间数据稳定传输 ; 链路层重发机制是当节点数据发送失败时, 链路层会重发, 直到发送成功或重发次数到达设定的阈值为止, 提高了数据成功到达率 ; 重复包判断机制是节点根据发送数据包的源节点地址及数据包中的 dsn 域判断该包是不是重复包, 如果是重复包, 则不处理, 防止节点收到同一个数据包的多个拷贝
PlatformMacC 向上层提供的接口有 AMSend Receive AMPacket Packet Snoop 等 AMSend 接口实现数据的发送,Receive 接口实现数据的接收,Snoop 是接收发往其它节点的数据,AMPacket 接口用于设置和提取数据包的源节点地址 目的地址等信息,Packet 接口主要是得到数据包的有效数据长度 (payload length) 最大有数据长度 有效数据的起始地址等 AMSend Receive Snoop 都是参数化接口, 参数为一个 8 位的 id 号, 类似于 TCP/IP 协议中的端口号 两个节点通信时, 发送节点使用的 AMSend 接口的参数 id 必须与接收节点的 Receive 接口的参数 id 一致
在 TinyOS 操作系统下, 所有的数据包都封装到一个叫 message_t 的结构体中 message_t 结构体包含四个部分 :header data footer metadata 四个部分 其中 header 中包含了数据包长度 fcf dsn 源地址 目的地址等信息 ;metadata 包含了 rssi 等信息, 详见 cc2420.h Message.h platform_message.h 其中,metadata 部分不需要通过射频发送出去, 只是在发送前和接收后提取或写入相应的域
四 程序流程图
五 关键代码解析 /* 节点启动完毕 */ event void Boot.booted() /* 开启射频 */ call AtosControl.start(); /* 开启串口通信 */ call UartStdControl.start(); LED_YELLOW_OFF; LED_BLUE_OFF; ADBG_APP( "\r\n###############################################\r\n"); ADBG_APP( " [P2PDEMO] My Address = 0x%x, Group = 0x%x\r\n", ADBG_N(call AMPacket.address()), ADBG_N(TOS_IEEE_PANID)); ADBG_APP( "###############################################\r\n"); m_input_type= INPUT_ADDRESS; post showmenu(); ADBG_APP() 类似于 C 语言中的 printf() 格式化输出到串口助手 ADBG_N() 完成数据格式的转换, 数值不变 m_input_type 变量有两个值 INPUT_ADDRESS 和 INPUT_DATA 以区别输入是地址还是需要传送的数据
/* 发送数据部分 */ task void senddata() uint8_t i; uint8_t* payload = call Packet.getPayload(&m_msg, NULL); uint16_t address = call AMPacket.address(); uint16_t dest_address= getdestaddress(); ADBG_APP( "\r\n\r\n* Sending... from [%d], to [%d], len=[%d]\r\n", ADBG_N(address), ADBG_N(dest_address), ADBG_N(m_len) ); call AMSend.send(dest_address, &m_msg, m_len); //LED_BLUE_TOGGLE; uint16_t getdestaddress() 是一个内部函数功能为将从串口输入的地址字符串转化为真实地址, 返回从串口输入的地址 Packet.getPayload(&m_msg, NULL) 返回消息包的有效载荷区, AMPacket.address() 返回消息包得源地址 AMSend.send(dest_address, &m_msg, m_len) 为发送信息
/* 从串口接收数据 */ /*async 事件在硬件接收到无线信号的第一个字节后触发 */ async event void UartStream.receivedByte(uint8_t c) if(c!= '\r') if (m_input_type == INPUT_DATA) /* 输入数据 */ uint8_t* payload = (uint8_t*)call Packet.getPayload(&m_msg, NULL); if(m_len >= call Packet.maxPayloadLength()) return; payload[m_len++] = c; ADBG_APP( "%c", c);
if(m_len < call Packet.maxPayloadLength()) return; else /* 输入地址 */ if(m_address_index < MAX_ADDRESS_LEN) m_address_str[m_address_index++] = c; ADBG_APP( "%c", c); if(m_address_index < MAX_ADDRESS_LEN) return;
* 按下回车键或者到达最大长度, 则处理 */ if(m_input_type== INPUT_DATA) post senddata(); else /* 地址处理完毕, 准备输入数据 */ m_input_type= INPUT_DATA; post showmenu(); 该异步事件响应的条件是串口有键盘输入, 每次接受一个字符并将该字符打印出来, 如果输入回车, 则调用发送数据任务
/* 射频接收数据 */ event message_t* Receive.receive(message_t* msg, void* payload, uint8_t len) uint8_t i; ADBG_APP( "\r\n*receive, len = [%d], DATA:\r\n", ADBG_N(len)); for(i=0; i < len; i++) ADBG_APP( "%c", ((uint8_t*)payload)[i]); ADBG_APP( "\r\n"); LED_YELLOW_TOGGLE; m_input_type = INPUT_ADDRESS;
六 实验任务 在上述实验的基础上, 通过修改代码, 使节点在收到数据后立即回送收到的字符串数据, 并在串口助手中显示出来 Tips: 分析增加节点收到数据回送字符串的功能, 那么需要修改的事件为 : vent message_t* Receive.receive(message_t* msg, void* payload, uint8_t len) 修改节点在接收到其他节点信息后的行为, 添加自动回复的功能 ( 由于节点的程序都是一样的, 添加代码时要考虑避免形成节点回复的无限循环 )