【DWM1000】 code 解密6一TAG 狀態機第一步

 

咱們前面分析過,不論ANCHOR 仍是TAG,前面變量的初始化基本都是同樣的,只是狀態機必須明確區分不一樣的設備類型。咱們從開始看TAG。因爲初始化TAG的 testAppState同樣初始化爲TA_INIT。app

    INST_STATES testAppState ;             int instance_init_s(int mode) TA_INIT函數

 

     case TA_INIT :ui

            // printf("TA_INIT") ;this

            switch (inst->mode)spa

            {ssr

                case TAG:事件

                {ip

                         int mode = 0;ci

 

                    dwt_enableframefilter(DWT_FF_DATA_EN | DWT_FF_ACK_EN); //allow data, ACK frames;get

                    inst->frameFilteringEnabled = 1 ;

                    dwt_setpanid(inst->panid);

                    dwt_seteui(inst->eui64);

#if (USING_64BIT_ADDR==0)

                                         //the short address is assigned by the anchor

#else

                    //set source address into the message structure

                    memcpy(&inst->msg.sourceAddr[0], inst->eui64, ADDR_BYTE_SIZE_L);

#endif

 

                    //change to next state - send a Poll message to 1st anchor in the list

                    inst->mode = TAG_TDOA ;

                    inst->testAppState = TA_TXBLINK_WAIT_SEND;

                                         memcpy(inst->blinkmsg.tagID, inst->eui64, ADDR_BYTE_SIZE_L);

 

                    mode = (DWT_LOADUCODE|DWT_PRESRV_SLEEP|DWT_CONFIG|DWT_TANDV);

 

                                               if((dwt_getldotune() != 0)) //if we need to use LDO tune value from OTP kick it after sleep

                                               {

                                                        mode |= DWT_LOADLDO;

                                               }

 

                                               if(inst->configData.txPreambLength == DWT_PLEN_64)  //if using 64 length preamble then use the corresponding OPSet

                                               {

                                                        mode |= DWT_LOADOPSET;

                                               }

#if (DEEP_SLEEP == 1)

                    if (inst->sleep_en)

                        dwt_configuresleep(mode, DWT_WAKE_WK|DWT_WAKE_CS|DWT_SLP_EN); //configure the on wake parameters (upload the IC config settings)

#endif

 

                }

                break;

 

   dwt_enableframefilter(DWT_FF_DATA_EN | DWT_FF_ACK_EN); //allow data, ACK frames;

    inst->frameFilteringEnabled = 1 ;

控制濾波器,只接受DATA 和ACK數據,而且將frameFilteringEnabled 設置爲1. 主要這個不TAG的frameFilteringEnabled,與前面的ANCHOR的frameFilteringEnabled 是一個東西,可是賦值分爲兩個,由於是兩份代碼分別跑在兩個模塊中。

    dwt_setpanid(inst->panid);

                    dwt_seteui(inst->eui64);

Panid 和 64位地址設定,與ANCHOR同樣。

#if (USING_64BIT_ADDR==0)

                                         //the short address is assigned by the anchor

#else

                    //set source address into the message structure

                    memcpy(&inst->msg.sourceAddr[0], inst->eui64, ADDR_BYTE_SIZE_L);

#endif

因爲短地址尚未,因此msg.sourceAddr目前只能是64位長地址。

    inst->mode = TAG_TDOA ;

這個mode以前沒有用過,咱們先記錄下,之後確定會用到TAG_TDOA

inst->testAppState = TA_TXBLINK_WAIT_SEND;

這個testAppState記錄上,下次進去testapprun_s 找做案現場用

  memcpy(inst->blinkmsg.tagID, inst->eui64, ADDR_BYTE_SIZE_L);

又一個變量被設置,咱們先記錄,後面用的時候查看, 這裏保存了TAG的長地址

     mode = (DWT_LOADUCODE|DWT_PRESRV_SLEEP|DWT_CONFIG|DWT_TANDV);

 

                                               if((dwt_getldotune() != 0)) //if we need to use LDO tune value from OTP kick it after sleep

                                               {

                                                        mode |= DWT_LOADLDO;

                                               }

 

                                               if(inst->configData.txPreambLength == DWT_PLEN_64)  //if using 64 length preamble then use the corresponding OPSet

                                               {

                                                        mode |= DWT_LOADOPSET;

                                               }

mode是個變量,給這個mode 賦了不少值

#if (DEEP_SLEEP == 1)

                    if (inst->sleep_en)

                        dwt_configuresleep(mode, DWT_WAKE_WK|DWT_WAKE_CS|DWT_SLP_EN); //configure the on wake parameters (upload the IC config settings)

#endif

 

                }

                break;

若是咱們沒有使用sleep,前面mode都感受沒有用了,mode主要做用是告訴chip醒來之後須要恢復那些量,咱們先不具體分析了。如今break了,和ANCHOR同樣,返回值爲0,符合while條件會再次跳入到testapprun_s。

 

咱們根據上面的testAppState = TA_TXBLINK_WAIT_SEND;再次找做案現場

        case TA_TXBLINK_WAIT_SEND :

            {

                                     int flength = (BLINK_FRAME_CRTL_AND_ADDRESS + FRAME_CRC);

 

                //blink frames with IEEE EUI-64 tag ID

                inst->blinkmsg.frameCtrl = 0xC5 ;

                inst->blinkmsg.seqNum = inst->frame_sn++;

 

                                     dwt_writetxdata(flength, (uint8 *)  (&inst->blinkmsg), 0) ; // write the frame data

                                     dwt_writetxfctrl(flength, 0);

 

 

                                     //using wait for response to do delayed receive

                                     inst->wait4ack = DWT_RESPONSE_EXPECTED;

 

                                     dwt_setrxtimeout((uint16)inst->fwtoTimeB_sy);  //units are symbols

                                     //set the delayed rx on time (the ranging init will be sent after this delay)

                                     dwt_setrxaftertxdelay((uint32)inst->rnginitW4Rdelay_sy);  //units are 1.0256us - wait for wait4respTIM before RX on (delay RX)

 

                                     dwt_starttx(DWT_START_TX_IMMEDIATE | inst->wait4ack); //always using immediate TX and enable dealyed RX

 

                                     inst->instToSleep = 1; //go to Sleep after this blink

                inst->testAppState = TA_TX_WAIT_CONF ; // wait confirmation

                inst->previousState = TA_TXBLINK_WAIT_SEND ;

                inst->done = INST_DONE_WAIT_FOR_NEXT_EVENT; //will use RX FWTO to time out (set below)

 

            }

            break ; // end case TA_TXBLINK_WAIT_SEND

 

其中以下幾步是DWM1000 代碼中發送數據的基本流程

dwt_writetxdata(flength, (uint8 *)  (&inst->blinkmsg), 0) ;

dwt_writetxfctrl(flength, 0);

dwt_setrxtimeout((uint16)inst->fwtoTimeB_sy);  //units are symbols

dwt_setrxaftertxdelay((uint32)inst->rnginitW4Rdelay_sy);

dwt_starttx(DWT_START_TX_IMMEDIATE | inst->wait4ack);

 

 

發送了一個數據包,數據包的內容爲

inst->blinkmsg.frameCtrl = 0xC5 ;

inst->blinkmsg.seqNum = inst->frame_sn++;

 

其中還求必須有迴應

//using wait for response to do delayed receive

inst->wait4ack = DWT_RESPONSE_EXPECTED;

發送完延時打開接收器(設定rx接收timeout以及打開接收器的時間)

dwt_setrxtimeout((uint16)inst->fwtoTimeB_sy);  //units are symbols

dwt_setrxaftertxdelay((uint32)inst->rnginitW4Rdelay_sy);

 

設定了一些變量,有些仍是很重要的。

inst->instToSleep = 1; //go to Sleep after this blink

inst->testAppState = TA_TX_WAIT_CONF ; // wait confirmation

inst->previousState = TA_TXBLINK_WAIT_SEND ;

inst->done = INST_DONE_WAIT_FOR_NEXT_EVENT; //will use RX FWTO to time out (set below)

 

一樣根據inst->testAppState = TA_TX_WAIT_CONF ; 找下次進去testapprun_s 的做案現場。

 

到如今爲止,咱們分析代碼發現,ANCHOR在等TAG發數據,如今TAG給它發送了,ANCHOR應該會收到數據了,而TAG依然會接着執行。 咱們先看TAG,而後在看ANCHOR。 記住目前的狀態是ANCHOR準備接收數據了。

 

接着看TAG,退出testapprun_s時,done爲INST_DONE_WAIT_FOR_NEXT_EVENT;

 

 

    if(done == INST_DONE_WAIT_FOR_NEXT_EVENT_TO) //we are in RX and need to timeout (Tag needs to send another poll if no Rx frame)

    {

        if(instance_data[instance].mode == TAG_TDOA)

        {

                  instance_data[instance].instancetimer += instance_data[instance].tagBlinkSleepTime_ms; //set timeout time

            instance_data[instance].instancetimer_en = 1; //start timer

        }

        instance_data[instance].stoptimer = 0 ; //clear the flag - timer can run if instancetimer_en set (set above)

        instance_data[instance].done = INST_NOT_DONE_YET;

看後面的註釋,目前TAG發送一筆Blink信號後,確實有個延時打開接收器的動做,因此說確實如今是RX狀態。

if(done == INST_DONE_WAIT_FOR_NEXT_EVENT_TO) //we are in RX and need to timeout

咱們再看看INST_DONE_WAIT_FOR_NEXT_EVENT_TO 這個宏定義,能夠看出須要等待一個timeout,就知道if判斷裏面是開啓定時器,等待一段時間了

#define INST_DONE_WAIT_FOR_NEXT_EVENT_TO    2   //this signifies that the current event has been processed and that instance is waiting for next one with a timeout

//which will trigger if no event coming in specified time

咱們再來分析定時器代碼,由於咱們前面分析,TAG如今的mode是TAG_TDOA,因此摘錄出其對應的代碼

        if(instance_data[instance].mode == TAG_TDOA)

        {

            instance_data[instance].instancetimer += instance_data[instance].tagBlinkSleepTime_ms; //set timeout time

            instance_data[instance].instancetimer_en = 1; //start timer

        }

        instance_data[instance].stoptimer = 0 ;

 //clear the flag - timer can run if instancetimer_en set (set above)

        instance_data[instance].done = INST_NOT_DONE_YET;

咱們標註顏色的兩個變量,咱們搜索一下以前是否有初始化

uint32       instancetimer;                  

// e.g. this timer is used to timeout Tag when in deep sleep so it can send the next poll message

int tagBlinkSleepTime_ms; instancesettagsleepdelay  1000

咱們沒有看到instancetimer的初始化,咱們暫時考慮它爲0,可是tagBlinkSleepTime_ms 是1000,因此經過第一句賦值語句instancetimer 等於1000了。

其它幾個變量instancetimer_en和stoptimer 立馬會用到,注意一下done此時被賦值爲INST_NOT_DONE_YET,這裏也記錄一下,後面看怎麼走了。

 

接着看代碼

if((instance_data[instance].instancetimer_en == 1) && (instance_data[instance].stoptimer == 0))

這個if裏面兩個變量斷定與剛纔徹底同樣,因此立馬用到了它們,並且知足條件,接着看if裏面的內容

  if(instance_data[instance].instancetimer < portGetTickCount())

  {

                event_data_t dw_event;

        instance_data[instance].instancetimer_en = 0;

                dw_event.rxLength = 0;

                dw_event.type = DWT_SIG_RX_TIMEOUT;

                dw_event.type2 = 0x80 | DWT_SIG_RX_TIMEOUT;

                //printf("PC timeout DWT_SIG_RX_TIMEOUT\n");

                instance_putevent(dw_event);

  }

If條件裏變量instancetimer 是咱們剛剛計算賦值的,而portGetTickCount()函數咱們以前沒有遇到過,簡單看下

#define portGetTickCount()                      portGetTickCnt()

 

unsigned long portGetTickCnt(void)

{

         return time32_incr;

}

咱們看到這裏,它返回一個time32_incr. 看到這裏絕對這個變量沒有初始化,假定是0,那就錯誤了。 這裏確定是有個定時器了,time32_incr是一個全局變量,在timer中斷裏增長。 因此portGetTickCnt() 返回一個實時時間量,再看咱們以前的instancetimer認爲是

instance_data[instance].instancetimer += instance_data[instance].tagBlinkSleepTime_ms; 如今感受instance_data[instance].instancetimer應該也是一個在定時器累加的所有量,否則二者沒有可比性,無法有相對延時的概念。

簡單看下time32_incr 一些像代碼。

void SysTick_Handler(void)

{

         time32_incr++;

#ifdef FILESYSTEM_ENABLE

         fsd_service();

#endif

}

經過下面的語句判判定時時間是否到了

if(instance_data[instance].instancetimer < portGetTickCount())

裏面的語句,就是產生一個事件,事件type爲DWT_SIG_RX_TIMEOUT,經過instance_putevent(dw_event)加入到事件列表,咱們以前是經過peek查看是否有事件。

這幾個event 相關的函數暫時不會影響咱們分析大局,先暫時不看它們了。

instancetimer_en 設置爲0,標誌着中止計時。

instance_data[instance].instancetimer_en = 0

 

雖然咱們把TAG代碼中的instance_run中的代碼所有分析完了,可是其實TAG實際跑代碼不是這樣的。正確的順序應該是,接着咱們剛纔設定定時器à 查看定時器是否到期(沒有到期)à返回Main 函數(咱們分析過ANCHOR,除了打印信息,沒有實質內容)à從新 instance_runà……定時器到期,設定event事件。

 

其中……可能重複了不少次,咱們須要再看看裏面怎麼執行的,是否還會增長定時器等等,咱們逐一再看看,這段時間是TAG發送完blink後打開接收器等待ANCHOR應答的時間段,雖然實際上時間可能1s不到,可是咱們分析代碼可能須要幾個小時甚至更長。 接着看第二次進入instance_run。

int done = INST_NOT_DONE_YET;

int message = instance_peekevent(); //get any of the received events from ISR

 

while(done == INST_NOT_DONE_YET)

{

         //int state = instance_data[instance].testAppState;

            done = instance_localdata[instance].testapprun_fn(&instance_data[instance], message) ;                                               // run the communications application

         //we've processed message

         message = 0;

}

注意和這裏,由於咱們假定是時間沒有到,因此peekevent應該仍是啥也沒有,因此message返回的仍是0. 因此咱們會再次進入testapprun_s。 咱們須要找上次testAppState,

inst->testAppState = TA_TX_WAIT_CONF ; // wait confirmation

inst->previousState = TA_TXBLINK_WAIT_SEND ;

東西記不住1是返回去看代碼,而是用筆記錄,咱們以前分析有記錄。直接在testapprun_s 找相應的case

case TA_TX_WAIT_CONF :  //after tx,waif for comfirm

這裏代碼很多,咱們須要根據if刪減一下,這裏事件TA_TX_WAIT_CONF,其實就是等待是否有應答,由於TAG 在發送blink信號的時候明確提出須要應答

 {

event_data_t* dw_event = instance_getevent(11); //get and clear this event

//NOTE: Can get the ACK before the TX confirm event for the frame requesting the ACK

//this happens because if polling the ISR the RX event will be processed 1st and then the TX event

//thus the reception of the ACK will be processed before the TX confirmation of the frame that requested it.

if(dw_event->type != DWT_SIG_TX_DONE) //wait for TX done confirmation

  {

         if(dw_event->type == DWT_SIG_RX_TIMEOUT) //got RX timeout - i.e. did not get the response (e.g. ACK)

         {

         //printf("RX timeout in TA_TX_WAIT_CONF (%d)\n", inst->previousState);

//we need to wait for SIG_TX_DONE and then process the timeout and re-send the frame if needed

             inst->gotTO = 1;

         }

  inst->done = INST_DONE_WAIT_FOR_NEXT_EVENT;

  break;

}

  inst->done = INST_NOT_DONE_YET;

 

                if(inst->previousState == TA_TXFINAL_WAIT_SEND)// 不知足

                {

                 ……

                }

                else if (inst->gotTO) //timeout

                {

                                               //printf("got TO in TA_TX_WAIT_CONF\n");

                    inst_processrxtimeout(inst);

                    inst->gotTO = 0;

                                               inst->wait4ack = 0 ; //clear this

                                               break;

                }

                else

                {

                                               inst->txu.txTimeStamp = dw_event->timeStamp;

 

                                               if(inst->previousState == TA_TXPOLL_WAIT_SEND) // 不知足

                                               {

                                   ……

                                               }

 

         inst->testAppState = TA_RXE_WAIT ;                      // After sending, tag expects response/report, anchor waits to receive a final/new poll

                    //fall into the next case (turn on the RX)

                                               message = 0;

                }

 

            }

 

咱們先一部分一部分的分析

if(dw_event->type != DWT_SIG_TX_DONE) //wait for TX done confirmation

  {

         if(dw_event->type == DWT_SIG_RX_TIMEOUT) //got RX timeout - i.e. did not get the response (e.g. ACK)

         {

         //printf("RX timeout in TA_TX_WAIT_CONF (%d)\n", inst->previousState);

//we need to wait for SIG_TX_DONE and then process the timeout and re-send the frame if needed

             inst->gotTO = 1;

         }

  inst->done = INST_DONE_WAIT_FOR_NEXT_EVENT;

  break;

}

DWT_SIG_TX_DONE 這個事件應該是發送一幀數據後,DWM1000 中斷裏產生的,咱們剛纔在TAG發送了一幀數據,因此若是DWM1000 處理完了,應該會put event,事件type是DWT_SIG_TX_DONE。 好,那咱們假設,下發數據後,DWM1000 尚未發送出去,咱們代碼已經執行到這裏了,確實知足這個判斷。 繼續執行裏面的

if(dw_event->type == DWT_SIG_RX_TIMEOUT)

DWT_SIG_RX_TIMEOUT, 這個事件咱們以前見過,是定時器溢出觸發的的,咱們剛纔假定DWM1000 很快執行到這裏,因此沒有溢出,不知足條件。直接執行了。

  inst->done = INST_DONE_WAIT_FOR_NEXT_EVENT;

  break;

和TAG 上次退出時同樣。同樣分別是有以下幾個關鍵變量沒有修改

inst->done = INST_DONE_WAIT_FOR_NEXT_EVENT;

inst->testAppState = TA_TX_WAIT_CONF ; // wait confirmation

inst->previousState = TA_TXBLINK_WAIT_SEND ;

由於這個時候定時器已經開啓了,咱們看看TAG此時退出到run裏會執行那些。

    if(done == INST_DONE_WAIT_FOR_NEXT_EVENT_TO) //we are in RX and need to timeout (Tag needs to send another poll if no Rx frame)

    {

        if(instance_data[instance].mode == TAG) //Tag (is either in RX or sleeping)

        {

           ……

        }

        if(instance_data[instance].mode == TAG_TDOA)

        {

            instance_data[instance].instancetimer += instance_data[instance].tagBlinkSleepTime_ms; //set timeout time

            instance_data[instance].instancetimer_en = 1; //start timer

        }

        instance_data[instance].stoptimer = 0 ; //clear the flag - timer can run if instancetimer_en set (set above)

        instance_data[instance].done = INST_NOT_DONE_YET;

    }

再次給instancetimer它賦值,咱們以前所instancetimer 是個動態量,分析有誤。。。。。

###############》 其實定時時長沒有變,因此仍是和原來等待時間同樣,後面持續在看是否溢出。==è從新分析instancetimer。

 

好,這是一種假設,另外一種假設,依然針對下面這幾行代碼。

if(dw_event->type != DWT_SIG_TX_DONE) //wait for TX done confirmation

  {

         if(dw_event->type == DWT_SIG_RX_TIMEOUT) //got RX timeout - i.e. did not get the response (e.g. ACK)

         {

         //printf("RX timeout in TA_TX_WAIT_CONF (%d)\n", inst->previousState);

//we need to wait for SIG_TX_DONE and then process the timeout and re-send the frame if needed

             inst->gotTO = 1;

         }

  inst->done = INST_DONE_WAIT_FOR_NEXT_EVENT;

  break;

}

咱們分析代碼能夠知道,當沒有發送完一直在等待事件DWT_SIG_TX_DONE,加入一種狀況,DWM1000 壞掉了或者中斷配置有問題,這個事件一直等不到,那麼,上面的循環一直執行到定時器溢出。會知足後面的if(dw_event->type == DWT_SIG_RX_TIMEOUT),判斷裏面講inst->gotTO = 1。 這個分支代碼也很長了,由於咱們可能須要在instance_run獲取些信息了。 暫時不考慮怎麼極端的狀況。先預留一個DWM1000配置有誤或者損壞TX後執行狀況代碼分析。

 

好了,咱們假定DWM1000 一切正常,因此過了一段時間,收到了DWT_SIG_TX_DONE,那就不知足以下if條件,直接日後看吧。

if(dw_event->type != DWT_SIG_TX_DONE) //wait for TX done confirmation

 

inst->done = INST_NOT_DONE_YET;

 

if(inst->previousState == TA_TXFINAL_WAIT_SEND)

                {

                ……

                }

                else if (inst->gotTO) //timeout

                {

                                               ……

                }

                else

                {

                                               inst->txu.txTimeStamp = dw_event->timeStamp;

 

                                               if(inst->previousState == TA_TXPOLL_WAIT_SEND)

                                               {

                     ……

                    }

                    inst->testAppState = TA_RXE_WAIT ;            

         // After sending, tag expects response/report, anchor waits to receive a final/new poll

          //fall into the next case (turn on the RX)

                                               message = 0;

                }

 

            }

 

            //break ; // end case TA_TX_WAIT_CONF

 

把不知足條件的代碼註釋掉,發現實際上當TAG發送完blink後這裏只是簡單的給幾個重要的變量賦值,好好記錄一下,根據經驗這個很重要

inst->done = INST_NOT_DONE_YET;

inst->testAppState = TA_RXE_WAIT ;

一個全局變量txu.txTimeStamp賦值,這個初始化的時候沒有動過,因此是0. 其中dw_event->timestamp 這個應該是DWM1000 在發送數據的時候MARK的時間,由於須要知道接收發送數據的時間換算距離。 其實發送blink 的時間應該沒有什麼意義,咱們暫時不考慮,用到在回來看。

後面有個比較詭異的地方,沒有break,直接會執行後面的case

   //break ; // end case TA_TX_WAIT_CONF

 

後面的case是TA_RXE_WAIT,咱們在ANCHOR分析過,它是打開接收器,在TA_RXE_WAIT後面重要變量被修改了

  inst->testAppState = TA_RX_WAIT_DATA;

咱們根據上面代碼分析經驗,咱們簡要瞅一眼TA_RX_WAIT_DATA。

  case TA_RX_WAIT_DATA :   //already recive a message                   // Wait RX data

                      //printf("TA_RX_WAIT_DATA %d", message) ;           

switch (message)

            {

在TA_RX_WAIT_DATA 會根據message執行不一樣的代碼,咱們前面分析了,若是沒有event或者一些沒有message 的event產生時,TA_RX_WAIT_DATA其實啥都不執行。也就是隻有就收到無線信號時,message裏面纔是一個真實的數據。

 

分析到這裏,TAG也在等ANCHOR的數據了。

 

咱們回顧一下,ANCHOR啓動後直接開始接收器等到TAG發送數據,分析TAG,TAG先發送一筆blink給ANCHOR,AHCHOR怎麼回覆blink咱們尚未分析,TAG此時正在等ANCHOR的回覆了,卡在這裏了,咱們下一節的內容主要分析ANCHOR接收blink以及回覆blink。

遺留問題:TAG開了一個定時器,最後是取消了仍是溢出了?

相關文章
相關標籤/搜索