5.2. RFD Periodic Reporting of Ambient Temperature from TM102

5.2.1. Description

Implements an RFD application in which the following data is reported to the gateway every few seconds.

  • On-chip temperature sensor output (2 bytes)
  • On-chip Vcc sensor output (2 bytes)
  • External temperature sensor output “TMP102” (4 bytes)

The RFD sleeps in low power mode and wakes up every few seconds to report sensor data. When sleeping, all the components (MSP430, CC2520 and the temperature sensor) are in low power/shutdown mode to reduce energy consumption thereby increasing battery life. On waking up, this app wakes up the TMP102 and triggers a conversion. After a single conversion, the TMP102 goes back to shutdown mode.

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

  • DEV_TYPE_RFD
  • RFD_APP_1
  • PLTFRM_ON_CHIP_TEMP_SENSOR_ENA
  • PLTFRM_ON_CHIP_VCC_SENSE_ENA
  • PLTFRM_TMP102_TEMP_SENSOR_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 (On-chip temperature sensor output (signed 2 byte value))
  • 4 bytes (TMP102 sensor output (signed 4 byte value))

The TMP102 driver code is in pltfrm/src/tmp102.c

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

5.2.2. Code

#ifdef DEV_TYPE_RFD
#ifdef RFD_APP_1
#if defined(PLTFRM_TMP102_TEMP_SENSOR_ENA) \
    && defined(PLTFRM_ON_CHIP_VCC_SENSE_ENA) \
    && defined(PLTFRM_ON_CHIP_TEMP_SENSOR_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 <tmp102.h>

RFD_APP_state_t RFD_APP_state = RFD_APP_STATE_CONVERSION_DONE;


#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;

void RFD_APP_TMP102_convTmoHndlr( )
{
   // No need to do anything here. The purpose of the timer interrupt
   // is to wake up the micro. After waking up, RFD_APP_wakeUpProc( )
   // will be called.
   return;
}

void RFD_APP_buildSendSnsrUpdate(SINT32_t tmp102Val)
{
   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
                    + PLTFRM_ON_CHIP_TEMP_SENSOR_OUTPUT_LEN
                    + TMP102_SENSOR_OUTPUT_VALUE_SZ;

   // seq-nr                            <2 bytes>
   // bit mask                          <1 byte / 3 bits valid (0, 1 and 2)>
   // On-chip Vcc sensor o/p            <2 bytes>
   // Internal temp sensor o/p          <2 bytes>
   // External temp sensor TMP102 o/p   <4 bytes>

   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;
       }

       {
          SINT16_t temp16 = 0;
          PLTFRM_onChipTempSensorInit();
          temp16 = PLTFRM_readOnChipTempSensor();
          buff_p = UTIL_htons(buff_p, temp16);
          snsrFlag |= BIT1;
       }

       if (tmp102Val < -255000)
       {
          if (TMP102_getTempVal(PLTFRM_TMP102_1_DEV_ID, &tmp102Val) != PLTFRM_STS_SUCCESS)
          {
              SYS_fatal();
          }
       }
       buff_p = UTIL_htonl(buff_p, tmp102Val);
       snsrFlag |= BIT2;

       *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;
           SYS_SET_WAKEUP_INTERVAL(RFD_APP_1_DFLT_WAKE_UP_INTERVAL_SECS);
       }
   }

   return;
}

void RFD_APP_wakeUpProc( )
{
   SINT32_t tempVal;
   UINT16_t tmoVal;

   if (RFD_APP_state == RFD_APP_STATE_WAIT_CONVERSION)
   {
       RFD_APP_buildSendSnsrUpdate((SINT32_t)-255000);
       RFD_APP_state = RFD_APP_STATE_CONVERSION_DONE;
   }
   else
   {
       PLTFRM_sts_t sts;
       sts = TMP102_startSingleConv(PLTFRM_TMP102_1_DEV_ID,
                                    &tempVal,
                                    &tmoVal);
       if ((sts != PLTFRM_STS_SUCCESS) && (sts != PLTFRM_STS_OPN_IN_PROGRESS))
       {
           SYS_fatal();
       }
       else
       {
           if (sts == PLTFRM_STS_OPN_IN_PROGRESS)
           {
               if (PLTFRM_startTimerA1(0, tmoVal, RFD_APP_TMP102_convTmoHndlr) != PLTFRM_STS_SUCCESS)
               {
                   SYS_fatal();
               }
               else
               {
                   SYS_globalEvtMsk1 |= SYS_GLOBAL_EVT_ENTER_LPM_REQUEST;
                   RFD_APP_state = RFD_APP_STATE_WAIT_CONVERSION;
                   SYS_SET_WAKEUP_INTERVAL(0);
               }
           }
           else
           {
               RFD_APP_buildSendSnsrUpdate(tempVal);
               RFD_APP_state = RFD_APP_STATE_CONVERSION_DONE;
           }
       }
   }
}

void RFD_APP_nodeJoinDoneInd(void)
{
   SYS_SET_WAKEUP_INTERVAL(RFD_APP_1_DFLT_WAKE_UP_INTERVAL_SECS);
   SYS_globalEvtMsk1 |= SYS_GLOBAL_EVT_ENTER_LPM_REQUEST;
   RFD_APP_state = RFD_APP_STATE_CONVERSION_DONE;
   return;
}

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)
{
   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_globalEvtMsk1 |= SYS_GLOBAL_EVT_ENTER_LPM_REQUEST;
           }
           break;

      default:
           break;
   }

   return;
}

void RFD_APP_init(void)
{
   SYS_SET_WAKEUP_INTERVAL(RFD_APP_1_DFLT_WAKE_UP_INTERVAL_SECS);
}

#endif
#endif
#endif