For with fix for disconnection notifications

Fork of nRF51822 by Nordic Semiconductor

Revision:
46:2bfbbe290083
Child:
56:a1071b629aa3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nordic/app_common/app_gpiote.c	Wed Jul 16 10:54:22 2014 +0100
@@ -0,0 +1,360 @@
+/* Copyright (c) 2012 Nordic Semiconductor. All Rights Reserved.
+ *
+ * The information contained herein is property of Nordic Semiconductor ASA.
+ * Terms and conditions of usage are described in detail in NORDIC
+ * SEMICONDUCTOR STANDARD SOFTWARE LICENSE AGREEMENT.
+ *
+ * Licensees are granted free, non-transferable use of the information. NO
+ * WARRANTY of ANY KIND is provided. This heading must NOT be removed from
+ * the file.
+ *
+ */
+
+#include "app_gpiote.h"
+#include <stdlib.h>
+#include <string.h>
+#include "app_util.h"
+#include "app_util_platform.h"
+#include "nrf_error.h"
+#include "nrf_gpio.h"
+
+
+/**@brief GPIOTE user type. */
+typedef struct
+{
+    uint32_t                   pins_mask;             /**< Mask defining which pins user wants to monitor. */
+    uint32_t                   pins_low_to_high_mask; /**< Mask defining which pins will generate events to this user when toggling low->high. */
+    uint32_t                   pins_high_to_low_mask; /**< Mask defining which pins will generate events to this user when toggling high->low. */
+    uint32_t                   sense_high_pins;       /**< Mask defining which pins are configured to generate GPIOTE interrupt on transition to high level. */
+    app_gpiote_event_handler_t event_handler;         /**< Pointer to function to be executed when an event occurs. */
+} gpiote_user_t;
+
+STATIC_ASSERT(sizeof(gpiote_user_t) <= GPIOTE_USER_NODE_SIZE);
+STATIC_ASSERT(sizeof(gpiote_user_t) % 4 == 0);
+
+static uint32_t        m_enabled_users_mask;          /**< Mask for tracking which users are enabled. */
+static uint8_t         m_user_array_size;             /**< Size of user array. */
+static uint8_t         m_user_count;                  /**< Number of registered users. */
+static gpiote_user_t * mp_users = NULL;               /**< Array of GPIOTE users. */
+
+
+/**@brief Function for toggling sense level for specified pins.
+ *
+ * @param[in]   p_user   Pointer to user structure.
+ * @param[in]   pins     Bitmask specifying for which pins the sense level is to be toggled.
+ */
+static void sense_level_toggle(gpiote_user_t * p_user, uint32_t pins)
+{
+    uint32_t pin_no;
+
+    for (pin_no = 0; pin_no < NO_OF_PINS; pin_no++)
+    {
+        uint32_t pin_mask = (1 << pin_no);
+
+        if ((pins & pin_mask) != 0)
+        {
+            uint32_t sense;
+
+            // Invert sensing.
+            if ((p_user->sense_high_pins & pin_mask) == 0)
+            {
+                sense                    = GPIO_PIN_CNF_SENSE_High << GPIO_PIN_CNF_SENSE_Pos;
+                p_user->sense_high_pins |= pin_mask;
+            }
+            else
+            {
+                sense                    = GPIO_PIN_CNF_SENSE_Low << GPIO_PIN_CNF_SENSE_Pos;
+                p_user->sense_high_pins &= ~pin_mask;
+            }
+
+            NRF_GPIO->PIN_CNF[pin_no] &= ~GPIO_PIN_CNF_SENSE_Msk;
+            NRF_GPIO->PIN_CNF[pin_no] |= sense;
+        }
+    }
+}
+
+
+/**@brief Function for handling the GPIOTE interrupt.
+ */
+void GPIOTE_IRQHandler(void)
+{
+    uint8_t  i;
+    uint32_t pins_changed;
+    uint32_t pins_state = NRF_GPIO->IN;
+
+    // Clear event.
+    NRF_GPIOTE->EVENTS_PORT = 0;
+
+    // Check all users.
+    for (i = 0; i < m_user_count; i++)
+    {
+        gpiote_user_t * p_user = &mp_users[i];
+
+        // Check if user is enabled.
+        if (((1 << i) & m_enabled_users_mask) != 0)
+        {
+            uint32_t transition_pins;
+            uint32_t event_low_to_high;
+            uint32_t event_high_to_low;
+
+            // Find set of pins on which there has been a transition.
+            transition_pins = (pins_state ^ ~p_user->sense_high_pins) & p_user->pins_mask;
+
+            // Toggle SENSE level for all pins that have changed state.
+            sense_level_toggle(p_user, transition_pins);
+
+            // Second read after setting sense.
+            // Check if any pins have changed while serving this interrupt.
+            pins_changed = NRF_GPIO->IN ^ pins_state;
+            if (pins_changed)
+            {
+                // Transition pins detected in late stage.
+                uint32_t late_transition_pins;
+
+                pins_state          |= pins_changed;
+
+                // Find set of pins on which there has been a transition.
+                late_transition_pins = (pins_state ^ ~p_user->sense_high_pins) & p_user->pins_mask;
+
+                // Toggle SENSE level for all pins that have changed state in last phase.
+                sense_level_toggle(p_user, late_transition_pins);
+
+                // Update pins that has changed state since the interrupt occurred.
+                transition_pins |= late_transition_pins;
+            }
+
+            // Call user event handler if an event has occurred.
+            event_high_to_low = (~pins_state & p_user->pins_high_to_low_mask) & transition_pins;
+            event_low_to_high = (pins_state & p_user->pins_low_to_high_mask) & transition_pins;
+
+            if ((event_low_to_high | event_high_to_low) != 0)
+            {
+                p_user->event_handler(event_low_to_high, event_high_to_low);
+            }
+        }
+    }
+}
+
+
+/**@brief Function for sense disabling for all pins for specified user.
+ *
+ * @param[in]  user_id   User id.
+ */
+static void pins_sense_disable(app_gpiote_user_id_t user_id)
+{
+    uint32_t pin_no;
+
+    for (pin_no = 0; pin_no < 32; pin_no++)
+    {
+        if ((mp_users[user_id].pins_mask & (1 << pin_no)) != 0)
+        {
+            NRF_GPIO->PIN_CNF[pin_no] &= ~GPIO_PIN_CNF_SENSE_Msk;
+            NRF_GPIO->PIN_CNF[pin_no] |= GPIO_PIN_CNF_SENSE_Disabled << GPIO_PIN_CNF_SENSE_Pos;
+        }
+    }
+}
+
+
+uint32_t app_gpiote_init(uint8_t max_users, void * p_buffer)
+{
+    if (p_buffer == NULL)
+    {
+        return NRF_ERROR_INVALID_PARAM;
+    }
+
+    // Check that buffer is correctly aligned.
+    if (!is_word_aligned(p_buffer))
+    {
+        return NRF_ERROR_INVALID_PARAM;
+    }
+
+    // Initialize file globals.
+    mp_users             = (gpiote_user_t *)p_buffer;
+    m_user_array_size    = max_users;
+    m_user_count         = 0;
+    m_enabled_users_mask = 0;
+
+    memset(mp_users, 0, m_user_array_size * sizeof(gpiote_user_t));
+
+    // Initialize GPIOTE interrupt (will not be enabled until app_gpiote_user_enable() is called).
+    NRF_GPIOTE->INTENCLR = 0xFFFFFFFF;
+
+    NVIC_ClearPendingIRQ(GPIOTE_IRQn);
+    NVIC_SetPriority(GPIOTE_IRQn, APP_IRQ_PRIORITY_HIGH);
+    NVIC_EnableIRQ(GPIOTE_IRQn);
+
+    return NRF_SUCCESS;
+}
+
+
+uint32_t app_gpiote_user_register(app_gpiote_user_id_t     * p_user_id,
+                                  uint32_t                   pins_low_to_high_mask,
+                                  uint32_t                   pins_high_to_low_mask,
+                                  app_gpiote_event_handler_t event_handler)
+{
+    // Check state and parameters.
+    if (mp_users == NULL)
+    {
+        return NRF_ERROR_INVALID_STATE;
+    }
+    if (event_handler == NULL)
+    {
+        return NRF_ERROR_INVALID_PARAM;
+    }
+    if (m_user_count >= m_user_array_size)
+    {
+        return NRF_ERROR_NO_MEM;
+    }
+
+    // Allocate new user.
+    mp_users[m_user_count].pins_mask             = pins_low_to_high_mask | pins_high_to_low_mask;
+    mp_users[m_user_count].pins_low_to_high_mask = pins_low_to_high_mask;
+    mp_users[m_user_count].pins_high_to_low_mask = pins_high_to_low_mask;
+    mp_users[m_user_count].event_handler         = event_handler;
+
+    *p_user_id = m_user_count++;
+
+    // Make sure SENSE is disabled for all pins.
+    pins_sense_disable(*p_user_id);
+
+    return NRF_SUCCESS;
+}
+
+
+uint32_t app_gpiote_user_enable(app_gpiote_user_id_t user_id)
+{
+    uint32_t pin_no;
+    uint32_t pins_state;
+
+    // Check state and parameters.
+    if (mp_users == NULL)
+    {
+        return NRF_ERROR_INVALID_STATE;
+    }
+    if (user_id >= m_user_count)
+    {
+        return NRF_ERROR_INVALID_PARAM;
+    }
+
+    // Clear any pending event.
+    NRF_GPIOTE->EVENTS_PORT = 0;
+    pins_state              = NRF_GPIO->IN;
+
+    // Enable user.
+    if (m_enabled_users_mask == 0)
+    {
+        NRF_GPIOTE->INTENSET = GPIOTE_INTENSET_PORT_Msk;
+    }
+    m_enabled_users_mask |= (1 << user_id);
+
+    // Enable sensing for all pins for specified user.
+    mp_users[user_id].sense_high_pins = 0;
+    for (pin_no = 0; pin_no < 32; pin_no++)
+    {
+        uint32_t pin_mask = (1 << pin_no);
+
+        if ((mp_users[user_id].pins_mask & pin_mask) != 0)
+        {
+            uint32_t sense;
+
+            if ((pins_state & pin_mask) != 0)
+            {
+                sense = GPIO_PIN_CNF_SENSE_Low << GPIO_PIN_CNF_SENSE_Pos;
+            }
+            else
+            {
+                sense = GPIO_PIN_CNF_SENSE_High << GPIO_PIN_CNF_SENSE_Pos;
+                mp_users[user_id].sense_high_pins |= pin_mask;
+            }
+
+            NRF_GPIO->PIN_CNF[pin_no] &= ~GPIO_PIN_CNF_SENSE_Msk;
+            NRF_GPIO->PIN_CNF[pin_no] |= sense;
+        }
+    }
+
+    return NRF_SUCCESS;
+}
+
+
+uint32_t app_gpiote_user_disable(app_gpiote_user_id_t user_id)
+{
+    // Check state and parameters.
+    if (mp_users == NULL)
+    {
+        return NRF_ERROR_INVALID_STATE;
+    }
+    if (user_id >= m_user_count)
+    {
+        return NRF_ERROR_INVALID_PARAM;
+    }
+
+    // Disable sensing for all pins for specified user.
+    pins_sense_disable(user_id);
+
+    // Disable user.
+    m_enabled_users_mask &= ~(1UL << user_id);
+    if (m_enabled_users_mask == 0)
+    {
+        NRF_GPIOTE->INTENCLR = GPIOTE_INTENSET_PORT_Msk;
+    }
+
+    return NRF_SUCCESS;
+}
+
+
+uint32_t app_gpiote_pins_state_get(app_gpiote_user_id_t user_id, uint32_t * p_pins)
+{
+    gpiote_user_t * p_user;
+
+    // Check state and parameters.
+    if (mp_users == NULL)
+    {
+        return NRF_ERROR_INVALID_STATE;
+    }
+    if (user_id >= m_user_count)
+    {
+        return NRF_ERROR_INVALID_PARAM;
+    }
+
+    // Get pins.
+    p_user  = &mp_users[user_id];
+    *p_pins = NRF_GPIO->IN & p_user->pins_mask;
+
+    return NRF_SUCCESS;
+}
+
+#if defined(SVCALL_AS_NORMAL_FUNCTION) || defined(SER_CONNECTIVITY)
+uint32_t app_gpiote_input_event_handler_register(const uint8_t                    channel,
+                                                 const uint32_t                   pin,
+                                                 const uint32_t                   polarity,
+                                                 app_gpiote_input_event_handler_t event_handler)
+{
+    (void)sense_level_toggle(NULL, pin);
+    return NRF_ERROR_NOT_SUPPORTED;
+}
+
+uint32_t app_gpiote_input_event_handler_unregister(const uint8_t channel)
+{
+    return NRF_ERROR_NOT_SUPPORTED;
+}
+
+uint32_t app_gpiote_end_irq_event_handler_register(app_gpiote_input_event_handler_t event_handler)
+{
+    return NRF_ERROR_NOT_SUPPORTED;
+}
+
+uint32_t app_gpiote_end_irq_event_handler_unregister(void)
+{
+    return NRF_ERROR_NOT_SUPPORTED;
+}
+
+uint32_t app_gpiote_enable_interrupts(void)
+{
+    return NRF_ERROR_NOT_SUPPORTED;
+}
+
+uint32_t app_gpiote_disable_interrupts(void)
+{
+    return NRF_ERROR_NOT_SUPPORTED;
+}
+#endif // SVCALL_AS_NORMAL_FUNCTION || SER_CONNECTIVITY