UP智能家居之CC2530源码分析
时间:10-02
整理:3721RD
点击:
UP智能家居之CC2530源码分析
主要是为了记录学习博创的zigbee系统CC2530时的一些笔记.这是我第一次接触产品级的代码,确实在阅读源码时学到不少东西.
CC2530 特性
RF/Layout
2.4-GHz IEEE 802.15.4 Compliant RF Transceiver
Excellent Receiver Sensitivity and Robustness to Interference
Programmable Output Power Up to 4.5 dBm
Very Few External Components
Only a Single Crystal Needed for Asynchronous Networks
6-mm × 6-mm QFN40 Package
Suitable for Systems Targeting Compliance With Worldwide Radio-
Frequency Regulations: ETSI EN 300 328 and EN 300 440 (Europe),
FCC CFR47 Part 15 (US) and ARIB STD-T-66 (Japan)
ZStack 是一个片上系统,cc2530使用片内一个flash存储这些代码和数据.关于这个系统的OSAL(Operating System Abstraction Layer),网上已经有很多分析.我就不多说了,本文只关心osal的api的使用,不关心它的实现原理.附 osal API 中文版:
(竟然只找到了中文版,我在ti官方都找不到相关文件)
zStack从zmain.c开始运行.
用merge对比官方例程的zmain.c发现主要在初始化时增加了一个函数.
[cpp] view plain copy print?在CODE上查看代码片派生到我的代码片
/*********************************************************************
* @fn zmain_ram_init
* @brief Initialize ram for stack "high-water-mark" observations.
* @Return none
*********************************************************************/
static void zmain_ram_init( void )
{
uint8 *end;
uint8 *ptr;
// Initialize the call (parameter) stack
end = (uint8*)CSTK_BEG; // Lower end
ptr = (uint8*)(*( __idata uint16*)(CSTK_PTR)); // Upper end
while ( --ptr > end )
*ptr = STACK_INIT_VALUE;
// Initialize the return (address) stack
ptr = (uint8*)RSTK_END - 1; // Upper end
while ( --ptr > (uint8*)SP )
*(__idata uint8*)ptr = STACK_INIT_VALUE;
}
对比官方demo和up的sampleApp.c文件,up工程在SampleApp_Init 初始化中增加了从flash读取节点类型和设备类型
[cpp] view plain copy print?在CODE上查看代码片派生到我的代码片
NodeHead = NULL;
gSensorMode = 0x01; //00 查询模式 01 中断模式,自动上报信息
gIntFlag = 0x00; //no interrupt
gDevType = CheckDeviceType();
gSensorType = CheckSensorType(); //在初始化的时候设置 "传感器类型" 全局变量 //add by @wei
if(gSensorType == (sensor_t)SENSOR_SHT11)
{ Sht11Init(); }
else if(gSensorType == (sensor_t)SENSOR_SET)
{
//HalLedBlink( HAL_LED_2, 4, 50, (1000 / 4) );
//HalLedBlink( HAL_LED_3, 4, 50, (1000 / 4) );
SensorSetIO();
}
else
{ SensorIO_Init(); }
以及将串口事件注册到任务队列中
[cpp] view plain copy print?在CODE上查看代码片派生到我的代码片
MT_UartRegisterTaskID( SampleApp_TaskID ); //add by 1305106
然后进入事件循环:
[cpp] view plain copy print?在CODE上查看代码片派生到我的代码片
uint16 SampleApp_ProcessEvent( uint8 task_id, uint16 events )
{
afIncomingMSGPacket_t *MSGpkt;
(void)task_id; // Intentionally unreferenced parameter
if ( events & SYS_EVENT_MSG )
{
MSGpkt = (afIncomingMSGPacket_t *)osal_msg_receive( SampleApp_TaskID );
while ( MSGpkt )
{
switch ( MSGpkt->hdr.event )
{
// Received when a messages is received (OTA) for this endpoint
case AF_INCOMING_MSG_CMD:
HalLedBlink( HAL_LED_1, 4, 50, (1000 / 4) ); //receive message -> blink led //@wei zigbee网络
SampleApp_MessageMSGCB( MSGpkt ); //This function processes any incoming data - probably from other devices.
break;
case SPI_INCOMING_ZAPP_DATA:
SampleApp_ProcessMTMessage(MSGpkt); //receive uart data 重点
MT_UartAppFlowControl (MT_UART_ZAPP_RX_READY);
break;
// Received whenever the device changes state in the network
case ZDO_STATE_CHANGE:
SampleApp_NwkState = (devStates_t)(MSGpkt->hdr.status);
if ( (SampleApp_NwkState == DEV_ZB_COORD)
|| (SampleApp_NwkState == DEV_ROUTER)
|| (SampleApp_NwkState == DEV_END_DEVICE) )
{
HalLedSet(HAL_LED_2, HAL_LED_MODE_ON);
}
else
{
// Device is no longer in the network
}
break;
default:
break;
}
osal_msg_deallocate( (uint8 *)MSGpkt ); // Release the memory
MSGpkt = (afIncomingMSGPacket_t *)osal_msg_receive( SampleApp_TaskID ); // Next - if one is available
}
return (events ^ SYS_EVENT_MSG); // return unprocessed events
}
if ( events & SAMPLEAPP_SEND_SENSOR_INT_EVT )
{
SampleApp_Process_SENSOR_INT();<span style="white-space:pre"> </span>
return ( events ^ SAMPLEAPP_SEND_SENSOR_INT_EVT);
}
if ( events & SAMPLEAPP_CMD_RESET_RSP_EVT )
{
SystemReset();
//return ( events ^ SAMPLEAPP_SEND_SENSOR_INT_EVT);
}
return 0; // Discard unknown events
}
我们不按照代码顺序来分析.可以从数据的流向来看: 即 上位机-->串口-->下位机(zigbee协调器)-->zigbee网络-->
串口数据处理函数
[cpp] view plain copy print?在CODE上查看代码片派生到我的代码片
void SampleApp_ProcessMTMessage(afIncomingMSGPacket_t *msg)
{
Config_CmdProcessing((uint8*)msg); //接收来自串口的 配置命令
NodeInfo_CmdProcessing((uint8*)msg); //接收来自串口的 节点处理命令
[cpp] view plain copy print?在CODE上查看代码片派生到我的代码片
}
[cpp] view plain copy print?在CODE上查看代码片派生到我的代码片
//<span style="font-family: Arial, Helvetica, sans-serif;">afIncomingMSGPacket_t 结构体如下</span>
[cpp] view plain copy print?在CODE上查看代码片派生到我的代码片
typedef struct
{
osal_event_hdr_t hdr; /* OSAL Message header */
uint16 groupId; /* Message's group ID - 0 if not set */
uint16 clusterId; /* Message's cluster ID */
afAddrType_t srcAddr; /* Source Address, if endpoint is STUBAPS_INTER_PAN_EP,
it's an InterPAN message */
uint16 macDestAddr; /* MAC header destination short address */
uint8 endPoint; /* destination endpoint */
uint8 wasBroadcast; /* TRUE if network destination was a broadcast address */
uint8 LinkQuality; /* The link quality of the received data frame */
uint8 correlation; /* The raw correlation value of the received data frame */
int8 rssi; /* The received RF power in units dBm */
uint8 SecurityUse; /* deprecated */
uint32 timestamp; /* receipt timestamp from MAC */
afMSGCommandFormat_t cmd; /* Application Data */
} afIncomingMSGPacket_t;
[cpp] view plain copy print?在CODE上查看代码片派生到我的代码片
void Config_CmdProcessing(uint8 *pBuf)
{
uint16 cmd;
uint8 *pData = pBuf+MT_RPC_POS_CMD1;
/*************--cmd frame format--****************/
/*** | sop | cmd | len | data | fcs | ***/
/*** | 1 | 2 | 1 | len | 1 | ***/
cmd = BUILD_UINT16( pData[2], pData[1] );
switch(cmd)
{
case CONFIG_CMD_SET_DEV_TYPE_REQ:
Config_ProcessSetDevTypeReq(pData); break;
[cpp] view plain copy print?在CODE上查看代码片派生到我的代码片
<span style="white-space:pre"> </span>//最终调用了osal_nv_write 把接收数据保存到flash
[cpp] view plain copy print?在CODE上查看代码片派生到我的代码片
}
其中 MT_RPC_POS_CMD1 的值为 2 .一开始很奇怪明明afIncomingMSGPacket_t 结构体的真正数据在最后一个,按一字节对齐来算怎么也不可能只是指针位置+2..我猜测可能是串口接收数据过程中,数据被保存到afIncomingMSGPacket_t 结构体,见此函数
[cpp] view plain copy print?在CODE上查看代码片派生到我的代码片
MSGpkt = (afIncomingMSGPacket_t *)osal_msg_receive( SampleApp_TaskID );
每个事件数据分配的内存可能是不一样的.但是都统一当成afIncomingMSGPacket_t 指针来处理.最终处理时再强制转化为字节数组.
命令处理同理.
[cpp] view plain copy print?在CODE上查看代码片派生到我的代码片
void NodeInfo_CmdProcessing(uint8 *pBuf)
{
uint16 cmd;
uint8 *pData = pBuf+MT_RPC_POS_CMD1;
/*************--cmd frame format--****************/
/*** | sop | cmd | len | data | fcs | ***/
/*** | 1 | 2 | 1 | len | 1 | ***/
cmd = BUILD_UINT16( pData[2], pData[1] );
switch(cmd)
{
case NODEINFO_CMD_NWK_CONNECT_REQ:
NodeInfo_ProcessNwkConnectReq(pData); break;
case NODEINFO_CMD_GET_NWK_DESP_REQ:
NodeInfo_ProcessGetNwkDespReq(pData); break;
case NODEINFO_CMD_GET_NWK_TOPO_REQ:
NodeInfo_ProcessReportOutNode(); //通过zigbee网络传递请求
NodeInfo_ProcessGetNwkTopoReq(pData); break;
[cpp] view plain copy print?在CODE上查看代码片派生到我的代码片
//...
[cpp] view plain copy print?在CODE上查看代码片派生到我的代码片
}
在几个请求中,最重要的就是NODEINFO_CMD_GET_NWK_TOPO_REQ 了,在后面服务器端的代码分析中,服务器会开辟一个线程不断发送这个请求,以实时更新zigbee网络状态.
//这个函数从zigbee节点数据链表中提取每个节点短地址,并分别转发NODEINFO_CMD_GET_NWK_TOPO_REQ 请求.
//至于这个链表什么时候建立的 在后面的代码讲到
[cpp] view plain copy print?在CODE上查看代码片派生到我的代码片
void NodeInfo_ProcessReportOutNode( void )
{
pNode p;
uint8 nwkaddr[2];
for (p = NodeHead; p!=NULL ; p = p->next)
{
if(p->status == 0x00){
p->times++; // out flag
//HalUARTWrite ( 0, "\r\nout\r\n", 7 );
}
if((p->status == 0x00)&&(p->times==3)){
p->times=0;
//MT report out node status.!
nwkaddr[0] = HI_UINT16(p->nwkaddr);
nwkaddr[1] = LO_UINT16(p->nwkaddr);
SampleApp_BuildAndSendZToolResponse(NODEINFO_CMD_RPT_NODEOUT_RSP, 2, nwkaddr);//建立发送请求(类似一个模板)
[cpp] view plain copy print?在CODE上查看代码片派生到我的代码片
//Delay(5000);
}
// reset node's status
p->status = 0x00;
}
[cpp] view plain copy print?在CODE上查看代码片派生到我的代码片
uint8 SampleApp_SendNwkData(uint16 nwkAddr, uint8 clusterId, uint8 *data, uint8 dataLen)
{
if(nwkAddr == 0xFFFF)
SampleApp_General_DstAddr.addrMode = (afAddrMode_t)AddrBroadcast;
else
SampleApp_General_DstAddr.addrMode = (afAddrMode_t)Addr16Bit;
SampleApp_General_DstAddr.endPoint = SAMPLEAPP_ENDPOINT;
SampleApp_General_DstAddr.addr.shortAddr =nwkAddr;
if ( AF_DataRequest( &SampleApp_General_DstAddr, &SampleApp_epDesc,//真正的发送函数.
clusterId,
dataLen,
data,
&SampleApp_TransID,// transfer id
AF_DISCV_ROUTE,
AF_DEFAULT_RADIUS ) == afStatus_SUCCESS )
[cpp] view plain copy print?在CODE上查看代码片派生到我的代码片
//....
[cpp] view plain copy print?在CODE上查看代码片派生到我的代码片
}
协调器代码分析就到这吧