Mouse code for the MacroRat

Dependencies:   ITG3200 QEI

Revision:
18:6a4db94011d3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-dev/targets/TARGET_NORDIC/TARGET_NRF5/sdk/drivers_nrf/gpiote/nrf_drv_gpiote.c	Sun May 14 23:18:57 2017 +0000
@@ -0,0 +1,607 @@
+/* 
+ * Copyright (c) 2015 Nordic Semiconductor ASA
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * 
+ *   1. Redistributions of source code must retain the above copyright notice, this list 
+ *      of conditions and the following disclaimer.
+ *
+ *   2. Redistributions in binary form, except as embedded into a Nordic Semiconductor ASA 
+ *      integrated circuit in a product or a software update for such product, must reproduce 
+ *      the above copyright notice, this list of conditions and the following disclaimer in 
+ *      the documentation and/or other materials provided with the distribution.
+ *
+ *   3. Neither the name of Nordic Semiconductor ASA nor the names of its contributors may be 
+ *      used to endorse or promote products derived from this software without specific prior 
+ *      written permission.
+ *
+ *   4. This software, with or without modification, must only be used with a 
+ *      Nordic Semiconductor ASA integrated circuit.
+ *
+ *   5. Any software provided in binary or object form under this license must not be reverse 
+ *      engineered, decompiled, modified and/or disassembled. 
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+
+
+#include "nrf_drv_gpiote.h"
+#include "nrf_drv_common.h"
+#include "nrf_drv_config.h"
+#include "app_util_platform.h"
+#include "nrf_assert.h"
+
+#define FORBIDDEN_HANDLER_ADDRESS ((nrf_drv_gpiote_evt_handler_t)UINT32_MAX)
+#define PIN_NOT_USED              (-1)
+#define PIN_USED                  (-2)
+#define NO_CHANNELS               (-1)
+#define SENSE_FIELD_POS           (6)
+#define SENSE_FIELD_MASK          (0xC0)
+
+/**
+ * @brief Macro for conveting task-event index to an address of an event register.
+ *
+ * Macro utilizes the fact that registers are grouped together in ascending order.
+ */
+#define TE_IDX_TO_EVENT_ADDR(idx)   (nrf_gpiote_events_t)((uint32_t)NRF_GPIOTE_EVENTS_IN_0+(sizeof(uint32_t)*(idx)))
+
+/**
+ * @brief Macro for conveting task-event index to an address of a task register.
+ *
+ * Macro utilizes the fact that registers are grouped together in ascending order.
+ */
+#define TE_IDX_TO_TASK_ADDR(idx)   (nrf_gpiote_tasks_t)((uint32_t)NRF_GPIOTE_TASKS_OUT_0+(sizeof(uint32_t)*(idx)))
+
+//lint -save -e661
+typedef struct
+{
+    nrf_drv_gpiote_evt_handler_t handlers[NUMBER_OF_GPIO_TE+GPIOTE_CONFIG_NUM_OF_LOW_POWER_EVENTS];
+    int8_t                       pin_assignments[NUMBER_OF_PINS];
+    int8_t                       port_handlers_pins[GPIOTE_CONFIG_NUM_OF_LOW_POWER_EVENTS];
+    nrf_drv_state_t              state;
+} gpiote_control_block_t;
+
+static gpiote_control_block_t m_cb;
+
+__STATIC_INLINE bool pin_in_use(uint32_t pin)
+{
+    return (m_cb.pin_assignments[pin] != PIN_NOT_USED);
+}
+
+__STATIC_INLINE bool pin_in_use_as_non_task_out(uint32_t pin)
+{
+    return (m_cb.pin_assignments[pin] == PIN_USED);
+}
+
+__STATIC_INLINE bool pin_in_use_by_te(uint32_t pin)
+{
+    return (m_cb.pin_assignments[pin] >= 0 && m_cb.pin_assignments[pin] < NUMBER_OF_GPIO_TE) ? true : false;
+}
+
+__STATIC_INLINE bool pin_in_use_by_port(uint32_t pin)
+{
+    return (m_cb.pin_assignments[pin] >= NUMBER_OF_GPIO_TE);
+}
+
+__STATIC_INLINE bool pin_in_use_by_gpiote(uint32_t pin)
+{
+    return (m_cb.pin_assignments[pin] >= 0);
+}
+
+__STATIC_INLINE void pin_in_use_by_te_set(uint32_t pin,
+                                          uint32_t channel_id,
+                                          nrf_drv_gpiote_evt_handler_t handler,
+                                          bool is_channel)
+{
+    m_cb.pin_assignments[pin] = channel_id;
+    m_cb.handlers[channel_id] = handler;
+    if (!is_channel)
+    {
+        m_cb.port_handlers_pins[channel_id-NUMBER_OF_GPIO_TE] = (int8_t)pin;
+    }
+}
+
+__STATIC_INLINE void pin_in_use_set(uint32_t pin)
+{
+    m_cb.pin_assignments[pin] = PIN_USED;
+}
+
+__STATIC_INLINE void pin_in_use_clear(uint32_t pin)
+{
+    m_cb.pin_assignments[pin] = PIN_NOT_USED;
+}
+
+__STATIC_INLINE int8_t channel_port_get(uint32_t pin)
+{
+    return m_cb.pin_assignments[pin];
+}
+
+__STATIC_INLINE nrf_drv_gpiote_evt_handler_t channel_handler_get(uint32_t channel)
+{
+    return m_cb.handlers[channel];
+}
+
+static int8_t channel_port_alloc(uint32_t pin,nrf_drv_gpiote_evt_handler_t handler, bool channel)
+{
+    int8_t channel_id = NO_CHANNELS;
+    uint32_t i;
+
+    uint32_t start_idx = channel ? 0 : NUMBER_OF_GPIO_TE;
+    uint32_t end_idx = channel ? NUMBER_OF_GPIO_TE : (NUMBER_OF_GPIO_TE+GPIOTE_CONFIG_NUM_OF_LOW_POWER_EVENTS);
+    //critical section
+
+    for (i = start_idx; i < end_idx; i++)
+    {
+        if (m_cb.handlers[i] == FORBIDDEN_HANDLER_ADDRESS)
+        {
+            pin_in_use_by_te_set(pin, i, handler, channel);
+            channel_id = i;
+            break;
+        }
+    }
+    //critical section
+    return channel_id;
+}
+
+static void channel_free(uint8_t channel_id)
+{
+    m_cb.handlers[channel_id] = FORBIDDEN_HANDLER_ADDRESS;
+    if (channel_id >= NUMBER_OF_GPIO_TE)
+    {
+        m_cb.port_handlers_pins[channel_id-NUMBER_OF_GPIO_TE] = (int8_t)PIN_NOT_USED;
+    }
+}
+
+ret_code_t nrf_drv_gpiote_init(void)
+{
+    if (m_cb.state != NRF_DRV_STATE_UNINITIALIZED)
+    {
+        return NRF_ERROR_INVALID_STATE;
+    }
+
+    uint8_t i;
+    for (i = 0; i < NUMBER_OF_PINS; i++)
+    {
+        pin_in_use_clear(i);
+    }
+    for (i = 0; i < (NUMBER_OF_GPIO_TE+GPIOTE_CONFIG_NUM_OF_LOW_POWER_EVENTS); i++)
+    {
+        channel_free(i);
+    }
+
+    nrf_drv_common_irq_enable(GPIOTE_IRQn, GPIOTE_CONFIG_IRQ_PRIORITY);
+    nrf_gpiote_int_enable(GPIOTE_INTENSET_PORT_Msk);
+    m_cb.state = NRF_DRV_STATE_INITIALIZED;
+
+    return NRF_SUCCESS;
+}
+
+bool nrf_drv_gpiote_is_init(void)
+{
+    return (m_cb.state != NRF_DRV_STATE_UNINITIALIZED) ? true : false;
+}
+
+void nrf_drv_gpiote_uninit(void)
+{
+    ASSERT(m_cb.state!=NRF_DRV_STATE_UNINITIALIZED);
+
+    uint32_t i;
+    for (i = 0; i < NUMBER_OF_PINS; i++)
+    {
+        if (pin_in_use_as_non_task_out(i))
+        {
+            nrf_drv_gpiote_out_uninit(i);
+        }
+        else if( pin_in_use_by_gpiote(i))
+        {
+            /* Disable gpiote_in is having the same effect on out pin as gpiote_out_uninit on
+             * so it can be called on all pins used by GPIOTE.
+             */
+            nrf_drv_gpiote_in_uninit(i);
+        }
+    }
+    m_cb.state = NRF_DRV_STATE_UNINITIALIZED;
+}
+
+ret_code_t nrf_drv_gpiote_out_init(nrf_drv_gpiote_pin_t pin, 
+                                   nrf_drv_gpiote_out_config_t const * p_config)
+{
+    ASSERT(pin < NUMBER_OF_PINS);
+    ASSERT(m_cb.state == NRF_DRV_STATE_INITIALIZED);
+    ASSERT(p_config);
+
+    ret_code_t result = NRF_SUCCESS;
+
+    if (pin_in_use(pin))
+    {
+        result = NRF_ERROR_INVALID_STATE;
+    }
+    else
+    {
+        if (p_config->task_pin)
+        {
+            int8_t channel = channel_port_alloc(pin, NULL, true);
+
+            if (channel != NO_CHANNELS)
+            {
+                nrf_gpiote_task_configure(channel, pin, p_config->action, p_config->init_state);
+            }
+            else
+            {
+                result = NRF_ERROR_NO_MEM;
+            }
+        }
+        else
+        {
+            pin_in_use_set(pin);
+        }
+
+        if (result == NRF_SUCCESS)
+        {
+            if (p_config->init_state == NRF_GPIOTE_INITIAL_VALUE_HIGH)
+            {
+                nrf_gpio_pin_set(pin);
+            }
+            else
+            {
+                nrf_gpio_pin_clear(pin);
+            }
+            
+            nrf_gpio_cfg_output(pin);
+        }
+    }
+
+    return result;
+}
+
+void nrf_drv_gpiote_out_uninit(nrf_drv_gpiote_pin_t pin)
+{
+    ASSERT(pin < NUMBER_OF_PINS);
+    ASSERT(pin_in_use(pin));
+
+    if (pin_in_use_by_te(pin))
+    {
+        channel_free((uint8_t)channel_port_get(pin));
+        nrf_gpiote_te_default(channel_port_get(pin));
+    }
+    pin_in_use_clear(pin);
+
+    nrf_gpio_cfg_default(pin);
+}
+
+void nrf_drv_gpiote_out_set(nrf_drv_gpiote_pin_t pin)
+{
+    ASSERT(pin < NUMBER_OF_PINS);
+    ASSERT(pin_in_use(pin));
+    ASSERT(!pin_in_use_by_te(pin))
+
+    nrf_gpio_pin_set(pin);
+}
+
+void nrf_drv_gpiote_out_clear(nrf_drv_gpiote_pin_t pin)
+{
+    ASSERT(pin < NUMBER_OF_PINS);
+    ASSERT(pin_in_use(pin));
+    ASSERT(!pin_in_use_by_te(pin))
+
+    nrf_gpio_pin_clear(pin);
+}
+
+void nrf_drv_gpiote_out_toggle(nrf_drv_gpiote_pin_t pin)
+{
+    ASSERT(pin < NUMBER_OF_PINS);
+    ASSERT(pin_in_use(pin));
+    ASSERT(!pin_in_use_by_te(pin))
+
+    nrf_gpio_pin_toggle(pin);
+}
+
+void nrf_drv_gpiote_out_task_enable(nrf_drv_gpiote_pin_t pin)
+{
+    ASSERT(pin < NUMBER_OF_PINS);
+    ASSERT(pin_in_use(pin));
+    ASSERT(pin_in_use_by_te(pin))
+
+    nrf_gpiote_task_enable(m_cb.pin_assignments[pin]);
+}
+
+void nrf_drv_gpiote_out_task_disable(nrf_drv_gpiote_pin_t pin)
+{
+    ASSERT(pin < NUMBER_OF_PINS);
+    ASSERT(pin_in_use(pin));
+    ASSERT(pin_in_use_by_te(pin))
+
+    nrf_gpiote_task_disable(m_cb.pin_assignments[pin]);
+}
+
+uint32_t nrf_drv_gpiote_out_task_addr_get(nrf_drv_gpiote_pin_t pin)
+{
+    ASSERT(pin < NUMBER_OF_PINS);
+    ASSERT(pin_in_use_by_te(pin));
+    
+    nrf_gpiote_tasks_t task = TE_IDX_TO_TASK_ADDR(channel_port_get(pin));
+    return nrf_gpiote_task_addr_get(task);
+}
+
+void nrf_drv_gpiote_out_task_force(nrf_drv_gpiote_pin_t pin, uint8_t state)
+{
+    ASSERT(pin < NUMBER_OF_PINS);
+    ASSERT(pin_in_use(pin));
+    ASSERT(pin_in_use_by_te(pin));
+    
+    nrf_gpiote_outinit_t init_val = state ? NRF_GPIOTE_INITIAL_VALUE_HIGH : NRF_GPIOTE_INITIAL_VALUE_LOW;
+    nrf_gpiote_task_force(m_cb.pin_assignments[pin], init_val);
+}
+
+void nrf_drv_gpiote_out_task_trigger(nrf_drv_gpiote_pin_t pin)
+{
+    ASSERT(pin < NUMBER_OF_PINS);
+    ASSERT(pin_in_use(pin));
+    ASSERT(pin_in_use_by_te(pin));
+
+    nrf_gpiote_tasks_t task = TE_IDX_TO_TASK_ADDR(channel_port_get(pin));;
+    nrf_gpiote_task_set(task);
+}
+
+ret_code_t nrf_drv_gpiote_in_init(nrf_drv_gpiote_pin_t pin,
+                                  nrf_drv_gpiote_in_config_t const * p_config,
+                                  nrf_drv_gpiote_evt_handler_t evt_handler)
+{
+    ASSERT(pin < NUMBER_OF_PINS);
+    ret_code_t result = NRF_SUCCESS;
+    /* Only one GPIOTE channel can be assigned to one physical pin. */
+    if (pin_in_use_by_gpiote(pin))
+    {
+        result = NRF_ERROR_INVALID_STATE;
+    }
+    else
+    {
+        int8_t channel = channel_port_alloc(pin, evt_handler, p_config->hi_accuracy);
+        if (channel != NO_CHANNELS)
+        {
+            if (p_config->is_watcher)
+            {
+                nrf_gpio_cfg_watcher(pin);
+            }
+            else
+            {
+                nrf_gpio_cfg_input(pin,p_config->pull);
+            }
+
+            if (p_config->hi_accuracy)
+            {
+                nrf_gpiote_event_configure(channel, pin,p_config->sense);
+            }
+            else
+            {
+                m_cb.port_handlers_pins[channel-NUMBER_OF_GPIO_TE] |= (p_config->sense)<< SENSE_FIELD_POS;
+            }
+        }
+        else
+        {
+            result = NRF_ERROR_NO_MEM;
+        }
+    }
+    return result;
+}
+
+void nrf_drv_gpiote_in_event_enable(nrf_drv_gpiote_pin_t pin, bool int_enable)
+{
+    ASSERT(pin < NUMBER_OF_PINS);
+    ASSERT(pin_in_use_by_gpiote(pin));
+    if (pin_in_use_by_port(pin))
+    {
+        uint8_t pin_and_sense = m_cb.port_handlers_pins[channel_port_get(pin)-NUMBER_OF_GPIO_TE];
+        nrf_gpiote_polarity_t polarity = (nrf_gpiote_polarity_t)(pin_and_sense >> SENSE_FIELD_POS);
+        nrf_gpio_pin_sense_t sense;
+        if (polarity == NRF_GPIOTE_POLARITY_TOGGLE)
+        {
+            /* read current pin state and set for next sense to oposit */
+            sense = (nrf_gpio_pins_read() & (1 << pin)) ?
+                    NRF_GPIO_PIN_SENSE_LOW : NRF_GPIO_PIN_SENSE_HIGH;
+        }
+        else
+        {
+            sense = (polarity == NRF_GPIOTE_POLARITY_LOTOHI) ?
+                    NRF_GPIO_PIN_SENSE_HIGH : NRF_GPIO_PIN_SENSE_LOW;
+        }
+        nrf_gpio_cfg_sense_set(pin,sense);
+    }
+    else if(pin_in_use_by_te(pin))
+    {
+        int32_t channel = (int32_t)channel_port_get(pin);
+        nrf_gpiote_events_t event = TE_IDX_TO_EVENT_ADDR(channel);
+       
+        nrf_gpiote_event_enable(channel);
+
+        nrf_gpiote_event_clear(event);
+        if (int_enable)
+        {
+            nrf_drv_gpiote_evt_handler_t handler = channel_handler_get(channel_port_get(pin));
+            // Enable the interrupt only if event handler was provided.
+            if (handler)
+            {
+                nrf_gpiote_int_enable(1 << channel);
+            }
+        }
+    }
+}
+
+void nrf_drv_gpiote_in_event_disable(nrf_drv_gpiote_pin_t pin)
+{
+    ASSERT(pin < NUMBER_OF_PINS);
+    ASSERT(pin_in_use_by_gpiote(pin));
+    if (pin_in_use_by_port(pin))
+    {
+        nrf_gpio_cfg_sense_set(pin,NRF_GPIO_PIN_NOSENSE);
+    }
+    else if(pin_in_use_by_te(pin))
+    {
+        int32_t channel = (int32_t)channel_port_get(pin);
+        nrf_gpiote_event_disable(channel);
+        nrf_gpiote_int_disable(1 << channel);
+    }
+}
+
+void nrf_drv_gpiote_in_uninit(nrf_drv_gpiote_pin_t pin)
+{
+    ASSERT(pin < NUMBER_OF_PINS);
+    ASSERT(pin_in_use_by_gpiote(pin));
+    nrf_drv_gpiote_in_event_disable(pin);
+    if(pin_in_use_by_te(pin))
+    {
+        nrf_gpiote_te_default(channel_port_get(pin));
+    }
+    nrf_gpio_cfg_default(pin);
+    channel_free((uint8_t)channel_port_get(pin));
+    pin_in_use_clear(pin);
+}
+
+bool nrf_drv_gpiote_in_is_set(nrf_drv_gpiote_pin_t pin)
+{
+    ASSERT(pin < NUMBER_OF_PINS);
+    return nrf_gpio_pin_read(pin) ? true : false;
+}
+
+uint32_t nrf_drv_gpiote_in_event_addr_get(nrf_drv_gpiote_pin_t pin)
+{
+    ASSERT(pin < NUMBER_OF_PINS);
+    ASSERT(pin_in_use_by_te(pin));
+    
+    nrf_gpiote_events_t event = TE_IDX_TO_EVENT_ADDR(channel_port_get(pin));
+    return nrf_gpiote_event_addr_get(event);
+}
+
+void GPIOTE_IRQHandler(void)
+{
+    uint32_t status = 0;
+    uint32_t input = 0;
+
+    /* collect status of all GPIOTE pin events. Processing is done once all are collected and cleared.*/
+    uint32_t i;
+    nrf_gpiote_events_t event = NRF_GPIOTE_EVENTS_IN_0;
+    uint32_t mask = (uint32_t)NRF_GPIOTE_INT_IN0_MASK;
+    for (i = 0; i < NUMBER_OF_GPIO_TE; i++)
+    {
+        if (nrf_gpiote_event_is_set(event) && nrf_gpiote_int_is_enabled(mask))
+        {
+            nrf_gpiote_event_clear(event);
+            status |= mask;
+        }
+        mask <<= 1;
+        /* Incrementing to next event, utilizing the fact that events are grouped together
+         * in ascending order. */
+        event = (nrf_gpiote_events_t)((uint32_t)event + sizeof(uint32_t));
+    }
+
+    /* collect PORT status event, if event is set read pins state. Processing is postponed to the
+     * end of interrupt. */
+    if (nrf_gpiote_event_is_set(NRF_GPIOTE_EVENTS_PORT))
+    {
+        nrf_gpiote_event_clear(NRF_GPIOTE_EVENTS_PORT);
+        status |= (uint32_t)NRF_GPIOTE_INT_PORT_MASK;
+        input = nrf_gpio_pins_read();
+    }
+
+    /* Process pin events. */
+    if (status & NRF_GPIOTE_INT_IN_MASK)
+    {
+        mask = (uint32_t)NRF_GPIOTE_INT_IN0_MASK;
+        for (i = 0; i < NUMBER_OF_GPIO_TE; i++)
+        {
+            if (mask & status)
+            {
+                nrf_drv_gpiote_pin_t pin = nrf_gpiote_event_pin_get(i);
+                nrf_gpiote_polarity_t polarity = nrf_gpiote_event_polarity_get(i);
+                nrf_drv_gpiote_evt_handler_t handler = channel_handler_get(i);
+                handler(pin,polarity);
+            }
+            mask <<= 1;
+        }
+    }
+
+    if (status & (uint32_t)NRF_GPIOTE_INT_PORT_MASK)
+    {
+        /* Process port event. */
+        uint8_t repeat = 0;
+        uint32_t toggle_mask = 0;
+        uint32_t pins_to_check = 0xFFFFFFFFuL;
+
+        do
+        {
+            repeat = 0;
+            for (i = 0; i < GPIOTE_CONFIG_NUM_OF_LOW_POWER_EVENTS; i++)
+            {
+                uint8_t pin_and_sense = m_cb.port_handlers_pins[i];
+                nrf_drv_gpiote_pin_t pin = (pin_and_sense & ~SENSE_FIELD_MASK);
+
+                if ((m_cb.port_handlers_pins[i] != PIN_NOT_USED)
+                    && ((1UL << pin) & pins_to_check))
+                {
+                    nrf_gpiote_polarity_t polarity =
+                                (nrf_gpiote_polarity_t)((pin_and_sense & SENSE_FIELD_MASK) >> SENSE_FIELD_POS);
+                    nrf_drv_gpiote_evt_handler_t handler = channel_handler_get(channel_port_get(pin));
+                    if (handler || polarity == NRF_GPIOTE_POLARITY_TOGGLE)
+                    {
+                        mask = 1 << pin;
+                        if (polarity == NRF_GPIOTE_POLARITY_TOGGLE)
+                        {
+                            toggle_mask |= mask;
+                        }
+                        nrf_gpio_pin_sense_t sense = nrf_gpio_pin_sense_get(pin);
+
+                        if (((mask & input) && (sense==NRF_GPIO_PIN_SENSE_HIGH)) ||
+                           (!(mask & input) && (sense==NRF_GPIO_PIN_SENSE_LOW))  )
+                        {
+                            if (polarity == NRF_GPIOTE_POLARITY_TOGGLE)
+                            {
+                                nrf_gpio_pin_sense_t next_sense = (sense == NRF_GPIO_PIN_SENSE_HIGH) ?
+                                        NRF_GPIO_PIN_SENSE_LOW : NRF_GPIO_PIN_SENSE_HIGH;
+                                nrf_gpio_cfg_sense_set(pin, next_sense);
+                                ++repeat;
+                            }
+                            if (handler)
+                            {
+                                handler(pin, polarity);
+                            }
+                        }
+                    }
+                }
+            }
+
+            if (repeat)
+            {
+                // When one of the pins in low-accuracy and toggle mode becomes active,
+                // it's sense mode is inverted to clear the internal SENSE signal.
+                // State of any other enabled low-accuracy input in toggle mode must be checked
+                // explicitly, because it does not trigger the interrput when SENSE signal is active.
+                // For more information about SENSE functionality, refer to Product Specification.
+                uint32_t new_input = nrf_gpio_pins_read();
+                if (new_input == input)
+                {
+                    //No change.
+                    repeat = 0;
+                }
+                else
+                {
+                    input = new_input;
+                    pins_to_check = toggle_mask;
+                }
+            }
+        }
+        while (repeat);
+    }
+}
+//lint -restore