AnsweredAssumed Answered

Current reading

Question asked by Joohee Kim on Jun 27, 2019
Latest reply on Jul 2, 2019 by Mario Ignacio Castaneda Lopez

Hello, everyone.

I want to read the current of a sensor using the NHS 3152.

I already had a NHS 3152 starter kit. 

 

 

NHS 3152 has a temperature sensor and android applications. 

Therefore, I used this app_demo_dp_tlogger, and modify the code from measuring the temperature to current. 

And, I want to receive the current level to my phone. 

 

I have some questions. 

First, What parts should I change the code to read current instead the temperature?

[I2D code]

"int i2dValue;

int i2dNativeValue;
Chip_IOCON_SetPinConfig(NSS_IOCON, IOCON_ANA0_4, IOCON_FUNC_1); /* Set pin function to analog */
; /* wait */
}
i2dNativeValue = Chip_I2D_GetValue(NSS_I2D);

 

[maintlogger code]

/*
* Copyright (c), NXP Semiconductors
* (C)NXP B.V. 2014-2018
* All rights are reserved. Reproduction in whole or in part is prohibited without
* the written consent of the copyright owner. NXP reserves the right to make
* changes without notice at any time. NXP makes no warranty, expressed, implied or
* statutory, including but not limited to any implied warranty of merchantability
* or fitness for any particular purpose, or that the use will not infringe any
* third party patent, copyright or trademark. NXP must not be liable for any loss
* or damage arising from its use.
*/


#include <string.h>
#include "board.h"
#include "ndeft2t/ndeft2t.h"
#include "compress/compress.h"
#include "storage/storage.h"
#include "event/event.h"
#include "event_tag.h"
#include "temperature.h"
#include "msghandler.h"
#include "msghandler_protocol.h"
#include "memory.h"
#include "timer.h"
#include "validate.h"

/* ------------------------------------------------------------------------- */

/**
* Use the define @c APP_MAINTAIN_SWD_CONNECTION to start debugging without the risk of losing the debug connection due
* to power-off or deep power down.
* When this is enabled, measurements are still taken according to the configuration, and communication is always
* possible, both via SWD and via NFC.
*
* Enable this in a debug build configuration only, and during development and debugging only!
*
* @c APP_MAINTAIN_SWD_CONNECTION can also be defined in your Project settings.
* Under LPCXPresso: Project > Properties > C/C++ Build > Settings > Tool Settings > MCU C Compiler > Symbols
* @note When this define is enabled, #APP_NO_MEASUREMENT_IN_NFC_FIELD is ignored.
*/
#undef APP_MAINTAIN_SWD_CONNECTION
#if defined(APP_MAINTAIN_SWD_CONNECTION)
#define USEPLACEHOLDER false
#elif defined(APP_NO_MEASUREMENT_IN_NFC_FIELD)
#define USEPLACEHOLDER true
#else
#define USEPLACEHOLDER false
#endif

/**
* @def APP_NO_MEASUREMENT_IN_NFC_FIELD
* We can do a proper temperature measurement while in an NFC field, but the resulting value is not
* representative as the NFC field will heat up the IC quickly and significantly.
* Instead, a placeholder value can be used, but this requires careful interpretation on the host side.
* The define @c APP_NO_MEASUREMENT_IN_NFC_FIELD allows you to switch between two different approaches:
* - Always make a proper measurement regardless of the presence of the NFC field
* This is the default behavior.
* - Do _not_ make a measurement when an NFC field is present but instead store a placeholder value.
* Define @c APP_NO_MEASUREMENT_IN_NFC_FIELD in your Project settings.
* Under LPCXPresso: Project > Properties > C/C++ Build > Settings > Tool Settings > MCU C Compiler > Symbols
* Take care to add this to all build configurations you want them added to.
*/

/**
* @def BOARD_ENABLE_WAKEUP
* Define @c BOARD_ENABLE_WAKEUP in your board header file.
* This define serves two purposes:
* - We can accept a configuration, but defer logging until a start trigger is given. That trigger is either receiving a
* separate start command - #APP_MSG_ID_START - or detecting the WAKEUP pin is pulled low. The latter can be enabled
* or disabled.
* The define @c BOARD_ENABLE_WAKEUP allows you to switch between two different approaches:
* - When undefined: Do _not_ allow to start via the WAKEUP-pin.
* - When defined: Monitor the WAKEUP pin when a configuration as been given but the start is delayed indefinitely -
* using the parameter #APP_MSG_DELAY_START_INDEFINITELY. When the WAKEUP pin detects a low, a first measurement
* is made.
* .
* - The temperature logger Demo PCBs have a button attached to the WAKEUP pin. This define enables a check -
* performed at startup only - on the WAKEUP pin. When the pin is actively pulled low - by pushing the button and
* holding it down - execution is then paused until the pin is high again. The implementation is done in #ResetISR,
* and provides a break-in possibility for a debugger connected via SWD to halt the ARM core before the SWD
* functionality is (possibly) turned off in firmware.
* .
*/

#if !(MEMORY_FIRSTUNUSEDEEPROMOFFSET < EVENT_EEPROM_FIRST_ROW*64)
#error The SW memory map as defined through the default diversity settings and those overridden in app_sel.h is wrong. Fix it.
#endif

#if !(EVENT_EEPROM_LAST_ROW < STORAGE_EEPROM_FIRST_ROW)
#error The SW memory map as defined through the default diversity settings and those overridden in app_sel.h is wrong. Fix it.
#endif
#if !(ALON_WORD_SIZE <= STORAGE_CONFIG_ALON_REGISTER)
#error The SW memory map as defined through the default diversity settings and those overridden in app_sel.h is wrong. Fix it.
#endif

/* ------------------------------------------------------------------------- */

/**
* Just assign a reasonable number. It must accommodate for all the overhead that comes with the complete ndef
* message, plus it must be a multiple of 4.
*/
#define MAX_COMMAND_MESSAGE_SIZE 0x44

/**
* In seconds.
* Allow the - assumed - corresponding host to issue a first command in the given time window.
* A few seconds also allows for easier grabbing hold of a debug session.
*/
#define FIRST_HOST_TIMEOUT 3

/**
* In seconds.
* We're assuming the host will continually exchange commands and responses. If after some timeout no command
* has been received, we abort communication and shut down. When a field is still present, we will automatically
* wake up again from Deep Power Down and refresh the NFC shared memory with a new initial message.
* This way we prevent a possible hang-up when both sides are waiting indefinitely for an NDEF message to be
* written by the other side.
* No need to set the timeout too strict: set it reasonably long enough to never hamper any execution flow,
* while still being short enough to re-enable communication from a user perspective.
*/
#define HOST_TIMEOUT 20

/**
* In seconds.
* From what was observed, the power off/power on/(re-)select sequence takes place in the order of a few 100ms
* at most. Waiting a full second seems more than enough to also take small changes in physical placement into
* account.
*/
#define LAST_HOST_TIMEOUT 1

/**
* In seconds.
* No need to set the watchdog timeout too strict: set it long enough to never hamper any execution flow,
* while still being short enough to re-enable communication from a user perspective.
* Just ensure it is higher than #HOST_TIMEOUT.
*/
#define WATCHDOG_TIMEOUT (HOST_TIMEOUT + 5)

/* ------------------------------------------------------------------------- */

void App_FieldStatusCb(bool isPresent);
void App_MsgAvailableCb(void);
void App_MsgReadCb(void);
int App_CompressCb(int eepromByteOffset, int bitCount, void * pOut);
int App_DecompressCb(const uint8_t * pData, int bitCount, void * pOut);

static void Init(void);
static void InitApp(void);
static void DeInit(const bool waitBeforeDisconnect);
static void ExecuteMeasurementMode(const bool usePlaceholder);
static bool ExecuteCommunicationMode(void);
#ifdef BOARD_ENABLE_WAKEUP
static void CheckExternalTrigger(void);
#endif
static bool GenerateNextAutomaticCommand(void);

int main(void); /**< Application's main entry point. Declared here since it is referenced in ResetISR. */

/* ------------------------------------------------------------------------- */

/**
* - Set to @c true in #App_MsgAvailableCb when a new NDEF message is available.
* - Set to @c false in the loop #ExecuteCommunicationMode when the new NDEF message is read out.
* .
*/
static volatile bool sMessageAvailable = false;

/**
* - Set to @c true in #App_MsgReadCb when a current NDEF message in NCF shared memory is read by the NFC tag reader.
* - Set to @c false in the loop #ExecuteCommunicationMode when the new NDEF message is written.
*/
static volatile bool sMessageRead = false;

/** Set to @c true to reset the command sequence as generated by #GenerateNextAutomaticCommand */
static bool sResetAutomaticCommandGeneration = true;

/* ------------------------------------------------------------------------- */

/**
* Handler for (ARM) Reset Interrupt.
* Implements and overrides the WEAK function in the startup module.
*/
void ResetISR(void)
{
/* Increasing the system clock as soon as possible to reduce the startup time:
* the NFC tag reader times out
* - on Android after ~40ms (although some phones will wait up to 100 ms)
* - on iOS after ~16ms
*
* Setting the clock to 2MHz is the maximum: when
* - running without a battery
* - at 4MHz
* - when the field is provided by some phones (e.g. S5)
* a voltage drop to below 1.2V was observed - effectively resetting the chip.
*/
Chip_Clock_System_SetClockFreq(2 * 1000 * 1000);

#ifdef BOARD_ENABLE_WAKEUP
/* Chip nor board library have been initialized yet. We therefore directly use the registers. */
NSS_SYSCON->SYSAHBCLKCTRL |= CLOCK_PERIPHERAL_IOCON; /* Enable the IOCON clock. */
NSS_SYSCON->SYSAHBCLKCTRL |= CLOCK_PERIPHERAL_GPIO; /* Enable the GPIO clock. */
NSS_IOCON->REG[0] = (IOCON_FUNC_0 | IOCON_RMODE_PULLUP); /* Enable pull-up on the WAKEUP pin (0). */
NSS_GPIO->DIR &= ~(1UL << 0); /* Just to be sure: configure the WAKEUP pin (0) as input. */
while (!(NSS_GPIO->DATA[1 << 0])) {
; /* Wait for as long as the WAKEUP pin (0) is low. */
}
#endif

Startup_VarInit();
main();
}

#ifdef BOARD_ENABLE_WAKEUP
/**
* Handler for PIO0_0 / WAKEUP pin.
* Implements and overrides the WEAK function in the startup module.
*/
void PIO0_0_IRQHandler(void)
{
Chip_SysCon_StartLogic_ClearStatus(SYSCON_STARTSOURCE_PIO0_0);
if (Memory_IsReadyToStart()) {
Memory_AddToState(APP_MSG_EVENT_STARTING);
/* Configure the time to make a first measurement: start the RTC-down counter.
* A first measurement will then be made in the main context, not under this interrupt.
* Cheat a bit: assume 'within 1 second' is as good as 'immediately'.
*/
Timer_StartMeasurementTimeout(1);
}
}
#endif

/**
* Called under interrupt.
* @see NDEFT2T_FIELD_STATUS_CB
* @see pNdeft2t_FieldStatus_Cb_t
*/
void App_FieldStatusCb(bool isPresent)
{
if (isPresent) {
Timer_StartHostTimeout(HOST_TIMEOUT);
}
else {
/* A PCD (Proximity Coupled Device, i.e. the NFC tag reader) can do very strange things, a.o. power off the
* field and immediately power on the field again, or 10+ times select the same device as part of its illogic
* procedure to select a PICC (Proximity Integrated Circuit Card, i.e. the NFC tag) and start communicating
* with it. (I'm primarily pointing to NFC-enabled Android phones now.)
* Instead of deciding to Power-off or go to Deep Power Down immediately, it is more robust to additionally
* check if during a small interval no NFC field is started again.
* The loop in ExecuteCommunicationMode() may thus not look at the NFC interrupt status, but at the result of
* the timer interrupt.
*/
Timer_StartHostTimeout(LAST_HOST_TIMEOUT);
}
}

/**
* Called under interrupt.
* @see NDEFT2T_MSG_AVAILABLE_CB
* @see pNdeft2t_MsgAvailable_Cb_t
*/
void App_MsgAvailableCb(void)
{
sMessageAvailable = true;
Timer_StartHostTimeout(HOST_TIMEOUT);
}

/**
* Called under interrupt.
* @see NDEFT2T_MSG_READ_CB
* @see pNdeft2t_MsgRead_Cb_t
*/
void App_MsgReadCb(void)
{
sMessageRead = true;
Timer_StartHostTimeout(HOST_TIMEOUT);
}

/* ------------------------------------------------------------------------- */

/**
* Connects the compress module with the storage module. Provides compression of data.
* @see STORAGE_COMPRESS_CB
* @see pStorage_CompressCb_t
*/
int App_CompressCb(int eepromByteOffset, int bitCount, void * pOut)
{
ASSERT(bitCount == STORAGE_UNCOMPRESSED_BLOCK_SIZE_IN_BITS);
(void)bitCount; /* suppress [-Wunused-parameter]: its value is known to be STORAGE_UNCOMPRESSED_BLOCK_SIZE_IN_BITS. */
uint8_t data[STORAGE_UNCOMPRESSED_BLOCK_SIZE_IN_BYTES];
Chip_EEPROM_Read(NSS_EEPROM, eepromByteOffset, data, STORAGE_UNCOMPRESSED_BLOCK_SIZE_IN_BYTES);
int length = Compress_Encode(data, STORAGE_UNCOMPRESSED_BLOCK_SIZE_IN_BYTES, pOut, STORAGE_UNCOMPRESSED_BLOCK_SIZE_IN_BYTES);
return length * 8;
}

/**
* Connects the compress module with the storage module. Provides decompression of data.
* @see STORAGE_DECOMPRESS_CB
* @see pStorage_DecompressCb_t
*/
int App_DecompressCb(const uint8_t * pData, int bitCount, void * pOut)
{
int length = Compress_Decode(pData, STORAGE_IDIVUP(bitCount, 8), pOut, STORAGE_UNCOMPRESSED_BLOCK_SIZE_IN_BYTES);
return (length == STORAGE_UNCOMPRESSED_BLOCK_SIZE_IN_BYTES) ? STORAGE_UNCOMPRESSED_BLOCK_SIZE_IN_BITS : 0;
}

/* ------------------------------------------------------------------------- */

/**
* - Initializes drivers and modules. Initialization is expected to be done once per complete active lifetime.
* - Calls #InitApp.
* .
*/
static void Init(void)
{
Board_Init();

#ifndef DEBUG
Chip_WWDT_Start(WATCHDOG_TIMEOUT);
/* The watchdog will be fed - by calling Chip_WWDT_Feed - in ExecuteCommunicationMode in a while loop when the NFC
* field is present. A reset will then occur when in either the main contect or in an interrupt too many seconds are
* spent, i.e. when it is stuck somewhere.
*/
#endif

(void)Temperature_Measure(TSEN_7BITS, false);

Chip_NFC_Init(NSS_NFC);
NDEFT2T_Init();
Chip_EEPROM_Init(NSS_EEPROM);

Timer_Init();
InitApp();
}

/**
* Initializes and configures APP modules. Initialization is expected to be done multiple times per complete active
* lifetime (always going through the cycle @c #DeInitAp - @c InitApp) when #APP_MAINTAIN_SWD_CONNECTION is defined.
*/
static void InitApp(void)
{
bool accepted = Memory_Init();
AppMsgInit(accepted);

sResetAutomaticCommandGeneration = true;
/* Trigger the generation of a multi-record message as initial response. Do this unconditionally:
* - it's a tiny bit faster
* - it will allow tag readers who tap later, while the IC is still awake, to start the communication properly.
*/
GenerateNextAutomaticCommand();

#ifdef BOARD_ENABLE_WAKEUP
if (Memory_IsReadyToStart()) {
NVIC_EnableIRQ(PIO0_0_IRQn); /* PIO0_0_IRQHandler is called when this interrupt fires. */
Chip_SysCon_StartLogic_SetEnabledMask(SYSCON_STARTSOURCE_PIO0_0);
}
#endif
}

/**
* De-initializes APP modules. De-Initialization is expected to be done multiple times per complete active
* lifetime (always going through the cycle @c DeInitApp - #InitApp) when #APP_MAINTAIN_SWD_CONNECTION is defined.
*/
static void DeInitApp(void)
{
Memory_DeInit();
}

/**
* - Calls #DeInitApp
* - Cleanly closes everything down, decides which low power state to go to - Deep Power Down or Power-off, and enters
* that state using the correctly determined parameters.
* .
* @note Wake-up conditions other than a reset pulse or the presence of an NFC field - both of which cannot be disabled
* nor require configuration - must have been set beforehand.
* @param waitBeforeDisconnect Present to aid the SW developer. If @c true, it will wait - not sleep - for a couple of
* seconds before disconnecting the battery. The argument has no effect if Deep Power Down mode is selected.
* The extra time window allows for easier breaking in using SWD, allowing time to halt the core and flash new
* firmware. However, it will @c not touch any PIO, or ensure that SWD functionality is offered.
* The default value should be @c false, i.e. go to Power-off state without delay: typical user behavior is to bring
* the IC in and out the NFC field quickly, before stabilizing on a correct position. Having a time penalty of several
* seconds - during which the host SW may already have made several decisions about the use and state of the IC -
* diminishes the user experience.
*/
static void DeInit(const bool waitBeforeDisconnect)
{
/* Before (possibly) going to DPD mode, we need to determine whether switching must be enabled. We enable switching
* when the battery is low, to ensure we can use the NFC interface as power supply in case the battery dies while
* in DPD mode.
* It is assumed that when the BOD detector indicates a battery voltage of 1.8 V or higher, the time spent in DPD
* mode is not enough to drain the battery to a value below 1.72 V.
*/
bool bod;
Chip_PMU_SetBODEnabled(true);
bod = ((Chip_PMU_GetStatus() & PMU_STATUS_BROWNOUT) != 0);
Chip_PMU_SetBODEnabled(false);
if (bod) {
Memory_AddToState(APP_MSG_EVENT_BOD);
}

bool isReadyToStart = Memory_IsReadyToStart();
bool isMonitoring = Memory_IsMonitoring();
bool isFull = Memory_IsFull();

DeInitApp();
Chip_EEPROM_DeInit(NSS_EEPROM);
NDEFT2T_DeInit();

if (isReadyToStart) {
#ifdef BOARD_ENABLE_WAKEUP
Chip_PMU_SetWakeupPinEnabled(true);
#endif
Chip_PMU_PowerMode_EnterDeepPowerDown(bod);
/* This function never returns. */
}
else if (isMonitoring || isFull) {
/* When full, we still want to keep track of time. The timer is not stopped in ExecuteMeasurementMode when
* a measurement cannot be stored, so we will still wake up periodically (making a futile attempts at storing a
* new measurement), and can then decide on the correct argument value for
* Chip_PMU_PowerMode_EnterDeepPowerDown.
*/
Chip_PMU_PowerMode_EnterDeepPowerDown(bod);
/* This function never returns. */
}
else {
if (waitBeforeDisconnect) {
Chip_Clock_System_BusyWait_ms(3000); /* Give some extra time to intervene via SWD. */
}
Chip_PMU_Switch_OpenVDDBat();
/* Normally, this function never returns. However, when providing power via SWD or any other PIO this will not
* work - current is flowing through the bondpad ring via the SWD pin, still powering a small part of the
* VDD_ALON domain.
* This situation is not covered by HW design: we can't rely on anything being functional or even harmless.
* Just ensure nothing happens, and wait until all power is gone.
*/
}
for(;;);
}

#ifdef BOARD_ENABLE_WAKEUP
static void CheckExternalTrigger(void)
{
if (Memory_IsReadyToStart()) {
Memory_AddToState(APP_MSG_EVENT_STARTING);
ExecuteMeasurementMode(false);
}
}
#endif

/**
* To be used in 'automatic' mode, where the NFC tag reader does not issue any command, but instead continually reads
* the NFC shared memory, expecting the firmware to timely update the contents. That is done by waiting for a 'message
* read' callback issued by NDEFT2T - #App_MsgReadCb, and then create a next command ourselves and feed it to
* #AppMsgHandleCommand.
* @return @c true when a command was generated and presented to #AppMsgHandleCommand; @c false otherwise.
* @note The generation of new commands can be reset by setting #sResetAutomaticCommandGeneration to @c true.
*/
static bool GenerateNextAutomaticCommand(void)
{
static const uint8_t sGetConfigCommand[2] = {APP_MSG_ID_GETCONFIG, 0}; /* Used when sIndex <= 1 */
static const uint8_t sGetResponseCommand[2] = {MSG_ID_GETRESPONSE, 0}; /* Used when sIndex == 4 */
static uint8_t sGetMeasurementsCommand[4] = {APP_MSG_ID_GETMEASUREMENTS, 0, 0, 0}; /* Used when sIndex == 2 */
static int sIndex = 0;
static int sOffset = 0;

const uint8_t * pData;
int length;

if (sResetAutomaticCommandGeneration) {
sResetAutomaticCommandGeneration = false;
NDEFT2T_EnableAutomaticMode();
sIndex = 0;
}

switch (sIndex) {
case 0:
pData = sGetConfigCommand;
length = sizeof(sGetConfigCommand);

sOffset = Storage_GetCount(); /* Prepare the next call */
sIndex++;
break;

case 1:
/* See comment in App_FieldStatusCb. On Android, there are multiple NFC_INT_TARGETREAD interrupts before
* the low-level NFC selection process is finished and the NFC connection is kept stable on the tag reader
* side. For the ARM, this means it better keeps the first message stable until it can be sure
* the message has been read and handled by the final and intended application.
* After trial and error, it seems that allowing/enforcing one extra redundant read is a safe value.
*/
pData = NULL;
length = 0;
sIndex++;
break;

case 2:
/* Correct offset for this call. */
if (sOffset >= APP_MSG_MAX_NR_OF_VALUES_IN_GETMEASUREMENTS_RESPONSE) {
sOffset -= APP_MSG_MAX_NR_OF_VALUES_IN_GETMEASUREMENTS_RESPONSE;
}
else {
sOffset = 0;
}
sGetMeasurementsCommand[2] = (uint8_t)(sOffset & 0x00FF);
sGetMeasurementsCommand[3] = (uint8_t)((sOffset >> 8) & 0x00FF);
pData = sGetMeasurementsCommand;
length = sizeof(sGetMeasurementsCommand);
sIndex++;
break;

case 3:
/* For an unknown reason, immediately retrieving the next measurements will at times result in gaps:
* iOS logs will then show a read-out sequence of message ... n-2, n-1, n, n, n+2, n+3, ...
* The "easiest" solution is then to provide the data twice as slow.
*/
pData = NULL;
length = 0;
/* Prepare the next call */
if (sOffset == 0) {
sIndex++;
}
else {
sIndex--;
}
break;

case 4:
pData = sGetResponseCommand;
length = sizeof(sGetResponseCommand);
sIndex++;
break;

default:
pData = NULL;
length = 0;
break;
}

if (pData && length) {
AppMsgHandleCommand(length, pData);
}
return (pData && length);
}

/**
* Perform all actions required when one measurement is due.
* @param usePlaceholder Indicates whether a placeholder must be stored (@c true) or a proper temperature measurement
* must be performed (@c false).
*/
static void ExecuteMeasurementMode(const bool usePlaceholder)
{
/* Entering this function means we are logging or are about to make a first measurement. In the latter case the
* state is still APP_MSG_EVENT_STARTING. Calling the function below redundantly does no harm.
*/
Memory_AddToState(APP_MSG_EVENT_LOGGING);

/* First prepare the next wake-up moment. */
const MEMORY_CONFIG_T * config = Memory_GetConfig();
ASSERT(config->status & APP_MSG_EVENT_LOGGING);
uint32_t startTime = 0;
Event_GetByTag(EVENT_TAG_LOGGING, (uint32_t)&startTime);
ASSERT(startTime != 0);
int elapsed = Chip_RTC_Time_GetValue(NSS_RTC) - (int)startTime;
/* runningTime: enter if running indefinitely.
* startTime: enter if logging state is not yet reached.
* elapsed: enter if time is not expired
*/
if ((config->cmd.runningTime == 0) || ((elapsed >= 0) && (elapsed < (int)config->cmd.runningTime))) {
/* The RTC consists of two timers. The down counter is used to leave Deep power down mode, but stops when it
* reaches 0. The up counter is never stopped. The time spent during booting, measuring temperature and
* reaching this point is not tracked by the down counter, but can be detected using the up counter.
* When we see an accumulated untracked time of more than 1 second (and thus we enter the if block below),
* we reduce the sleep time with 1 second. On average, we're then still on track.
*
* The check (deviation > 1) is performed as => (elapsed - sampleCount * interval > 1)
*/
int interval = (int)config->cmd.interval;
if ((Storage_GetCount() * interval) + 1 < elapsed) {
if (interval > 1) {
interval--;
}
}
Timer_StartMeasurementTimeout(interval);
}
else {
if (elapsed < 0) {
/* This block should never be entered: there is no logical scenario in which the program counter ends up in
* here. The only reason why elasped can be negative, is when the RTC timer got reset, which indicates a
* BOD or a reset pulse. In Memory_Init, this would then be detected, and the state adjusted accordingly:
* a call to this function would then never be triggered.
* Still, we're here now. And there is no sense in making further measurements. Just do nothing. Safest
* seems just to mark this end state and error condition - again, as it should be superfluous.
*/
Memory_AddToState(APP_MSG_EVENT_STOPPED | APP_MSG_EVENT_BOD);
}
else {
/* Enough time spent logging and monitoring. Do not schedule a new measurement. */
Memory_AddToState(APP_MSG_EVENT_STOPPED | APP_MSG_EVENT_EXPIRED);
}
Timer_StopMeasurementTimeout();
}

/* Only now make the measurement. */
Temperature_Reset();
if (!usePlaceholder) {
Temperature_Measure(TSEN_10BITS, false);
}
int data = Temperature_Get();
if (Storage_Write((STORAGE_TYPE *)&data, 1) != 1) {
/* Either compression failed; either storage is full. */
Memory_AddToState(APP_MSG_EVENT_STOPPED | APP_MSG_EVENT_FULL);
/* There are two possibilities here:
* - either we just stop, save the battery and go to power-off. No need to stop the timer, since power-off is
* imminent.
* - Or we continue to keep track of time, in which case it is most prudent to still wake up periodically so we
* can decide correctly on the value of the enableSwitching parameter of Chip_PMU_PowerMode_EnterDeepPowerDown.
* Either way, no need to call Timer_StopMeasurementTimeout here.
*/
}
if (!usePlaceholder) {
Validate_Temperature((STORAGE_TYPE)data);
}
}

/**
* Implements a while loop, waiting for an NDEF message in the NFC shared memory. the Ndeft2t module is used for this.
* When a message is detected, it is parsed as a 'command' in the msg module and a response is written in the NFC shared
* memory.
* This function returns when either
* - no message is received in a reasonable time limit
* - at least one message has been received (and answered to), and later the NFC field is removed.
* @return @c true when at least one message has been received (valid or not); @c false otherwise.
* @note When the RTC down counter reaches zero, #ExecuteMeasurementMode is called.
*/
static bool ExecuteCommunicationMode(void)
{
__attribute__ ((section(".noinit"))) __attribute__((aligned (4)))
static uint8_t sData[MAX_COMMAND_MESSAGE_SIZE];

__attribute__ ((section(".noinit"))) __attribute__((aligned (4)))
static uint8_t sNdefInstance[NDEFT2T_INSTANCE_SIZE];

bool messageReceived = false;

/* Safest is to just try to communicate. It will be stopped or restarted using the callbacks provided by the
* NDEFT2T module. By using Timer_CheckHostTimeout in the while loop below, the while loop will be
* stopped when the field has been removed.
*/
Timer_StartHostTimeout(FIRST_HOST_TIMEOUT);

#ifndef DEBUG
Chip_WWDT_Feed();
#endif
/* Wait for a command. Send responses based on these commands. */
while (!Timer_CheckHostTimeout()) {
/* Do not call Chip_PMU_PowerMode_EnterSleep here: an interrupt can have occurred between the check above
* and the call below, resulting in an everlasting while loop.
*/
if (sMessageAvailable) {
sMessageAvailable = false;
messageReceived = true;
if (NDEFT2T_GetMessage(sNdefInstance, sData, sizeof(sData))) {
const uint8_t * data;
int length;
NDEFT2T_PARSE_RECORD_INFO_T recordInfo;
while (NDEFT2T_GetNextRecord(sNdefInstance, &recordInfo)) {
if (recordInfo.type == NDEFT2T_RECORD_TYPE_MIME) {
data = NDEFT2T_GetRecordPayload(sNdefInstance, &length);
AppMsgHandleCommand(length, data);
}
}
}
}

if (sMessageRead) {
GenerateNextAutomaticCommand();
sMessageRead = false;
}

if (Timer_CheckMeasurementTimeout()) {
ExecuteMeasurementMode(USEPLACEHOLDER);
}
#ifndef DEBUG
if ((Chip_NFC_GetStatus(NSS_NFC) & NFC_STATUS_SEL) != 0) {
/* Only feed when NFC is still detected. This to avoid a hang where the while loop, checking on
* Timer_CheckHostTimeout is never ending.
*/
Chip_WWDT_Feed();
}
#endif
}

return messageReceived;
}

/* -------------------------------------------------------------------------------- */

int main(void)
{
Init();

PMU_DPD_WAKEUPREASON_T wakeup = Chip_PMU_PowerMode_GetDPDWakeupReason();
bool waitBeforeDisconnect = (wakeup == PMU_DPD_WAKEUPREASON_NONE);
if (wakeup == PMU_DPD_WAKEUPREASON_RTC) {
ExecuteMeasurementMode(false);
}
#ifdef BOARD_ENABLE_WAKEUP
else if (wakeup == PMU_DPD_WAKEUPREASON_WAKEUPPIN) {
CheckExternalTrigger();
}
#endif
else {
/* An NFC field may be present, or not. There is no guaranteed way to detect this, since the case
* 'connecting the battery due to the presence of an NFC field' is not captured in a register, only
* 'leaving Deep Power Down due to the presence of an NFC field'.
* Also, the IC might be started due to a reset pulse, but an NFC field may now have become present.
* We can't also look at the momentary status, since if an NFC field is present and the NFC reader is in the
* process of selecting this IC, the field may be suspended for a few milliseconds just now.
* Or, it may be completely gone by now.
* There is too much uncertainty: safest is to just try to communicate.
*/

#if defined(APP_MAINTAIN_SWD_CONNECTION)
/* Avoid the use the Deep Power Down and Power-off low-power states and maintain a debugging connection over
* SWD. Current consumption does not have focus here.
*/
for (;;) {
ExecuteCommunicationMode();
DeInitApp();
InitApp();
}
#else
/* Normal operation. Use the Deep Power Down and Power-off low-power states and preserve battery as much as
* possible.
*/
if (ExecuteCommunicationMode()) {
waitBeforeDisconnect = false;
}
#endif
}

DeInit(waitBeforeDisconnect); /* Does not return. */
return 0;
}

Outcomes