You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mynewt.apache.org by GitBox <gi...@apache.org> on 2018/03/24 19:01:35 UTC

[GitHub] sterlinghughes closed pull request #889: implementation of common button events

sterlinghughes closed pull request #889: implementation of common button events
URL: https://github.com/apache/mynewt-core/pull/889
 
 
   

This is a PR merged from a forked repository.
As GitHub hides the original diff on merge, it is displayed below for
the sake of provenance:

As this is a foreign pull request (from a fork), the diff is supplied
below (as it won't show otherwise due to GitHub magic):

diff --git a/hw/util/button/include/button/button.h b/hw/util/button/include/button/button.h
new file mode 100644
index 000000000..3dd2be7fe
--- /dev/null
+++ b/hw/util/button/include/button/button.h
@@ -0,0 +1,374 @@
+#ifndef _BUTTON_H_
+#define _BUTTON_H_
+
+#include <stdbool.h>
+#include <os/os.h>
+
+/**
+ * This library generate events in the default queue to deal 
+ * with user interactions. These events need to be processed
+ * (by the main program or a thread) so that the associated 
+ * callback is triggered.
+ *
+ * According to the selected mode it is possible to deal with actions
+ * such as: click, double click, long click, long double click.
+ * And to make the last action auto-repeat (like a key).
+ *
+ * It can also generate event to reflect the actual button state,
+ * which is a mix of: pressed / doubled / long / repeating.
+ *
+ * The action differ from the state, as the action is generated
+ * when the button is released or after a small timeout.
+ *
+ * When a button is actively participating in an emulation, the state
+ * change event is emited but the action is not.
+ * For example button 3 = button 1 + button 2
+ *    a simultaneous click on button 1 and 2, will emit 
+ *    a click for button 3, but neither for 1 or 2.
+ *
+ *
+ *
+ * Small example, using the debounce package to drive the buttons.
+ *
+ * 
+ *
+ * button_t btns[] = {
+ *    { .id       = 1, // optional
+ *      .children = (button_t *[]){ &btns[2], NULL },
+ *      .mode     = BUTTON_MODE_MOUSE ,
+ *    },
+ *    { .id       = 2, // optional
+ *      .children = (button_t *[]){ &btns[2], NULL },
+ *      .mode     = BUTTON_MODE_TOUCH | BUTTON_FLG_REPEATING, 
+ *    },
+ *    { .id       = 3, // optional
+ *      .emulated = (button_t *[]){ &btns[0], &btns[1], NULL },
+ *      .mode     = BUTTON_MODE_BUTTON, 
+ *    },
+ * };
+ *
+ * button_init(btns, 3, button_callback);
+ *
+ *
+ * void button_debounce_handler(debounce_pin_t *d) {
+ *    button_t *button = (button_t *) d->arg;
+ *    bool   pressed = !debounce_state(d);
+ *
+ *    button_set_low_level_state(button, pressed);
+ * }
+ *
+ * debounce_pin_t dbtn_1, dbtn_2;
+ * debounce_init(&dbtn_1, BUTTON_1, HAL_GPIO_PULL_UP, 5);
+ * debounce_init(&dbtn_2, BUTTON_2, HAL_GPIO_PULL_UP, 5);
+ *
+ * debounce_start(&dbtn_1, DEBOUNCE_CALLBACK_EVENT_ANY,
+ *		  button_debounce_handler, &btns[0]);
+ * debounce_start(&dbtn_2, DEBOUNCE_CALLBACK_EVENT_ANY,
+ *                button_debounce_handler, &btns[1]);
+ *
+ *
+ *
+ * void button_callback(button_t *button, uint8_t type, uint8_t flags) {
+ *   if (type != BUTTON_ACTION) // Only interested by action
+ *	return;
+ *
+ *   switch(button->id) {
+ *   case 1:
+ *     if (flags & BUTTON_FLG_MISSED)
+ *       alert("some action was lost");
+ *     console_printf("BUTTON[%d] ", button->id);
+ *     if (flags & BUTTON_FLG_PRESSED) {
+ *	 console_printf("ACTION=");
+ *	 if (flags & BUTTON_FLG_LONG)	   console_printf("long ");
+ *       if (flags & BUTTON_FLG_DOUBLED)   console_printf("double ");
+ *       console_printf("click");
+ *	 if (flags & BUTTON_FLG_REPEATING) console_printf(" repeated");
+ *       console_printf("\n");
+ *     }
+ *     break;
+ *   case 2:
+ *     // Look at action, 
+ *     // but don't make special handling for repeated or missed
+ *     switch(flags & BUTTON_MASK_BASIC) {
+ *     case BUTTON_LONG_CLICK:  volume_off();    break;
+ *     case BUTTON_CLICK:       volume_dec(1);   break;
+ *     case BUTTON_DBLCLICK:    volume_dec(10);  break;
+ *     }
+ *     break;
+ *   }
+ * }
+ *
+ */
+
+/**
+ * Allow to only keep the pressed / double / long information.
+ * As it is generally usefull to discard the error parts of the flags
+ * (missed)
+ */
+#define BUTTON_MASK_BASIC     0x07
+
+/**
+ * Allow to only keep the pressed / double / long / repeat information.
+ * A it is generally usefull to discard the error parts of the flags
+ * (missed)
+ */
+#define BUTTON_MASK_FULL      0x0F
+
+
+/**
+ * Pressed state/action
+ */
+#define BUTTON_FLG_PRESSED		0x01
+#if MYNEWT_VAL(BUTTON_USE_DOUBLE)
+/**
+ * Doubled pressed state/action
+ */
+#define BUTTON_FLG_DOUBLED		0x02
+#endif
+#if MYNEWT_VAL(BUTTON_USE_LONG)
+/**
+ * Long pressed state/action
+ */
+#define BUTTON_FLG_LONG			0x04
+#endif
+#if MYNEWT_VAL(BUTTON_USE_REPEAT)
+/**
+ * Repeating state, continuously repeating last action
+ */
+#define BUTTON_FLG_REPEATING		0x08
+#endif
+/**
+ * Some event have been missed (not enough buffer event, 
+ *  increase BUTTON_EVENT_MAX)
+ */
+#define BUTTON_FLG_MISSED		0x40
+
+
+/**
+ * Indicate State Changed
+ */
+#define BUTTON_STATE_CHANGED  		0x01
+/**
+ * Indicate Action
+ */
+#define BUTTON_ACTION 			0x02
+
+
+/**
+ * Behave as a standard button (click action)
+ */
+#define BUTTON_MODE_BUTTON     (BUTTON_FLG_PRESSED)
+
+/**
+ * A click action
+ */
+#define BUTTON_CLICK           (BUTTON_FLG_PRESSED)
+
+/**
+ * A pressed state
+ */
+#define BUTTON_PRESSED         (BUTTON_FLG_PRESSED)
+
+/**
+ * A released state
+ */
+#define BUTTON_RELEASED        (0)
+
+
+#if MYNEWT_VAL(BUTTON_USE_DOUBLE)
+/**
+ * Behave as a mouse button (click, double click action)
+ */
+#define BUTTON_MODE_MOUSE      (BUTTON_MODE_BUTTON | BUTTON_FLG_DOUBLED)
+
+/**
+ * A double click action
+ */ 
+#define BUTTON_DBLCLICK        (BUTTON_CLICK       | BUTTON_FLG_DOUBLED)
+
+/**
+ * A double pressed state
+ */ 
+#define BUTTON_DBLPRESSED      (BUTTON_PRESSED     | BUTTON_FLG_DOUBLED)
+#endif
+
+#if MYNEWT_VAL(BUTTON_USE_LONG)
+/**
+ * Behave as a "pen" (click, and long press)
+ */
+#define BUTTON_MODE_PEN        (BUTTON_MODE_BUTTON | BUTTON_FLG_LONG)
+
+/**
+ * A long click action
+ */
+#define BUTTON_LONG_CLICK      (BUTTON_CLICK       | BUTTON_FLG_LONG)
+
+/**
+ * A long pressed state
+ */
+#define BUTTON_LONG_PRESSED    (BUTTON_PRESSED     | BUTTON_FLG_LONG)
+
+#endif
+
+#if MYNEWT_VAL(BUTTON_USE_DOUBLE) && MYNEWT_VAL(BUTTON_USE_LONG)
+/**
+ * Behave as a "touch" (click, double click, long press, double long press)
+ */ 
+#define BUTTON_MODE_TOUCH      (BUTTON_MODE_MOUSE  | BUTTON_FLG_LONG)
+/**
+ * A long double click action
+ */
+#define BUTTON_LONG_DBLCLICK   (BUTTON_DBLCLICK    | BUTTON_FLG_LONG)
+
+/**
+ * A long double pressed state
+ */
+#define BUTTON_LONG_DBLPRESSED (BUTTON_DBLPRESSED  | BUTTON_FLG_LONG)
+#endif
+
+
+#if MYNEWT_VAL(BUTTON_USE_REPEAT)
+/**
+ * A repeating pressed state
+ */
+#define BUTTON_PRESSED_REPEATING (BUTTON_PRESSED | BUTTON_FLG_REPEATING)
+
+/**
+ * A repeated click action
+ */
+#define BUTTON_CLICK_REPEATED    (BUTTON_CLICK | BUTTON_FLG_REPEATING)
+
+#if MYNEWT_VAL(BUTTON_USE_LONG)
+/**
+ * A repeating long pressed state
+ */
+#define BUTTON_LONG_PRESSED_REPEATING (BUTTON_PRESSED | BUTTON_FLG_REPEATING)
+
+/**
+ * A repeated long click action
+ */
+#define BUTTON_LONG_CLICK_REPEATED    (BUTTON_CLICK | BUTTON_FLG_REPEATING)
+#endif
+
+#if MYNEWT_VAL(BUTTON_USE_DOUBLE)
+/**
+ * A repeating double pressed state
+ */
+#define BUTTON_DBLPRESSED_REPEATING (BUTTON_DBLPRESSED | BUTTON_FLG_REPEATING)
+
+/**
+ * A repeated double click action
+ */
+#define BUTTON_DBLCLICK_REPEATED    (BUTTON_DBLCLICK | BUTTON_FLG_REPEATING)
+#endif
+
+#if MYNEWT_VAL(BUTTON_USE_DOUBLE) && MYNEWT_VAL(BUTTON_USE_LONG)
+/**
+ * A repeating long double pressed state
+ */
+#define BUTTON_LONG_DBLPRESSED_REPEATING (BUTTON_LONG_DBLPRESSED | BUTTON_FLG_REPEATING)
+
+/**
+ * A repeated long double click action
+ */
+#define BUTTON_LONG_DBLCLICK_REPEATED    (BUTTON_LONG_DBLCLICK | BUTTON_FLG_REPEATING)
+#endif
+#endif
+
+/**
+ * Button id
+ */
+typedef uint8_t button_id_t;
+
+/**
+ * Button definition
+ */
+typedef struct button {
+    /**
+     * Button identifier. (For user purpose, not used internaly)
+     */
+    button_id_t id;
+    /**
+     * Button behaviour.
+     * Type of state changed or action that should be taken into account.
+     */
+    uint8_t mode;
+    /*
+     * Current button state
+     */
+    uint8_t state;
+#if MYNEWT_VAL(BUTTON_USE_DOUBLE) || \
+    MYNEWT_VAL(BUTTON_USE_LONG  ) || \
+    MYNEWT_VAL(BUTTON_USE_REPEAT)
+    /*
+     * Finite state machine state
+     */
+    uint8_t fsm_state;
+    /*
+     * Callout for driving FSM timeout
+     */
+    struct os_callout callout;
+#endif
+#if MYNEWT_VAL(BUTTON_USE_EMULATION)
+    /**
+     * List (NULL-terminated) of buttons participating in the emulation.
+     * You will need to populate the from field for this button
+     * and children fields of the participating buttons.
+     */
+    struct button **emulated;
+    /**
+     * List (NULL-terminated) of buttons depending on this one.
+     */
+    struct button **children; 
+    /*
+     * Is this button currently behing emulated
+     */
+    bool emulating;      
+#endif
+#if MYNEWT_VAL(BUTTON_USE_FILTERING)
+    struct {
+	/**
+	 * Enable filtering (reducing number of events emited)
+	 */
+	bool enabled;
+	/**
+	 * List of state change to emit, based on BUTTON_FLG_*
+	 */
+	uint8_t state;
+	/**
+	 * List of action to emit, base on BUTTON_FLG_*
+	 */
+	uint8_t action;
+    } filter;
+#endif
+} button_t;
+
+/**
+ * Definition of the callback use to notify of action or state change.
+ *
+ * @param button	concerned button
+ * @param type		type of event (BUTTON_STATE_CHANGED or BUTTON_ACTION)
+ * @param flags		flag indicating the action or state change
+ *                      (see BUTTON_FLG_*)
+ */
+typedef void (*button_callback_t)(button_t *button, uint8_t type, uint8_t flags);
+
+/**
+ * Drive the button, by setting the the low level state (pressed / released)
+ * when it happens.
+ *
+ * @param button	button
+ * @param pressed	low level button state
+ */
+void button_set_low_level_state(button_t *button, bool pressed);
+
+/**
+ * Initialisation of the buttons
+ *
+ * @param buttons	buttons definition
+ * @param count		number of defined buttons
+ * @param cb		callback used to notify of state change or action
+ */
+void button_init(button_t *buttons, unsigned int count, button_callback_t cb);
+
+#endif
diff --git a/hw/util/button/pkg.yml b/hw/util/button/pkg.yml
new file mode 100644
index 000000000..b9b406c22
--- /dev/null
+++ b/hw/util/button/pkg.yml
@@ -0,0 +1,28 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+# 
+#  http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+pkg.name: hw/util/button
+pkg.description: Manage user interaction with a button
+pkg.author: "Apache Mynewt <de...@mynewt.apache.org>"
+pkg.homepage: "http://mynewt.apache.org/"
+pkg.keywords:
+    - button
+
+pkg.deps:
+    - kernel/os
diff --git a/hw/util/button/src/button.c b/hw/util/button/src/button.c
new file mode 100644
index 000000000..bdbdec939
--- /dev/null
+++ b/hw/util/button/src/button.c
@@ -0,0 +1,501 @@
+#include <assert.h>
+#include <syscfg/syscfg.h>
+
+#include "button/button.h"
+
+#define _BUTTON_FSM_INIT			0
+#define _BUTTON_FSM_PRESSED			1
+#define _BUTTON_FSM_WAIT_DBLPRESSED		2
+#define _BUTTON_FSM_DBLPRESSED			3
+#define _BUTTON_FSM_HOLD_OR_REPEAT		4
+
+#define _BUTTON_RELEASED			0
+#define _BUTTON_PRESSED				1
+#define _BUTTON_TIMEOUT				2
+
+struct button_event {
+    struct os_event os_event;
+    uint8_t type;
+    uint8_t flags;
+};
+
+#define BUTTON_POST_STATE_EVENT(button, flags)	\
+    button_post_event(button, BUTTON_STATE_CHANGED, flags)
+
+#define BUTTON_POST_ACTION_EVENT(button, flags)	\
+    button_post_event(button, BUTTON_ACTION, flags)
+
+static struct button_event button_event[MYNEWT_VAL(BUTTON_EVENT_MAX)] = { 0 };
+static button_callback_t button_callback = NULL;
+
+static struct button_event *
+button_alloc_event(void)
+{
+    for (int i = 0 ; i < MYNEWT_VAL(BUTTON_EVENT_MAX) ; i++) 
+	if (!OS_EVENT_QUEUED(&button_event[i].os_event))
+	    return &button_event[i];
+    return NULL;
+}
+
+/**
+ * Process generated event, using the user defined callback.
+ *
+ * @param ev generated event
+ */
+static void
+button_event_handler(struct os_event *ev)
+{
+    struct button_event *b_ev;
+    button_t *button;
+
+    b_ev   = (struct button_event *)ev;
+    button = (button_t *)ev->ev_arg;
+    button_callback(button, b_ev->type, b_ev->flags);
+}
+
+/**
+ * Post an event to the default queue.
+ * 
+ * @param button	button generating the event
+ * @param type		type of event (state or action)
+ * @param flags		event description (BUTTON_FLG_*)
+ *
+ * @return		-1 unable to post event (not enough buffer)
+ *                       0 event posted
+ *                       1 event not posted due to filtering
+ */
+static int
+button_post_event(button_t *button, uint8_t type, uint8_t flags)
+{
+    struct button_event *evt;
+
+#if MYNEWT_VAL(BUTTON_USE_FILTERING)
+    if (button->filter.enabled) {
+	uint8_t filter = 0xff;
+	switch(type) {
+#if MYNEWT_VAL(BUTTON_EMIT_STATE_CHANGED)
+	case BUTTON_STATE_CHANGED:
+	    filter = button->filter.state;
+	    break;
+#endif
+#if MYNEWT_VAL(BUTTON_EMIT_ACTION)
+	case BUTTON_ACTION:
+	    filter = button->filter.action;
+	    break;
+#endif
+	}
+	if (~filter & flags) {
+	    return 1;
+	}
+    }
+#endif
+
+    evt = button_alloc_event();
+    if (evt) {
+	evt->os_event.ev_cb  = button_event_handler;
+	evt->os_event.ev_arg = button;
+	evt->type            = type;
+	evt->flags           = flags;
+	os_eventq_put(os_eventq_dflt_get(), &evt->os_event);
+	return 0;
+    } else {
+	button->state |= BUTTON_FLG_MISSED;
+	return -1;
+    }
+}
+
+#if MYNEWT_VAL(BUTTON_USE_EMULATION)
+/**
+ * Perform button emulation.
+ *
+ * @param button	the button to emulate
+ */
+static void
+button_emulating(button_t *button)
+{
+    bool pressed  = true;
+    bool released = true;
+    
+    for (button_t **from = button->emulated ; *from ; from++) {
+	if ((*from)->state & BUTTON_FLG_PRESSED) {
+	    released = false;
+	} else {
+	    pressed  = false;
+	}
+    }
+    
+    if (pressed != !released)
+	return;
+
+    if (pressed || (released && button->emulating)) {
+	button->emulating = pressed;
+	button_set_low_level_state(button, pressed);
+    }
+}
+
+/**
+ * Process children of a button. Used for emulating button.
+ *
+ * @param button	the button to look for children
+ */
+static void
+button_process_children(button_t *button)
+{
+    if (button->children == NULL)
+	return;
+
+    for (button_t **child = button->children ; *child ; child++)
+	if ((*child)->emulated)
+	    button_emulating(*child);
+}
+
+/**
+ * Check if one of the children is using the action, and so
+ * we shouldn't generate one for ourself.
+ *
+ * @param button	the button to look for children
+ */
+static bool
+button_stealed_action(button_t *button)
+{
+    if (button->children == NULL)
+	return false;
+
+    for (button_t **child = button->children ; *child ; child++)
+	if ((*child)->emulated && (*child)->emulating)
+	    return true;
+
+    return false;
+}
+#endif
+
+/**
+ * Use low level action, to generated button state and action.
+ * This one deal with simple state/action, where only pressed/released/click
+ * are considered.
+ *
+ * @param button	button to process
+ * @param action	low level action associated to the button
+ *			(_BUTTON_PRESSED, _BUTTON_RELEASED)
+ */
+static void
+button_exec_simple(button_t *button, int action)
+{
+    assert(action != _BUTTON_TIMEOUT);
+
+    switch(action) {
+    case _BUTTON_PRESSED:
+	button->state  =  BUTTON_FLG_PRESSED;
+	break;
+    case _BUTTON_RELEASED:
+#if MYNEWT_VAL(BUTTON_EMIT_ACTION)
+#if MYNEWT_VAL(BUTTON_USE_EMULATION)
+	if (!button_stealed_action(button))
+#endif
+	    BUTTON_POST_ACTION_EVENT(button, button->state);
+#endif
+	button->state &= ~BUTTON_FLG_PRESSED;
+	break;
+    }
+
+#if MYNEWT_VAL(BUTTON_EMIT_STATE_CHANGED)
+    BUTTON_POST_STATE_EVENT(button, button->state);
+#endif
+    
+#if MYNEWT_VAL(BUTTON_USE_EMULATION)
+    button_process_children(button);
+#endif
+}
+
+#if MYNEWT_VAL(BUTTON_USE_DOUBLE) || \
+    MYNEWT_VAL(BUTTON_USE_LONG  ) || \
+    MYNEWT_VAL(BUTTON_USE_REPEAT)
+/**
+ * Use low level action, to generated button state and action.
+ * This one deal with complexe action, such as generating double click, 
+ * long click, repeating action, ...
+ *
+ * @param button	the button to process
+ * @param action	low level action associated to the button
+ *			(_BUTTON_PRESSED, _BUTTON_RELEASED, _BUTTON_TIMEOUT)
+ */
+static void
+button_exec_fsm(button_t *button, int action)
+{
+    struct os_callout *callout;
+
+    callout = &button->callout;
+    
+    switch (button->fsm_state) {
+    case _BUTTON_FSM_INIT:
+	switch(action) {
+	case _BUTTON_PRESSED:
+	    goto do_pressed;
+	case _BUTTON_RELEASED:
+	    goto do_nothing;
+	case _BUTTON_TIMEOUT:
+	    goto do_assert;
+	}
+	break;
+
+    case _BUTTON_FSM_PRESSED:
+	switch(action) {
+	case _BUTTON_PRESSED:
+	    goto do_nothing;
+	case _BUTTON_RELEASED:
+#if MYNEWT_VAL(BUTTON_USE_DOUBLE)
+	    if (button->mode & BUTTON_FLG_DOUBLED) {
+		goto to_wait_dblpressed;
+	    } else {
+#endif
+		goto do_release;
+#if MYNEWT_VAL(BUTTON_USE_DOUBLE)
+	    }
+#endif
+	case _BUTTON_TIMEOUT:
+#if MYNEWT_VAL(BUTTON_USE_LONG)
+	    if (button->mode & BUTTON_FLG_LONG) {
+	        goto do_longpress;
+#if MYNEWT_VAL(BUTTON_USE_REPEAT)
+	    } else if (button->mode & BUTTON_FLG_REPEATING) {
+		goto do_repeat;
+#endif
+            } else {
+		goto do_assert;
+	    }
+#elif MYNEWT_VAL(BUTTON_USE_REPEAT)
+            goto do_repeat;
+#else
+	    goto do_assert;
+#endif
+	}
+	break;
+	
+#if MYNEWT_VAL(BUTTON_USE_DOUBLE)
+    case _BUTTON_FSM_WAIT_DBLPRESSED:
+	switch(action) {
+	case _BUTTON_TIMEOUT:
+	    goto do_release;
+	case _BUTTON_PRESSED:
+	    goto do_dblpressed;
+	case _BUTTON_RELEASED:
+	    goto do_nothing;
+	}
+	break;
+
+    case _BUTTON_FSM_DBLPRESSED:
+	switch(action) {
+	case _BUTTON_TIMEOUT :
+#if MYNEWT_VAL(BUTTON_USE_LONG)
+	    if (button->mode & BUTTON_FLG_LONG) {
+		goto do_longpress;
+#if MYNEWT_VAL(BUTTON_USE_REPEAT)
+	    } else if (button->mode & BUTTON_FLG_REPEATING) {
+		goto do_repeat;
+#endif
+	    } else {
+		goto do_assert;
+	    }
+#elif MYNEWT_VAL(BUTTON_USE_REPEAT)
+	    goto do_repeat;
+#else
+	    goto do_assert;
+#endif
+	case _BUTTON_RELEASED: goto do_release;
+	case _BUTTON_PRESSED : goto do_nothing;
+	} 
+	break;
+#endif
+
+#if MYNEWT_VAL(BUTTON_USE_LONG  ) || \
+    MYNEWT_VAL(BUTTON_USE_REPEAT)
+    case _BUTTON_FSM_HOLD_OR_REPEAT:
+	switch(action) {
+	case _BUTTON_TIMEOUT:
+#if MYNEWT_VAL(BUTTON_USE_REPEAT)
+	    if (button->mode & BUTTON_FLG_REPEATING) {
+		goto do_repeat;
+	    } else {
+#endif
+		goto do_assert;
+#if MYNEWT_VAL(BUTTON_USE_REPEAT)
+	    }
+#endif
+	case _BUTTON_RELEASED:
+	    goto do_release;
+	case _BUTTON_PRESSED:
+	    goto do_nothing;
+	}
+	break;
+#endif
+    }
+
+ do_assert:
+    assert(0);
+    
+ do_nothing:
+    return;
+    
+ do_pressed:
+#if MYNEWT_VAL(BUTTON_USE_LONG)
+    if (button->mode & BUTTON_FLG_LONG) {
+        os_callout_reset(callout, MYNEWT_VAL(BUTTON_LONGHOLD_TICKS));
+#if MYNEWT_VAL(BUTTON_USE_REPEAT)
+    } else if (button->mode & BUTTON_FLG_REPEATING) {
+	os_callout_reset(callout, MYNEWT_VAL(BUTTON_REPEAT_FIRST_TICKS));
+#endif
+    }
+#elif MYNEWT_VAL(BUTTON_USE_REPEAT)
+    os_callout_reset(callout, MYNEWT_VAL(BUTTON_REPEAT_FIRST_TICKS));
+#endif
+    button->state = BUTTON_FLG_PRESSED;
+#if MYNEWT_VAL(BUTTON_EMIT_STATE_CHANGED)
+    BUTTON_POST_STATE_EVENT(button, button->state);
+#endif
+#if MYNEWT_VAL(BUTTON_USE_EMULATION)
+    button_process_children(button);
+#endif
+    button->fsm_state = _BUTTON_FSM_PRESSED;
+    return;
+    
+#if MYNEWT_VAL(BUTTON_USE_DOUBLE)
+ to_wait_dblpressed:
+    os_callout_reset(callout, MYNEWT_VAL(BUTTON_DBLCLICK_TICKS));
+    button->fsm_state = _BUTTON_FSM_WAIT_DBLPRESSED;
+    return;
+    
+ do_dblpressed:
+#if MYNEWT_VAL(BUTTON_USE_LONG)
+    if (button->mode & BUTTON_FLG_LONG) {
+	os_callout_reset(callout, MYNEWT_VAL(BUTTON_LONGHOLD_TICKS));
+#if MYNEWT_VAL(BUTTON_USE_REPEAT)
+    } else if (button->mode & BUTTON_FLG_REPEATING) {
+	os_callout_reset(callout, MYNEWT_VAL(BUTTON_REPEAT_FIRST_TICKS)); 
+#endif
+    } else {
+	os_callout_stop(callout);
+    }	
+#elif MYNEWT_VAL(BUTTON_USE_REPEAT)
+    os_callout_reset(callout, MYNEWT_VAL(BUTTON_REPEAT_FIRST_TICKS)); 
+#else
+    os_callout_stop(callout);
+#endif
+    button->state |= BUTTON_FLG_DOUBLED;
+#if MYNEWT_VAL(BUTTON_EMIT_STATE_CHANGED)
+    BUTTON_POST_STATE_EVENT(button, button->state);
+#endif
+    button->fsm_state = _BUTTON_FSM_DBLPRESSED;
+    return;
+#endif
+
+#if MYNEWT_VAL(BUTTON_USE_LONG)
+ do_longpress:
+#if MYNEWT_VAL(BUTTON_USE_REPEAT)
+    if (button->mode & BUTTON_FLG_REPEATING)
+	os_callout_reset(callout, MYNEWT_VAL(BUTTON_REPEAT_FIRST_TICKS));
+#endif
+    button->state |= BUTTON_FLG_LONG;
+#if MYNEWT_VAL(BUTTON_EMIT_STATE_CHANGED)
+    BUTTON_POST_STATE_EVENT(button, button->state);
+#endif
+    button->fsm_state = _BUTTON_FSM_HOLD_OR_REPEAT;
+    return;
+#endif
+    
+#if MYNEWT_VAL(BUTTON_USE_REPEAT)
+ do_repeat:
+    os_callout_reset(callout, MYNEWT_VAL(BUTTON_REPEAT_TICKS));
+    
+#if MYNEWT_VAL(BUTTON_EMIT_ACTION)
+#if MYNEWT_VAL(BUTTON_USE_EMULATION)
+    if (!button_stealed_action(button))
+#endif
+	BUTTON_POST_ACTION_EVENT(button, button->state);
+#endif
+    
+    if (!(button->state & BUTTON_FLG_REPEATING)) {
+	button->state |= BUTTON_FLG_REPEATING;
+#if MYNEWT_VAL(BUTTON_EMIT_STATE_CHANGED)
+	BUTTON_POST_STATE_EVENT(button, button->state);
+#endif
+    }
+    return;
+#endif
+    
+ do_release:
+    os_callout_stop(callout);
+
+#if MYNEWT_VAL(BUTTON_EMIT_ACTION)
+#if MYNEWT_VAL(BUTTON_USE_EMULATION)
+    if (!button_stealed_action(button)) {
+#endif
+#if MYNEWT_VAL(BUTTON_USE_REPEAT)
+	if (!(button->state & BUTTON_FLG_REPEATING))
+#endif
+	    BUTTON_POST_ACTION_EVENT(button, button->state);
+#if MYNEWT_VAL(BUTTON_USE_EMULATION)
+    }
+#endif
+#endif
+    button->state &= ~BUTTON_FLG_PRESSED;
+#if MYNEWT_VAL(BUTTON_EMIT_STATE_CHANGED)
+    BUTTON_POST_STATE_EVENT(button, button->state);
+#endif
+#if MYNEWT_VAL(BUTTON_USE_EMULATION)
+    button_process_children(button);
+#endif
+    button->fsm_state = _BUTTON_FSM_INIT;
+    return;
+}
+
+
+/**
+ * Callout function used for processing timeout.
+ * Used for processing complexe action.
+ *
+ * @param ev		event from callout
+ */
+static void
+button_fsm_callout(struct os_event *ev)
+{
+    button_t *button;
+
+    button = (button_t *)ev->ev_arg;
+    button_exec_fsm(button, _BUTTON_TIMEOUT);
+}
+#endif
+
+void
+button_init(button_t *buttons, unsigned int count, button_callback_t cb)
+{
+    button_callback = cb;
+    
+#if MYNEWT_VAL(BUTTON_USE_DOUBLE) || \
+    MYNEWT_VAL(BUTTON_USE_LONG  ) || \
+    MYNEWT_VAL(BUTTON_USE_REPEAT)
+    for (unsigned int i = 0 ; i < count ; i++) {
+	button_t *button = &buttons[i];
+	os_callout_init(&button->callout, os_eventq_dflt_get(),
+			button_fsm_callout, button);
+    }
+#endif
+}
+
+void
+button_set_low_level_state(button_t *button, bool pressed)
+{
+    int action;
+
+    action = pressed ? _BUTTON_PRESSED : _BUTTON_RELEASED;
+#if MYNEWT_VAL(BUTTON_USE_DOUBLE) || \
+    MYNEWT_VAL(BUTTON_USE_LONG  ) || \
+    MYNEWT_VAL(BUTTON_USE_REPEAT)
+    if (button->mode & ~(BUTTON_FLG_PRESSED)) {
+	button_exec_fsm(button, action);
+    } else {
+	button_exec_simple(button, action);
+    }
+#else
+    button_exec_simple(button, action);
+#endif
+}
diff --git a/hw/util/button/syscfg.yml b/hw/util/button/syscfg.yml
new file mode 100644
index 000000000..ab54f16b0
--- /dev/null
+++ b/hw/util/button/syscfg.yml
@@ -0,0 +1,72 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#  http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+syscfg.defs:
+    BUTTON_DBLCLICK_TICKS:
+        description: >
+            Maximum time in wich a second click should be performed
+            to consider it a double click. This will also introduce
+            a delay for generating the single click event.
+        value: '(OS_TICKS_PER_SEC / 4)'
+    BUTTON_LONGHOLD_TICKS:
+        description: >
+            Minimum time to wait with the button pressed to consider
+            it a long hold (long press, long click, long double click).
+        value: '(OS_TICKS_PER_SEC)'
+    BUTTON_REPEAT_FIRST_TICKS:
+        description: >
+            Time to wait before generating the first repeated action.
+        value: '(OS_TICKS_PER_SEC)'
+    BUTTON_REPEAT_TICKS:
+        description: >
+            Time to wait before generating consecutive repeated action.
+        value: '(OS_TICKS_PER_SEC)'
+    BUTTON_EVENT_MAX:
+        description: >
+            Maximum number of pending button event. (about 20bytes/event)
+        value: 10
+    BUTTON_USE_DOUBLE:
+        description: >
+            Include code for double click.
+        value: 1
+    BUTTON_USE_LONG:
+        description: >
+            Include code for long click/dblclick.
+        value: 1
+    BUTTON_USE_REPEAT:
+        description: >
+            Include code for auto-repeating last action.
+        value: 0
+    BUTTON_USE_EMULATION:
+        description: >
+            Include code for emulating buttons using simultaneous click
+        value: 0
+    BUTTON_USE_FILTERING:
+        description: >
+            Allow rejecting of event for which we are not interrested
+            to be notified.
+        value: 0
+    BUTTON_EMIT_ACTION:
+        description: >
+            Include code for generation of action event.
+        value: 1
+    BUTTON_EMIT_STATE_CHANGED:
+        description: >
+            Include code for generation of state changed event.
+        value: 0


 

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services