智能家居无线传感网通用监控协议的设计与实现(2)

    智能家居的无线终端设备千差万别,未来也不知道有多少新玩意出现。必须有囊括一切的设备描述能力,否则通用性免谈!好在应阁物联网科技的设备接口设计做到了这点。下面设计一个终端设备(硬件已经实现了): 有1个LED指示灯(可控制),一个温度传感器、一个湿度传感器。每5秒采集一次温湿度数据报告给监控平台。但监控平台可以设置采样的周期(1--60秒)。设计流程与协调其类似。

1、设备初始化代码

void Initdevicestable(void)   //1、硬件厂家必须描述子设备数量表:在应用程序初始化后调用该函数
{
    deviceinfo = (devicetable_t *)osal_mem_alloc(sizeof(devicetable_t));//动态分配结构体
    memset(deviceinfo, 0, sizeof(devicetable_t));   //首先全部清零
    //对六类子设备填写数据
    setdevicetypeandnumbers(&deviceinfo->subdevices[DO],DO,1); //有1个LED灯开关
    setdevicetypeandnumbers(&deviceinfo->subdevices[AI],AI,2); ////有1个温度传感器和1个湿度传感器
    setdevicetypeandnumbers(&deviceinfo->subdevices[AO],AO,1);  //有1个AO设备:采样周期1--60秒
       
    sprintf(deviceinfo->description,"应阁温湿度传感器");
    deviceinfo->PanID=_NIB.nwkPanId;
    InitDeviceDescription();      //始化子设备的描述
}

void InitDeviceDescription(void)  //2、硬件厂家必须初始化子设备的描述
{
  uint8 i;
  uint8 devnumbers=getdevicenumbers(deviceinfo->subdevices[DO]);  //DO子设备数量
  i=sizeof(devicedescription_t);
  DODevices = (devicedescription_t *) osal_mem_alloc( devnumbers * i);//动态分配结构体

  for (i=0;i   {
    memset((void *)(DODevices+i), 0, sizeof(devicedescription_t));   //首先全部清零
    DODevices[i].devicenumber=(DO<<5)+i;  //类型+序号
    DODevices[i].subtype=OPEN;
    strcpy(DODevices[i].unit,""); //计量单位:无  
    sprintf(DODevices[i].description,"第%d个LED灯",i+1); 
    sprintf(DODevices[i].operation,"点击DO切换开关"); 
  }
 
  devnumbers=getdevicenumbers(deviceinfo->subdevices[AI]);  //AI子设备数量
  i=sizeof(devicedescription_t);
  AIDevices = (devicedescription_t *) osal_mem_alloc( devnumbers * i);//动态分配结构体
  for (i=0;i   {
    memset((void *)(AIDevices+i), 0, sizeof(devicedescription_t));   //首先全部清零
    AIDevices[i].devicenumber=(AI<<5)+i;  //类型+序号
    AIDevices[i].subtype=Unknow;
    if (i==0)
    {
      strcpy(AIDevices[i].unit,"℃"); //温度传感器:计量单位 
      sprintf(AIDevices[i].description,"温度传感器"); 
      sprintf(AIDevices[i].operation,""); 
    }
    else if (i==1)
    {
      strcpy(AIDevices[i].unit,"%"); //湿度传感器:计量单位 
      sprintf(AIDevices[i].description,"湿度传感器"); 
      sprintf(AIDevices[i].operation,"");
    }
    else
    {
      strcpy(AIDevices[i].unit,""); //计量单位:无   
      sprintf(AIDevices[i].description,"未知设备"); 
      sprintf(AIDevices[i].operation,"未知设备"); 
    }
  }
   
  devnumbers=getdevicenumbers(deviceinfo->subdevices[AO]);  //AO子设备数量
  i=sizeof(devicedescription_t);
  AODevices = (devicedescription_t *) osal_mem_alloc( devnumbers * i);//动态分配结构体
  for (i=0;i   {
    memset((void *)(AODevices+i), 0, sizeof(devicedescription_t));   //首先全部清零
    AODevices[i].devicenumber=(AO<<5)+i;  //类型+序号
    AODevices[i].subtype=Unknow;
    if (i==0)
    {
      strcpy(AODevices[i].unit,"毫秒"); //采样周期
      sprintf(AODevices[i].description,"定时采样周期"); 
      sprintf(AODevices[i].operation,"输入毫秒数"); 
    }
    else
    {
      strcpy(AODevices[i].unit,""); //计量单位:无   
      sprintf(AODevices[i].description,"未知设备"); 
      sprintf(AODevices[i].operation,"未知设备"); 
    }
  }
  //如果有其他类型的子设备,需要一一填写结构体
  //............. 
}

2、入网后报告设备信息

static void NotifyCoordinatorDevices(void)  //报告设备信息给协调器
{
  uint8 i,size;
  uint8 cnt;
  uint16 addr;
  devicedescription_t* devdes;
//交互命令CMD协议定义,应用数据帧FF FX ADDR SIZE DATA
//数据内容标识头=0xFFF0+CMD; 第3,4个字节为设备ID号
//第5个字节SIZE为后面数据DATA的字节数
//#define SENDDATAHead 0xFFF0// 交互数据内容识头
//#define SENDDEVTABLE 0     // 发送设备信息表,E-->C
//#define SENDDEVDESCP 1     // 发送子设备描述记录,E-->C
//#define SENDDEVSTATE 2     // 发送子设备状态数据,E-->C
//#define SENDDEVCTRLL 3     // 控制子设备工作指令,C-->E
  //1、发送设备数据表
  uint8 table[80];
  addr=NLME_GetShortAddr();
  table[0]=SENDDATAHead>>8;
  table[1]=(SENDDATAHead & 0x00F0)+SENDDEVTABLE;
  table[2]=addr&0xFF;
  table[3]=addr>>8;
  table[4]=sizeof(devicetable_t);
  memcpy((void*)(table+5), (void*)deviceinfo, table[4]);
  while(true)
    {
      if(AF_DataRequest( &GenericApp_DstAddr, &GenericApp_epDesc,
             GENERICAPP_CLUSTERID,
             5+table[4],  //这个参数就是发送的数据的长度
             (uint8 *)table,
             &GenericApp_TransID,
             AF_DISCV_ROUTE,
             AF_DEFAULT_RADIUS ) == afStatus_SUCCESS ) break;
       else
       {
         HalLedSet(HAL_LED_1, HAL_LED_MODE_TOGGLE); //LED指示一下
         DelayMS(500); //稍微延时后重发 
       }
    }
  //2、发送各个子设备的描述
  /*****************DO**************************/
  DelayMS(1000); //稍微延时
  cnt=getdevicenumbers(deviceinfo->subdevices[DO]);  //DO子设备数量
  size=sizeof(devicedescription_t); //子设备信息描述结构体大小
  for (i=0;i   { 
    //HalLedSet(HAL_LED_2, HAL_LED_MODE_BLINK);
    //HalLedBlink(HAL_LED_2,3,50,500);
    devdes=DODevices+i;
    table[1]=(SENDDATAHead & 0x00F0)+SENDDEVDESCP; //发送子设备信息描述
    table[4]=size;
    memcpy((void*)(table+5), (void*)devdes, size);
    while(true)
    {
       if (AF_DataRequest( &GenericApp_DstAddr, &GenericApp_epDesc,
             GENERICAPP_CLUSTERID,
             5+size,//这个参数就是发送的数据的长度
             (void *)table,
             &GenericApp_TransID,
             AF_DISCV_ROUTE,
             AF_DEFAULT_RADIUS ) == afStatus_SUCCESS ) break;
       else
       {
         HalLedSet(HAL_LED_1, HAL_LED_MODE_TOGGLE); //LED指示一下
         //DelayMS(500); //稍微验收后重发
         HalLedBlink(HAL_LED_2,3,50,500);
       }
    }
    DelayMS(1000); //稍微延时
  }
  /*****************AI**************************/
  cnt=getdevicenumbers(deviceinfo->subdevices[AI]);  //AI子设备数量
  size=sizeof(devicedescription_t); //子设备信息描述结构体大小
  for (i=0;i   { 
    //HalLedSet(HAL_LED_2, HAL_LED_MODE_BLINK);
    //HalLedBlink(HAL_LED_2,3,50,500);
    devdes=AIDevices+i;
    table[1]=(SENDDATAHead & 0x00F0)+SENDDEVDESCP; //发送子设备信息描述
    table[4]=size;
    memcpy((void*)(table+5), (void*)devdes, size);
    while(true)
    {
       if (AF_DataRequest( &GenericApp_DstAddr, &GenericApp_epDesc,
             GENERICAPP_CLUSTERID,
             5+size,//这个参数就是发送的数据的长度
             (void *)table,
             &GenericApp_TransID,
             AF_DISCV_ROUTE,
             AF_DEFAULT_RADIUS ) == afStatus_SUCCESS ) break;
       else
       {
         HalLedSet(HAL_LED_1, HAL_LED_MODE_TOGGLE); //LED指示一下
         //DelayMS(500); //稍微验收后重发
         HalLedBlink(HAL_LED_2,3,50,500);
       }
    }
    DelayMS(500); //稍微延时
  }
    /*****************AI**************************/
  cnt=getdevicenumbers(deviceinfo->subdevices[AO]);  //AO子设备数量
  size=sizeof(devicedescription_t); //子设备信息描述结构体大小
  for (i=0;i   { 
    devdes=AODevices+i;
    table[1]=(SENDDATAHead & 0x00F0)+SENDDEVDESCP; //发送子设备信息描述
    table[4]=size;
    memcpy((void*)(table+5), (void*)devdes, size);
    while(true)
    {
       if (AF_DataRequest( &GenericApp_DstAddr, &GenericApp_epDesc,
             GENERICAPP_CLUSTERID,
             5+size,//这个参数就是发送的数据的长度
             (void *)table,
             &GenericApp_TransID,
             AF_DISCV_ROUTE,
             AF_DEFAULT_RADIUS ) == afStatus_SUCCESS ) break;
       else
       {
         HalLedSet(HAL_LED_1, HAL_LED_MODE_TOGGLE); //LED指示一下
         //DelayMS(500); //稍微验收后重发
         HalLedBlink(HAL_LED_2,3,50,500);
       }
    }
    DelayMS(500); //稍微延时
  }
}

3、收到监控平台数据指令的处理

static void GenericApp_MessageMSGCB( afIncomingMSGPacket_t *pkt )//接受处理函数
{
  uint8 buffer[120];
  uint16 addr;
  uint8 cmd;
  uint8 type;
  uint8 number;
  uint16 addrself;
  addrself=NLME_GetShortAddr();
  //需要根据具体硬件设计来修改该函数,有待完善....//
  switch ( pkt->clusterId )
  {
    case GENERICAPP_CLUSTERID:
        osal_memcpy(buffer,pkt->cmd.Data,pkt->cmd.DataLength); //获取应用数据
        //交互命令CMD协议定义,应用数据帧FF FX ADDR SIZE DATA
        //数据内容标识头=0xFFF0+CMD; 第3,4个字节为设备ID号
        //第5个字节SIZE为后面数据DATA的字节数
        //提取地址,验证地址码?可能是广播
        if(pkt->cmd.DataLength<6) return; //协议规定了至少6个字节
        if(buffer[0]!=0xFF || (buffer[1]>>4)!=0x0F) return;
        addr=buffer[2]+(buffer[3]<<8); //验证地址码?
        if (addrself!=addr && addr!=0xFFFF) return; //不是发给自己的,或者广播地址
        ProcessTempHumiData(buffer);
        break;
  }
}

void ProcessTempHumiData(uint8* buffer)
{
  uint16 addr;
  uint8 cmd;
  uint8 type;
  uint8 number;
  uint8 *data;
  //需要根据具体硬件设计来修改该函数,有待完善....//
  //交互命令CMD协议定义,应用数据帧FF FX ADDR SIZE DATA
  //数据内容标识头=0xFFF0+CMD; 第3,4个字节为设备ID号
  //第5个字节SIZE为后面数据DATA的字节数
  //提取地址,验证地址码?可能是广播
  cmd=buffer[1] & 0x0F;
  if (cmd==SENDDEVCTRLL)  // 3:控制子设备工作指令,P-->C-->E
  { //高3位:子设备类型,低五位:子设备编号0--15
    type=buffer[5]>>5;
    number=buffer[5]&0x1F;
    if (type==DO) //DO子设备
    {
      if(number==0)
      {
         //HalLedSet(HAL_LED_1,HAL_LED_MODE_TOGGLE);
         P1_0=buffer[6];
         buffer[1]=0xF0+SENDDEVSTATE;// 负责返回实际状态SENDDEVSTATE 2:发送子设备状态数据,E<-->C<-->P
         buffer[6]=P1_0; //查看接线图
         buffer[4]=2;    //两个字节的数据
         AF_DataRequest( &GenericApp_DstAddr, &GenericApp_epDesc,
                 GENERICAPP_CLUSTERID,
                 7,
                 buffer,
                 &GenericApp_TransID,
                 AF_DISCV_ROUTE,
                 AF_DEFAULT_RADIUS );
      }
      else if (number==1)
      {
         //HalLedSet(HAL_LED_2,HAL_LED_MODE_TOGGLE);
         P1_1=buffer[6];
         buffer[1]=0xF0+SENDDEVSTATE;// 负责返回实际状态SENDDEVSTATE 2:发送子设备状态数据,E<-->C<-->P
         buffer[6]=P1_1; //查看接线图
         buffer[4]=2;    //两个字节的数据
         AF_DataRequest( &GenericApp_DstAddr, &GenericApp_epDesc,
                 GENERICAPP_CLUSTERID,
                 7,
                 buffer,
                 &GenericApp_TransID,
                 AF_DISCV_ROUTE,
                 AF_DEFAULT_RADIUS );
      }
    }
    if (type==AO) //AO子设备
    {
      if(number==0) //调节采样周期
      {       
        data= (uint8 *)osal_mem_alloc(buffer[4]);//动态分配数据
        memset(data,0,buffer[4]);
        memcpy(data,&buffer[6],buffer[4]-1);
        addr=atoi(data);
        if (addr>=1000 && addr<=60000)
        {
          My_SEND_MSG_TIMEOUT=addr;
          osal_start_timerEx( GenericApp_TaskID,
                        GENERICAPP_SEND_MSG_EVT,
                        My_SEND_MSG_TIMEOUT);
         
          buffer[1]=0xF0+SENDDEVSTATE;// 负责返回实际状态SENDDEVSTATE 2:发送子设备状态数据,E<-->C<-->P
          AF_DataRequest( &GenericApp_DstAddr, &GenericApp_epDesc,
                 GENERICAPP_CLUSTERID,
                 buffer[4]+5,
                 buffer,
                 &GenericApp_TransID,
                 AF_DISCV_ROUTE,
                 AF_DEFAULT_RADIUS );         
        }       
        osal_mem_free(data);
      }
    }
  }
  else if (cmd==SENDDEVSTATE)// SENDDEVSTATE 2:发送子设备状态数据,E<-->C<-->P
  { //高3位:子设备类型,低五位:子设备编号0--15
    type=buffer[5]>>5;
    number=buffer[5]&0x1F;
    if (type==DO) //获取DO子设备状态
    {
      if(number==0)
      {
         buffer[6]=P1_0; //查看接线图
         buffer[4]=2;    //两个字节的数据
         AF_DataRequest( &GenericApp_DstAddr, &GenericApp_epDesc,
                 GENERICAPP_CLUSTERID,
                 7,
                 buffer,
                 &GenericApp_TransID,
                 AF_DISCV_ROUTE,
                 AF_DEFAULT_RADIUS );        
      }
      else if (number==1)
      {
         buffer[6]=P1_1; //查看接线图
         buffer[4]=2;    //两个字节的数据
         AF_DataRequest( &GenericApp_DstAddr, &GenericApp_epDesc,
                 GENERICAPP_CLUSTERID,
                 7,
                 buffer,
                 &GenericApp_TransID,
                 AF_DISCV_ROUTE,
                 AF_DEFAULT_RADIUS );     
      }
      else if (number==0x1F) //所有DO子设备状态
      {
         buffer[6]=P1_0; //查看接线图
         buffer[7]=P1_1; //查看接线图
         buffer[4]=3;    //3个字节的数据
         AF_DataRequest( &GenericApp_DstAddr, &GenericApp_epDesc,
                 GENERICAPP_CLUSTERID,
                 8,
                 buffer,
                 &GenericApp_TransID,
                 AF_DISCV_ROUTE,
                 AF_DEFAULT_RADIUS );     
      }
    }
    else if (type==AI) //获取AI子设备状态
    {
      if(number==0)
      {
        //GenericApp_Send_TempSensor_Message();       
      }
      else if (number==1)
      {
        //GenericApp_Send_LightSensor_Message();     
      }
      else if (number==0x1F) //所有AI子设备状态
      {
        GenericApp_Send_TempHumitureSensor_Message();     
      }
    }
    else if (type==AO) //获取AO 子设备状态:采样周期
    {
      if(number==0)
      {
         GenericApp_Send_Sample_Time();
      }
      else if (number==1)
      {
        //GenericApp_Send_LightSensor_Message();     
      }
      else if (number==0x1F) //所有A0子设备状态
      {
         GenericApp_Send_Sample_Time();
      }
    }
  }
}

   只要程序设计者,合理规划设备的功能,任何复杂的设备都可以统一监控。是不是很爽?就像上面例子的AO子设备,其实是一项功能,并没有实际的硬件电路支持(定时器除外)。需要详细工程项目案例的代码,请到http://www.ionfox.com.cn/ZigBeeDevice.zip下载查看运行。开发环境:IAR8.10.1

   祝你的设备哪里都可以用。



你可能感兴趣的:(智能家居,ZigBee,监控协议)