天天看點

TinyOS平台下一些代碼的分析



(一)資料采集子產品

底層-->高層

SHT->SHTData--> SensorCollection-->AtoSensorCollection-->ANTTreenetNode

  1. 資料傳輸子產品

    主要是AtosRoute

    節點 --------------------------->      基站

     AtosRouteC.SendData---------------->AtosRouteC.Intercept

    具體結構如下:

    1、發送部分

    App.AMSend -> AtosRouteC.SendData;(此處APP指節點程式)

    command error_t SendData.send(am_addr_t addr, message_t*msg, uint8_t len)

    {(中間省略大部分代碼)

    return call SubSendData.send(addr, msg, len);

    }

            components newAtosRouteSendC(ATOS_ROUTE_MSG_ID_DATA) as SendDataC;

            AtosRouteP.SubSendData -> SendDataC;

            AtosRouteP.ReceiveData -> SendDataC;

            components newAtosRouteSendP(AR_RESOURCE_ID, MSG_ID);

            AMSend = AtosRouteSendP;

        commanderror_t AMSend.send(am_addr_t addr, message_t* msg,                                                                uint8_t len)

        {atomic

        {RF_MSG_GET_ROUTE_RESOURCEID(msg)= AR_RESOURCE_ID;

        //存儲header->route_resource_id

        RF_MSG_GET_TYPE(msg)= MSG_ID;

        //存儲metadata->type

        returncall AtosRouteSend.send(addr, msg, len);

    }}

    components AtosRouteSendCenterC;

    AtosRouteSendP.AtosRouteSend->AtosRouteSendCenterC.AtosRouteSend[AR_RESOURCE_ID];

    components newAtosRouteSendQueueC(AR_RESOURCE_COUNT);

    AtosRouteSendCenterP.SubAtosRouteSend ->AtosRouteSendQueueC;

    #include "AtosRoute.h"

    generic module AtosRouteSendQueueP()//發送隊列,當中仍然接入了更加底層的剖面操作子產品、資料包處理操作、無線傳輸子產品等等,在結構叙述中我們将其視作發送子產品的底層,具體将在正文中進行分析

    但是為了結構的完整我們加入以下幾個更加底層的子產品

    AtosRouteEngineProfileP

    AtosRouteEngineProfileTableP(uint32_t FLASH_ADDR)

    這兩個底層的子產品的作用基本就是将資料寫入最後的FLASH_ADDR裡面了,這裡面的語句比較晦澀,直接針對引腳的操作比較多,如果電路設計要進行變更将更多的關注這兩個子產品,但是本文不對電路裝置進行更改,是以這兩個子產品就不在正文中進行分析贅述了。

    整理以上結構如下作為資料發送:

    高層-->底層

    ANTTreenetNode->AtosRoute->AtosRouteSend->AtosRouteSend(ATOS_ROUTE_MSG_ID_DATA)->AtosRouteSendCenter->AtosRouteSendQueue->AtosRouteEngineProfile->AtosRouteEngineProfileTable(uint32_tFLASH_ADDR)

    2、接收部分

    module ActiveMessageAddressC  {

    provides async command am_addr_t amAddress();

    provides async command void setAmAddress(am_addr_t a);

    }

    implementation {

    bool set = FALSE;

    am_addr_t addr;

    async command am_addr_t amAddress() {

    if (!set) {

    addr = TOS_NODE_ID;

    set = TRUE;

    }

    return addr;

    }

    async command void setAmAddress(am_addr_t a) {

    set = TRUE;

    addr = a;

    }}//最底層擷取位址子產品

        componentsActiveMessageAddressC;

        RfPacketP.ActiveMessageAddress-> ActiveMessageAddressC;

    configuration RfReliableMacPacketC

    {   providesinterface AMPacket;

    (省略)}

    implementation

    {(省略) 

    components RfPacketC;

        AMPacket=RfPacketC;

        SubPacket =RfPacketC;

    (省略)}

    configuration PlatformMacPacketC

    {   providesinterface AMPacket;

    (省略)}

    implementation

    {(省略)

        AMPacket =RfReliableMacPacketC.AMPacket;

    }

    configuration AtosRoutePacketC

    {   providesinterface AMPacket;

    (省略)}

    implementation

    {(省略)  componentsPlatformMacPacketC;

        AMPacket=PlatformMacPacketC;

    (省略)}

        command boolAtosRouteEngine.forwardDefault(message_t *msg)

        {

            return (!call AtosRouteEngine.isRoot());

        }//當AMPacket.address()與初始值不同時說明已經成功讀到了位址

        command boolAtosRouteEngine.isRoot()

        {

            return (call AMPacket.address() ==ATE_PROFILE_ROOT_ADDR);

        }//ATE_PROFILE_ROOT_ADDR的值為0x0001,此處用來判斷AMPacket.address()是否是初始值

    configuration AtosRouteEngineC

    {(省略)

        providesinterface AtosRouteEngine;

    }

    implementation

    {(省略)

            components AtosRouteEngineProfileC;

            AtosControl = AtosRouteEngineProfileC;

            AtosRouteEngine = AtosRouteEngineProfileC;

    (省略)}

    configuration AtosRouteC{(省略)}

    implementation

    {(省略)

        componentsAtosRouteEngineC;

        AtosRouteP.AtosRouteEngine-> AtosRouteEngineC;

    (省略)}

    configuration ANTTreenetBaseC{}

    implementation

    {(省略)

        componentsAtosRouteC;

        App.Intercept-> AtosRouteC;

    (省略)}

    整理以上結構如下作為資料接收:

    底層->高層

    ActiveMessageAddress->RfPacket->RfReliableMacPacket->PlatformMacPacket-> AtosRoutePacket->AtosRouteEngine->AtosRoute->ANTTreenetBase

  2. 總體架構
    TinyOS平台下一些代碼的分析

    圖七:ATOS樹狀網絡軟體構架

    大緻的架構如上圖所示,在如上的架構當中,有很大一部分不在我們環境監測這個課題範圍之内,都是一些資料格式的轉換,還有一些指針的操作,隻是為了架構的完整性羅列出來,不在正文當中贅述。而根據以上的架構我們可以做很多事情,根據不同的需求在不同的地方對程式稍加修改就可以實作各種各樣的功能。比如當傳感器因為老化或者其他原因産生系統誤差時,可以再SHTP.nc中加入一段誤差補償的程式。對于一些對極限值要求很敏感的場合,可以再ANTTreenetNodeP.nc當中直接發出動作,簡單的如用LED_BLUE_ON直接打開發光二極管,修改相應的電路将發光二極管更換成放大電路和警報器,這樣操作雖然增加了成本,但是節約了反應時間,适用于一些對時間精度要求較高的場合。

    對于一些運算量較大但要求在基站中直接完成的資料處理項目可以直接修改ANTTreenetBase.nc。根據這些不同的要求,以溫濕度傳感器為例,在SHTDataP.nc,ANTTreeNodeP.nc,ANTTreeBaseP等程式中加入了一些标簽,在正文中講詳細說明,然而在總結與展望當中将舉一個筆者認為具有一定普适性資料處理方案并将一些程式加入到這些标簽當中。而正文主要分析一些關鍵的程式和運作結果,實作的功能是以溫濕度為例進行實時的環境監測,并不對資料進行處理,相應的實驗結果通過序列槽助手SSCOM32進行監聽。

  1. 程式分析與設計

    基于TinyOS的例程:樹狀網絡通信例程進行修改的程式設計不同于自己從零開始的程式設計,需要花更多的時間熟悉整個系統的結構,并在其中找到切入點。因為硬體系統基本沒有變化,特别是通信部分,是以在那一部分就比較簡略的帶過,但是會詳細的介紹其中一些變量的含義,這是我們應用時候必須知道的,然而通信子產品當中還有一些複雜的資料結構的轉換對我們而言是沒有太大必要了解甚至換了一套裝置之後就完全不同的,那些程式将不作介紹。但是其中AtosRouteSendQueueP.nc檔案的算法,在檔案傳輸中的作用比較大,将拿出來進行介紹。然而程式的修改将主要在資料采集部分(對于高時間精度要求的項目而言),以及基站主程式ANTTreenetBaseP.nc,是以這兩部分會作詳細分析。

  1. SHTP.nc

    #include "SHT.h"

    module SHTP

    {    providesinterface Init;

        providesinterface SHT;

        uses interfaceTimer<TMilli> as WaitTimer;

    }

    implementation

    {#define SHT_NOACK     0

    #define SHT_ACK         1

    #define SHT_MODE_TEMP   0

    #define SHT_MODE_HUMI   1

                            //adr  command r/w

    #define SHT_STATUS_REG_W      0x06   //000   0011   0

    #define SHT_STATUS_REG_R       0x07   //000   0011   1

    #define SHT_MEASURE_TEMP       0x03   //000   0001   1

    #define SHT_MEASURE_HUMI       0x05   //000   0010   1

    #define SHT_RESET              0x1e   //000   1111   0

    #define DELAY_TICK(n)   {tick=(n);while (tick--);}

    enum

    {

        SHT_STATE_NONE,

        SHT_STATE_TEMP,

        SHT_STATE_HUMI,

    };

        uint8_t m_state =SHT_STATE_NONE;//工作狀态。

        uint8_t tick;//延時用計數器單元。

    uint8_t m_error =0;//錯誤标志。

        uint16_t m_temperature;//四位16進制溫度資料,經過轉換可以變成實型。

        uint16_t m_humidity;//四位16進制濕度資料,經過轉換可以變成實型。

        uint8_t m_checksum;//校驗碼。

        uint8_t *p_value;//發送監測資料的指針。

        task void readDoneTask();

        command error_t Init.init()

        {

            call WaitTimer.stop();

            m_state = SHT_STATE_NONE;

            return SUCCESS;

        }//初始化。

        uint8_t sendByte(uint8_tvalue)//按位輸出。

        {

            uint8_t i, error;

         SHT_DATA_OUT; 

    //#define SHT_DATA_OUT   MAKE_IO_PIN_OUTPUT(P1_DIR, 7)

         SHT_SCK_OUT;

    #define SHT_SCK_OUT    MAKE_IO_PIN_OUTPUT(P0_DIR, 4)

    //更改時鐘輸出引腳。

            for (i=0x80; i>0; i/=2)

            {

                if (i & value)

                { SHT_DATA = 1; }

                else

                {  SHT_DATA = 0; }

                SHT_SCK = 1;

                DELAY_TICK(3);

                SHT_SCK = 0;

            }

    //按位輸出value的值,每位sck的時間周期為3,資料從SHT_DATA口出,SHT_SCK作為時鐘信号。

            SHT_DATA = 1;

            SHT_SCK = 1;

            SHT_DATA_IN; //用SHT_DATA位(P0_5)來接收回報的信号。

            error = SHT_DATA;

            SHT_SCK = 0;

            return error;//傳回的信号SHT_DATA位(P0_5)應當為0,否則出錯。

        }

        uint8_t recvByte(uint8_t ack)//按位輸入。

        {   uint8_t i,val = 0;

            SHT_SCK_OUT;

            SHT_DATA_OUT;//輸出 DATA P0_5和 SCK P0_4的值。

            SHT_DATA = 1;//P0_5出高電平。

            SHT_DATA_IN;//P0_5輸入打開。

            for (i=0x80; i>0; i/=2)

            {  SHT_SCK = 1;

               DELAY_TICK(1);

                if (SHT_DATA)

                {

                    val = (val | i);

                }

               SHT_SCK = 0;

            }

    //SCK P0_4每輸出一個高電平,DATA P0_5讀入一位、按位讀入SHT_DATA的值到val中。

            SHT_DATA_OUT;

            SHT_DATA = !ack; //如果ack=1,SHT_DATA輸出的就是0 。              SHT_SCK = 1;                            //clk #9 for ack。

            DELAY_TICK(10);

    //輸出!ack的值,時長為10

            SHT_SCK = 0;

            SHT_DATA = 1;                          //release DATA-line。

            return val;//傳回值為讀到的資料。

        }

        uint8_t start()//通過SHT_DATA、SHT_SCK輸出标志電平來表示開始工作。

        {   SHT_DATA_OUT;

            SHT_SCK_OUT;

            SHT_DATA = 1;

            SHT_SCK = 0;

            //_nop_();

            DELAY_TICK(1);

            SHT_SCK = 1;

            //_nop_();

            DELAY_TICK(1);

            SHT_DATA = 0;

            //_nop_();

            DELAY_TICK(1);

            SHT_SCK = 0;

            DELAY_TICK(3);//_nop_();*3

            SHT_SCK = 1;

            //_nop_();

            DELAY_TICK(1);

            SHT_DATA = 1;

            //_nop_();

            DELAY_TICK(1);

            SHT_SCK = 0;

    //start電平:

    //輸出 時間   1 2  3  4 5  6  7 8  -

    //DATA P0_5  1  1 0  0  0 0  0  1  1

    //SCK  p0_4  0 1  1  0  0  0 1  1  0

        }

        void reset()

    // 通信重置:在開始通信之後,至少有9個SCK周期 DATA-line=1。

    //      _____________________________________________________         ________

        //DATA:                                                     |_______|

        //          _   _    _    _   _    _   _    _    _       ___     ___

        // SCK :__| |__| |__| |__| |__| |__| |__| |__| |__| |______|   |___|  |______

        {   uint8_t i;

            SHT_DATA_OUT;

            SHT_SCK_OUT;

            SHT_DATA = 1;

            SHT_SCK = 0;                    //初始狀态。

            for (i=0; i<9; i++)                  //9個SCK 周期  。    

     {      SHT_SCK = 1;

                DELAY_TICK(1);

                SHT_SCK = 0;

                DELAY_TICK(1);

            }

    //輸出上面給的重置電平。

            start();                  

    //輸出start電平。

        }

        void enableDataInt()

        {}

        void disableDataInt()

        {}//然而這兩個函數我也不知道用來幹什麼。

        uint8_t cmdReset()

        // 通過軟重置方式對傳感器進行重置 。

        {

            reset();              //輸出重置電平和開始電平。

            m_error +=sendByte(SHT_RESET);       //通過按位輸出SHT_RESET=0x1E=00011110電平方式對傳感器傳輸重置信号。

            return m_error;      //當傳感器沒有回報信号時認為重置失敗。

        }

            uint8_t cmdMeasure()

        // 溫濕度讀取指令的傳達。

    {   reset();

            start();                   //開始傳輸信号發送。

            if (m_state ==SHT_STATE_TEMP)

            {   //ADBG(1, "\r\nSHT temp");此處作輸出可以測試溫度檢測信号是否發送。

                p_value = (uint8_t*)(&m_temperature);//value指針指向溫度。

                m_error +=sendByte(SHT_MEASURE_TEMP);//通過按位發送000 0001 1至P0_5即SHT_DATA來向傳感器傳輸測試溫度的指令。

            }

            else

            {

                //ADBG(1, "\r\nSHThumi");此處作輸出可以測試濕度檢測信号是否發送。

                p_value = (uint8_t*)(&m_humidity);//value指針指向濕度。

                m_error +=sendByte(SHT_MEASURE_HUMI);//按位發送000 0010 1至P0_5即SHT_DATA來向傳感器傳輸測試濕度的指令。

            }//當傳感器沒有回報信号時認為指令發送失敗。

            if(m_error > 0)

            {

               post readDoneTask();//對上級發送讀取失敗的信号。

               return m_error;

            }

            callWaitTimer.startOneShot(SHT_TIMEOUT);//延遲300ms一次。

            return m_error;

        }

    event voidWaitTimer.fired()

    //通過定時器觸發的方式來向上層傳輸資料。

        {

           //ADBG(1, "\r\nWaitTimer.fired state=%d", ADBG_N(m_state));這個輸出可以用來測試定時器是否觸發。

            if(m_state == SHT_STATE_TEMP  ||  m_state == SHT_STATE_HUMI)

            {

               SHT_DATA_IN;

                if(SHT_DATA) m_error += 1; // 讀取逾時,傳感器仍在發送資料,判定出錯。

                if(m_error > 0)

                {  post readDoneTask();

                   return;

                }//出錯直接跳轉輸出出錯結果。

               //ADBG(1, "\r\nNO error");這個輸出可以用來檢測傳感器傳輸是否有錯誤發生,當沒有時輸出no error。

               *(p_value)  =recvByte(SHT_ACK);    //讀入高八位。

               *(p_value+1) = recvByte(SHT_ACK);   //讀入低八位  。                   m_checksum = recvByte(SHT_NOACK);  //讀入校驗位  。                if (m_state < SHT_STATE_HUMI)

                {   //ADBG(1, "\r\nSHT NEXT");與cmdMeasure中的輸出配合,可以用來檢測cmdMeasure是否觸發。

                    m_state++;

                    cmdMeasure();

                }//按順序讀溫度、濕度。

                else

                {  post readDoneTask();

                }//向上層傳遞成功取數的信号以及相應的結果。

            }

        }

        task void readDoneTask()

        {   error_t result = (m_error > 0) ? FAIL :SUCCESS;

            //ADBG(1,"\r\nreadDoneTask");

            atomic m_state =SHT_STATE_NONE;//重置m_state。

            signal SHT.readDone(result,m_temperature, m_humidity);//像上一層傳遞讀取成功或失敗以及相應的結果。

        }

    command error_tSHT.read()

    //可調用的讀數指令函數。

        {   //ADBG(1, "\r\nSHT state=%d",m_state);

            atomic

            {if (m_state != SHT_STATE_NONE)

             {if (m_state >=SHT_STATE_NONE  &&  m_state <= SHT_STATE_HUMI)

                    { return FAIL; }

                    m_state =SHT_STATE_NONE;

                }

                m_state =SHT_STATE_TEMP;

            }//當資料正在被别的程式讀取時直接輸出出錯。

           m_error = 0;

           cmdMeasure();//測量。

            returnSUCCESS;

        }

        defaultevent void SHT.readDone(error_t result, uint16_t temperature, uint16_thumidity) {}//在外部編輯的預設事件在這裡進行聲明。

    command voidSHT.calcRealValue(float *temperature, float *humidity, uint16_t raw_temperatue,uint16_t raw_humidity)

    //換算4位16進制原始資料為實型資料。

        {

                #define D1 -39.66    

                #define D2 +0.01     

                #define C1 -4.0

                #define C2 0.0405

                #define C3 -2.8E-6

                #define T1 0.01

                #define T2 0.00008

                float RH1;    

                *temperature = D1 + D2 * raw_temperatue;

                RH1 = C3*raw_humidity*raw_humidity +C2*raw_humidity + C1; 

                *humidity =(*temperature-25)*(T1+T2*raw_humidity) + RH1;  

        }

    }

    對SHTP.nc的分析可以将傳感器感測資料底層傳輸的各個引腳、傳輸方式(串行雙工)等基本特性充分的了解,當硬體系統變更之後可以在這裡作出相應的修改。尤其是對于一些可以通過數學方法進行補償的系統誤差可以作出相應的代碼寫進calcRealValue()函數中,這段代碼中用到的庫函數将附在附件當中,有重要的地方在文中直接給出注釋了。

  2. SHTDataP.nc

    module SHTDataP

    {   providesinterface SensorData; 

        usesinterface SHT;

    }//向上層提供接口SensorData,對下層使用接口SHT。

    implementation

    {   uint8_t*m_value;//指向溫濕度資料存放位址。

        uint8_tm_len;//資料長度。

        command error_tSensorData.read(uint8_t* p_value)

        {  

            m_value = p_value;

            return call SHT.read();

        }//調用SHT的主動讀取資料函數對資料進行讀取。

        event void SHT.readDone(error_t result,uint16_t temperature, uint16_t humidity)

    //溫濕度資料讀取成功,對其進行計算和顯示。

        {

    float temp,hum;

    ADBG(900,"\n\n\n1=====T&H GET=====1");

    ADBG(900, "\n\ntemperatureData = %04x\n", temperature);

    ADBG(900, "humidity Data =%04x\n", humidity);

    callSHT.calcRealValue(&temp, &hum, temperature, humidity);

    //調用SHT.calcRealValue()函數對溫濕度兩組四位十六進制資料進行轉化,使之成為能夠進行資料處理的實型資料。

    ADBG(900, "temp =%f\n", temp);

    ADBG(900, "hum =%f\n", hum);

    ADBG(900,"2=====T&H GET=====2");

           memcpy(m_value, &temperature, 2);

           memcpy((m_value + 2), &humidity, 2);

    //到這裡用memcpy函數将資料從緩存區取到m_value位址中資料才算是開始傳輸。

    ADBG(900,"DATATRANS1(FEEL->)p_value=%x\n\n\n",(int)m_value);

    //輸出資料此時的位址。

            m_len = 4;//溫濕度資料長度是定值4個比特。

            signal SensorData.readDone(m_value, m_len, result);

    //向上層傳遞資料。

        }

        default eventvoid SensorData.readDone(uint8_t* p_value, uint8_t len, error_t result) {}//SHT中聲明過的預設事件在這裡定義為空。

    }

    通過對這段代碼的解析我們不難發現,除了最上層、最底層和極少數中間層次的一些代碼比較複雜,算法比較值得推敲,中間這些代碼大多數是對已有的功能進行分類和整理,添加一些類似潤滑劑的功能,使那些功能适用于特定的場合。甚至此處僅有的一個輸出功能也是我自己加上去的。然而這些代碼對于整個結構的構成卻是極其關鍵的。下面這段程式更将這個性質展現出來。

  3. SensorCollection

    #include"SensorCollection.h"

    configurationSensorCollectionC

    {provides interfaceSensorCollection;

    }

    implementation

    {

        components SensorCollectionP;

        SensorCollection = SensorCollectionP;

        #ifdefined(ALL_ASO) || defined(ASO_TH)

        componentsSHTDataC;//溫濕度傳感子產品。

        SensorCollectionP.SensorData[SENSOR_ID_SHT]-> SHTDataC;

        #endif

        #ifdefined(ALL_ASO) || defined(ASO_T)

        componentsDS18B20DataC;//單線數字溫度傳感器子產品。

        SensorCollectionP.SensorData[SENSOR_ID_DS18B20]-> DS18B20DataC;

        #endif

        #ifdefined(ALL_ASO) || defined(ASO_BDT) 

        componentsBdtempDataC;//單闆目前溫度傳感器子產品。

        SensorCollectionP.SensorData[SENSOR_ID_BDTEMP]-> BdtempDataC;

        #endif

        #ifdefined(ALL_ASO) || defined(ASO_ALCOHOL) 

        componentsAlcoholDataC;//酒精傳感器子產品。

        SensorCollectionP.SensorData[SENSOR_ID_ALCOHOL]-> AlcoholDataC;

        #endif

        #ifdefined(ALL_ASO) || defined(ASO_LIGHT)

        componentsLightDataC;//光照傳感器子產品。

        SensorCollectionP.SensorData[SENSOR_ID_LIGHT]-> LightDataC;

        #endif

        #ifdefined(ALL_ASO) || defined(ASO_FLUX)

        componentsFLUXDataC;//流量傳感器子產品。

        SensorCollectionP.SensorData[SENSOR_ID_FLUX]-> FLUXDataC;

        #endif

        #ifdefined(ALL_ASO) || defined(ASO_BLOOD_PRESSURE)

        componentsBloodPressureDataC;//血壓傳感器子產品。

        SensorCollectionP.SensorData[SENSOR_ID_BLOODPRESSURE]-> BloodPressureDataC;

        #endif

        #ifdefined(ALL_ASO) || defined(ASO_ALTITUDE)

        componentsAltitudeDataC;//高度傳感器子產品。

        SensorCollectionP.SensorData[SENSOR_ID_ALTITUDE]-> AltitudeDataC;

        #endif

        #ifdefined(ALL_ASO) || defined(ASO_HOARE)

        componentsHoareDataC;//霍爾傳感器子產品。

        SensorCollectionP.SensorData[SENSOR_ID_HOARE]-> HoareDataC;

        #endif

        #ifdefined(ALL_ASO) || defined(ASO_RAIN)

        componentsRainDataC;//雨滴傳感器子產品。

        SensorCollectionP.SensorData[SENSOR_ID_RAIN]-> RainDataC;

        #endif

        #ifdefined(ALL_ASO) || defined(ASO_FIRE)

        componentsFireDataC;//火焰傳感器子產品。

        SensorCollectionP.SensorData[SENSOR_ID_FIRE]-> FireDataC;

        #endif

        #ifdefined(ALL_ASO) || defined(ASO_MAX_SOUND)

        componentsMaxSoundDataC;//最大分貝傳感器。

        SensorCollectionP.SensorData[SENSOR_ID_MAXSOUND]-> MaxSoundDataC;

        #endif

        #ifdefined(ALL_ASO) || defined(ASO_AD0)

        componentsnew AdcDataC(ADC_AIN0) as AdcDataC0;

        SensorCollectionP.SensorData[SENSOR_ID_AD0]-> AdcDataC0;

        #endif

        #ifdefined(ALL_ASO) || defined(ASO_AD1)

        componentsnew AdcDataC(ADC_AIN1) as AdcDataC1;

        SensorCollectionP.SensorData[SENSOR_ID_AD1]-> AdcDataC1;

        #endif

        #ifdefined(ALL_ASO) || defined(ASO_AD2)

        componentsnew AdcDataC(ADC_AIN2) as AdcDataC2;

        SensorCollectionP.SensorData[SENSOR_ID_AD2]-> AdcDataC2;

        #endif

        #ifdefined(ALL_ASO) || defined(ASO_AD3)

        componentsnew AdcDataC(ADC_AIN3) as AdcDataC3;

        SensorCollectionP.SensorData[SENSOR_ID_AD3]-> AdcDataC3;

        #endif

        #ifdefined(ALL_ASO) || defined(ASO_AD4)

        componentsnew AdcDataC(ADC_AIN4) as AdcDataC4;

        SensorCollectionP.SensorData[SENSOR_ID_AD4]-> AdcDataC4;

        #endif

        #ifdefined(ALL_ASO) || defined(ASO_AD5)

        componentsnew AdcDataC(ADC_AIN5) as AdcDataC5;

        SensorCollectionP.SensorData[SENSOR_ID_AD5]-> AdcDataC5;

        #endif

        #ifdefined(ALL_ASO) || defined(ASO_AD6)

        componentsnew AdcDataC(ADC_AIN6) as AdcDataC6;

        SensorCollectionP.SensorData[SENSOR_ID_AD6]-> AdcDataC6;

        #endif

        #ifdefined(ALL_ASO) || defined(ASO_AD7)

        componentsnew AdcDataC(ADC_AIN7) as AdcDataC7;

        SensorCollectionP.SensorData[SENSOR_ID_AD7]-> AdcDataC7;

        #endif

        #ifdefined(ALL_ASO) || defined(ASO_AD0_O)

        componentsnew AdcOffsetDataC(ADC_AIN0) as AdcDataC0_O;

        SensorCollectionP.SensorData[SENSOR_ID_AD0_O]-> AdcDataC0_O;

        #endif

        #ifdefined(ALL_ASO) || defined(ASO_AD1_O)

        componentsnew AdcOffsetDataC(ADC_AIN1) as AdcDataC1_O;

        SensorCollectionP.SensorData[SENSOR_ID_AD1_O]-> AdcDataC1_O;

        #endif

        #ifdefined(ALL_ASO) || defined(ASO_AD2_O)

        componentsnew AdcOffsetDataC(ADC_AIN2) as AdcDataC2_O;

        SensorCollectionP.SensorData[SENSOR_ID_AD2_O]-> AdcDataC2_O;

        #endif

        #ifdefined(ALL_ASO) || defined(ASO_AD3_O)

        componentsnew AdcOffsetDataC(ADC_AIN3) as AdcDataC3_O;

        SensorCollectionP.SensorData[SENSOR_ID_AD3_O]-> AdcDataC3_O;

        #endif

        #ifdefined(ALL_ASO) || defined(ASO_AD4_O)

        componentsnew AdcOffsetDataC(ADC_AIN4) as AdcDataC4_O;

        SensorCollectionP.SensorData[SENSOR_ID_AD4_O]-> AdcDataC4_O;

        #endif

        #ifdefined(ALL_ASO) || defined(ASO_AD5_O)

        componentsnew AdcOffsetDataC(ADC_AIN5) as AdcDataC5_O;

        SensorCollectionP.SensorData[SENSOR_ID_AD5_O]-> AdcDataC5_O;

        #endif

        #ifdefined(ALL_ASO) || defined(ASO_AD6_O)

        componentsnew AdcOffsetDataC(ADC_AIN6) as AdcDataC6_O;

        SensorCollectionP.SensorData[SENSOR_ID_AD6_O]-> AdcDataC6_O;

        #endif

        #ifdefined(ALL_ASO) || defined(ASO_AD7_O)

        componentsnew AdcOffsetDataC(ADC_AIN7) as AdcDataC7_O;

        SensorCollectionP.SensorData[SENSOR_ID_AD7_O]-> AdcDataC7_O;

        #endif

        #ifdefined(ALL_ASO) || defined(ASO_WM)

        componentsWaterMeterDataC;//水深。

        SensorCollectionP.SensorData[SENSOR_ID_WATER_METER]-> WaterMeterDataC;

        #endif

        #ifdefined(ALL_ASO) || defined(ASO_INC)

        componentsIncreasingDataC;//計數器。

        SensorCollectionP.SensorData[SENSOR_ID_INC]-> IncreasingDataC;

        #endif

        #ifdefined(ALL_ASO) || defined(ASO_INNER_TEMP)

        componentsInnerTemperatureDataC;//内部溫度。

        SensorCollectionP.SensorData[SENSOR_ID_INNER_TEMP]-> InnerTemperatureDataC;

        #endif

        #ifdefined(ALL_ASO) || defined(ASO_GPS)

        componentsGpsSensorC;//GSP。

        SensorCollectionP.SensorData[SENSOR_ID_GPS]-> GpsSensorC;

        #endif

        componentsMcuSleepC;

        McuSleepC.ModuleReset-> SensorCollectionP;

    }

        針對溫濕度傳感器而言,其實有一大段的接口在這裡并沒有連接配接上去,然而對整體結構來說這樣搭建是至關重要的,對于這個子產品而言,它的接口部分,就是檔案名以C結尾的代碼,比以P結尾的主程式更加重要。

    下面是對應的以P結尾的主程式:

    #include "SensorCollection.h"

    module SensorCollectionP

    {   providesinterface SensorCollection;

        providesinterface ModuleReset;

        uses interfaceSensorData[uint8_t id];

    }//提供接口SensorCollection和ModuleReset,使用接口SensorData。

    implementation

    {

        boolm_sensoring = FALSE;//感測資料是否已經抵達。

        uint8_t*m_sensor_data = NULL;//資料指針。

        uint8_tm_sensor_len = 0;//資料長度。

    uint8_t m_sensor_count = 0;//計數。

        uint8_tm_sensor_index = 0;//索引。

        sensor_id_t*m_sensors = NULL;

        boolisValidSensor(uint8_t index)

        {

            atomic

            {

                return(m_sensors != NULL  && (index< m_sensor_count));

            }

        }//判斷傳感器是否有效。

        uint8_tgetSensorOffset(uint8_t index)

    //擷取傳感器資料補償。

        {

            atomic

            {

                uint8_toffset = 0;

                uint8_ti =0;

                if(index > m_sensor_count)

                {

                    return 0;

                }//擷取失敗。

                for(i=0; i < index; ++i)

                {

                    offset += m_sensors[i].len;

                }//補償=之前的傳感器資料長度之和。

                returnoffset;

            }

        }

        task voidsensorEnd()

        {

            atomic

            {

                if(!m_sensoring)

                {

                    return;

                }

            }

            signalSensorCollection.sensorDone(m_sensor_data, getSensorOffset(m_sensor_count),SUCCESS);//向上傳遞傳感器資料和補償長度。

            atomic m_sensoring = FALSE;

        }

        task voidsensorNow()

    //讀數。

        {

            uint8_t sensor_id = 0;

            uint8_t sensor_offset = 0;

            atomic

            {

                if(!m_sensoring)

                {

                    return;

                }

                if( !isValidSensor(m_sensor_index) )

                {

                    post sensorEnd();

                    return;

                }//當不符合要求時直接傳送失敗的結果。

                sensor_id= m_sensors[m_sensor_index].id;//傳感器類型擷取。

                sensor_offset= getSensorOffset(m_sensor_index);//資料補償擷取。

            }

            if (callSensorData.read[sensor_id](m_sensor_data + sensor_offset) != SUCCESS)

            {

                atomicm_sensor_index++;

                postsensorNow();

            }//讀取失敗時直接對下一個資料進行讀取,當這個資料是最後一個資料時,通過對索引的自加使索引超出長度進而判定讀數失敗,讀數成功時資料存放至位址m_sensor_data + sensor_offset為首的,以len為長度的空間中。

        }

        command error_tSensorCollection.startSensor(uint8_t* data, sensor_id_t* sensor, uint8_tcount)//提供可調用的指令函數,初始化傳感器。

        {

            atomic

            {

                m_sensor_data= data;//确定資料的存放位置。

                m_sensor_count= count;//确定資料個數。

                m_sensors= sensor;//确定傳感器類型。

                m_sensor_index= 0;

                m_sensoring= TRUE;

                postsensorNow();//從第0個資料開始讀數。

            }

            return SUCCESS;

        }

        event voidSensorData.readDone[uint8_t id](uint8_t* p_value, uint8_t len, error_tresult)//定義SensorData中聲明過的預設事件readDone。

        {

            atomic

            {

                if(!m_sensoring)

                {

                    return;

                }

                m_sensor_index++;

            }

            post sensorNow();//按順序讀數。

        }

        default eventvoid SensorCollection.sensorDone(uint8_t* data, uint8_t len, error_t result) {}//聲明預設的外部定義事件。

        default commanderror_t SensorData.read[uint8_t id](uint8_t* p_value)

        {

            return FAIL;

        }//定義SensorData中聲明的預設指令。

        command error_tModuleReset.reset(uint8_t reset_level)

        {

            atomic

            {

                m_sensoring= FALSE;

                returnSUCCESS;

            }

        }//定義ModuleReset中聲明的指令。

    }

    然而實際上資料在SensorData當中就已經讀出來了。這個程式就是對不同的SensorData讀出的資料進行總結和整理。然而對于已知類型的傳感器應用項目可以跳過這個程式直接接入相應的SensorData。但是對于這個整個樹狀傳感網絡而言,這個程式非常重要。對于傳感器類型是從外部定義而非自檢測的這一瑕疵,我們的程式是寫在節點上的,然而在我們的硬體結構中一個節點隻能有一種類型的傳感器,是以不會産生沖突。雖然确實提供了多類型傳感資料上傳的機制,然而其實并沒有什麼用。對于多類型傳感器構成節點的系統中,這個程式是有問題的,它是按照溫濕度、單線數字溫度……GSP的順序一個一個地執行相應的SensorData,而對應的SensorData再到底層去根據引腳上的序列槽輸入的資料進行分析得到的資料,然而不同的SensorData并沒有區分序列槽輸入的資料是什麼類型傳感器産生的,他們隻是單純的處理資料,是以這裡就需要對底層的程式進行修改,方式可以是通過不同引腳對不同的類型傳感器讀數或者設定不同的start電平等等。

  4. AtoSensorCollectionP.nc

    #include "SensorCollection.h"

    module AtoSensorCollectionP

    {

        providesinterface AtoSensorCollection;

        usesinterface SensorCollection;

    }

    implementation

    {

        sensor_id_t  sensors[] =

        {

            #ifdef ASO_TH

                {SENSOR_ID_SHT,SENSOR_LEN_SHT},

            #endif

            (省略)

                {255,255}

        };//通過外部指令define的ASO類型來确定相應的傳感器類型

        #definesensor_count  (sizeof(sensors) /sizeof(sensors[0]) - 1)

        command error_tAtoSensorCollection.startSensor(uint8_t* data)

        {

            return callSensorCollection.startSensor(data, sensors, sensor_count);

        }//向下傳遞資料存放位址、傳感器類型和傳感器個數

        event void SensorCollection.sensorDone(uint8_t*data, uint8_t len, error_t result)

        {

            signal AtoSensorCollection.sensorDone(data,len, result);

        }//直接将SensorCollection中讀到的資料上傳

        default eventvoid AtoSensorCollection.sensorDone(uint8_t* data, uint8_t len, error_t result){}

    }

  5. ANTTreenetNodeP.nc

    #include "AtosRoute.h"

    #define DBG_LEV 100

    module ANTTreenetNodeP

    {

        uses {

            interface Boot;

            interface AtosControl as AtosNetControl;

            interface AMPacket;

            interface Packet;

            interface PacketEx;

            interface AtoSensorCollection;

            interface AMSend;

            interface Timer<TMilli> asSensorTimer;

            interface StdControl as SystemHeartControl;

        }

    }

    implementation

    {

        message_tm_sensor_msg;//标準格式的資訊資料。

        uint8_tm_sensor_length = 0;//長度。

        uint8_t*p_sensor_payload;//傳感器資料。

        uintsensor_retry = 0;//重新開機次數。

        boolm_sensoring = FALSE;//取數完成标志位。

        uint16_ttemperature,humidity;//四位16進制溫濕度資料。

        task voidenableSensor()

        {

            callSensorTimer.startPeriodic(CONFIG_SENSOR_RATE);

        }//通過定時器方式定時周期性開啟傳感器,在makefile中設定,此處為1000ms。

        task void disableSensor()

        {

            call SensorTimer.stop();

        }//通過關閉定時器停止傳感器取數。

        task void sensorDataTask()

        {   error_t result;

            result = call AtoSensorCollection.startSensor(p_sensor_payload);

    //取數。

            if(result != SUCCESS)

            {  

                if(sensor_retry++ < 3)

                {

                    post sensorDataTask();

                }

                else

                {

                    atomic m_sensoring = FALSE;

                }

            }

        }//取數失敗重試3次,都不成功則确定失敗。

        event voidBoot.booted()

    //主函數、初始化。

        {

            uint8_t *data_header;

            ADBG(DBG_LEV, "\r\n============Boot.booted ==========\r\n");

    //輸出啟動标志。

            //call SystemHeartControl.start();開啟監控系統,這裡為了在序列槽助手SSCOM32中得到的輸出更加的簡潔,将其關閉。

            data_header = (uint8_t *)callPacket.getPayload(&m_sensor_msg, NULL);

            data_header[0] = ANT_NODE_TYPE;

            //确定傳輸資料包的標頭位址,并将節點類型寫入資料包的第一位。

            p_sensor_payload = data_header + 1;

            call AtosNetControl.start();

            post enableSensor();

    //從資料包的第二位開始寫入傳感器傳輸來的資訊。

        }

        event voidSensorTimer.fired()

    //通過定時器觸發資料采集。

        {   ADBG(DBG_LEV, "\n\n====== SensorTimerfired  %d======\r\n",(int)m_sensoring);//輸出定時器觸發标志。    

            atomic

            {   if(m_sensoring) return;

                m_sensoring= TRUE;

            }//取數完成時直接跳回,不進行取數。

            sensor_retry = 0;

            post sensorDataTask();

    //取數未完成時,更改取數完成标志,重置取數次數并啟動取數功能。

        }

        task voidsendMsgTask()

    //資訊發送。

        {   uint8_t i;

            LED_BLUE_TOGGLE;//改變藍色LED燈的明暗狀态。

            ADBG1(DBG_LEV, "\nsensorpayload:");

            for (i=0; i < m_sensor_length; ++i)

            {

                ADBG(DBG_LEV,"%02x ", (int)p_sensor_payload[i]);

            }//用%02x格式分别輸出采集到的資料。

            if (call AMSend.send(0x0001, &m_sensor_msg, m_sensor_length + 1) !=SUCCESS)//增加一位傳感器類型。

            {

                atomicm_sensoring = FALSE;

            }//資訊傳輸失敗時将取數完成标志置為未完成,進而進行重新取數。

        }

        event voidAtoSensorCollection.sensorDone(uint8_t* data, uint8_t len, error_t result)

    //對AtoSensorCollection聲明過的sensorDone進行定義。

        {   float temp,hum;

           memcpy(&temperature,(p_sensor_payload),2);

           memcpy(&humidity,(p_sensor_payload+2),2);

    temp=-39.66+0.01*temperature;

    hum=(temp-25)*(0.01+0.00008*(humidity))+(-2.8E-6)*(humidity)+0.0405    *(humidity)-4.0;

    //對取到的資料進行簡單處理,使之成為相應的4位16進制資料以及能夠用來進行計算的實型資料。

            ADBG(DBG_LEV,"\n\n\nDATATRANS2(->>>>>>>>NNNNNNNODE)p_value=%x",(int)p_sensor_payload);

    //輸出資料傳輸進入節點的标志,并輸出存放的位址

            ADBG(DBG_LEV, "\n\ntemperature Data = %04x\n", temperature);

            ADBG(DBG_LEV, "humidity Data =%04x\n", humidity);

    //輸出4位16進制格式的資料。

    ADBG(900, "temp = %f\n", temp);

    ADBG(900, "hum = %f\n", hum);

    //輸出實型格式資料。

    ADBG(DBG_LEV, "Sensor data done, data len = %d,result=%d\n\n\n", (int)len, (int)result);//輸出資料長度和采內建功标志。

    if(result == SUCCESS)

            {

                m_sensor_length= len;

                postsendMsgTask();

            }

            else

            {

                atomicm_sensoring = FALSE;

            }//資料采內建功時對資料進行傳輸,采集失敗時将取數完成标志置為未完成,進而進行重新取數。

            m_sensoring = FALSE;

        }

        event voidAMSend.sendDone(message_t* msg, error_t err)

        {ADBG(DBG_LEV,"\n\n\nDATATRANS3(NODE->>>>>>>>)msg=%x\n\n\n",(int)msg);

    //資料傳送結束時輸出資料從節點送出的标志。

            atomic m_sensoring = FALSE;

        //将取數完成标志置為未完成,進而進行重新取數。

    }}

  6. AtosRouteSendQueueP.nc

    #include "AtosRoute.h"

    generic module AtosRouteSendQueueP()

    //資料發送隊列。

    {

        providesinterface AtosControl;

        providesinterface AtosRouteSend;

        uses interfaceQueueEx<message_t *> as SendQueue;

        uses interfaceAtosRouteSend as SubAtosRouteSend;

        uses interfaceAMPacket;

        uses interfacePacket;

    }

    implementation

    {

        bool m_sending =FALSE;//發送完成标志位。

        task voidsendNext()

        {

            message_t *msg;

            MSG_HEADER_T *header;

            atomic

            {   if(m_sending) return;//資料發送完成标志位為真時直接傳回。

                if(call SendQueue.empty())

                {   return;    }//資料發送隊列為空時直接傳回。

                msg= call SendQueue.dequeue();//出隊操作。

                if( call SubAtosRouteSend.send(

                        callAMPacket.destination(msg), msg, call Packet.payloadLength(msg)

                    ) == SUCCESS)

                {

                    atomic m_sending = TRUE;

                }//發送成功,将資料發送完成标志位置1.

                else

                {   signal AtosRouteSend.sendDone(msg,ERR_ROUTE_SEND_QUEUE_FAIL);

                    atomic m_sending = FALSE;

                    post sendNext();

                }//發送失敗,向上傳送失敗的結果,并傳送隊列中的下一個資訊。

            }

        }

        intindexOfMessage(uint8_t route_resource_id)

        {

            atomic

            {

                uint8_ti;

                uint8_tsize = call SendQueue.size();//取隊列長度。

                for(i=0; i < size; ++i)

                {   message_t *msg = (message_t *)callSendQueue.element(i);                    if((msg != NULL) && (RF_MSG_GET_ROUTE_RESOURCEID(msg) ==route_resource_id))

                    {

                        returni;

                    }

                }//逐個尋找對應的資訊,找到時傳回序号。

                return-1;

            }//未找到傳回-1。

        }

        error_tenqueueMessage(message_t *msg)

    //入隊操作。

        {   atomic

            {   if(indexOfMessage( RF_MSG_GET_ROUTE_RESOURCEID(msg) ) >= 0)

                {   return ERR_ROUTE_SEND_QUEUE_EXISTS;

                }//有相同資料存在于隊列中,傳回相同資料已存在錯誤。

                if(call SendQueue.enqueue(msg) != SUCCESS)

                {   return ERR_ROUTE_SEND_QUEUE_FULL;

                }//入隊。失敗時傳回隊列溢出錯誤。

                postsendNext();//繼續發送操作。

                returnSUCCESS;

            }

        }

        event voidSubAtosRouteSend.sendDone(message_t *msg, error_t result)

    //定義SubAtosRouteSend中聲明的事件sendDone。

        {   atomic

            {   if(!m_sending) return; }//如果發送未完成直接傳回。

            signal AtosRouteSend.sendDone(msg, result);

    //向上傳送資料傳輸完成标志msg, result。

            atomic m_sending = FALSE;

            post sendNext();//繼續發送操作。

        }

        commanderror_t AtosRouteSend.send(am_addr_t addr, message_t *msg, uint8_t len)

        {//向上層提供資料發送功能。

            atomic

            {   returnenqueueMessage(msg); }//入隊,等待發送。

        }

        default eventvoid AtosRouteSend.sendDone(message_t *msg, error_t result)

        {//聲明預設事件AtosRouteSend.sendDone。

        }

        boolm_started = FALSE;

        commanderror_t AtosControl.start()

        {   atomic

            {   m_sending= FALSE;

                callSendQueue.clear();//清空隊列。

                m_started = TRUE;

                returnSUCCESS;

            }

        }//啟動發送。

        command error_tAtosControl.stop()

        {

            atomic

            {

                m_started= FALSE;

                m_sending= FALSE;

                callSendQueue.clear();//隊列清空。

                returnSUCCESS;

            }

        }//關閉發送。

        command boolAtosControl.isStarted()

        {

            atomic return m_started;

        }//判斷發送是否啟動。

    }

    這個程式在資料傳輸子產品中比較有代表性,它運用到了消息隊列的方式,通過消息隊列來對要發送的消息進行查重等操作,上層穿過來的資料通過入隊和出隊操作進出緩存區。

  7. ANTTreenetBaseP.nc

    #include "message.h"

    #include "AtosRoute.h"

    #include "AtpCmdPacket.h"

    #define DBG_LEV 20

    module ANTTreenetBaseP

    {   uses

        {   interface Boot;

            interface AMPacket;

            interface Packet;

            interface PacketEx;

            interface AtosControl as AtosNetControl;

            interface Intercept;

            interface AtpCmdComm;

            interface StdControl as SystemHeartControl;

        }

    }

    implementation

    {   message_tm_msg;

        message_tcmd_msg;

        task voidinitTask()

        {   call AtosNetControl.start();

        }//啟動傳感網絡控制。

        event voidBoot.booted() {

            ADBG(100,"#########Boot.bootedmyaddr=%x#########\n", (int)call AMPacket.address());//輸出開始标志,以及資料包位址。

            call SystemHeartControl.start();//開啟監控系統。

            post initTask();//打開傳感網絡控制。

        }

        uint16_tprepareReport(message_t * msg, uint8_t *report, atosroute_data_header_t*data_header, void *_payload, uint16_t len)

        {//資料彙總。

            struct

            {   uint16_t  sensor_type;

                uint16_tsource;

                uint16_torg;

                uint16_tseq;

                uint8_thopcount;

            } payload_head;//資料頭格式定義。

            uint8_t *payload = (uint8_t *)_payload;//資料位址。

            uint8_t payload_len = len - 1;//資料長度。

    float temp,hum; //實型溫濕度資料。

    uint16_ttemperature,humidity;//4位16進制溫濕度資料

            if (len < 1)

            {   return0;         }//未收到資料,直接傳回。

            // payload中最開始的一位是傳感器類型。

            payload_head.sensor_type = payload[0];

            payload_head.org = data_header->orgi_addr;

            payload_head.source =data_header->second_addr;

            if (payload_head.source == 0)

            {   payload_head.source= payload_head.org;   }

            payload_head.seq = 0xff02;

            payload_head.hopcount =data_header->hop_real;

            // 将整理好的資料頭寫入report。

            memcpy(report, &payload_head, sizeof(payload_head));

            // 跳過傳感器類型,将資料寫入report。

            memcpy_so(report, sizeof(payload_head), 128, payload + 1, payload_len);

           memcpy(&temperature, (payload + 1),2);

           memcpy(&humidity,(payload + 3),2);

    temp=-39.66+0.01*temperature;

    hum=(temp-25)*(0.01+0.00008*(humidity))+(-2.8E-6)*(humidity)+0.0405*(humidity)-4.0;

        ADBG(DBG_LEV,"\n\n\n DATATRANS4(->>>>>>>>>>BBBBBBASE)payload=%x\n",(int)payload);

        ADBG(DBG_LEV,"len=%d\n",(int)len);

    //輸出資料傳輸進入基站的标志,并輸出存放的位址,以及資料長度。

    ADBG(DBG_LEV, "\n\ntemperature Data = %04x\n",temperature);

    ADBG(DBG_LEV, "humidity Data = %04x\n",humidity);

    //輸出4位16進制格式的資料。

    ADBG(900, "temp = %f\n", temp);

    ADBG(900, "hum = %f\n", hum);

    //輸出實型格式資料。

            return len + sizeof(payload_head) - 1;//傳回report長度。

        }

        event boolIntercept.forward(message_t* msg, void* payload, uint16_t len){//資料接收。

            uint8_t i;

            uint8_t report_payload[128];

            uint16_t report_len;

            atp_cmd_packet_t cmd_packet;

            atosroute_data_header_t *data_header =(atosroute_data_header_t *)call PacketEx.getPacketHeader(msg);//資料頭位址。

            cmd_packet.cmd = 0x2430;//硬體型号。

            cmd_packet.len = prepareReport(msg,cmd_packet.data, data_header, payload, len);//整理資料到report中。

            callAtpCmdComm.sendCmdPacket(&cmd_packet);//打開協定轉換子產品。

            LED_BLUE_TOGGLE;//藍色LED燈明暗狀态改變。

            return FALSE;

        }

        event voidAtpCmdComm.sendCmdPacketDone(atp_cmd_packet_t *packet, error_t error) {   }

        event voidAtpCmdComm.receivedCmdPacket(atp_cmd_packet_t *packet, error_t error) {    }//定義協定轉換子產品中聲明的事件。

    }

能看完的都是棒棒的,但是文章裡應該有很多地方是有問題的,因為是三年前寫的東西了,希望大家批評,我會修改的,O(∩_∩)O謝謝!

繼續閱讀