You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mynewt.apache.org by je...@apache.org on 2019/12/05 12:36:19 UTC

[mynewt-core] 02/06: sys/console: Add in-RAM implementation of history

This is an automated email from the ASF dual-hosted git repository.

jerzy pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mynewt-core.git

commit ecc5cfee49fd54039f458b8b382b61d5ea3ae92a
Author: Jerzy Kasenberg <je...@codecoup.pl>
AuthorDate: Wed Nov 13 15:34:41 2019 +0100

    sys/console: Add in-RAM implementation of history
    
    Code is mostly copied from existing console.c file.
---
 sys/console/full/history_ram/pkg.yml           |  32 ++++
 sys/console/full/history_ram/src/history_ram.c | 234 +++++++++++++++++++++++++
 sys/console/full/history_ram/syscfg.yml        |  27 +++
 3 files changed, 293 insertions(+)

diff --git a/sys/console/full/history_ram/pkg.yml b/sys/console/full/history_ram/pkg.yml
new file mode 100644
index 0000000..870da71
--- /dev/null
+++ b/sys/console/full/history_ram/pkg.yml
@@ -0,0 +1,32 @@
+#
+# 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: sys/console/full/history_ram
+pkg.description: RAM only console history.
+pkg.author: "Apache Mynewt <de...@mynewt.apache.org>"
+pkg.homepage: "http://mynewt.apache.org/"
+pkg.keywords:
+
+pkg.deps:
+    - "@apache-mynewt-core/hw/hal"
+    - "@apache-mynewt-core/kernel/os"
+    - "@apache-mynewt-core/sys/console/full"
+
+pkg.init:
+    console_history_ram_pkg_init: 'MYNEWT_VAL(CONSOLE_HISTORY_RAM_SYSINIT_STAGE)'
diff --git a/sys/console/full/history_ram/src/history_ram.c b/sys/console/full/history_ram/src/history_ram.c
new file mode 100644
index 0000000..e08fda0
--- /dev/null
+++ b/sys/console/full/history_ram/src/history_ram.c
@@ -0,0 +1,234 @@
+/*
+ * 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.
+ */
+
+#include <stdint.h>
+#include <ctype.h>
+#include <os/mynewt.h>
+#include <console/history.h>
+
+#ifndef bssnz_t
+/* Just in case bsp.h does not define it, in this case console history will
+ * not be preserved across software resets
+ */
+#define bssnz_t
+#endif
+
+#define HISTORY_SIZE MYNEWT_VAL(CONSOLE_HISTORY_RAM_HISTORY_SIZE)
+
+bssnz_t static char console_hist_lines[HISTORY_SIZE][ MYNEWT_VAL(CONSOLE_MAX_INPUT_LEN) ];
+
+bssnz_t static struct console_hist {
+    uint32_t magic;
+    uint8_t head;
+    uint8_t count;
+    char *lines[HISTORY_SIZE + 1];
+} console_hist;
+
+static size_t
+trim_whitespace(const char *str, char *out, size_t out_size)
+{
+    const char *end;
+    size_t len;
+
+    if (out_size == 0) {
+        return 0;
+    }
+
+    /* Skip leading space */
+    while (isspace((unsigned char)*str)) {
+        str++;
+    }
+
+    if (*str == 0) { /* All spaces? */
+        *out = 0;
+        return 0;
+    }
+
+    /* Skip trailing space */
+    end = str + strlen(str) - 1;
+    while (isspace((unsigned char)*end)) {
+        end--;
+    }
+
+    end++;
+
+    /* Set output size to minimum of trimmed string length and buffer size minus 1 */
+    len = min(end - str, out_size - 1);
+
+    /* Copy trimmed string and add null terminator */
+    memcpy(out, str, len);
+    out[len] = 0;
+
+    return len;
+}
+
+static uint8_t
+ring_buf_next(uint8_t i)
+{
+    return (uint8_t) ((i + 1) % HISTORY_SIZE);
+}
+
+static uint8_t
+ring_buf_prev(uint8_t i)
+{
+    return i == 0 ? HISTORY_SIZE - 1 : i - 1;
+}
+
+static bool
+console_hist_is_full(void)
+{
+    return console_hist.count == HISTORY_SIZE;
+}
+
+static bool
+console_hist_move_to_head(char *line)
+{
+    struct console_hist *sh = &console_hist;
+    char *match = NULL;
+    uint8_t prev;
+    uint8_t curr;
+    uint8_t left;
+
+    left = sh->count;
+    curr = ring_buf_prev(sh->head);
+    while (left) {
+        if (strcmp(sh->lines[curr], line) == 0) {
+            match = sh->lines[curr];
+            break;
+        }
+        curr = ring_buf_next(curr);
+        left--;
+    }
+
+    if (!match) {
+        return false;
+    }
+
+    prev = curr;
+    curr = ring_buf_next(curr);
+    while (curr != sh->head) {
+        sh->lines[prev] = sh->lines[curr];
+        prev = curr;
+        curr = ring_buf_next(curr);
+    }
+
+    sh->lines[prev] = match;
+
+    return true;
+}
+
+history_handle_t
+console_history_add(const char *line)
+{
+    struct console_hist *sh = &console_hist;
+    char buf[MYNEWT_VAL(CONSOLE_MAX_INPUT_LEN)];
+    size_t len;
+
+    len = trim_whitespace(line, buf, sizeof(buf));
+    if (len == 0) {
+        return 0;
+    }
+
+    if (console_hist_move_to_head(buf)) {
+        return 1;
+    }
+
+    strcpy(sh->lines[sh->head], buf);
+    sh->head = ring_buf_next(sh->head);
+    if (!console_hist_is_full()) {
+        sh->count++;
+    }
+    return 1;
+}
+
+history_handle_t
+console_history_find(history_handle_t start, history_find_type_t search_type,
+                     void *arg)
+{
+    int num;
+
+    switch (search_type) {
+    case HFT_PREV:
+        num = start + (arg ? *(int *)arg : 1);
+        if (num > console_hist.count) {
+            return 0;
+        }
+        return num;
+    case HFT_NEXT:
+        num = start - (arg ? *(int *)arg : 1);
+        if (num <= 0) {
+            return 0;
+        }
+        return num;
+    default:
+        return 0;
+    }
+}
+
+int
+console_history_get(history_handle_t handle, size_t offset, char *buf,
+                    size_t buf_size)
+{
+    const char *line;
+    size_t line_len;
+    int num = (int)handle;
+
+    if (num > console_hist.count || num < 1) {
+        return SYS_EINVAL;
+    }
+
+    if (num <= console_hist.head) {
+        line = console_hist.lines[console_hist.head - num];
+    } else {
+        line = console_hist.lines[console_hist.head + HISTORY_SIZE - num];
+    }
+
+    line_len = strlen(line);
+    if (line_len <= offset) {
+        return 0;
+    }
+    line += offset;
+    line_len -= offset;
+
+    if (line_len > buf_size) {
+        line_len = buf_size;
+    }
+    memcpy(buf, line, line_len);
+
+    return line_len;
+}
+
+int
+console_history_ram_pkg_init(void)
+{
+    struct console_hist *sh = &console_hist;
+    int i;
+
+    if (sh->magic != 0xBABEFACE) {
+        memset(console_hist_lines, 0, sizeof(console_hist_lines));
+        memset(&console_hist, 0, sizeof(console_hist));
+
+        for (i = 0; i < HISTORY_SIZE; i++) {
+            sh->lines[i] = console_hist_lines[i];
+        }
+        sh->magic = 0xBABEFACE;
+    }
+
+    return 0;
+}
diff --git a/sys/console/full/history_ram/syscfg.yml b/sys/console/full/history_ram/syscfg.yml
new file mode 100644
index 0000000..5fdb86a
--- /dev/null
+++ b/sys/console/full/history_ram/syscfg.yml
@@ -0,0 +1,27 @@
+# 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:
+    CONSOLE_HISTORY_RAM_HISTORY_SIZE:
+        description: >
+            Number of lines to be stored in console history.
+        value: 10
+    CONSOLE_HISTORY_RAM_SYSINIT_STAGE:
+        description: >
+            Sysinit stage for the in ram console history.
+        value: 1000