Skip to content

Commit

Permalink
samples: dect_phy: dect_shell: new startup_cmd added
Browse files Browse the repository at this point in the history
New command to store shell commands
to be run sequentially after a bootup.
Default max of 6 mem slots available for commands.

Signed-off-by: Jani Hirsimäki <[email protected]>
  • Loading branch information
jhirsi authored and rlubos committed Nov 6, 2024
1 parent 61ef13f commit f1fd584
Show file tree
Hide file tree
Showing 11 changed files with 543 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,8 @@ DECT NR+ samples
* The ``dect mac`` command.
A brief MAC-level sample on top of DECT PHY interface with new commands to create a periodic cluster beacon, scan for it, associate or disassociate a PT/client, and send data to a FT/beacon random access window.
This is not a full MAC implementation and not fully compliant with DECT NR+ MAC specification (`ETSI TS 103 636-4`_).
* The ``startup_cmd`` command.
This command is used to store shell commands to be run sequentially after bootup.

* Updated:

Expand Down
1 change: 1 addition & 0 deletions samples/dect/dect_phy/dect_shell/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,4 @@ target_sources(app PRIVATE src/shell.c)
add_subdirectory(src/print)
add_subdirectory(src/utils)
add_subdirectory_ifdef(CONFIG_DESH_DECT_PHY src/dect)
add_subdirectory_ifdef(CONFIG_DESH_STARTUP_CMDS src/startup_cmd)
4 changes: 4 additions & 0 deletions samples/dect/dect_phy/dect_shell/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,8 @@ config DESH_DECT_PHY
help
DECT NR+ PHY api shell tools

config DESH_STARTUP_CMDS
bool "Possibility to run stored shell commands from settings after bootup"
default y

endmenu
26 changes: 26 additions & 0 deletions samples/dect/dect_phy/dect_shell/README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -876,6 +876,32 @@ Example: starting of cluster beacon and sending RA data to it
Stopping beacon.
Beacon TX stopped, cause: User Initiated.
Running commands at bootup
==========================

DeSh command: ``startup_cmd``.

You can use the ``startup_cmd`` command to store shell commands to be run sequentially after bootup.

Example: starting of cluster beacon and sending RA data to it
-------------------------------------------------------------

* FT/Beacon device - Set a command to start a cluster beacon five seconds after bootup:

.. code-block:: console
desh:~$ startup_cmd -t 5 --mem_slot 1 --cmd_str "dect sett -t 1234"
desh:~$ startup_cmd --mem_slot 2 --cmd_str "dect mac beacon_start"
* PT/Client device - Set a command to start scanning for the beacon 60 seconds after bootup, associate to it, and send RA data to it:

.. code-block:: console
desh:~$ startup_cmd -t 60 --mem_slot 1 --cmd_str "dect sett -t 1235"
desh:~$ startup_cmd --mem_slot 2 --cmd_str "dect mac beacon_scan -c 0"
desh:~$ startup_cmd --mem_slot 3 -d 60 --cmd_str "dect mac associate -t 1234"
desh:~$ startup_cmd --mem_slot 4 -d 10 --cmd_str "dect mac rach_tx -t 1234 -d data"
Building
********

Expand Down
28 changes: 27 additions & 1 deletion samples/dect/dect_phy/dect_shell/src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,24 @@

#include <dk_buttons_and_leds.h>

#if defined(CONFIG_DESH_STARTUP_CMDS)
#include "startup_cmd_ctrl.h"
#endif
#include "desh_defines.h"
#include "desh_print.h"

BUILD_ASSERT(IS_ENABLED(CONFIG_SHELL_BACKEND_SERIAL),
"CONFIG_SHELL_BACKEND_SERIAL shell backend must be enabled");

/***** Work queue and work item definitions *****/

#if defined(CONFIG_DESH_STARTUP_CMDS)
#define DESH_COMMON_WORKQUEUE_STACK_SIZE 4096
#define DESH_COMMON_WORKQ_PRIORITY 5
K_THREAD_STACK_DEFINE(desh_common_workq_stack, DESH_COMMON_WORKQUEUE_STACK_SIZE);
struct k_work_q desh_common_work_q;
#endif

/* Global variables */
const struct shell *desh_shell;

Expand Down Expand Up @@ -163,14 +175,28 @@ int main(void)
*/
desh_print_reset_reason();

#if defined(CONFIG_DESH_STARTUP_CMDS)
struct k_work_queue_config cfg = {
.name = "desh_common_workq",
};

k_work_queue_start(
&desh_common_work_q,
desh_common_workq_stack,
K_THREAD_STACK_SIZEOF(desh_common_workq_stack),
DESH_COMMON_WORKQ_PRIORITY,
&cfg);
#endif
err = nrf_modem_lib_init();
if (err) {
/* Modem library initialization failed. */
printk("Could not initialize nrf_modem_lib, err %d\n", err);
printk("Fatal error\n");
return 0;
}

#if defined(CONFIG_DESH_STARTUP_CMDS)
startup_cmd_ctrl_init();
#endif
#if defined(CONFIG_DK_LIBRARY)
err = dk_leds_init();
if (err) {
Expand Down
11 changes: 11 additions & 0 deletions samples/dect/dect_phy/dect_shell/src/startup_cmd/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#
# Copyright (c) 2024 Nordic Semiconductor
#
# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
#

target_include_directories(app PRIVATE .)

target_sources(app PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/startup_cmd_ctrl.c)
target_sources(app PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/startup_cmd_shell.c)
target_sources(app PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/startup_cmd_settings.c)
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
/*
* Copyright (c) 2024 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
*/

#include <zephyr/kernel.h>
#include <stdio.h>

#include <zephyr/shell/shell.h>

#include "desh_print.h"
#include "startup_cmd_settings.h"

extern struct k_work_q desh_common_work_q;
extern const struct shell *desh_shell;

/* Work for running commands: */
struct startup_cmd_worker_data {
struct k_work_delayable work;
uint8_t running_mem_slot;
};
static struct startup_cmd_worker_data startup_cmd_worker_data;

static bool running;

static void startup_cmd_worker(struct k_work *work_item)
{
int len = 0;
int err;
struct k_work_delayable *delayable_work = k_work_delayable_from_work(work_item);
struct startup_cmd_worker_data *data_ptr =
CONTAINER_OF(delayable_work, struct startup_cmd_worker_data, work);
struct startup_cmd current_cmd_data;

err = startup_cmd_settings_cmd_data_read_by_memslot(
&current_cmd_data, data_ptr->running_mem_slot);
if (err) {
desh_error("(%s): Cannot read startup_cmd data for mem_slot %d",
(__func__), data_ptr->running_mem_slot);
return;
}

len = strlen(current_cmd_data.cmd_str);
if (len) {
desh_print("Starting to execute sett_cmd %d \"%s\"...",
data_ptr->running_mem_slot, current_cmd_data.cmd_str);
shell_execute_cmd(desh_shell, current_cmd_data.cmd_str);
}

/* We are done for this one. Schedule next stored command. */
if (data_ptr->running_mem_slot < STARTUP_CMD_MAX_COUNT) {
startup_cmd_worker_data.running_mem_slot++;
k_work_schedule_for_queue(
&desh_common_work_q,
&startup_cmd_worker_data.work,
K_SECONDS(startup_cmd_settings_cmd_delay_get(
startup_cmd_worker_data.running_mem_slot)));
} else {
/* No more commands to run */
startup_cmd_worker_data.running_mem_slot = 0;
}
}

static bool startup_cmd_can_be_started(void)
{
return (!running && startup_cmd_settings_enabled());
}

void startup_cmd_ctrl_settings_loaded(void)
{
int starttime = startup_cmd_settings_starttime_get();

if (startup_cmd_can_be_started()) {
startup_cmd_worker_data.running_mem_slot = 1;
k_work_schedule_for_queue(
&desh_common_work_q, &startup_cmd_worker_data.work, K_SECONDS(starttime));
running = true;
}
}

void startup_cmd_ctrl_init(void)
{
k_work_init_delayable(&startup_cmd_worker_data.work, startup_cmd_worker);
startup_cmd_settings_init();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
/*
* Copyright (c) 2024 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
*/

#ifndef DESH_STARTUP_CMD_CTRL_H
#define DESH_STARTUP_CMD_CTRL_H

void startup_cmd_ctrl_settings_loaded(void);
void startup_cmd_ctrl_init(void);

#endif /* DESH_STARTUP_CMD_CTRL_H */
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
/*
* Copyright (c) 2024 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
*/

#include <stdio.h>
#include <stdlib.h>
#include <zephyr/shell/shell.h>
#include <zephyr/settings/settings.h>

#include "desh_defines.h"
#include "desh_print.h"

#include "startup_cmd_ctrl.h"
#include "startup_cmd_settings.h"

#define STARTUP_CMD_SETTINGS_KEY "startup_cmd"
#define STARTUP_CMD_SETTINGS_VAL "data"

/* ****************************************************************************/

static struct startup_cmd_data startup_cmd_data;

/* ****************************************************************************/

/**@brief Callback when settings_load() is called. */
static int startup_cmd_settings_handler(
const char *key, size_t len, settings_read_cb read_cb, void *cb_arg)
{
int ret;

if (strcmp(key, STARTUP_CMD_SETTINGS_VAL) == 0) {
ret = read_cb(cb_arg, &startup_cmd_data, sizeof(startup_cmd_data));
if (ret < 0) {
printk("Failed to read dect startup_cmd_data, error: %d", ret);
return ret;
}
return 0;
}
return -ENOENT;
}

/* ****************************************************************************/

char *startup_cmd_settings_cmd_str_get(uint8_t mem_slot)
{
__ASSERT_NO_MSG(mem_slot >= 1 && mem_slot <= STARTUP_CMD_MAX_COUNT);
return startup_cmd_data.cmd[mem_slot - 1].cmd_str;
}

int startup_cmd_settings_cmd_delay_get(int mem_slot)
{
__ASSERT_NO_MSG(mem_slot >= 1 && mem_slot <= STARTUP_CMD_MAX_COUNT);
return startup_cmd_data.cmd[mem_slot - 1].delay;
}

int startup_cmd_settings_starttime_get(void)
{
return startup_cmd_data.starttime;
}


int startup_cmd_settings_data_read(struct startup_cmd_data *out_startup_cmd_data)
{
memcpy(out_startup_cmd_data, &startup_cmd_data, sizeof(struct startup_cmd_data));
return 0;
}

int startup_cmd_settings_cmd_data_read_by_memslot(
struct startup_cmd *out_cmd_data, int mem_slot)
{
if (mem_slot < 1 || mem_slot > STARTUP_CMD_MAX_COUNT) {
return -EINVAL;
}
memcpy(out_cmd_data, &startup_cmd_data.cmd[mem_slot - 1], sizeof(struct startup_cmd));
return 0;
}


int startup_cmd_settings_data_save(struct startup_cmd_data *new_startup_cmd_data)
{
int ret = settings_save_one(STARTUP_CMD_SETTINGS_KEY "/" STARTUP_CMD_SETTINGS_VAL,
new_startup_cmd_data, sizeof(struct startup_cmd_data));

if (ret) {
desh_error("Cannot save startup_cmd settings, err: %d", ret);
return ret;
}

startup_cmd_data = *new_startup_cmd_data;

desh_print("startup_cmd settings saved");

return ret;
}

bool startup_cmd_settings_enabled(void)
{
for (uint8_t i = 0; i < STARTUP_CMD_MAX_COUNT; i++) {
if (strlen(startup_cmd_data.cmd[i].cmd_str)) {
return true;
}
}
return false;
}

/* ****************************************************************************/

void startup_cmd_settings_data_print(void)
{
int starttime = startup_cmd_settings_starttime_get();
char *cmd_str;

desh_print("startup_cmd config:");
desh_print(" Start time: %d", starttime);

for (uint8_t i = 1; i <= STARTUP_CMD_MAX_COUNT; i++) {
desh_print(" Command #%d:", i);
cmd_str = startup_cmd_settings_cmd_str_get(i);
if (strlen(cmd_str)) {
desh_print(" String: %s", cmd_str);
desh_print(" Delay: %d", startup_cmd_settings_cmd_delay_get(i));
} else {
desh_print(" No command");
}
}
}

/* ****************************************************************************/

static int startup_cmd_settings_loaded(void)
{
/* All loaded, let's make them effective. */
startup_cmd_ctrl_settings_loaded();
return 0;
}

static struct settings_handler cfg = { .name = STARTUP_CMD_SETTINGS_KEY,
.h_set = startup_cmd_settings_handler,
.h_commit = startup_cmd_settings_loaded };

int startup_cmd_settings_init(void)
{
int err;

memset(&startup_cmd_data, 0, sizeof(startup_cmd_data));
startup_cmd_data.starttime = STARTUP_CMD_STARTTIME_DEFAULT;
for (int i = 0; i < STARTUP_CMD_MAX_COUNT; i++) {
startup_cmd_data.cmd[i].delay = STARTUP_CMD_DELAY_DEFAULT;
}

err = settings_subsys_init();
if (err) {
desh_error("(%s): Failed to initialize settings subsystem, error: %d",
(__func__), err);
return err;
}
err = settings_register(&cfg);
if (err) {
desh_error("(%s): Cannot register settings handler %d", (__func__), err);
return err;
}
err = settings_load();
if (err) {
desh_error("(%s): Cannot load settings %d", (__func__), err);
return err;
}
return 0;
}
Loading

0 comments on commit f1fd584

Please sign in to comment.