【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开了一个定时器,最后是取消了仍是溢出了?

相关文章
相关标签/搜索