5.5. RFD PIR Motion Sensing Based on EKMC160111X

5.5.1. Description

Implements an RFD application which sends the state of the attached PIR motion sensor (EKMC160111X) whenever the latter detects motion in it’s field of view. Following data is reported.

  • On-chip Vcc sensor output (2 bytes)
  • Count of the number of times the sensor has detected motion since the node joined the network.

The RFD stays for the most part in deep sleep (micro sleeps in LPM3 and the radio sleeps in LPM2). Whenever the motion sensor detects motion, it interrupts the micro. The micro increments a variable which represents the number of times the motion has been detected. Interrupts from the motion sensor are masked at this point. After the app reports this event to the gateway and gets an ack, it then debounces the motion sensor. On expiry of the debounce interval, the app re-enables interrupt handling from the motion sensor and then puts the micro into LPM3.

When building an RFD executable which includes rfd_app_4.c, these macros need to enabled :-

  • DEV_TYPE_RFD
  • RFD_APP_4
  • PLTFRM_ON_CHIP_VCC_SENSE_ENA
  • PLTFRM_EKMC160111X_ENA

The data packet sent out by this app has the following format :-

  • 2 bytes (packet sequence number)
  • 1 byte (sensor bit mask with value 0x7)
  • 2 bytes (On-chip Vcc sensor output (unsigned 2 byte value))
  • 2 bytes (motion detected event count)

The EKMC160111 PIR motion sensor driver code is in pltfrm/src/ekmc160111x.c

To learn more about the sensors and the API, visit sections EKMC160111X (Panasonic) and On-Chip Voltage Sensor (TI MSP430).

5.5.2. Code

#ifdef DEV_TYPE_RFD

#ifdef RFD_APP_4

#if defined(PLTFRM_EKMC160111X_ENA) \
    && defined(PLTFRM_ON_CHIP_VCC_SENSE_ENA)

#include <typedefs.h>
#include <system.h>
#include <pltfrm.h>
#include <util.h>
#include <mac_pib.h>
#include <adp.h>
#include <rfd_app.h>
#include <ekmc160111x.h>


#define RFD_APP_DATA_SEQ_NR_SZ   2
#define RFD_APP_DATA_SNSR_BIT_MSK_SZ   1

UINT16_t RFD_APP_pktSeqNr = 0;

// Stats
UINT16_t RFD_APP_dataTxReqCnt = 0;
UINT16_t RFD_APP_dataRxReqFailCnt = 0;
UINT16_t RFD_APP_cnfrmOkCnt = 0;
UINT16_t RFD_APP_cnfrmFlrCnt = 0;

UINT16_t RFD_APP_motionSenseCnt = 0;


void RFD_APP_buildSendSnsrUpdate(void)
{
   UINT8_t pktLen = ADP_ELEMENT_TYPE_LEN
                    + RFD_APP_DATA_SEQ_NR_SZ
                    + RFD_APP_DATA_SNSR_BIT_MSK_SZ
                    + PLTFRM_ON_CHIP_VCC_SENSOR_OUTPUT_LEN
                    + sizeof(RFD_APP_motionSenseCnt);
   UINT8_t evtPendFlag = 0x0;

   if (EKMC160111X_checkPendingEvt(PLTFRM_EKMC160111X_1_DEV_ID, &evtPendFlag) == PLTFRM_STS_SUCCESS)
   {
       if (evtPendFlag)
       {
           RFD_APP_motionSenseCnt ++;
       }
       else
       {
           // No event pending !! Put the node back to sleep.
           SYS_globalEvtMsk1 |= SYS_GLOBAL_EVT_ENTER_LPM_REQUEST;
           return;
       }
   }
   else
   {
       SYS_fatal();
   }

   // seq-nr                     <2 bytes>
   // bit mask                   <1 byte / 2 bits valid (0 and 1) >
   // On chip Vcc sensor o/p     <2 bytes>
   // Reed switch state o/p      <1 byte>

   ADP_cntxt.txParams.bdHndl = SYS_allocMem(pktLen);
   if (SYS_BD_HNDL_IS_VALID(ADP_cntxt.txParams.bdHndl))
   {
       UINT8_t *buff_p = SYS_GET_BD_BUFF(ADP_cntxt.txParams.bdHndl);
       UINT8_t *flag_p, snsrFlag = 0x0;

       buff_p += ADP_ELEMENT_TYPE_LEN;

       RFD_APP_pktSeqNr ++;
       buff_p = UTIL_htons(buff_p, RFD_APP_pktSeqNr);

       flag_p = buff_p;
       buff_p ++;  // skip sensor flag field ...

       {
          UINT16_t vcc = 0;
          pltfrm_vccSenseInit( );
          vcc = pltfrm_vccSense();
          buff_p = UTIL_htons(buff_p, vcc);
          snsrFlag |= BIT0;
       }

       {
           buff_p = UTIL_htons(buff_p, RFD_APP_motionSenseCnt);
           snsrFlag |= BIT1;
       }

       *flag_p = snsrFlag;

       ADP_cntxt.txParams.destShortAddr = LPWMN_COORD_MAC_SHORT_ADDR;

       RFD_APP_dataTxReqCnt ++;

       if (ADP_appPyldTxReq() != ADP_STS_SUCCESS)
       {
           RFD_APP_dataRxReqFailCnt ++;
           SYS_globalEvtMsk1 |= SYS_GLOBAL_EVT_ENTER_LPM_REQUEST;
       }
   }
}

void RFD_APP_wakeUpProc( )
{
   RFD_APP_buildSendSnsrUpdate();
}

void RFD_APP_nodeJoinDoneInd(void)
{
   // Enable interrupts from the motion sensor
   if (EKMC160111X_unMaskDevEvent(PLTFRM_EKMC160111X_1_DEV_ID) != PLTFRM_STS_SUCCESS)
   {
       SYS_fatal();
   }

   RFD_APP_wakeUpProc( );
}

void RFD_APP_prepareToEnterLPM(void)
{
   // Interrupts are disabled globally at this point.
   // The MSP430 will go into deep sleep mode on returning
   // from this function.
   return;
}

void RFD_APP_wakeUpTimerExpEvt(void)
{
   // Called on expiry of the debounce interval
   EKMC160111X_unMaskDevEvent(PLTFRM_EKMC160111X_1_DEV_ID);

   // Micro will wake up only when interrupted by the motion sensor
   SYS_SET_WAKEUP_INTERVAL(0);

   return;
}

void APP_procGPIOEvt()
{
   return;
}

void RFD_APP_evtHndlr(UINT16_t globalEvtId, void *params_p)
{
   switch (globalEvtId)
   {
      case SYS_GLOBAL_EVT_ADP_DATA_CONFIRM:
           {
              ADP_dataCnfrmParams_s *dcParams_p = (ADP_dataCnfrmParams_s *)params_p;
              if (dcParams_p->sts == ADP_STS_SUCCESS)
              {
                  RFD_APP_cnfrmOkCnt ++;
              }
              else
              {
                  RFD_APP_cnfrmFlrCnt ++;
              }
              SYS_SET_WAKEUP_INTERVAL(EKMC160111X_DFLT_DEBOUNCE_TIME);
              SYS_globalEvtMsk1 |= SYS_GLOBAL_EVT_ENTER_LPM_REQUEST;
           }
           break;

      default:
           break;
   }

   return;
}

void RFD_APP_init(void)
{
   // Micro will wake up only when interrupted by the motion sensor
   SYS_SET_WAKEUP_INTERVAL(0);

   return;
}

#endif
#endif
#endif