This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

CC2652R: Running another application for sensor reading alongside a ZED example

Part Number: CC2652R
Other Parts Discussed in Thread: Z-STACK

Hello TI!

I want to make use of the Z-Stack to tell my ZC to turn on/off the light from my ZED. The condition for turning on/off comes from some processing of the data of a continuously running sensor which is connected to the ZED with I2C.

Now, I want this sensor application to work with one of the ZED examples, such as zed_sw, where my sensor task runs until a change of state is confirmed and tells my zed_sw to send a toggle on/off to ZC. After this the sensor task runs again. What comes to mind is implementing my sensor code into zed_sw or creating a new task. Is this possible? How should I move forward?

Thanks in advance.

  • Hello christng,

    You can adapt and port the i2ctmp TI Driver example or your developed I2C code directly into zed_samplesw.c, where initialization is handled in zclSampleSw_Init and a I2C callback either directly calls zclGeneral_SendOnOff_CmdToggle or creates an application event (typically defined in zcl_samplesw.h) to be directly handled in zclSampleSw_process_loop.  This is also a great opportunity to use the Sensor Controller, please reference the Sensor Controller Studio examples and SimpleLink Academy Labs.

    Regards,
    Ryan

  • Thanks for the reply and suggestions. I didn't seem to get the notification until just recently so I have been looking at introducing a new task for my presence sensor reading. I did this as it felt like it was less work on the sensor application as it works fine independently. Also, I appreciate the patience. I'm stretching into a huge unknown field of everything here.

    I tried this out on the zed_sampleapp and not the zed_sw with CUI disabled (because my sensor application uses display_uart for sensor printing).

    What I have done so far is:

    1. Constructed a new task with a lower priority than the zed_sampleapp.
    2. Introduced a shared global variable which is a bool presence.
    3. Introduced a new semaphore sem2 which gets posted from my sensor application whenever a change in presence is detected.
    4. A non waiting semaphore_pend(sem2) in the zed_sw process_loop which changes a local bool newChange to TRUE when sem2 is posted.

    What I am thinking of doing further:

    1. An updatePresence() function in process_loop that calls zclGeneral_SendOnOff_CmdToggle depending on bool presence and then changes the local bool newChange to FALSE.

    I hope that made sense.

    So what I'm thinking is that because TIRTOS is based on preemptive scheduling, conflicts regarding the shared variable shouldn't be a problem as one is only reading and the other writing to this variable. The sensor-task gets to process and report as long as there is nothing to do for the z-stack-task and zed_sw-task. The tasks with higher priority runs when they need to so no conflict? The zed_sw-task is looped through every ~1s so the updatePresence() will be called within a reasonable time.

    What I need to do now is do all this on the zed_sw

    My question:

    1. Is it possible to use CUI without the UART-features? I only want the handler for button-commissioning.
    2. How do I manage the BDB commissioning without CUI?
    3. Do you have any input on my approach?

    Thanks in advance

  • 1. Yes

    2. you can use API bdb_StartCommissioning

    3. I would suggest you to create a periodic event to do sensor reading.

  • 1. Remove BOARD_DISPLAY_USE_UART
    2. Reference CONFIG_BTN_LEFT of zclSampleSw_processKey
    3. A periodic timer (see zclSampleSw_initializeClocks) would be less complicated

    Regards,
    Ryan

  • Thanks for the quick reply both! I will look into the periodic event.

    Have a great weekend

  • Good day

    The sensor reading behaviour seems to work now, but I have a problem with the commisioning. So I tried with the default examples again.

    Using two LP-CC2652R with the bdb-commisioning my ZED switches its state between:

    Initialized -> Discovered -> Joining -> Joined Unsecure -> Joining -> Joined Unsecure -> Initialized.

    This is done on a newly imported example of zed_sw and zc_light. I also tried to reset to FN and reconnecting the two Launchpads, but I still get the same behaviour.

    How do I fix this?

  • Try to mass erase your chip and download application to test again.

  • Thank you!

    Everything seems to work as intended, but I only have one last question regarding the SendOnOff_Cmd; The ZC seems to miss the On/Off command sent from the ZED occasionally, is there any way to confirm that the command is acquired? Some kind of handshake or something.

  • If all MAC/NWK retries have been exhausted the you can enable APS ACKs as demonstrated in the Zigbee Fundamental Project Development SLA, this way APS retries are also implemented.  But for parent/child devices, zstackmsg_CmdIDs_AF_DATA_CONFIRM_IND (refer to the Z-Stack API guide) status should be sufficient (check for matching transID).

    Regards,
    Ryan

  • I agree with Ryan to enable APS ack but if your coordinator misses receiving command frequently, there might be something wrong with your RF hardware and I would also suggest you to use sniffer to check what exactly happens over the air.

  • Hello,

    It seems like there's rather a problem with how the On/Off command gets sent from my function. Testing with the BTN-2, which toggles the light, works fine and manages to toggle while my own function seems to fail occasionally (approx. 2 of 10 times).

    Below is the function for just simply sending an on/off command.

    void zclSampleSw_actionToggleLight(void)
    {
        zstack_getZCLFrameCounterRsp_t rsp;

        Zstackapi_getZCLFrameCounterReq(appServiceTaskId, &rsp);
        zclSampleSw_UpdateStatusLine();

        if(prevPresence != presence)
        {
            if(presence)
            {
                zclGeneral_SendOnOff_CmdOn( SAMPLESW_ENDPOINT, &zclSampleSw_DstAddr, FALSE, rsp.zclFrameCounter );
            }else
            {
                zclGeneral_SendOnOff_CmdOff( SAMPLESW_ENDPOINT, &zclSampleSw_DstAddr, FALSE, rsp.zclFrameCounter );
            }
            prevPresence = presence;
            Display_printf(display, 0, 0, "%s", presence ? "Presence: TRUE\n" : "Presence: FALSE\n");
        }
    }

    And this function is attached to the process_loop as such:

    static void zclSampleSw_process_loop(void)
    {
        /* Forever loop */
        for(;;)
        {
            zstackmsg_genericReq_t *pMsg = NULL;
            bool msgProcessed = FALSE;

                /* Wait for response message */
            if(Semaphore_pend(appSemHandle, BIOS_WAIT_FOREVER ))
            {
                /* Retrieve the response message */
                if( (pMsg = (zstackmsg_genericReq_t*) OsalPort_msgReceive( appServiceTaskId )) != NULL)
                {
                    /* Process the message from the stack */
                    zclSampleSw_processZStackMsgs(pMsg);

                    // Free any separately allocated memory
                    msgProcessed = Zstackapi_freeIndMsg(pMsg);
                }

                if((msgProcessed == FALSE) && (pMsg != NULL))
                {
                    OsalPort_msgDeallocate((uint8_t*)pMsg);
                }

    #ifndef CUI_DISABLE
                zclsampleApp_ui_event_loop();
                zclSampleSw_UpdateStatusLine();
    #endif

                zclSampleSw_actionToggleLight();


    #if ZG_BUILD_ENDDEVICE_TYPE
                if ( appServiceTaskEvents & SAMPLEAPP_END_DEVICE_REJOIN_EVT )
                {
                  zstack_bdbZedAttemptRecoverNwkRsp_t zstack_bdbZedAttemptRecoverNwkRsp;

                  Zstackapi_bdbZedAttemptRecoverNwkReq(appServiceTaskId,&zstack_bdbZedAttemptRecoverNwkRsp);

                  appServiceTaskEvents &= ~SAMPLEAPP_END_DEVICE_REJOIN_EVT;
                }
    #endif
            }
        }
    }

    What is the difference between pressing the button and a function call inside the loop?

  • You are calling zclSampleSw_actionToggleLight on each iteration of zclSampleSw_process_loop, the frequency of which is unreliable and should not be depended on.  Instead, you should be creating a sample application event (see zcl_samplesw.h) which is set by the change/callback of a peripheral (timer, UART, GPIO, etc) and then checked, acted on, and cleared inside of the main processing loop.

    Regards,
    Ryan

  • I will try to do the periodic timer as you guys suggested.

    1. Is there a reason the events are defined (in zcl_samplesw.h)  as (0x0001, 0x0002, 0x0004, 0x0008, 0x0010) ?
    2. How should I start the periodic timer? In zclSamplwSw_Init?
    3. The one initialized in zclSampleSw_initializeClocks() is a "one-shot" timer. For my periodic timer; Do I need to set a clockDuration if I set a clockPeriod of 1000?
  • 1. Event is defined as bit flag and that's why you see they are defined as 0x0001, 0x0002, 0x0004, 0x0008, 0x0010.

    2. Yes, you can create periodic timer event in zclSamplwSw_Init

    3. When you create timer event with UtilTimer_construct, you can give clockDuration as 1000 which means the event callback would be trigger 1000ms later and keep clockPeriod as 0. In your event, you can call UtilTimer_setTimeout(1000) and UtilTimer_start to schedule next periodic event.

  • I've made the periodic timer and checked, acted on and cleared the event in the processing loop but still get the same behaviour as I had before. The BTN-2 toggle still works fine while the on/off fails occasionally. The timer starts after ZED manages to join in the network.

    Have I misunderstood the approach you suggested?

    static void zclSampleSw_process_loop(void)
    {
        /* Forever loop */
        for(;;)
        {
            zstackmsg_genericReq_t *pMsg = NULL;
            bool msgProcessed = FALSE;

                /* Wait for response message */
            if(Semaphore_pend(appSemHandle, BIOS_WAIT_FOREVER ))
            {
                /* Retrieve the response message */
                if( (pMsg = (zstackmsg_genericReq_t*) OsalPort_msgReceive( appServiceTaskId )) != NULL)
                {
                    /* Process the message from the stack */
                    zclSampleSw_processZStackMsgs(pMsg);

                    // Free any separately allocated memory
                    msgProcessed = Zstackapi_freeIndMsg(pMsg);
                }

                if((msgProcessed == FALSE) && (pMsg != NULL))
                {
                    OsalPort_msgDeallocate((uint8_t*)pMsg);
                }

    #ifndef CUI_DISABLE
                zclsampleApp_ui_event_loop();
                zclSampleSw_UpdateStatusLine();
    #endif
                if ( appServiceTaskEvents & SAMPLEAPP_SENSOR_UPDATE_EVT )
                {
                    if(prevPresence != presence)
                    {
                        zstack_getZCLFrameCounterRsp_t rsp;

                        Zstackapi_getZCLFrameCounterReq(appServiceTaskId, &rsp);

                        if(presence == true)
                        {
                            zclGeneral_SendOnOff_CmdOn( SAMPLESW_ENDPOINT, &zclSampleSw_DstAddr, FALSE, rsp.zclFrameCounter );
                        }
                        if(presence == false)
                        {
                            zclGeneral_SendOnOff_CmdOff( SAMPLESW_ENDPOINT, &zclSampleSw_DstAddr, FALSE, rsp.zclFrameCounter );
                        }
                        prevPresence = presence;
                        Display_printf(display, 0, 0, "%s", presence ? "Presence: TRUE\n" : "Presence: FALSE\n");
                    }

                    appServiceTaskEvents &= ~SAMPLEAPP_SENSOR_UPDATE_EVT;

                    UtilTimer_setTimeout( sensorClkHandle, SAMPLEAPP_SENSOR_UPDATE_DELAY );
                    UtilTimer_start(&sensorClkStruct);
                    Display_printf(display, 0, 0, "Periodic timer event!");
                }

    #if ZG_BUILD_ENDDEVICE_TYPE
                if ( appServiceTaskEvents & SAMPLEAPP_END_DEVICE_REJOIN_EVT )
                {
                    zstack_bdbZedAttemptRecoverNwkRsp_t zstack_bdbZedAttemptRecoverNwkRsp;

                    Zstackapi_bdbZedAttemptRecoverNwkReq(appServiceTaskId,&zstack_bdbZedAttemptRecoverNwkRsp);

                    appServiceTaskEvents &= ~SAMPLEAPP_END_DEVICE_REJOIN_EVT;
                }

    ..............................................................................

    Thanks for your help

  • Can you do sniffer log and attach it for us to check what happens over the air?

  • I notice from my Smart RF Sniffer Agent that the Incoming Packets field doesn't increment when an On/Off command is unsuccessful, but gets updated when it does successfully. I recon that it has to be a fault in my implementation then?

  • You can add CCS breakpoints, check the return of zclGeneral_SendOnOff_CmdOn, and there is zstackmsg_CmdIDs_AF_DATA_CONFIRM_IND (previously discussed) as well to monitor packet sending errors.  What is contained in your timer callback and what is the value of SAMPLEAPP_SENSOR_UPDATE_DELAY?

    Regards,
    Ryan

  • I don't see any On/Off command is sent in your sniffer logs. Are you sure your periodic event is triggered and zclGeneral_SendOnOff_CmdOn/zclGeneral_SendOnOff_CmdOff is called?

  • Hello YiKai and Ryan!

    Yes, I'm sure my periodic event is triggered as I've included a console print which happens every SAMPLEAPP_SENSOR_UPDATE_DELAY (1000 ms). I also see that my ZC_Light gets turned on and off by triggering the presence sensor. Debugging confirms that I call on the zclGeneral_SendOnOff_CmdOn/zclGeneral_SendOnOff_CmdOff.

    My timer callback:

    static void zclSampleSw_processLightTimeoutCallback(UArg a0)
    {
        (void)a0;

        appServiceTaskEvents |= SAMPLEAPP_SENSOR_UPDATE_EVT;

        Semaphore_post(appSemHandle);
    }

    Using AF_DATA_CONFIRM_IND:

    Successful packet send:

    Status: 0x00

    Endpoint: 8

    Failed packet send:

    Status: 0x01

    Endpoint: 8

  • So I found out what the error/bug/feature was.

    By placing my hand over the ZED board/antenna in a particular manner while sending the command, it got sent successfully. I managed to reproduce this "solution" about 100% of the times it failed to send. 

    By repeatedly sending the command until success (see code below) I observed how it went form failing all the time, to successfully sending the command when I slowly placed my hand around the board?

    if (pInd->req.status != 0)
                  {
                      Zstackapi_getZCLFrameCounterReq(appServiceTaskId, &sensor_rsp);

                      if (presence)
                      {
                          zclGeneral_SendOnOff_CmdOn( SAMPLESW_ENDPOINT, &zclSampleSw_DstAddr, FALSE, sensor_rsp.zclFrameCounter );
                      }else
                      {
                          zclGeneral_SendOnOff_CmdOff( SAMPLESW_ENDPOINT, &zclSampleSw_DstAddr, FALSE, sensor_rsp.zclFrameCounter );
                      }
                      Display_printf(display, 0, 0, "Resent command for transId %d\n", pInd->req.transID);
                      Task_sleep(1000);
                  }

    I have no explanation for this