zigbee 笔记5

zigbee ZCL流程分析

现在一般淘宝上面买的zigbee开发板给的资料都是ZStack-CC2530-2.3.0-1.4.0这个版本的资料,但是这个是已经比较旧的版本了,和现在ZHA,ZLL还是有点不一样的,其中主要不一样的地方就是ZCL,自己理解来说,我觉得ZCL是TI在zigbee收发的基础函数上面封装的一套规范,通过ZCL可以直接使用ZHA和ZLL的规范,不需要管具体发送的是什么数据;

但是,好了,现在不管发送什么数据,但是我现在想要多做一个透传接口,发现就很困难了;我现在遇到的问题就是这样的,公司zigbee网关外包出去,里面有封装好透传接口,主要用于门锁的透传加密数据,但是现在终端和路由是我们自己开发,就需要把这个透传接口加上去;这时候就需要清除了解ZCL具体的收发的封装了;下面我们来分析一下:

  • 主要操作的文件是zcl.c, zcl_general.c, app.c这3个文件

  • 先来看应用程序吧,zcl_samplesw.c:

    static zclGeneral_AppCallbacks_t zclSampleSw_CmdCallbacks =
    {zclSampleSw_BasicResetCB,               // Basic Cluster Reset commandzclSampleSw_IdentifyCB,                 // Identify command
    #ifdef ZCL_EZMODENULL,                                   // Identify EZ-Mode Invoke commandNULL,                                   // Identify Update Commission State command
    #endifNULL,                                   // Identify Trigger Effect commandzclSampleSw_IdentifyQueryRspCB,         // Identify Query Response commandzclgetonoff,                                   // On/Off cluster commandsNULL,                                   // On/Off cluster enhanced command Off with EffectNULL,                                   // On/Off cluster enhanced command On with Recall Global SceneNULL,                                   // On/Off cluster enhanced command On with Timed Off
    #ifdef ZCL_LEVEL_CTRLNULL,                                   // Level Control Move to Level commandNULL,                                   // Level Control Move commandNULL,                                   // Level Control Step commandNULL,                                   // Level Control Stop command
    #endif
    #ifdef ZCL_GROUPSNULL,                                   // Group Response commands
    #endif
    #ifdef ZCL_SCENESNULL,                                   // Scene Store Request commandNULL,                                   // Scene Recall Request commandNULL,                                   // Scene Response command
    #endif
    #ifdef ZCL_ALARMSNULL,                                   // Alarm (Response) commands
    #endif
    #ifdef SE_UK_EXTNULL,                                   // Get Event Log commandNULL,                                   // Publish Event Log command
    #endifNULL,                                   // RSSI Location commandNULL,                                    // RSSI Location Response commandzclDoorLockDataIn                       //doorlock function,在这里添加doorlock的回调函数
    };
    ...
    static void zclDoorLockDataIn(uint8 *data,uint16 len);//注册门锁数据回调函数
    //具体操作函数
    static void zclDoorLockDataIn(uint8 *data,uint16 len){HalLedSet(HAL_LED_2, HAL_LED_MODE_OFF);}
    
  • 好了,应用程序端就这么简单,在注册回调函数里面添加透传接口的回调,但是想想都知道,直接在回调列表里面添加肯定不行,那么我们看看这个结构体zclGeneral_AppCallbacks_t 的定义,来到了zcl_general.h文件,那么我们就继续照葫芦画瓢:

    typedef struct
    {zclGCB_BasicReset_t               pfnBasicReset;                // Basic Cluster Reset commandzclGCB_Identify_t                 pfnIdentify;                  // Identify command
    #ifdef ZCL_EZMODEzclGCB_IdentifyEZModeInvoke_t     pfnIdentifyEZModeInvoke;      // Identify EZ-Mode Invoke commandzclGCB_IdentifyUpdateCommState_t  pfnIdentifyUpdateCommState;   // Identify Update Commission State command
    #endifzclGCB_IdentifyTriggerEffect_t    pfnIdentifyTriggerEffect;     // Identify Trigger Effect commandzclGCB_IdentifyQueryRsp_t         pfnIdentifyQueryRsp;          // Identify Query Response commandzclGCB_OnOff_t                    pfnOnOff;                     // On/Off cluster commandszclGCB_OnOff_OffWithEffect_t      pfnOnOff_OffWithEffect;       // On/Off cluster enhanced command Off with EffectzclGCB_OnOff_OnWithRecallGlobalScene_t  pfnOnOff_OnWithRecallGlobalScene;  // On/Off cluster enhanced command On with Recall Global ScenezclGCB_OnOff_OnWithTimedOff_t     pfnOnOff_OnWithTimedOff;      // On/Off cluster enhanced command On with Timed Off
    #ifdef ZCL_LEVEL_CTRLzclGCB_LevelControlMoveToLevel_t  pfnLevelControlMoveToLevel;   // Level Control Move to Level commandzclGCB_LevelControlMove_t         pfnLevelControlMove;          // Level Control Move commandzclGCB_LevelControlStep_t         pfnLevelControlStep;          // Level Control Step commandzclGCB_LevelControlStop_t         pfnLevelControlStop;          // Level Control Stop command
    #endif
    #ifdef ZCL_GROUPSzclGCB_GroupRsp_t                 pfnGroupRsp;                  // Group Response commands
    #endif
    #ifdef ZCL_SCENESzclGCB_SceneStoreReq_t            pfnSceneStoreReq;             // Scene Store Request commandzclGCB_SceneRecallReq_t           pfnSceneRecallReq;            // Scene Recall Request commandzclGCB_SceneRsp_t                 pfnSceneRsp;                  // Scene Response command
    #endif
    #ifdef ZCL_ALARMSzclGCB_Alarm_t                    pfnAlarm;                     // Alarm (Response) commands
    #endif
    #ifdef SE_UK_EXTzclGCB_GetEventLog_t              pfnGetEventLog;               // Get Event Log commandzclGCB_PublishEventLog_t          pfnPublishEventLog;           // Publish Event Log command
    #endifzclGCB_Location_t                 pfnLocation;                  // RSSI Location commandzclGCB_LocationRsp_t              pfnLocationRsp;               // RSSI Location Response commandzclGCB_DoorLock_t                 pfnDoorLock;                    //添加doorlock门锁回调函数} zclGeneral_AppCallbacks_t;
    

    修改这个结构体,然后定义一下zclGCB_DoorLock_t这个回调函数:

    typedef void (*zclGCB_DoorLock_t)( uint8 *data,uint16 len);//我们需要透传数据和数据长度
    

    好了,zcl_general.h文件我们也改好了;

  • 下面我们要正式分析zcl流程了:

    ZCL的所有数据都是在zcl.c里面的uint16 zcl_event_loop( uint8 task_id, uint16 events );这里跑的;

    uint16 zcl_event_loop( uint8 task_id, uint16 events )
    {uint8 *msgPtr;(void)task_id;  // Intentionally unreferenced parameterif ( events & SYS_EVENT_MSG ){msgPtr = osal_msg_receive( zcl_TaskID );while ( msgPtr != NULL ){uint8 dealloc = TRUE;if ( *msgPtr == AF_INCOMING_MSG_CMD )//就是这里,对各种命令数据进行处理{zcl_ProcessMessageMSG( (afIncomingMSGPacket_t *)msgPtr );//我们debug进去看看}else{uint8 taskID;taskID = zcl_getExternalFoundationHandler( (afIncomingMSGPacket_t *)msgPtr );if ( taskID != TASK_NO_TASK ){// send it to another task to process.osal_msg_send( taskID, msgPtr );dealloc = FALSE;}}....
    }
    

    我们看到具体处理数据的是zcl_ProcessMessageMSG( (afIncomingMSGPacket_t *)msgPtr ),进去看看,比较长:

    zclProcMsgStatus_t zcl_ProcessMessageMSG( afIncomingMSGPacket_t *pkt )
    {endPointDesc_t *epDesc;zclIncoming_t inMsg;//这个就是接收到的数据,zclLibPlugin_t *pInPlugin;zclDefaultRspCmd_t defautlRspCmd;uint8 options;uint8 securityEnable;uint8 interPanMsg;ZStatus_t status = ZFailure;uint8 defaultResponseSent = FALSE;// InitializerawAFMsg = (afIncomingMSGPacket_t *)pkt;inMsg.msg = pkt;inMsg.attrCmd = NULL;inMsg.pData = NULL;inMsg.pDataLen = 0;inMsg.pData = zclParseHdr( &(inMsg.hdr), pkt->cmd.Data );//官方就是这么取数据的inMsg.pDataLen = pkt->cmd.DataLength;inMsg.pDataLen -= (uint16)(inMsg.pData - pkt->cmd.Data);// memcpy(gStr1,inMsg.pData,30); 可以这样取数据到数组看看透传过来的数据对不对?// Temporary workaround to allow callback functions access to the// transaction sequence number.  Callback functions will call// zcl_getParsedTransSeqNum() to retrieve this number.savedZCLTransSeqNum = inMsg.hdr.transSeqNum;// Find the wanted endpoint,获取端点信息epDesc = afFindEndPointDesc( pkt->endPoint );if ( epDesc == NULL ){rawAFMsg = NULL;return ( ZCL_PROC_EP_NOT_FOUND );   // Error, ignore the message}if ( ( epDesc->simpleDesc == NULL ) ||( zcl_DeviceOperational( pkt->endPoint, pkt->clusterId, inMsg.hdr.fc.type,inMsg.hdr.commandID, epDesc->simpleDesc->AppProfId ) == FALSE ) ){rawAFMsg = NULL;return ( ZCL_PROC_NOT_OPERATIONAL ); // Error, ignore the message}#if defined ( INTER_PAN )if ( StubAPS_InterPan( pkt->srcAddr.panId, pkt->srcAddr.endPoint ) ){// No foundation command is supported thru Inter-PAN communication.// But the Light Link cluster uses a different Frame Control format// for it's Inter-PAN messages, where the messages could be confused// with the foundation commands.if ( zcl_ProfileCmd( inMsg.hdr.fc.type ) ){rawAFMsg = NULL;return ( ZCL_PROC_INTERPAN_FOUNDATION_CMD );}interPanMsg = TRUE;options = AF_TX_OPTIONS_NONE;}else
    #endif{interPanMsg = FALSE;options = zclGetClusterOption( pkt->endPoint, pkt->clusterId );}if ( pkt->cmd.DataLength < ZCL_VALID_MIN_HEADER_LEN  ){return ( ZCL_PROC_INVALID );   // Error, ignore the message}// Find the appropriate plugin,获取回调pInPlugin = zclFindPlugin( pkt->clusterId, epDesc->simpleDesc->AppProfId );// Local and remote Security options must match except for Default Response commandif ( ( pInPlugin != NULL ) && !zcl_DefaultRspCmd( inMsg.hdr ) )//这里和安防有关,有些工程师需要用到密钥的,就和这里有关,我们的架构没有密钥,开发的网络,所以可以不管这里{securityEnable = ( options & AF_EN_SECURITY ) ? TRUE : FALSE;.......}// Is this a foundation type message,if ( !interPanMsg && zcl_ProfileCmd( inMsg.hdr.fc.type ) )//我们debug正常的onoff指令是跑到下面的else那里的,所以这里如果你的透传接口是跑到下面的代码,就要看看你的inMsg.hdr.fc.type这里的type是否赋值错误,我自己添加的时候就是出现这样的情况,所以就自己添加了特殊处理的代码,下面说。。。{........}else  // Not a foundation type message, so it must be specific to the cluster ID.{if ( pInPlugin && pInPlugin->pfnIncomingHdlr )//和onoff指令一样进到这里了,但是往下不了,有可能和你的透传接口的custerID有关,是否pInPlugin的custerID和透传ID一样{// The return value of the plugin function will be//  ZSuccess - Supported and need default response//  ZFailure - Unsupported//  ZCL_STATUS_CMD_HAS_RSP - Supported and do not need default rsp//  ZCL_STATUS_INVALID_FIELD - Supported, but the incoming msg is wrong formatted//  ZCL_STATUS_INVALID_VALUE - Supported, but the request not achievable by the h/w//  ZCL_STATUS_SOFTWARE_FAILURE - Supported but ZStack memory allocation failsstatus = pInPlugin->pfnIncomingHdlr( &inMsg );//就是这里了,执行到这里基本上已经成功,这里执行了之后会调用zcl_general.c里面的回调处理方法找到相关的处理函数再回调上去到应用层,具体处理回调函数是:static ZStatus_t zclGeneral_HdlIncoming( zclIncoming_t *pInMsg )if ( status == ZCL_STATUS_CMD_HAS_RSP || ( interPanMsg && status == ZSuccess ) ){rawAFMsg = NULL;return ( ZCL_PROC_SUCCESS ); // We're done}}
    .......
    }
    

    下面我们继续,上面说到if ( !interPanMsg && zcl_ProfileCmd( inMsg.hdr.fc.type ) ) 这里跑的和onoff指令不一样,进不到else那里,发现是这个type问题,我们往上找,看哪里有给type赋值,发现是这个函数:

    inMsg.pData = zclParseHdr( &(inMsg.hdr), pkt->cmd.Data );,就是这个一开始取数据的时候执行的函数,我们进去看看:

    uint8 *zclParseHdr( zclFrameHdr_t *hdr, uint8 *pData )
    {// Clear the headerzcl_memset( (uint8 *)hdr, 0, sizeof ( zclFrameHdr_t ) );// Parse the Frame Control//这里处理一下门锁的cmd-typeif(*pData==0x1c){//我是直接debug,然后发现透传的时候传到这里的是0x1c,所以直接进行特殊处理,后来发现manuSpecific也要进行处理,所以就写成这样了,建议如果懂真正流程的话不要和我这么改,我是不懂的hdr->fc.type =1;hdr->fc.manuSpecific =0;}else{hdr->fc.type = zcl_FCType( *pData );hdr->fc.manuSpecific = zcl_FCManuSpecific( *pData ) ? 1 : 0;}if ( zcl_FCDirection( *pData ) ){hdr->fc.direction = ZCL_FRAME_SERVER_CLIENT_DIR;}else{hdr->fc.direction = ZCL_FRAME_CLIENT_SERVER_DIR;}...
    }
    

    修改完了就可以进去下一步了,好了到了 if ( pInPlugin && pInPlugin->pfnIncomingHdlr )这里又卡住进不去了,debug看看,发现是没有找到pInPlugin ,往上找什么时候赋值,发现是:pInPlugin = zclFindPlugin( pkt->clusterId, epDesc->simpleDesc->AppProfId );这个给它赋值了,进入看看:

    
    static zclLibPlugin_t *plugins = (zclLibPlugin_t *)NULL;ZStatus_t zclGeneral_RegisterCmdCallbacks( uint8 endpoint, zclGeneral_AppCallbacks_t *callbacks )
    {zclGenCBRec_t *pNewItem;zclGenCBRec_t *pLoop;// Register as a ZCL Pluginif ( zclGenPluginRegisted == FALSE ){zcl_registerPlugin( ZCL_CLUSTER_ID_GEN_BASIC,ZCL_CLUSTER_ID_GEN_MULTISTATE_VALUE_BASIC,zclGeneral_HdlIncoming );//.......}
    }ZStatus_t zcl_registerPlugin( uint16 startClusterID,uint16 endClusterID, zclInHdlr_t pfnIncomingHdlr )
    {...// Fill in the plugin record.pNewItem->next = (zclLibPlugin_t *)NULL;pNewItem->startClusterID = startClusterID;pNewItem->endClusterID = endClusterID;pNewItem->pfnIncomingHdlr = pfnIncomingHdlr;// Find spot in listif (  plugins == NULL ){plugins = pNewItem;//在这里,然后再往上找发现在zclGeneral_RegisterCmdCallbacks里面调用了,然后再往上找发现在应用层初始化的时候调用了zclGeneral_RegisterCmdCallbacks,开始串起来了吧,就是要注册回调才能有这样的处理,发现startClusterID=0,endClusterID= 0x0014,难怪找不到回调}...
    }static zclLibPlugin_t *zclFindPlugin( uint16 clusterID, uint16 profileID )
    {zclLibPlugin_t *pLoop = plugins;//找一下这个全局变量(void)profileID;  // Intentionally unreferenced parameterwhile ( pLoop != NULL ){if ( ( clusterID >= pLoop->startClusterID ) && ( clusterID <= pLoop->endClusterID ) )//就是这里了,我们的透传ID是3073->0x0c01,看上面的分析{return ( pLoop );}else if(clusterID==0x0c01)//特殊处理一下雍敏网关的透传接口,因为它的透传接口不在该范围,doorlock,然后就能找到该回调了{return ( pLoop );}pLoop = pLoop->next;}return ( (zclLibPlugin_t *)NULL );
    }

    终于能进到: status = pInPlugin->pfnIncomingHdlr( &inMsg );这里了,然后百度发现这里就是回调到回调函数处理那里的:static ZStatus_t zclGeneral_HdlIncoming( zclIncoming_t *pInMsg );我们去到:zcl_general.c文件里面查看这个函数:

    static ZStatus_t zclGeneral_HdlIncoming( zclIncoming_t *pInMsg )
    {ZStatus_t stat = ZSuccess;#if defined ( INTER_PAN )if ( StubAPS_InterPan( pInMsg->msg->srcAddr.panId, pInMsg->msg->srcAddr.endPoint ) )return ( stat ); // Cluster not supported thru Inter-PAN
    #endifif ( zcl_ClusterCmd( pInMsg->hdr.fc.type ) )//这里我们已经在上面修改过了所以会走下一步{// Is this a manufacturer specific command?if ( pInMsg->hdr.fc.manuSpecific == 0 )//就是这里,我们也修改过了,所以可以走下一步{stat = zclGeneral_HdlInSpecificCommands( pInMsg );//我们进去看看}else{// We don't support any manufacturer specific command.stat = ZFailure;}}else{// Handle all the normal (Read, Write...) commands -- should never get herestat = ZFailure;}return ( stat );
    }
    

    继续进到 stat = zclGeneral_HdlInSpecificCommands( pInMsg );函数

    static ZStatus_t zclGeneral_ProcessDookLockInfo(zclIncoming_t *pInMsg, zclGeneral_AppCallbacks_t *pCBs );//定义门锁处理函数,透传接口处理//很明显了,就是这里回调函数到应用层的,我们看看
    static ZStatus_t zclGeneral_HdlInSpecificCommands( zclIncoming_t *pInMsg )
    {ZStatus_t stat;zclGeneral_AppCallbacks_t *pCBs;// make sure endpoint existspCBs = zclGeneral_FindCallbacks( pInMsg->msg->endPoint );//获取回调函数指针if ( pCBs == NULL )return ( ZFailure );switch ( pInMsg->msg->clusterId )//根据clusterID来分辨回调函数{#ifdef ZCL_BASICcase ZCL_CLUSTER_ID_GEN_BASIC:stat = zclGeneral_ProcessInBasic( pInMsg, pCBs );break;
    #endif // ZCL_BASIC#ifdef ZCL_IDENTIFYcase ZCL_CLUSTER_ID_GEN_IDENTIFY:stat = zclGeneral_ProcessInIdentity( pInMsg, pCBs );break;
    #endif // ZCL_IDENTIFY#ifdef ZCL_GROUPScase ZCL_CLUSTER_ID_GEN_GROUPS:if ( zcl_ServerCmd( pInMsg->hdr.fc.direction ) )stat = zclGeneral_ProcessInGroupsServer( pInMsg );elsestat = zclGeneral_ProcessInGroupsClient( pInMsg, pCBs );break;
    #endif // ZCL_GROUPS#ifdef ZCL_SCENEScase ZCL_CLUSTER_ID_GEN_SCENES:if ( zcl_ServerCmd( pInMsg->hdr.fc.direction ) )stat = zclGeneral_ProcessInScenesServer( pInMsg, pCBs );elsestat = zclGeneral_ProcessInScenesClient( pInMsg, pCBs );break;
    #endif // ZCL_SCENES#ifdef ZCL_ON_OFFcase ZCL_CLUSTER_ID_GEN_ON_OFF:stat = zclGeneral_ProcessInOnOff( pInMsg, pCBs );break;
    #endif // ZCL_ON_OFF#ifdef ZCL_LEVEL_CTRLcase ZCL_CLUSTER_ID_GEN_LEVEL_CONTROL:stat = zclGeneral_ProcessInLevelControl( pInMsg, pCBs );break;
    #endif // ZCL_LEVEL_CTRL#ifdef ZCL_ALARMScase ZCL_CLUSTER_ID_GEN_ALARMS:if ( zcl_ServerCmd( pInMsg->hdr.fc.direction ) )stat = zclGeneral_ProcessInAlarmsServer( pInMsg, pCBs );elsestat = zclGeneral_ProcessInAlarmsClient( pInMsg, pCBs );break;
    #endif // ZCL_ALARMS#ifdef ZCL_LOCATIONcase ZCL_CLUSTER_ID_GEN_LOCATION:if ( zcl_ServerCmd( pInMsg->hdr.fc.direction ) )stat = zclGeneral_ProcessInLocationServer( pInMsg, pCBs );elsestat = zclGeneral_ProcessInLocationClient( pInMsg, pCBs );break;
    #endif // ZCL_LOCATIONcase ZCL_CLUSTER_ID_DOORLOCK_INFO://参考onoff的回调函数,我们写好这个回调,这里要添加一些clusterID,在zcl.h文件里面:/*.....// Light Link cluster
    #define ZCL_CLUSTER_ID_LIGHT_LINK                           0x1000//door lock self control ID门锁自定义透传ID
    #define ZCL_CLUSTER_ID_DOORLOCK_INFO                         0x0C01
    .....*/stat = zclGeneral_ProcessDookLockInfo( pInMsg, pCBs );break;case ZCL_CLUSTER_ID_GEN_POWER_CFG:case ZCL_CLUSTER_ID_GEN_DEVICE_TEMP_CONFIG:case ZCL_CLUSTER_ID_GEN_ON_OFF_SWITCH_CONFIG:case ZCL_CLUSTER_ID_GEN_TIME:default:stat = ZFailure;break;}return ( stat );
    }//参考onoff的处理函数进行修改
    //door lock process门锁处理函数
    static ZStatus_t zclGeneral_ProcessDookLockInfo(zclIncoming_t *pInMsg, zclGeneral_AppCallbacks_t *pCBs )
    {ZStatus_t stat = ZSuccess;if ( pCBs->pfnDoorLock ){pCBs->pfnDoorLock( pInMsg->pData,pInMsg->pDataLen );}return ( stat );
    }
    

    至此,我们已经实现了这个回调功能了更加多的功能以后再说。

zigbee 笔记5相关推荐

  1. ZigBee笔记(zstack篇)

    前言 由于一些原因放弃个人博客,先逐渐将博客内容搬运至CSDN,本文原写于年初.zigbee篇默认掌握8051框架. zstack协议栈是ZigBee学习中极为重要的一部分,在实践中我们主要利用官方的 ...

  2. zigbee菜鸟笔记(一)zigbee的基础知识

    一.什么是zigbee 有问题发送邮件至468078841@qq.com ZigBee,也称紫蜂,是一种低速短距离传输的无线网上协议,底层是采用IEEE 802.15.4标准规范的媒体访问层与物理层. ...

  3. Zigbee HA 框架学习笔记

    Zigbee HA 框架学习笔记之DeviceID Zigbee HA 框架中支持众多的设备类型,这些类型以DeviceID的形式存在,此处做一个摘要. HA 支持的 Device ID Device ...

  4. 移动目标定位技术笔记1:WiFi、ZigBee、UWB技术

    一.Wifi技术 1.物理层和MAC层 这里移动设备的信号是从上向下逐层递交的,即应用层-传输层-网络层-LLC-MAC-PLCP-PMD. 隐藏节点和暴露节点的问题解决,NAV起了很大作用,如下: ...

  5. zigbee学习笔记---入门

    首先,本人是一名在读本科生,因为要参加本年度的物联网比赛,故需要掌握一定的Z-Stack知识.一周前本人对Z-Stack了解是完全空白,当时连什么是ZigBee都没听说过,不过本人是本校的物理实验室的 ...

  6. 【ember zigbee】序章:协议栈相关文档学习笔记

    原文地址:https://blog.csdn.net/tainjau/article/details/90648114 文章目录 写在前面 一.材料出处 二.文档解析 2.1.EZSP Protoco ...

  7. ZigBee开发笔记博文导航

    自博主更新该专栏也很久了,今天博主就给出关于ZigBee开发的一个导航,为的是读者朋友能更好找到自己所感兴趣的那一块,当然博主以后对ZigBee有新的发现和想法也会在第一时间发表在CSDN上,在此感谢 ...

  8. 《ZigBee实战演练》学习笔记

    <ZigBee实战演练>学习笔记 学习者:陈美 版本记录 u 2015/10/17起草 初步了解ZigBee是什么和开发环境的快速建立以及基础实验的第一个实验:点亮第一个LED. u 20 ...

  9. 第三章:zigbee学习笔记之物理层和mac层帧格式分析

    本文原地址:https://blog.csdn.net/tainjau/article/details/81634681 IEEE802.15.4工作组致力于无线个人区域网络(wireless per ...

最新文章

  1. vbox虚拟机无法使用计算机名称,win10/windows10启动virtualbox虚拟机提示“不能为虚拟电脑XX点击一个...
  2. Fiddler抓包工具详解(三)(fiddler监控面板+辅助工具)
  3. 22种编程语言新年快乐
  4. 警惕开源代码库中的安全隐患
  5. CWinThread
  6. statuml怎么添加用户_UML课后习题答案
  7. 官宣!2020年,这5类程序员要过苦日子!网友:明年咋活?!
  8. django-聚合函数
  9. Hadoop系列-HDFS HA高可用集群
  10. 在条件类型中使用 infer 关键字
  11. detours安装和使用
  12. 我大学时代的好朋友要结婚了!
  13. 自定义的BaseAdapter实现LIstView的展示
  14. 程序语言POJ 2406 Power Strings
  15. JSTL表达式的理解和使用
  16. 结构梁配筋最牛插件_多高层钢筋混凝土结构最困惑的29个问题及方法解析全汇总...
  17. linux b类地址设24位掩码,子网掩码的设置方法和作用
  18. 2个最好的中文图标搜索引擎
  19. ctf GetFlag
  20. 关于在JS中引入JS文件的JQ方法

热门文章

  1. 浙大计算机科学与技术专业课表,周亚金 - 浙江大学 - 计算机科学与技术
  2. 联果云全媒体广告是什么?现在创业做这个项目合适么?
  3. 王劲“大跃进造车”的背后,是心怀梦想还是圈钱?
  4. 我的世界服务器物品无法合成,《我的世界》MC玩家无法合成的五大物品,最后一个已经被移除了!...
  5. 数字金融崛起,科技撬动增长
  6. Tetrooj Box
  7. 大学四年,我是如何学习编程的?
  8. 命里有时终须有与我命由我不由天
  9. 怎么在win7中增加“显示桌面”快速启动栏
  10. 打开任务管理器只显示任务 不显示进程了怎么办?