一、开发环境及作用
IAR EW8051 + ZStack-CC2530-2.5.1a + CC Debugger + CC2530
接收终端ZigBee采集到的数据,将处理后的数据通过串口发送给wifi模块进行转发; 同时接收wifi模块发送的命令转发给终端
二、协调器初始化
void SampleApp_Init( uint8 task_id )
{
SampleApp_TaskID = task_id;
SampleApp_NwkState = DEV_INIT;
SampleApp_TransID = 0;
#if defined ( BUILD_ALL_DEVICES )
if ( readCoordinatorJumper() )
zgDeviceLogicalType = ZG_DEVICETYPE_COORDINATOR;
else
zgDeviceLogicalType = ZG_DEVICETYPE_ROUTER;
#endif // BUILD_ALL_DEVICES
#if defined ( HOLD_AUTO_START )
// HOLD_AUTO_START is a compile option that will surpress ZDApp
// from starting the device and wait for the application to
// start the device.
ZDOInitDevice(0);
#endif
SampleApp_ADDR_DstAddr.addrMode =(afAddrMode_t)AddrBroadcast;
SampleApp_ADDR_DstAddr.endPoint = SAMPLEAPP_ENDPOINT;
SampleApp_ADDR_DstAddr.addr.shortAddr = 0xFFFF; //广播
HalUARTInit();
halUARTCfg_t uartConfig;
uartConfig.configured = TRUE; // 2x30 don't care - see uart driver.
uartConfig.baudRate = HAL_UART_BR_115200; //波特率
uartConfig.flowControl = FALSE; //流控制
uartConfig.intEnable = TRUE;
uartConfig.callBackFunc = callBack; //开启回调函数
HalUARTOpen(HAL_UART_PORT_0, &uartConfig); //端口0
// MT_UartInit(); //协议栈自带的串口初始化;
MT_UartRegisterTaskID(task_id); //注册串口任务;指定当MT任务接收到串口数据时,传递到本任务来 task_id
// 简单描述符
SampleApp_epDesc.endPoint = SAMPLEAPP_ENDPOINT;
SampleApp_epDesc.task_id = &SampleApp_TaskID;
SampleApp_epDesc.simpleDesc
= (SimpleDescriptionFormat_t *)&SampleApp_SimpleDesc;
SampleApp_epDesc.latencyReq = noLatencyReqs;
// Register the endpoint description with the AF
afRegister( &SampleApp_epDesc );
// Register for all key events - This app will handle all key events
RegisterForKeys( SampleApp_TaskID );
#if defined ( LCD_SUPPORTED )
HalLcdWriteString( "SampleApp", HAL_LCD_LINE_1 );
#endif
}
三、任务处理函数
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 key is pressed
case KEY_CHANGE:
//SampleApp_HandleKeys( ((keyChange_t *)MSGpkt)->state, ((keyChange_t *)MSGpkt)->keys );
break;
case AF_INCOMING_MSG_CMD: //收到终端发送来的消息
SampleApp_MessageMSGCB( MSGpkt );
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 )
{
}
else
{
// Device is no longer in the network
}
break;
default:
break;
}
// Release the memory
osal_msg_deallocate( (uint8 *)MSGpkt );
// Next - if one is available
MSGpkt = (afIncomingMSGPacket_t *)osal_msg_receive( SampleApp_TaskID );
}
// return unprocessed events
return (events ^ SYS_EVENT_MSG);
}
return 0;
}
四、收到终端消息处理函数,将数据通过串口输出
void SampleApp_MessageMSGCB( afIncomingMSGPacket_t *pkt )
{
switch ( pkt->clusterId )
{
case SAMPLEAPP_P2P_CLUSTERID:
HalUARTWrite(0, "T&H:", 4); //提示接收到数据
HalUARTWrite(0, pkt->cmd.Data, pkt->cmd.DataLength); //输出接收到的数据
HalUARTWrite(0, "\r\n", 2); // 回车换行
break;
case SAMPLEAPP_PERIODIC_CLUSTERID: //可忽略
break;
}
}
五、接收wifi模块发送来的命令;通过广播将命令转发给终端 【采用回调函数;默认是使用DMA方式;从接收缓存区内直接读取】
uint8 *rxbuff; //自己定义的数据缓存区
static void callBack(uint8 port, uint8 event){
if ((event & (HAL_UART_RX_FULL | HAL_UART_RX_ABOUT_FULL | HAL_UART_RX_TIMEOUT))){
uint16 rxBufLen = Hal_UART_RxBufLen(HAL_UART_PORT_0);
HalUARTRead( HAL_UART_PORT_0,rxbuff,rxBufLen);
// HalUARTWrite(0,tmp,rxBufLen); 测试
AF_DataRequest( &SampleApp_ADDR_DstAddr,
&SampleApp_epDesc,
SAMPLEAPP_LED_CLUSTERID,
rxBufLen,
rxbuff,
&SampleApp_TransID,
AF_DISCV_ROUTE,
AF_DEFAULT_RADIUS );
// osal_memset(rxbuff,0,rxBufLen);
}
else if( event & (HAL_UART_TX_EMPTY |HAL_UART_TX_FULL ) )
{ return;}
}
六、使用回调函数遇到的问题!!!
使用回调函数;串口接收会引起回调;串口发送也会引起回调!!; 所以就要找到串口发送引起回调的地方;关闭它;通过一次次的单步运行终于在HAL层的文件中找到了
static void HalUARTPollDMA(void)
{
uint16 cnt = 0;
uint8 evt = 0;
if (HAL_UART_DMA_NEW_RX_BYTE(dmaCfg.rxHead))
{
uint16 tail = findTail();
// If the DMA has transferred in more Rx bytes, reset the Rx idle timer.
if (dmaCfg.rxTail != tail)
{
dmaCfg.rxTail = tail;
// Re-sync the shadow on any 1st byte(s) received.
if (dmaCfg.rxTick == 0)
{
dmaCfg.rxShdw = ST0;
}
dmaCfg.rxTick = HAL_UART_DMA_IDLE;
}
else if (dmaCfg.rxTick)
{
// Use the LSB of the sleep timer (ST0 must be read first anyway).
uint8 decr = ST0 - dmaCfg.rxShdw;
if (dmaCfg.rxTick > decr)
{
dmaCfg.rxTick -= decr;
dmaCfg.rxShdw = ST0;
}
else
{
dmaCfg.rxTick = 0;
}
}
cnt = HalUARTRxAvailDMA();
}
else
{
dmaCfg.rxTick = 0;
}
if (cnt >= HAL_UART_DMA_FULL)
{
evt = HAL_UART_RX_FULL;
}
else if (cnt >= HAL_UART_DMA_HIGH)
{
evt = HAL_UART_RX_ABOUT_FULL;
PxOUT |= HAL_UART_Px_RTS;
}
else if (cnt && !dmaCfg.rxTick)
{
evt = HAL_UART_RX_TIMEOUT;
}
if (dmaCfg.txMT)
{
dmaCfg.txMT = FALSE;
evt |= HAL_UART_TX_EMPTY;
}
if (dmaCfg.txShdwValid)
{
uint8 decr = ST0;
decr -= dmaCfg.txShdw;
if (decr > dmaCfg.txTick)
{
// No protection for txShdwValid is required
// because while the shadow was valid, DMA ISR cannot be triggered
// to cause concurrent access to this variable.
dmaCfg.txShdwValid = FALSE;
}
}
if (dmaCfg.txDMAPending && !dmaCfg.txShdwValid)
{
// UART TX DMA is expected to be fired and enough time has lapsed since last DMA ISR
// to know that DBUF can be overwritten
halDMADesc_t *ch = HAL_DMA_GET_DESC1234(HAL_DMA_CH_TX);
halIntState_t intState;
// Clear the DMA pending flag
dmaCfg.txDMAPending = FALSE;
HAL_DMA_SET_SOURCE(ch, dmaCfg.txBuf[dmaCfg.txSel]);
HAL_DMA_SET_LEN(ch, dmaCfg.txIdx[dmaCfg.txSel]);
dmaCfg.txSel ^= 1;
HAL_ENTER_CRITICAL_SECTION(intState);
HAL_DMA_ARM_CH(HAL_DMA_CH_TX);
do
{
asm("NOP");
} while (!HAL_DMA_CH_ARMED(HAL_DMA_CH_TX));
HAL_DMA_CLEAR_IRQ(HAL_DMA_CH_TX);
HAL_DMA_MAN_TRIGGER(HAL_DMA_CH_TX);
HAL_EXIT_CRITICAL_SECTION(intState);
}
else
{
halIntState_t his;
HAL_ENTER_CRITICAL_SECTION(his);
if ((dmaCfg.txIdx[dmaCfg.txSel] != 0) && !HAL_DMA_CH_ARMED(HAL_DMA_CH_TX)
&& !HAL_DMA_CHECK_IRQ(HAL_DMA_CH_TX))
{
HAL_EXIT_CRITICAL_SECTION(his);
HalUARTIsrDMA();
}
else
{
HAL_EXIT_CRITICAL_SECTION(his);
}
}
if (evt && (dmaCfg.uartCB != NULL))
{
dmaCfg.uartCB(HAL_UART_DMA-1, evt);
}
}
这个函数内部产生4个引起回调函数的事件evt
HAL_UART_RX_FULL——RX缓冲区满了
HAL_UART_RX_ABOUT_FULL——RX缓存区处于maxRxBUfSize 流量控制阀值 #define HAL_UART_DMA_HIGH (HAL_UART_DMA_RX_MAX / 2 - 16)=128/2-16=48
HAL_UART_RX_TIMEOUT——Rx空闲idletimout的时间
HAL_UART_TX_EMPTY——TX缓存区为空
将Tx的事件屏蔽掉,就不会进入发送的死循环了;
/*
if (dmaCfg.txMT)
{
dmaCfg.txMT = FALSE;
evt |= HAL_UART_TX_EMPTY;
}
*/