summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBill Richardson <wfrichar@chromium.org>2013-08-07 15:36:21 -0700
committerChromeBot <chrome-bot@google.com>2013-08-23 11:20:46 -0700
commit2f2dd1ce89ab502db1110616ab7e726d3ac4a2d2 (patch)
tree18782fe84b2919e0fe0c60829470a237ce14996b
parentcf5812c2539f40a9a5f9402711b8bae5adc453cf (diff)
downloadchrome-ec-2f2dd1ce89ab502db1110616ab7e726d3ac4a2d2.tar.gz
Add abstract "cond_t" type to detect state transitions.
We often need to watch for transitions between one state and another, so that we can issue warnings or take action ONCE. This abstracts that "have I already reacted to this" stuff into a single set of functions. For example, this code reads a GPIO every time through the loop, but it only generates an event when the GPIO value changes from 0 to 1: cond_t c; cond_init_false(&c); while(1) { int val = read_some_gpio(); cond_set(&c, val); if (cond_went_true(&c)) host_event(SOMETHING_HAPPENED); sleep(1); } BUG=none BRANCH=falco,peppy TEST=manual Note: This doesn't really need cherry-picking from ToT (it was a prerequisite for another CL that we decided NOT to backport), but it doesn't hurt. Other than the tests, nothing uses this. It's easier to just pull it in than to keep treating it as an exception. To test: make BOARD=falco runtests Original-Change-Id: I42393fcf3c4eb71b9551118a0f442d55c0691315 Signed-off-by: Bill Richardson <wfrichar@chromium.org> Reviewed-on: https://gerrit.chromium.org/gerrit/65071 (cherry picked from commit 0c8c2e453ab3960f315050fbb9808f438398624f) Change-Id: I44fe9a660016f3aa2ea2c7f8eb5c3e698d8f618f Reviewed-on: https://gerrit.chromium.org/gerrit/66838 Commit-Queue: Bill Richardson <wfrichar@chromium.org> Reviewed-by: Bill Richardson <wfrichar@chromium.org> Tested-by: Bill Richardson <wfrichar@chromium.org>
-rw-r--r--common/util.c58
-rw-r--r--include/util.h47
-rw-r--r--test/utils.c98
3 files changed, 202 insertions, 1 deletions
diff --git a/common/util.c b/common/util.c
index 5ccebeb063..0d7bff2710 100644
--- a/common/util.c
+++ b/common/util.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
+/* Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
@@ -272,3 +272,59 @@ int uint64divmod(uint64_t *n, int d)
*n = q;
return r;
}
+
+
+/****************************************************************************/
+/* stateful conditional stuff */
+
+enum cond_internal_bits {
+ COND_CURR_MASK = (1 << 0), /* current value */
+ COND_RISE_MASK = (1 << 1), /* set if 0->1 */
+ COND_FALL_MASK = (1 << 2), /* set if 1->0 */
+};
+
+void cond_init(cond_t *c, int val)
+{
+ if (val)
+ *c = COND_CURR_MASK;
+ else
+ *c = 0;
+}
+
+int cond_is(cond_t *c, int val)
+{
+ if (val)
+ return *c & COND_CURR_MASK;
+ else
+ return !(*c & COND_CURR_MASK);
+}
+
+
+void cond_set(cond_t *c, int val)
+{
+ if (val && cond_is(c, 0))
+ *c |= COND_RISE_MASK;
+ else if (!val && cond_is(c, 1))
+ *c |= COND_FALL_MASK;
+ if (val)
+ *c |= COND_CURR_MASK;
+ else
+ *c &= ~COND_CURR_MASK;
+}
+
+
+int cond_went(cond_t *c, int val)
+{
+ int ret;
+
+ if (val) {
+ ret = *c & COND_RISE_MASK;
+ *c &= ~COND_RISE_MASK;
+ }
+ else {
+ ret = *c & COND_FALL_MASK;
+ *c &= ~COND_FALL_MASK;
+ }
+
+ return ret;
+}
diff --git a/include/util.h b/include/util.h
index ed30ed4e46..0408940b35 100644
--- a/include/util.h
+++ b/include/util.h
@@ -101,4 +101,51 @@ int tolower(int c);
*/
int uint64divmod(uint64_t *v, int by);
+
+/****************************************************************************/
+/* Conditional stuff.
+ *
+ * We often need to watch for transitions between one state and another, so
+ * that we can issue warnings or take action ONCE. This abstracts that "have I
+ * already reacted to this" stuff into a single set of functions.
+ *
+ * For example:
+ *
+ * cond_t c;
+ *
+ * cond_init_false(&c);
+ *
+ * while(1) {
+ * int val = read_some_gpio();
+ * cond_set(&c, val);
+ *
+ * if (cond_went_true(&c))
+ * host_event(SOMETHING_HAPPENED);
+ * }
+ *
+ */
+typedef uint8_t cond_t;
+
+/* Initialize a conditional to a specific state. Do this first. */
+void cond_init(cond_t *c, int boolean);
+static inline void cond_init_false(cond_t *c) { cond_init(c, 0); }
+static inline void cond_init_true(cond_t *c) { cond_init(c, 1); }
+
+/* Set the current state. Do this as often as you like. */
+void cond_set(cond_t *c, int boolean);
+static inline void cond_set_false(cond_t *c) { cond_set(c, 0); }
+static inline void cond_set_true(cond_t *c) { cond_set(c, 1); }
+
+/* Get the current state. Do this as often as you like. */
+int cond_is(cond_t *c, int boolean);
+static inline int cond_is_false(cond_t *c) { return cond_is(c, 0); }
+static inline int cond_is_true(cond_t *c) { return cond_is(c, 1); }
+
+/* See if the state has transitioned. If it has, the corresponding function
+ * will return true ONCE only, until it's changed back.
+ */
+int cond_went(cond_t *c, int boolean);
+static inline int cond_went_false(cond_t *c) { return cond_went(c, 0); }
+static inline int cond_went_true(cond_t *c) { return cond_went(c, 1); }
+
#endif /* __CROS_EC_UTIL_H */
diff --git a/test/utils.c b/test/utils.c
index 3c92846417..e2230bfd44 100644
--- a/test/utils.c
+++ b/test/utils.c
@@ -185,6 +185,103 @@ static int test_scratchpad(void)
return EC_SUCCESS;
}
+static int test_cond_t(void)
+{
+ cond_t c;
+
+ /* one-shot? */
+ cond_init_false(&c);
+ cond_set_true(&c);
+ TEST_ASSERT(cond_went_true(&c));
+ TEST_ASSERT(!cond_went_true(&c));
+ TEST_ASSERT(!cond_went_true(&c));
+ cond_set_false(&c);
+ TEST_ASSERT(cond_went_false(&c));
+ TEST_ASSERT(!cond_went_false(&c));
+ TEST_ASSERT(!cond_went_false(&c));
+
+ /* one-shot when initially true? */
+ cond_init_true(&c);
+ cond_set_false(&c);
+ TEST_ASSERT(cond_went_false(&c));
+ TEST_ASSERT(!cond_went_false(&c));
+ TEST_ASSERT(!cond_went_false(&c));
+ cond_set_true(&c);
+ TEST_ASSERT(cond_went_true(&c));
+ TEST_ASSERT(!cond_went_true(&c));
+ TEST_ASSERT(!cond_went_true(&c));
+
+ /* still one-shot even if set multiple times? */
+ cond_init_false(&c);
+ cond_set_true(&c);
+ cond_set_true(&c);
+ cond_set_true(&c);
+ cond_set_true(&c);
+ cond_set_true(&c);
+ cond_set_true(&c);
+ TEST_ASSERT(cond_went_true(&c));
+ TEST_ASSERT(!cond_went_true(&c));
+ TEST_ASSERT(!cond_went_true(&c));
+ cond_set_true(&c);
+ cond_set_false(&c);
+ cond_set_false(&c);
+ cond_set_false(&c);
+ cond_set_false(&c);
+ cond_set_false(&c);
+ TEST_ASSERT(cond_went_false(&c));
+ TEST_ASSERT(!cond_went_false(&c));
+ TEST_ASSERT(!cond_went_false(&c));
+
+ /* only the detected transition direction resets it */
+ cond_set_true(&c);
+ TEST_ASSERT(!cond_went_false(&c));
+ TEST_ASSERT(cond_went_true(&c));
+ TEST_ASSERT(!cond_went_false(&c));
+ TEST_ASSERT(!cond_went_true(&c));
+ cond_set_false(&c);
+ TEST_ASSERT(!cond_went_true(&c));
+ TEST_ASSERT(!cond_went_true(&c));
+ TEST_ASSERT(cond_went_false(&c));
+ TEST_ASSERT(!cond_went_false(&c));
+ TEST_ASSERT(!cond_went_false(&c));
+ TEST_ASSERT(!cond_went_true(&c));
+ TEST_ASSERT(!cond_went_true(&c));
+
+ /* multiple transitions between checks should notice both edges */
+ cond_set_true(&c);
+ cond_set_false(&c);
+ cond_set_true(&c);
+ cond_set_false(&c);
+ cond_set_true(&c);
+ cond_set_false(&c);
+ TEST_ASSERT(cond_went_true(&c));
+ TEST_ASSERT(!cond_went_true(&c));
+ TEST_ASSERT(!cond_went_true(&c));
+ TEST_ASSERT(!cond_went_true(&c));
+ TEST_ASSERT(cond_went_false(&c));
+ TEST_ASSERT(!cond_went_false(&c));
+ TEST_ASSERT(!cond_went_false(&c));
+ TEST_ASSERT(!cond_went_false(&c));
+ TEST_ASSERT(!cond_went_true(&c));
+ TEST_ASSERT(!cond_went_true(&c));
+ TEST_ASSERT(!cond_went_false(&c));
+
+ /* Still has last value? */
+ cond_set_true(&c);
+ cond_set_false(&c);
+ cond_set_true(&c);
+ cond_set_false(&c);
+ TEST_ASSERT(cond_is_false(&c));
+ cond_set_false(&c);
+ cond_set_true(&c);
+ cond_set_false(&c);
+ cond_set_true(&c);
+ TEST_ASSERT(cond_is_true(&c));
+
+ /* well okay then */
+ return EC_SUCCESS;
+}
+
void run_test(void)
{
test_reset();
@@ -204,6 +301,7 @@ void run_test(void)
RUN_TEST(test_uint64divmod_2);
RUN_TEST(test_shared_mem);
RUN_TEST(test_scratchpad);
+ RUN_TEST(test_cond_t);
test_print_result();
}