ble mesh chat sample to send 255 bytes of data using nRF21540dk/nRF52840 where build 2 configurations for nRF2140dk/nRF52840, build3 is for enabling FEM using nRF52840dk/nRF52840 + shield nRF21540ek
This commit is contained in:
commit
b77fd5457c
6
.gitignore
vendored
Normal file
6
.gitignore
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
# editors
|
||||
*.swp
|
||||
*~
|
||||
|
||||
# build
|
||||
/build*/
|
19
CMakeLists.txt
Normal file
19
CMakeLists.txt
Normal file
@ -0,0 +1,19 @@
|
||||
#
|
||||
# Copyright (c) 2020 Nordic Semiconductor ASA
|
||||
#
|
||||
# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
|
||||
#
|
||||
cmake_minimum_required(VERSION 3.20.0)
|
||||
|
||||
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
|
||||
project(NONE)
|
||||
|
||||
# NORDIC SDK APP START
|
||||
target_sources(app PRIVATE
|
||||
src/main.c
|
||||
src/model_handler.c
|
||||
src/chat_cli.c)
|
||||
target_include_directories(app PRIVATE include)
|
||||
|
||||
|
||||
# NORDIC SDK APP END
|
33
Kconfig
Normal file
33
Kconfig
Normal file
@ -0,0 +1,33 @@
|
||||
#
|
||||
# Copyright (c) 2020 Nordic Semiconductor
|
||||
#
|
||||
# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
|
||||
#
|
||||
|
||||
source "Kconfig.zephyr"
|
||||
|
||||
menu "Nordic Bluetooth Mesh chat client sample"
|
||||
|
||||
config BT_MESH_CHAT_CLI_MESSAGE_LENGTH
|
||||
int "Max length of the message to be sent over mesh"
|
||||
default 90
|
||||
range 0 255
|
||||
help
|
||||
Impacts on memory size occupied by the buffer of a message to be
|
||||
published. This does not include null terminator. The message must also
|
||||
fit into the application SDU. Adjust BT_MESH_TX_SEG_MAX and
|
||||
BT_MESH_RX_SEG_MAX to be able to receive the longest messages.
|
||||
|
||||
config BT_MESH_CHAT_SAMPLE_PRESENCE_CACHE_SIZE
|
||||
int "Presence cache size"
|
||||
default 10
|
||||
range 0 32767
|
||||
help
|
||||
Presence cache stores previously received presence of chat clients.
|
||||
Recommended to be as big as number of chat clients in the mesh network.
|
||||
|
||||
endmenu
|
||||
|
||||
module = BT_MESH_CHAT_CLI
|
||||
module-str = BT Mesh Chat Client model
|
||||
source "${ZEPHYR_BASE}/subsys/logging/Kconfig.template.log_config"
|
13
Kconfig.sysbuild
Normal file
13
Kconfig.sysbuild
Normal file
@ -0,0 +1,13 @@
|
||||
#
|
||||
# Copyright (c) 2023 Nordic Semiconductor
|
||||
#
|
||||
# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
|
||||
#
|
||||
|
||||
source "${ZEPHYR_BASE}/share/sysbuild/Kconfig"
|
||||
|
||||
config NRF_DEFAULT_IPC_RADIO
|
||||
default y
|
||||
|
||||
config NETCORE_IPC_RADIO_BT_HCI_IPC
|
||||
default y
|
21
README.rst
Normal file
21
README.rst
Normal file
@ -0,0 +1,21 @@
|
||||
.. _bt_mesh_chat:
|
||||
|
||||
Bluetooth Mesh: Chat
|
||||
####################
|
||||
|
||||
.. contents::
|
||||
:local:
|
||||
:depth: 2
|
||||
|
||||
The Bluetooth® Mesh chat sample demonstrates how to use the mesh network to facilitate communication between nodes by text, using the :ref:`bt_mesh_chat_client_model`.
|
||||
|
||||
See the subpages for detailed documentation on the sample and its internal model.
|
||||
|
||||
.. _mesh_chat_subpages:
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
:caption: Subpages:
|
||||
|
||||
sample_description.rst
|
||||
chat_cli.rst
|
5
VERSION
Normal file
5
VERSION
Normal file
@ -0,0 +1,5 @@
|
||||
VERSION_MAJOR = 2
|
||||
VERSION_MINOR = 9
|
||||
PATCHLEVEL = 0
|
||||
VERSION_TWEAK = 0
|
||||
EXTRAVERSION =
|
9
boards/nrf52dk_nrf52832.conf
Normal file
9
boards/nrf52dk_nrf52832.conf
Normal file
@ -0,0 +1,9 @@
|
||||
#
|
||||
# Copyright (c) 2024 Nordic Semiconductor ASA
|
||||
#
|
||||
# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
|
||||
#
|
||||
################################################################################
|
||||
# Application overlay - nrf52dk_nrf52832
|
||||
|
||||
CONFIG_SOC_FLASH_NRF_PARTIAL_ERASE=n
|
19
boards/nrf54l15dk_nrf54l15_cpuapp.conf
Normal file
19
boards/nrf54l15dk_nrf54l15_cpuapp.conf
Normal file
@ -0,0 +1,19 @@
|
||||
#
|
||||
# Copyright (c) 2024 Nordic Semiconductor ASA
|
||||
#
|
||||
# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
|
||||
#
|
||||
################################################################################
|
||||
# Application overlay - nrf54l15
|
||||
|
||||
CONFIG_SOC_FLASH_NRF_PARTIAL_ERASE=n
|
||||
CONFIG_NVS=n
|
||||
CONFIG_NVS_LOOKUP_CACHE=n
|
||||
CONFIG_SETTINGS_NVS_NAME_CACHE=n
|
||||
CONFIG_ZMS=y
|
||||
CONFIG_SETTINGS_ZMS_SECTOR_COUNT=8
|
||||
CONFIG_ZMS_LOOKUP_CACHE=y
|
||||
CONFIG_ZMS_LOOKUP_CACHE_SIZE=512
|
||||
CONFIG_SETTINGS_ZMS_NAME_CACHE=y
|
||||
CONFIG_SETTINGS_ZMS_NAME_CACHE_SIZE=512
|
||||
CONFIG_ZMS_LOOKUP_CACHE_FOR_SETTINGS=y
|
110
chat_cli.rst
Normal file
110
chat_cli.rst
Normal file
@ -0,0 +1,110 @@
|
||||
.. _bt_mesh_chat_client_model:
|
||||
|
||||
Chat Client model
|
||||
#################
|
||||
|
||||
.. contents::
|
||||
:local:
|
||||
:depth: 2
|
||||
|
||||
The Chat Client model is a vendor model that allows communication with other such models, by sending text messages and providing the presence of the model instance.
|
||||
It demonstrates basics of a vendor model implementation.
|
||||
The model doesn't have a limitation on per-node instantiations of the model, and therefore can be instantiated on each element of the node.
|
||||
|
||||
Overview
|
||||
********
|
||||
|
||||
In this section, you can find more detailed information about the following aspects of the Chat Client:
|
||||
|
||||
* `Composition data structure`_
|
||||
* `Messages`_
|
||||
|
||||
.. _bt_mesh_chat_client_model_composition:
|
||||
|
||||
Composition data structure
|
||||
==========================
|
||||
|
||||
The Chat Client model is a vendor model, and therefore in the application, when defining the node composition data, it needs to be declared in the third argument in the :c:macro:`BT_MESH_ELEM` macro:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
static struct bt_mesh_elem elements[] = {
|
||||
BT_MESH_ELEM(1,
|
||||
BT_MESH_MODEL_LIST(
|
||||
BT_MESH_MODEL_CFG_SRV(&cfg_srv),
|
||||
BT_MESH_MODEL_HEALTH_SRV(&health_srv, &health_pub)),
|
||||
BT_MESH_MODEL_LIST(
|
||||
BT_MESH_MODEL_CHAT_CLI(&chat))),
|
||||
};
|
||||
|
||||
.. _bt_mesh_chat_client_model_messages:
|
||||
|
||||
Messages
|
||||
========
|
||||
|
||||
The Chat Client model defines the following messages:
|
||||
|
||||
Presence
|
||||
Used to report the current model presence.
|
||||
When the model periodic publication is configured, the Chat Client model will publish its current presence, regardless of whether it has been changed or not.
|
||||
Presence message has a defined length of 1 byte.
|
||||
|
||||
Presence Get
|
||||
Used to retrieve the current model presence.
|
||||
Upon receiving the Presence Get message, the Chat Client model will send the Presence message with the current model presence stored in the response.
|
||||
The message doesn't have any payload.
|
||||
|
||||
Message
|
||||
Used to send a non-private text message.
|
||||
The payload consists of the text string terminated by ``\0``.
|
||||
The length of the text string can be configured at the compile-time using :ref:`CONFIG_BT_MESH_CHAT_CLI_MESSAGE_LENGTH <CONFIG_BT_MESH_CHAT_CLI_MESSAGE_LENGTH>` option.
|
||||
|
||||
Private Message
|
||||
Used to send a private text message.
|
||||
When the model receives this message, it replies with the Message Reply.
|
||||
The payload consists of the text string terminated by ``\0``.
|
||||
The length of the text string can be configured at the compile-time using :ref:`CONFIG_BT_MESH_CHAT_CLI_MESSAGE_LENGTH <CONFIG_BT_MESH_CHAT_CLI_MESSAGE_LENGTH>` option.
|
||||
|
||||
Message Reply
|
||||
Used to reply on the received Private Message to confirm the reception.
|
||||
The message doesn't have any payload.
|
||||
|
||||
Configuration
|
||||
*************
|
||||
|config|
|
||||
|
||||
Configuration options
|
||||
=====================
|
||||
|
||||
The following configuration parameters are associated with the Chat Client model:
|
||||
|
||||
.. _CONFIG_BT_MESH_CHAT_CLI_MESSAGE_LENGTH:
|
||||
|
||||
CONFIG_BT_MESH_CHAT_CLI_MESSAGE_LENGTH - Message length configuration
|
||||
Maximum length of the message to be sent over the mesh network.
|
||||
|
||||
.. _bt_mesh_chat_client_model_states:
|
||||
|
||||
States
|
||||
******
|
||||
|
||||
The Chat Client model contains the following states:
|
||||
|
||||
Presence: ``bt_mesh_chat_cli_presence``:
|
||||
The Chat Client model enables a user to set a current presence of the client instantiated on the element of the node.
|
||||
It can have the following values:
|
||||
|
||||
* :c:enumerator:`BT_MESH_CHAT_CLI_PRESENCE_AVAILABLE` - The client is available.
|
||||
* :c:enumerator:`BT_MESH_CHAT_CLI_PRESENCE_AWAY` - The client is away.
|
||||
* :c:enumerator:`BT_MESH_CHAT_CLI_PRESENCE_INACTIVE` - The client is inactive.
|
||||
* :c:enumerator:`BT_MESH_CHAT_CLI_PRESENCE_DO_NOT_DISTURB` - The client is in "do not disturb" state.
|
||||
|
||||
Extended models
|
||||
***************
|
||||
|
||||
None.
|
||||
|
||||
Persistent storage
|
||||
******************
|
||||
|
||||
If :kconfig:option:`CONFIG_BT_SETTINGS` is enabled, the Chat Client stores its presence state.
|
222
include/chat_cli.h
Normal file
222
include/chat_cli.h
Normal file
@ -0,0 +1,222 @@
|
||||
/*
|
||||
* Copyright (c) 2020 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @defgroup bt_mesh_chat_cli
|
||||
* @{
|
||||
* @brief API for the Bluetooth Mesh Chat Client model.
|
||||
*/
|
||||
|
||||
#ifndef BT_MESH_CHAT_CLI_H__
|
||||
#define BT_MESH_CHAT_CLI_H__
|
||||
|
||||
#include <zephyr/bluetooth/mesh.h>
|
||||
#include <bluetooth/mesh/model_types.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* .. include_startingpoint_chat_cli_rst_1 */
|
||||
/** Company ID of the Bluetooth Mesh Chat Client model. */
|
||||
#define BT_MESH_CHAT_CLI_VENDOR_COMPANY_ID CONFIG_BT_COMPANY_ID_NORDIC
|
||||
|
||||
/** Model ID of the Bluetooth Mesh Chat Client model. */
|
||||
#define BT_MESH_CHAT_CLI_VENDOR_MODEL_ID 0x000A
|
||||
|
||||
/** Non-private message opcode. */
|
||||
#define BT_MESH_CHAT_CLI_OP_MESSAGE BT_MESH_MODEL_OP_3(0x0A, \
|
||||
BT_MESH_CHAT_CLI_VENDOR_COMPANY_ID)
|
||||
|
||||
/** Private message opcode. */
|
||||
#define BT_MESH_CHAT_CLI_OP_PRIVATE_MESSAGE BT_MESH_MODEL_OP_3(0x0B, \
|
||||
BT_MESH_CHAT_CLI_VENDOR_COMPANY_ID)
|
||||
|
||||
/** Message reply opcode. */
|
||||
#define BT_MESH_CHAT_CLI_OP_MESSAGE_REPLY BT_MESH_MODEL_OP_3(0x0C, \
|
||||
BT_MESH_CHAT_CLI_VENDOR_COMPANY_ID)
|
||||
|
||||
/** Presence message opcode. */
|
||||
#define BT_MESH_CHAT_CLI_OP_PRESENCE BT_MESH_MODEL_OP_3(0x0D, \
|
||||
BT_MESH_CHAT_CLI_VENDOR_COMPANY_ID)
|
||||
|
||||
/** Presence get message opcode. */
|
||||
#define BT_MESH_CHAT_CLI_OP_PRESENCE_GET BT_MESH_MODEL_OP_3(0x0E, \
|
||||
BT_MESH_CHAT_CLI_VENDOR_COMPANY_ID)
|
||||
/* .. include_endpoint_chat_cli_rst_1 */
|
||||
|
||||
#define BT_MESH_CHAT_CLI_MSG_MINLEN_MESSAGE 1
|
||||
#define BT_MESH_CHAT_CLI_MSG_MAXLEN_MESSAGE (\
|
||||
CONFIG_BT_MESH_CHAT_CLI_MESSAGE_LENGTH \
|
||||
+ 1) /* + \0 */
|
||||
#define BT_MESH_CHAT_CLI_MSG_LEN_MESSAGE_REPLY 0
|
||||
#define BT_MESH_CHAT_CLI_MSG_LEN_PRESENCE 1
|
||||
#define BT_MESH_CHAT_CLI_MSG_LEN_PRESENCE_GET 0
|
||||
|
||||
/** Bluetooth Mesh Chat Client Presence values. */
|
||||
enum bt_mesh_chat_cli_presence {
|
||||
BT_MESH_CHAT_CLI_PRESENCE_AVAILABLE,
|
||||
BT_MESH_CHAT_CLI_PRESENCE_AWAY,
|
||||
BT_MESH_CHAT_CLI_PRESENCE_INACTIVE,
|
||||
BT_MESH_CHAT_CLI_PRESENCE_DO_NOT_DISTURB
|
||||
};
|
||||
|
||||
/* Forward declaration of the Bluetooth Mesh Chat Client model context. */
|
||||
struct bt_mesh_chat_cli;
|
||||
|
||||
/* .. include_startingpoint_chat_cli_rst_2 */
|
||||
/** @def BT_MESH_MODEL_CHAT_CLI
|
||||
*
|
||||
* @brief Bluetooth Mesh Chat Client model composition data entry.
|
||||
*
|
||||
* @param[in] _chat Pointer to a @ref bt_mesh_chat_cli instance.
|
||||
*/
|
||||
#define BT_MESH_MODEL_CHAT_CLI(_chat) \
|
||||
BT_MESH_MODEL_VND_CB(BT_MESH_CHAT_CLI_VENDOR_COMPANY_ID, \
|
||||
BT_MESH_CHAT_CLI_VENDOR_MODEL_ID, \
|
||||
_bt_mesh_chat_cli_op, &(_chat)->pub, \
|
||||
BT_MESH_MODEL_USER_DATA(struct bt_mesh_chat_cli, \
|
||||
_chat), \
|
||||
&_bt_mesh_chat_cli_cb)
|
||||
/* .. include_endpoint_chat_cli_rst_2 */
|
||||
|
||||
/** Bluetooth Mesh Chat Client model handlers. */
|
||||
struct bt_mesh_chat_cli_handlers {
|
||||
/** @brief Called after the node has been provisioned, or after all
|
||||
* mesh data has been loaded from persistent storage.
|
||||
*
|
||||
* @param[in] cli Chat Client instance that has been started.
|
||||
*/
|
||||
void (*const start)(struct bt_mesh_chat_cli *chat);
|
||||
|
||||
/** @brief Handler for a presence message.
|
||||
*
|
||||
* @param[in] cli Chat client instance that received the text message.
|
||||
* @param[in] ctx Context of the incoming message.
|
||||
* @param[in] presence Presence of a Chat Client that published
|
||||
* the message.
|
||||
*/
|
||||
void (*const presence)(struct bt_mesh_chat_cli *chat,
|
||||
struct bt_mesh_msg_ctx *ctx,
|
||||
enum bt_mesh_chat_cli_presence presence);
|
||||
|
||||
/** @brief Handler for a non-private text message.
|
||||
*
|
||||
* @param[in] cli Chat client instance that received the text message.
|
||||
* @param[in] ctx Context of the incoming message.
|
||||
* @param[in] msg Pointer to a received text message terminated with
|
||||
* a null character, '\0'.
|
||||
*/
|
||||
void (*const message)(struct bt_mesh_chat_cli *chat,
|
||||
struct bt_mesh_msg_ctx *ctx,
|
||||
const uint8_t *msg);
|
||||
|
||||
/** @brief Handler for a private message.
|
||||
*
|
||||
* @param[in] cli Chat client that received the text message.
|
||||
* @param[in] ctx Context of the incoming message.
|
||||
* @param[in] msg Pointer to a received text message terminated with
|
||||
* a null character, '\0'.
|
||||
*/
|
||||
void (*const private_message)(struct bt_mesh_chat_cli *chat,
|
||||
struct bt_mesh_msg_ctx *ctx,
|
||||
const uint8_t *msg);
|
||||
|
||||
/** @brief Handler for a reply on a private message.
|
||||
*
|
||||
* @param[in] cli Chat client instance that received the reply.
|
||||
* @param[in] ctx Context of the incoming message.
|
||||
*/
|
||||
void (*const message_reply)(struct bt_mesh_chat_cli *chat,
|
||||
struct bt_mesh_msg_ctx *ctx);
|
||||
};
|
||||
|
||||
/* .. include_startingpoint_chat_cli_rst_3 */
|
||||
/**
|
||||
* Bluetooth Mesh Chat Client model context.
|
||||
*/
|
||||
struct bt_mesh_chat_cli {
|
||||
/** Access model pointer. */
|
||||
const struct bt_mesh_model *model;
|
||||
/** Publish parameters. */
|
||||
struct bt_mesh_model_pub pub;
|
||||
/** Publication message. */
|
||||
struct net_buf_simple pub_msg;
|
||||
/** Publication message buffer. */
|
||||
uint8_t buf[BT_MESH_MODEL_BUF_LEN(BT_MESH_CHAT_CLI_OP_MESSAGE,
|
||||
BT_MESH_CHAT_CLI_MSG_MAXLEN_MESSAGE)];
|
||||
/** Handler function structure. */
|
||||
const struct bt_mesh_chat_cli_handlers *handlers;
|
||||
/** Current Presence value. */
|
||||
enum bt_mesh_chat_cli_presence presence;
|
||||
};
|
||||
/* .. include_endpoint_chat_cli_rst_3 */
|
||||
|
||||
/** @brief Set the client presence and publish the presence to the mesh network.
|
||||
*
|
||||
* @param[in] chat Chat Client model instance to set presence on.
|
||||
* @param[in] presence Presence status to be published.
|
||||
*
|
||||
* @retval 0 Successfully set the preceive and sent the message.
|
||||
* @retval -EADDRNOTAVAIL Publishing is not configured.
|
||||
* @retval -EAGAIN The device has not been provisioned.
|
||||
*/
|
||||
int bt_mesh_chat_cli_presence_set(struct bt_mesh_chat_cli *chat,
|
||||
enum bt_mesh_chat_cli_presence presence);
|
||||
|
||||
/** @brief Get current presence value of a chat client.
|
||||
*
|
||||
* @param[in] chat Chat Client model instance to send the message.
|
||||
* @param[in] addr Address of the chat client to get presence value of.
|
||||
*
|
||||
* @retval 0 Successfully sent the message.
|
||||
* @retval -EINVAL The model is not bound to an application key.
|
||||
* @retval -EAGAIN The device has not been provisioned.
|
||||
*/
|
||||
int bt_mesh_chat_cli_presence_get(struct bt_mesh_chat_cli *chat,
|
||||
uint16_t addr);
|
||||
|
||||
/** @brief Send a text message.
|
||||
*
|
||||
* @param[in] cli Chat Client model instance to send the message.
|
||||
* @param[in] msg Pointer to a text message to send. Must be terminated with
|
||||
* a null character, '\0'.
|
||||
*
|
||||
* @retval 0 Successfully sent the message.
|
||||
* @retval -EADDRNOTAVAIL Publishing is not configured.
|
||||
* @retval -EAGAIN The device has not been provisioned.
|
||||
*/
|
||||
int bt_mesh_chat_cli_message_send(struct bt_mesh_chat_cli *chat,
|
||||
const uint8_t *msg);
|
||||
|
||||
/** @brief Send a text message to a specified destination.
|
||||
*
|
||||
* @param[in] cli Chat Client model instance to send the message.
|
||||
* @param[in] addr Address of the chat client to send message to.
|
||||
* @param[in] msg Pointer to a text message to send. Must be terminated with
|
||||
* a null character, '\0'.
|
||||
*
|
||||
* @retval 0 Successfully sent the message.
|
||||
* @retval -EINVAL The model is not bound to an application key.
|
||||
* @retval -EAGAIN The device has not been provisioned.
|
||||
*/
|
||||
int bt_mesh_chat_cli_private_message_send(struct bt_mesh_chat_cli *chat,
|
||||
uint16_t addr,
|
||||
const uint8_t *msg);
|
||||
|
||||
/** @cond INTERNAL_HIDDEN */
|
||||
extern const struct bt_mesh_model_op _bt_mesh_chat_cli_op[];
|
||||
extern const struct bt_mesh_model_cb _bt_mesh_chat_cli_cb;
|
||||
/** @endcond */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* BT_MESH_CHAT_CLI_H__ */
|
||||
|
||||
/** @} */
|
27
include/model_handler.h
Normal file
27
include/model_handler.h
Normal file
@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright (c) 2020 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @brief Model handler
|
||||
*/
|
||||
|
||||
#ifndef MODEL_HANDLER_H__
|
||||
#define MODEL_HANDLER_H__
|
||||
|
||||
#include <zephyr/bluetooth/mesh.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
const struct bt_mesh_comp *model_handler_init(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* MODEL_HANDLER_H__ */
|
12
nrf52840dk_nrf52840.overlay
Normal file
12
nrf52840dk_nrf52840.overlay
Normal file
@ -0,0 +1,12 @@
|
||||
// To get started, press Ctrl+Space to bring up the completion menu and view the available nodes.
|
||||
|
||||
// You can also use the buttons in the sidebar to perform actions on nodes.
|
||||
// Actions currently available include:
|
||||
|
||||
// * Enabling / disabling the node
|
||||
// * Adding the bus to a bus
|
||||
// * Removing the node
|
||||
// * Connecting ADC channels
|
||||
|
||||
// For more help, browse the DeviceTree documentation at https://docs.zephyrproject.org/latest/guides/dts/index.html
|
||||
// You can also visit the nRF DeviceTree extension documentation at https://docs.nordicsemi.com/bundle/nrf-connect-vscode/page/guides/ncs_configure_app.html#devicetree-support-in-the-extension
|
72
prj.conf
Normal file
72
prj.conf
Normal file
@ -0,0 +1,72 @@
|
||||
#
|
||||
# Copyright (c) 2020 Nordic Semiconductor ASA
|
||||
#
|
||||
# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
|
||||
#
|
||||
CONFIG_NCS_SAMPLES_DEFAULTS=y
|
||||
|
||||
# Deferred logging helps improve LPN power consumption
|
||||
# when friendship is established.
|
||||
CONFIG_LOG_MODE_DEFERRED=y
|
||||
|
||||
# General configuration
|
||||
CONFIG_NCS_APPLICATION_BOOT_BANNER_STRING="Mesh Chat"
|
||||
CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=2048
|
||||
CONFIG_FLASH=y
|
||||
CONFIG_FLASH_MAP=y
|
||||
CONFIG_NVS=y
|
||||
CONFIG_SETTINGS=y
|
||||
CONFIG_NVS_LOOKUP_CACHE=y
|
||||
CONFIG_SETTINGS_NVS_NAME_CACHE=y
|
||||
CONFIG_HWINFO=y
|
||||
CONFIG_DK_LIBRARY=y
|
||||
CONFIG_PM_SINGLE_IMAGE=y
|
||||
CONFIG_PM_PARTITION_SIZE_SETTINGS_STORAGE=0x8000
|
||||
CONFIG_SOC_FLASH_NRF_PARTIAL_ERASE=y
|
||||
|
||||
# Bluetooth configuration
|
||||
CONFIG_BT=y
|
||||
CONFIG_BT_DEVICE_NAME="Mesh Chat"
|
||||
CONFIG_BT_L2CAP_TX_BUF_COUNT=8
|
||||
CONFIG_BT_OBSERVER=y
|
||||
CONFIG_BT_PERIPHERAL=y
|
||||
CONFIG_BT_SETTINGS=y
|
||||
|
||||
# Disable unused Bluetooth features
|
||||
CONFIG_BT_CTLR_LE_ENC=n
|
||||
CONFIG_BT_PHY_UPDATE=n
|
||||
CONFIG_BT_CTLR_MIN_USED_CHAN=n
|
||||
CONFIG_BT_CTLR_PRIVACY=n
|
||||
|
||||
# Bluetooth Mesh configuration
|
||||
CONFIG_BT_MESH=y
|
||||
CONFIG_BT_MESH_RELAY=y
|
||||
CONFIG_BT_MESH_FRIEND=y
|
||||
CONFIG_BT_MESH_RX_SEG_MAX=22
|
||||
CONFIG_BT_MESH_TX_SEG_MAX=22
|
||||
CONFIG_BT_MESH_CHAT_CLI_MESSAGE_LENGTH=255
|
||||
CONFIG_BT_MESH_PB_GATT=y
|
||||
CONFIG_BT_MESH_GATT_PROXY=y
|
||||
CONFIG_BT_MESH_DK_PROV=y
|
||||
|
||||
# Enable Bluetooth Mesh models debug logs
|
||||
CONFIG_BT_MESH_LOG_LEVEL_DBG=y
|
||||
|
||||
# Enable Shell module and use UART as a backend
|
||||
CONFIG_SHELL=y
|
||||
CONFIG_SHELL_BACKEND_SERIAL=y
|
||||
CONFIG_FLASH_SHELL=n
|
||||
|
||||
CONFIG_LOG_BACKEND_RTT=n
|
||||
|
||||
# configure 21540dk and enable MPSL and FEM
|
||||
CONFIG_MPSL=y
|
||||
CONFIG_MPSL_FEM=y
|
||||
CONFIG_FEM=y # not set for nrf21540dk
|
||||
CONFIG_MPSL_FEM_NRF21540_GPIO_SPI=y
|
||||
CONFIG_MPSL_FEM_NRF21540_TX_GAIN_DB=20
|
||||
# CONFIG_BT_CTLR_TX_PWR_DBM=0 // not set for nrf21540dk
|
||||
CONFIG_BT_CTLR_TX_PWR_ANTENNA=20
|
||||
|
||||
CONFIG_MPSL_FEM_POWER_MODEL=y
|
||||
CONFIG_MPSL_FEM_POWER_MODEL_NRF21540_USE_BUILTIN=y
|
15
sample.yaml
Normal file
15
sample.yaml
Normal file
@ -0,0 +1,15 @@
|
||||
sample:
|
||||
description: Bluetooth Mesh Chat sample
|
||||
name: Bluetooth Mesh Chat
|
||||
tests:
|
||||
sample.bluetooth.mesh.chat:
|
||||
sysbuild: true
|
||||
build_only: true
|
||||
integration_platforms:
|
||||
- nrf52dk/nrf52832
|
||||
- nrf52840dk/nrf52840
|
||||
- nrf21540dk/nrf52840
|
||||
- nrf54l15dk/nrf54l15/cpuapp
|
||||
platform_allow: nrf52dk/nrf52832 nrf52840dk/nrf52840 nrf21540dk/nrf52840
|
||||
nrf54l15dk/nrf54l15/cpuapp
|
||||
tags: bluetooth ci_build sysbuild
|
227
sample_description.rst
Normal file
227
sample_description.rst
Normal file
@ -0,0 +1,227 @@
|
||||
.. _bt_mesh_chat_description:
|
||||
|
||||
Sample description
|
||||
##################
|
||||
|
||||
.. contents::
|
||||
:local:
|
||||
:depth: 2
|
||||
|
||||
The Bluetooth® Mesh chat sample demonstrates how the mesh network can be used to facilitate communication between nodes by text, using the :ref:`bt_mesh_chat_client_model`.
|
||||
|
||||
Requirements
|
||||
************
|
||||
|
||||
The sample supports the following development kits:
|
||||
|
||||
.. table-from-sample-yaml::
|
||||
|
||||
The sample also requires a smartphone with Nordic Semiconductor's nRF Mesh mobile app installed in one of the following versions:
|
||||
|
||||
* `nRF Mesh mobile app for Android`_
|
||||
* `nRF Mesh mobile app for iOS`_
|
||||
|
||||
Overview
|
||||
********
|
||||
|
||||
By means of the mesh network, the clients as mesh nodes can communicate with each other without the need of a server.
|
||||
The mesh chat sample is mainly designed for group communication, but it also supports one-on-one communication, as well as sharing the nodes presence.
|
||||
|
||||
This sample is used in :ref:`ug_bt_mesh_vendor_model` as an example of how to implement a vendor model for the Bluetooth Mesh in |NCS|.
|
||||
|
||||
The clients are nodes with a provisionee role in a mesh network.
|
||||
Provisioning is performed using the `nRF Mesh mobile app`_.
|
||||
This mobile application is also used to configure key bindings, and publication and subscription settings of the Bluetooth Mesh model instances in the sample.
|
||||
After provisioning and configuring the mesh models supported by the sample in the `nRF Mesh mobile app`_, you can communicate with other mesh nodes by sending text messages and obtaining their presence using the :ref:`shell module <shell_api>`.
|
||||
|
||||
Provisioning
|
||||
============
|
||||
|
||||
The provisioning is handled by the :ref:`bt_mesh_dk_prov`.
|
||||
It supports four types of out-of-band (OOB) authentication methods, and uses the Hardware Information driver to generate a deterministic UUID to uniquely represent the device.
|
||||
|
||||
Models
|
||||
======
|
||||
|
||||
The following table shows the Bluetooth Mesh chat composition data for this sample:
|
||||
|
||||
+---------------+
|
||||
| Element 1 |
|
||||
+===============+
|
||||
| Config Server |
|
||||
+---------------+
|
||||
| Health Server |
|
||||
+---------------+
|
||||
| Chat Client |
|
||||
+---------------+
|
||||
|
||||
The models are used for the following purposes:
|
||||
|
||||
* The :ref:`bt_mesh_chat_client_model` instance in the first element is used to communicate with the other Chat Client models instantiated on the other mesh nodes.
|
||||
* Config Server allows configurator devices to configure the node remotely.
|
||||
* Health Server provides ``attention`` callbacks that are used during provisioning to call your attention to the device.
|
||||
These callbacks trigger blinking of the LEDs.
|
||||
|
||||
The model handling is implemented in :file:`src/model_handler.c`.
|
||||
|
||||
User interface
|
||||
**************
|
||||
|
||||
Buttons:
|
||||
Can be used to input the OOB authentication value during provisioning.
|
||||
All buttons have the same functionality during this procedure.
|
||||
|
||||
LEDs:
|
||||
Show the OOB authentication value during provisioning if the "Push button" OOB method is used.
|
||||
|
||||
Terminal emulator:
|
||||
Used for the interaction with the sample.
|
||||
|
||||
Configuration
|
||||
*************
|
||||
|
||||
|config|
|
||||
|
||||
Source file setup
|
||||
=================
|
||||
|
||||
This sample is split into the following source files:
|
||||
|
||||
* A :file:`main.c` file to handle initialization.
|
||||
* A file for handling the Chat Client model, :file:`chat_cli.c`.
|
||||
* A file for handling Bluetooth Mesh models and communication with the :ref:`shell module <shell_api>`, :file:`model_handler.c`.
|
||||
|
||||
FEM support
|
||||
===========
|
||||
|
||||
.. include:: /includes/sample_fem_support.txt
|
||||
|
||||
Building and running
|
||||
********************
|
||||
|
||||
.. |sample path| replace:: :file:`samples/bluetooth/mesh/chat`
|
||||
|
||||
.. include:: /includes/build_and_run.txt
|
||||
|
||||
.. _bluetooth_mesh_chat_testing:
|
||||
|
||||
Testing
|
||||
=======
|
||||
|
||||
After programming the sample to your development kit, you can test it by using a smartphone with `nRF Mesh mobile app`_ installed.
|
||||
Testing consists of provisioning the device and configuring it for communication with other nodes.
|
||||
|
||||
After configuring the device, you can interact with the sample using the terminal emulator.
|
||||
|
||||
Provisioning the device
|
||||
-----------------------
|
||||
|
||||
.. |device name| replace:: :guilabel:`Mesh Chat`
|
||||
|
||||
.. include:: /includes/mesh_device_provisioning.txt
|
||||
|
||||
Configuring models
|
||||
------------------
|
||||
|
||||
See :ref:`ug_bt_mesh_model_config_app` for details on how to configure the mesh models with the nRF Mesh mobile app.
|
||||
|
||||
Create a new group and name it *Chat Channel*, then configure the Vendor model on the **Mesh Chat** node:
|
||||
|
||||
* Bind the model to **Application Key 1**.
|
||||
* Set the publication parameters:
|
||||
|
||||
* Destination/publish address: Select the created group **Chat Channel**.
|
||||
* Publication interval: Set the interval to recommended value of 10 seconds.
|
||||
* Retransmit count: Change the count as preferred.
|
||||
|
||||
* Set the subscription parameters: Select the created group **Chat Channel**.
|
||||
|
||||
Interacting with the sample
|
||||
---------------------------
|
||||
|
||||
1. Connect the development kit to the computer using a USB cable.
|
||||
The development kit is assigned a COM port (Windows), ttyACM device (Linux) or tty.usbmodem (MacOS).
|
||||
#. |connect_terminal_specific_ANSI|
|
||||
#. Enable local echo in the terminal to see the text you are typing.
|
||||
|
||||
After completing the steps above, a command can be sent to the sample.
|
||||
The sample supports the following commands:
|
||||
|
||||
chat \-\-help
|
||||
Prints help message together with the list of supported commands.
|
||||
|
||||
chat presence set <presence>
|
||||
Sets presence of the current client.
|
||||
The following values are supported: available, away, dnd, inactive.
|
||||
|
||||
chat presence get <node>
|
||||
Gets presence of a specified chat client.
|
||||
|
||||
chat private <node> <message>
|
||||
Sends a private text message to a specified chat client.
|
||||
Remember to wrap the message in double quotes if it has 2 or more words.
|
||||
|
||||
chat msg <message>
|
||||
Sends a text message to the chat.
|
||||
Remember to wrap the message in double quotes if it has 2 or more words.
|
||||
|
||||
Whenever the node changes its presence, or the local node receives another model's presence the first time, you will see the following message:
|
||||
|
||||
.. code-block:: none
|
||||
|
||||
<0x0002> is now available
|
||||
|
||||
When the model receives a message from another node, together with the message you will see the address of the element of the node that sent the message:
|
||||
|
||||
.. code-block:: none
|
||||
|
||||
<0x0002>: Hi there!
|
||||
|
||||
The messages posted by the local node will have ``<you>`` instead of the address of the element:
|
||||
|
||||
.. code-block:: none
|
||||
|
||||
<you>: Hello, 0x0002!
|
||||
<you> are now away
|
||||
|
||||
Private messages can be identified by the address of the element of the node that posted the message (enclosed in asterisks):
|
||||
|
||||
.. code-block:: none
|
||||
|
||||
<you>: *0x0004* See you!
|
||||
<0x0004>: *you* Bye!
|
||||
|
||||
When the reply is received, you will see the following:
|
||||
|
||||
.. code-block:: none
|
||||
|
||||
<0x0004> received the message
|
||||
|
||||
Note that private messages are only seen by those the messages are addressed to.
|
||||
|
||||
Dependencies
|
||||
************
|
||||
|
||||
This sample uses the following |NCS| libraries:
|
||||
|
||||
* :ref:`bt_mesh_dk_prov`
|
||||
* :ref:`dk_buttons_and_leds_readme`
|
||||
|
||||
In addition, it uses the following Zephyr libraries:
|
||||
|
||||
* :ref:`zephyr:kernel_api`:
|
||||
|
||||
* :file:`include/kernel.h`
|
||||
|
||||
* :ref:`zephyr:shell_api`:
|
||||
|
||||
* :file:`include/shell.h`
|
||||
* :file:`include/shell_uart.h`
|
||||
|
||||
* :ref:`zephyr:bluetooth_api`:
|
||||
|
||||
* :file:`include/bluetooth/bluetooth.h`
|
||||
|
||||
* :ref:`zephyr:bluetooth_mesh`:
|
||||
|
||||
* :file:`include/bluetooth/mesh.h`
|
320
src/chat_cli.c
Normal file
320
src/chat_cli.c
Normal file
@ -0,0 +1,320 @@
|
||||
/*
|
||||
* Copyright (c) 2019 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
|
||||
*/
|
||||
|
||||
#include <zephyr/bluetooth/mesh.h>
|
||||
#include "chat_cli.h"
|
||||
#include "mesh/net.h"
|
||||
#include <string.h>
|
||||
|
||||
#include <zephyr/logging/log.h>
|
||||
LOG_MODULE_DECLARE(chat);
|
||||
|
||||
BUILD_ASSERT(BT_MESH_MODEL_BUF_LEN(BT_MESH_CHAT_CLI_OP_MESSAGE,
|
||||
BT_MESH_CHAT_CLI_MSG_MAXLEN_MESSAGE) <=
|
||||
BT_MESH_RX_SDU_MAX,
|
||||
"The message must fit inside an application SDU.");
|
||||
BUILD_ASSERT(BT_MESH_MODEL_BUF_LEN(BT_MESH_CHAT_CLI_OP_MESSAGE,
|
||||
BT_MESH_CHAT_CLI_MSG_MAXLEN_MESSAGE) <=
|
||||
BT_MESH_TX_SDU_MAX,
|
||||
"The message must fit inside an application SDU.");
|
||||
|
||||
static void encode_presence(struct net_buf_simple *buf,
|
||||
enum bt_mesh_chat_cli_presence presence)
|
||||
{
|
||||
bt_mesh_model_msg_init(buf, BT_MESH_CHAT_CLI_OP_PRESENCE);
|
||||
net_buf_simple_add_u8(buf, presence);
|
||||
}
|
||||
|
||||
static const uint8_t *extract_msg(struct net_buf_simple *buf)
|
||||
{
|
||||
buf->data[buf->len - 1] = '\0';
|
||||
return net_buf_simple_pull_mem(buf, buf->len);
|
||||
}
|
||||
|
||||
static int handle_message(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx,
|
||||
struct net_buf_simple *buf)
|
||||
{
|
||||
struct bt_mesh_chat_cli *chat = model->rt->user_data;
|
||||
const uint8_t *msg;
|
||||
|
||||
msg = extract_msg(buf);
|
||||
|
||||
if (chat->handlers->message) {
|
||||
chat->handlers->message(chat, ctx, msg);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* .. include_startingpoint_chat_cli_rst_1 */
|
||||
static void send_message_reply(struct bt_mesh_chat_cli *chat,
|
||||
struct bt_mesh_msg_ctx *ctx)
|
||||
{
|
||||
BT_MESH_MODEL_BUF_DEFINE(msg, BT_MESH_CHAT_CLI_OP_MESSAGE_REPLY,
|
||||
BT_MESH_CHAT_CLI_MSG_LEN_MESSAGE_REPLY);
|
||||
bt_mesh_model_msg_init(&msg, BT_MESH_CHAT_CLI_OP_MESSAGE_REPLY);
|
||||
|
||||
(void)bt_mesh_model_send(chat->model, ctx, &msg, NULL, NULL);
|
||||
}
|
||||
|
||||
static int handle_private_message(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx,
|
||||
struct net_buf_simple *buf)
|
||||
{
|
||||
struct bt_mesh_chat_cli *chat = model->rt->user_data;
|
||||
const uint8_t *msg;
|
||||
|
||||
msg = extract_msg(buf);
|
||||
|
||||
if (chat->handlers->private_message) {
|
||||
chat->handlers->private_message(chat, ctx, msg);
|
||||
}
|
||||
|
||||
send_message_reply(chat, ctx);
|
||||
return 0;
|
||||
}
|
||||
/* .. include_endpoint_chat_cli_rst_1 */
|
||||
|
||||
static int handle_message_reply(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx,
|
||||
struct net_buf_simple *buf)
|
||||
{
|
||||
struct bt_mesh_chat_cli *chat = model->rt->user_data;
|
||||
|
||||
if (chat->handlers->message_reply) {
|
||||
chat->handlers->message_reply(chat, ctx);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int handle_presence(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx,
|
||||
struct net_buf_simple *buf)
|
||||
{
|
||||
struct bt_mesh_chat_cli *chat = model->rt->user_data;
|
||||
enum bt_mesh_chat_cli_presence presence;
|
||||
|
||||
presence = net_buf_simple_pull_u8(buf);
|
||||
|
||||
if (chat->handlers->presence) {
|
||||
chat->handlers->presence(chat, ctx, presence);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int handle_presence_get(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx,
|
||||
struct net_buf_simple *buf)
|
||||
{
|
||||
struct bt_mesh_chat_cli *chat = model->rt->user_data;
|
||||
|
||||
BT_MESH_MODEL_BUF_DEFINE(msg, BT_MESH_CHAT_CLI_OP_PRESENCE,
|
||||
BT_MESH_CHAT_CLI_MSG_LEN_PRESENCE);
|
||||
|
||||
encode_presence(&msg, chat->presence);
|
||||
|
||||
(void)bt_mesh_model_send(chat->model, ctx, &msg, NULL, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* .. include_startingpoint_chat_cli_rst_2 */
|
||||
const struct bt_mesh_model_op _bt_mesh_chat_cli_op[] = {
|
||||
{
|
||||
BT_MESH_CHAT_CLI_OP_MESSAGE,
|
||||
BT_MESH_LEN_MIN(BT_MESH_CHAT_CLI_MSG_MINLEN_MESSAGE),
|
||||
handle_message
|
||||
},
|
||||
{
|
||||
BT_MESH_CHAT_CLI_OP_PRIVATE_MESSAGE,
|
||||
BT_MESH_LEN_MIN(BT_MESH_CHAT_CLI_MSG_MINLEN_MESSAGE),
|
||||
handle_private_message
|
||||
},
|
||||
{
|
||||
BT_MESH_CHAT_CLI_OP_MESSAGE_REPLY,
|
||||
BT_MESH_LEN_EXACT(BT_MESH_CHAT_CLI_MSG_LEN_MESSAGE_REPLY),
|
||||
handle_message_reply
|
||||
},
|
||||
{
|
||||
BT_MESH_CHAT_CLI_OP_PRESENCE,
|
||||
BT_MESH_LEN_EXACT(BT_MESH_CHAT_CLI_MSG_LEN_PRESENCE),
|
||||
handle_presence
|
||||
},
|
||||
{
|
||||
BT_MESH_CHAT_CLI_OP_PRESENCE_GET,
|
||||
BT_MESH_LEN_EXACT(BT_MESH_CHAT_CLI_MSG_LEN_PRESENCE_GET),
|
||||
handle_presence_get
|
||||
},
|
||||
BT_MESH_MODEL_OP_END,
|
||||
};
|
||||
/* .. include_endpoint_chat_cli_rst_2 */
|
||||
|
||||
static int bt_mesh_chat_cli_update_handler(const struct bt_mesh_model *model)
|
||||
{
|
||||
struct bt_mesh_chat_cli *chat = model->rt->user_data;
|
||||
|
||||
/* Continue publishing current presence. */
|
||||
encode_presence(model->pub->msg, chat->presence);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* .. include_startingpoint_chat_cli_rst_3 */
|
||||
#ifdef CONFIG_BT_SETTINGS
|
||||
static int bt_mesh_chat_cli_settings_set(const struct bt_mesh_model *model,
|
||||
const char *name,
|
||||
size_t len_rd,
|
||||
settings_read_cb read_cb,
|
||||
void *cb_arg)
|
||||
{
|
||||
struct bt_mesh_chat_cli *chat = model->rt->user_data;
|
||||
|
||||
if (name) {
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
ssize_t bytes = read_cb(cb_arg, &chat->presence,
|
||||
sizeof(chat->presence));
|
||||
if (bytes < 0) {
|
||||
return bytes;
|
||||
}
|
||||
|
||||
if (bytes != 0 && bytes != sizeof(chat->presence)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
/* .. include_endpoint_chat_cli_rst_3 */
|
||||
|
||||
/* .. include_startingpoint_chat_cli_rst_4 */
|
||||
static int bt_mesh_chat_cli_init(const struct bt_mesh_model *model)
|
||||
{
|
||||
struct bt_mesh_chat_cli *chat = model->rt->user_data;
|
||||
|
||||
chat->model = model;
|
||||
|
||||
net_buf_simple_init_with_data(&chat->pub_msg, chat->buf,
|
||||
sizeof(chat->buf));
|
||||
chat->pub.msg = &chat->pub_msg;
|
||||
chat->pub.update = bt_mesh_chat_cli_update_handler;
|
||||
|
||||
return 0;
|
||||
}
|
||||
/* .. include_endpoint_chat_cli_rst_4 */
|
||||
|
||||
/* .. include_startingpoint_chat_cli_rst_5 */
|
||||
static int bt_mesh_chat_cli_start(const struct bt_mesh_model *model)
|
||||
{
|
||||
struct bt_mesh_chat_cli *chat = model->rt->user_data;
|
||||
|
||||
if (chat->handlers->start) {
|
||||
chat->handlers->start(chat);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
/* .. include_endpoint_chat_cli_rst_5 */
|
||||
|
||||
/* .. include_startingpoint_chat_cli_rst_6 */
|
||||
static void bt_mesh_chat_cli_reset(const struct bt_mesh_model *model)
|
||||
{
|
||||
struct bt_mesh_chat_cli *chat = model->rt->user_data;
|
||||
|
||||
chat->presence = BT_MESH_CHAT_CLI_PRESENCE_AVAILABLE;
|
||||
|
||||
if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
|
||||
(void) bt_mesh_model_data_store(model, true, NULL, NULL, 0);
|
||||
}
|
||||
}
|
||||
/* .. include_endpoint_chat_cli_rst_6 */
|
||||
|
||||
/* .. include_startingpoint_chat_cli_rst_7 */
|
||||
const struct bt_mesh_model_cb _bt_mesh_chat_cli_cb = {
|
||||
.init = bt_mesh_chat_cli_init,
|
||||
.start = bt_mesh_chat_cli_start,
|
||||
#ifdef CONFIG_BT_SETTINGS
|
||||
.settings_set = bt_mesh_chat_cli_settings_set,
|
||||
#endif
|
||||
.reset = bt_mesh_chat_cli_reset,
|
||||
};
|
||||
/* .. include_endpoint_chat_cli_rst_7 */
|
||||
|
||||
/* .. include_startingpoint_chat_cli_rst_8 */
|
||||
int bt_mesh_chat_cli_presence_set(struct bt_mesh_chat_cli *chat,
|
||||
enum bt_mesh_chat_cli_presence presence)
|
||||
{
|
||||
if (presence != chat->presence) {
|
||||
chat->presence = presence;
|
||||
|
||||
if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
|
||||
(void) bt_mesh_model_data_store(chat->model, true,
|
||||
NULL, &presence,
|
||||
sizeof(chat->presence));
|
||||
}
|
||||
}
|
||||
|
||||
encode_presence(chat->model->pub->msg, chat->presence);
|
||||
|
||||
return bt_mesh_model_publish(chat->model);
|
||||
}
|
||||
/* .. include_endpoint_chat_cli_rst_8 */
|
||||
|
||||
int bt_mesh_chat_cli_presence_get(struct bt_mesh_chat_cli *chat,
|
||||
uint16_t addr)
|
||||
{
|
||||
struct bt_mesh_msg_ctx ctx = {
|
||||
.addr = addr,
|
||||
.app_idx = chat->model->keys[0],
|
||||
.send_ttl = BT_MESH_TTL_DEFAULT,
|
||||
.send_rel = true,
|
||||
};
|
||||
|
||||
BT_MESH_MODEL_BUF_DEFINE(buf, BT_MESH_CHAT_CLI_OP_PRESENCE_GET,
|
||||
BT_MESH_CHAT_CLI_MSG_LEN_PRESENCE_GET);
|
||||
bt_mesh_model_msg_init(&buf, BT_MESH_CHAT_CLI_OP_PRESENCE_GET);
|
||||
|
||||
return bt_mesh_model_send(chat->model, &ctx, &buf, NULL, NULL);
|
||||
}
|
||||
|
||||
int bt_mesh_chat_cli_message_send(struct bt_mesh_chat_cli *chat,
|
||||
const uint8_t *msg)
|
||||
{
|
||||
struct net_buf_simple *buf = chat->model->pub->msg;
|
||||
|
||||
bt_mesh_model_msg_init(buf, BT_MESH_CHAT_CLI_OP_MESSAGE);
|
||||
|
||||
net_buf_simple_add_mem(buf, msg,
|
||||
strnlen(msg,
|
||||
CONFIG_BT_MESH_CHAT_CLI_MESSAGE_LENGTH));
|
||||
net_buf_simple_add_u8(buf, '\0');
|
||||
|
||||
return bt_mesh_model_publish(chat->model);
|
||||
}
|
||||
|
||||
/* .. include_startingpoint_chat_cli_rst_9 */
|
||||
int bt_mesh_chat_cli_private_message_send(struct bt_mesh_chat_cli *chat,
|
||||
uint16_t addr,
|
||||
const uint8_t *msg)
|
||||
{
|
||||
struct bt_mesh_msg_ctx ctx = {
|
||||
.addr = addr,
|
||||
.app_idx = chat->model->keys[0],
|
||||
.send_ttl = BT_MESH_TTL_DEFAULT,
|
||||
.send_rel = true,
|
||||
};
|
||||
|
||||
BT_MESH_MODEL_BUF_DEFINE(buf, BT_MESH_CHAT_CLI_OP_PRIVATE_MESSAGE,
|
||||
BT_MESH_CHAT_CLI_MSG_MAXLEN_MESSAGE);
|
||||
bt_mesh_model_msg_init(&buf, BT_MESH_CHAT_CLI_OP_PRIVATE_MESSAGE);
|
||||
|
||||
net_buf_simple_add_mem(&buf, msg,
|
||||
strnlen(msg,
|
||||
CONFIG_BT_MESH_CHAT_CLI_MESSAGE_LENGTH));
|
||||
net_buf_simple_add_u8(&buf, '\0');
|
||||
|
||||
return bt_mesh_model_send(chat->model, &ctx, &buf, NULL, NULL);
|
||||
}
|
||||
/* .. include_endpoint_chat_cli_rst_9 */
|
68
src/main.c
Normal file
68
src/main.c
Normal file
@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright (c) 2019 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
|
||||
*/
|
||||
|
||||
/** @file
|
||||
* @brief Nordic Mesh light sample
|
||||
*/
|
||||
#include <zephyr/bluetooth/bluetooth.h>
|
||||
#include <bluetooth/mesh/models.h>
|
||||
#include <bluetooth/mesh/dk_prov.h>
|
||||
#include <dk_buttons_and_leds.h>
|
||||
#include "model_handler.h"
|
||||
|
||||
#include <zephyr/logging/log.h>
|
||||
LOG_MODULE_REGISTER(chat, CONFIG_LOG_DEFAULT_LEVEL);
|
||||
|
||||
static void bt_ready(int err)
|
||||
{
|
||||
if (err) {
|
||||
printk("Bluetooth init failed (err %d)\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
printk("Bluetooth initialized\n");
|
||||
|
||||
err = dk_leds_init();
|
||||
if (err) {
|
||||
printk("Initializing LEDs failed (err %d)\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
err = dk_buttons_init(NULL);
|
||||
if (err) {
|
||||
printk("Initializing buttons failed (err %d)\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
err = bt_mesh_init(bt_mesh_dk_prov_init(), model_handler_init());
|
||||
if (err) {
|
||||
printk("Initializing mesh failed (err %d)\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
if (IS_ENABLED(CONFIG_SETTINGS)) {
|
||||
settings_load();
|
||||
}
|
||||
|
||||
/* This will be a no-op if settings_load() loaded provisioning info */
|
||||
bt_mesh_prov_enable(BT_MESH_PROV_ADV | BT_MESH_PROV_GATT);
|
||||
|
||||
printk("Mesh initialized\n");
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
printk("Initializing...\n");
|
||||
|
||||
err = bt_enable(bt_ready);
|
||||
if (err) {
|
||||
printk("Bluetooth init failed (err %d)\n", err);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
571
src/model_handler.c
Normal file
571
src/model_handler.c
Normal file
@ -0,0 +1,571 @@
|
||||
/*
|
||||
* Copyright (c) 2019 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <zephyr/bluetooth/bluetooth.h>
|
||||
#include <bluetooth/mesh/models.h>
|
||||
#include <dk_buttons_and_leds.h>
|
||||
|
||||
#include <zephyr/shell/shell.h>
|
||||
#include <zephyr/shell/shell_uart.h>
|
||||
|
||||
#include "chat_cli.h"
|
||||
#include "model_handler.h"
|
||||
|
||||
#include <zephyr/logging/log.h>
|
||||
LOG_MODULE_DECLARE(chat);
|
||||
|
||||
static const struct shell *chat_shell;
|
||||
|
||||
#define MAX_NODES 10
|
||||
|
||||
/******************************************************************************/
|
||||
/*************************** Health server setup ******************************/
|
||||
/******************************************************************************/
|
||||
/* Set up a repeating delayed work to blink the DK's LEDs when attention is
|
||||
* requested.
|
||||
*/
|
||||
static struct k_work_delayable attention_blink_work;
|
||||
static bool attention;
|
||||
static volatile bool message_acknowledged = false;
|
||||
|
||||
static void attention_blink(struct k_work *work)
|
||||
{
|
||||
static int idx;
|
||||
const uint8_t pattern[] = {
|
||||
BIT(0) | BIT(1),
|
||||
BIT(1) | BIT(2),
|
||||
BIT(2) | BIT(3),
|
||||
BIT(3) | BIT(0),
|
||||
};
|
||||
|
||||
if (attention) {
|
||||
dk_set_leds(pattern[idx++ % ARRAY_SIZE(pattern)]);
|
||||
k_work_reschedule(&attention_blink_work, K_MSEC(30));
|
||||
} else {
|
||||
dk_set_leds(DK_NO_LEDS_MSK);
|
||||
}
|
||||
}
|
||||
|
||||
static void attention_on(const struct bt_mesh_model *mod)
|
||||
{
|
||||
attention = true;
|
||||
k_work_reschedule(&attention_blink_work, K_NO_WAIT);
|
||||
}
|
||||
|
||||
static void attention_off(const struct bt_mesh_model *mod)
|
||||
{
|
||||
/* Will stop rescheduling blink timer */
|
||||
attention = false;
|
||||
}
|
||||
|
||||
static const struct bt_mesh_health_srv_cb health_srv_cb = {
|
||||
.attn_on = attention_on,
|
||||
.attn_off = attention_off,
|
||||
};
|
||||
|
||||
static struct bt_mesh_health_srv health_srv = {
|
||||
.cb = &health_srv_cb,
|
||||
};
|
||||
|
||||
BT_MESH_HEALTH_PUB_DEFINE(health_pub, 0);
|
||||
|
||||
/******************************************************************************/
|
||||
/***************************** Chat model setup *******************************/
|
||||
/******************************************************************************/
|
||||
struct presence_cache {
|
||||
uint16_t addr;
|
||||
enum bt_mesh_chat_cli_presence presence;
|
||||
};
|
||||
|
||||
/* Cache of Presence values of other chat clients. */
|
||||
static struct presence_cache presence_cache[
|
||||
CONFIG_BT_MESH_CHAT_SAMPLE_PRESENCE_CACHE_SIZE];
|
||||
|
||||
static const uint8_t *presence_string[] = {
|
||||
[BT_MESH_CHAT_CLI_PRESENCE_AVAILABLE] = "available",
|
||||
[BT_MESH_CHAT_CLI_PRESENCE_AWAY] = "away",
|
||||
[BT_MESH_CHAT_CLI_PRESENCE_DO_NOT_DISTURB] = "dnd",
|
||||
[BT_MESH_CHAT_CLI_PRESENCE_INACTIVE] = "inactive",
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns true if the specified address is an address of the local element.
|
||||
*/
|
||||
static bool address_is_local(const struct bt_mesh_model *mod, uint16_t addr)
|
||||
{
|
||||
return bt_mesh_model_elem(mod)->rt->addr == addr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the provided address is unicast address.
|
||||
*/
|
||||
static bool address_is_unicast(uint16_t addr)
|
||||
{
|
||||
return (addr > 0) && (addr <= 0x7FFF);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the node is new or the presence status is different from
|
||||
* the one stored in the cache.
|
||||
*/
|
||||
static bool presence_cache_entry_check_and_update(uint16_t addr,
|
||||
enum bt_mesh_chat_cli_presence presence)
|
||||
{
|
||||
static size_t presence_cache_head;
|
||||
size_t i;
|
||||
|
||||
/* Find address in cache. */
|
||||
for (i = 0; i < ARRAY_SIZE(presence_cache); i++) {
|
||||
if (presence_cache[i].addr == addr) {
|
||||
if (presence_cache[i].presence == presence) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Break since the node in the cache. */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Not in cache. */
|
||||
if (i == ARRAY_SIZE(presence_cache)) {
|
||||
for (i = 0; i < ARRAY_SIZE(presence_cache); i++) {
|
||||
if (!presence_cache[i].addr) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Cache is full. */
|
||||
if (i == ARRAY_SIZE(presence_cache)) {
|
||||
i = presence_cache_head;
|
||||
presence_cache_head = (presence_cache_head + 1)
|
||||
% CONFIG_BT_MESH_CHAT_SAMPLE_PRESENCE_CACHE_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Update cache. */
|
||||
presence_cache[i].addr = addr;
|
||||
presence_cache[i].presence = presence;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void print_client_status(void);
|
||||
|
||||
static void handle_chat_start(struct bt_mesh_chat_cli *chat)
|
||||
{
|
||||
print_client_status();
|
||||
}
|
||||
|
||||
static void handle_chat_presence(struct bt_mesh_chat_cli *chat,
|
||||
struct bt_mesh_msg_ctx *ctx,
|
||||
enum bt_mesh_chat_cli_presence presence)
|
||||
{
|
||||
if (address_is_local(chat->model, ctx->addr)) {
|
||||
if (address_is_unicast(ctx->recv_dst)) {
|
||||
shell_print(chat_shell, "<you> are %s",
|
||||
presence_string[presence]);
|
||||
}
|
||||
} else {
|
||||
if (address_is_unicast(ctx->recv_dst)) {
|
||||
shell_print(chat_shell, "<0x%04X> is %s", ctx->addr,
|
||||
presence_string[presence]);
|
||||
} else if (presence_cache_entry_check_and_update(ctx->addr,
|
||||
presence)) {
|
||||
shell_print(chat_shell, "<0x%04X> is now %s",
|
||||
ctx->addr,
|
||||
presence_string[presence]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
static void handle_chat_message(struct bt_mesh_chat_cli *chat,
|
||||
struct bt_mesh_msg_ctx *ctx,
|
||||
const uint8_t *msg)
|
||||
{
|
||||
/* Don't print own messages. */
|
||||
if (address_is_local(chat->model, ctx->addr)) {
|
||||
return;
|
||||
}
|
||||
|
||||
shell_print(chat_shell, "<0x%04X>: %s", ctx->addr, msg);
|
||||
}
|
||||
|
||||
struct node_message {
|
||||
uint16_t addr;
|
||||
uint8_t msg_count;
|
||||
bool is_active;
|
||||
int64_t last_seen;
|
||||
};
|
||||
|
||||
|
||||
static struct node_message node_stats[MAX_NODES];
|
||||
|
||||
|
||||
static void handle_rpl_full(void)
|
||||
{
|
||||
// Wait for any pending messages to complete
|
||||
k_sleep(K_MSEC(1000));
|
||||
|
||||
// Reset node tracking
|
||||
for (int i = 0; i < MAX_NODES; i++) {
|
||||
node_stats[i].msg_count = 0;
|
||||
node_stats[i].last_seen = k_uptime_get();
|
||||
}
|
||||
|
||||
LOG_INF("RPL management completed");
|
||||
}
|
||||
|
||||
|
||||
static void handle_chat_private_message(struct bt_mesh_chat_cli *chat,
|
||||
struct bt_mesh_msg_ctx *ctx,
|
||||
const uint8_t *msg)
|
||||
{
|
||||
if (!ctx || !msg) {
|
||||
LOG_ERR("Invalid message received");
|
||||
return;
|
||||
}
|
||||
|
||||
if (address_is_local(chat->model, ctx->addr)) {
|
||||
return;
|
||||
}
|
||||
|
||||
int64_t current_time = k_uptime_get();
|
||||
int available_slot = -1;
|
||||
|
||||
for (int i = 0; i < MAX_NODES; i++) {
|
||||
if (node_stats[i].addr == ctx->addr) {
|
||||
if ((current_time - node_stats[i].last_seen) > 5000) {
|
||||
LOG_INF("Node 0x%04X reconnected", ctx->addr);
|
||||
}
|
||||
node_stats[i].msg_count++;
|
||||
node_stats[i].last_seen = current_time;
|
||||
node_stats[i].is_active = true;
|
||||
LOG_INF("Message from 0x%04X (#%d): %s",
|
||||
ctx->addr, node_stats[i].msg_count, msg);
|
||||
return;
|
||||
}
|
||||
if (!node_stats[i].is_active && available_slot == -1) {
|
||||
available_slot = i;
|
||||
}
|
||||
}
|
||||
|
||||
if (available_slot != -1) {
|
||||
node_stats[available_slot].addr = ctx->addr;
|
||||
node_stats[available_slot].msg_count = 1;
|
||||
node_stats[available_slot].last_seen = current_time;
|
||||
node_stats[available_slot].is_active = true;
|
||||
LOG_INF("New node 0x%04X registered: %s", ctx->addr, msg);
|
||||
} else {
|
||||
LOG_WRN("Node tracking full - Message from 0x%04X dropped", ctx->addr);
|
||||
}
|
||||
}
|
||||
|
||||
static void handle_chat_message_reply(struct bt_mesh_chat_cli *chat,
|
||||
struct bt_mesh_msg_ctx *ctx)
|
||||
{
|
||||
message_acknowledged = true;
|
||||
shell_print(chat_shell, "<0x%04X> received the message", ctx->addr);
|
||||
}
|
||||
|
||||
static const struct bt_mesh_chat_cli_handlers chat_handlers = {
|
||||
.start = handle_chat_start,
|
||||
.presence = handle_chat_presence,
|
||||
.message = handle_chat_message,
|
||||
.private_message = handle_chat_private_message,
|
||||
.message_reply = handle_chat_message_reply,
|
||||
};
|
||||
|
||||
/* .. include_startingpoint_model_handler_rst_1 */
|
||||
static struct bt_mesh_chat_cli chat = {
|
||||
.handlers = &chat_handlers,
|
||||
};
|
||||
|
||||
static struct bt_mesh_elem elements[] = {
|
||||
BT_MESH_ELEM(
|
||||
1,
|
||||
BT_MESH_MODEL_LIST(
|
||||
BT_MESH_MODEL_CFG_SRV,
|
||||
BT_MESH_MODEL_HEALTH_SRV(&health_srv, &health_pub)),
|
||||
BT_MESH_MODEL_LIST(BT_MESH_MODEL_CHAT_CLI(&chat))),
|
||||
};
|
||||
/* .. include_endpoint_model_handler_rst_1 */
|
||||
|
||||
static void print_client_status(void)
|
||||
{
|
||||
if (!bt_mesh_is_provisioned()) {
|
||||
shell_print(chat_shell,
|
||||
"The mesh node is not provisioned. Please provision the mesh node before using the chat.");
|
||||
} else {
|
||||
shell_print(chat_shell,
|
||||
"The mesh node is provisioned. The client address is 0x%04x.",
|
||||
bt_mesh_model_elem(chat.model)->rt->addr);
|
||||
}
|
||||
|
||||
shell_print(chat_shell, "Current presence: %s",
|
||||
presence_string[chat.presence]);
|
||||
}
|
||||
|
||||
static const struct bt_mesh_comp comp = {
|
||||
.cid = CONFIG_BT_COMPANY_ID,
|
||||
.elem = elements,
|
||||
.elem_count = ARRAY_SIZE(elements),
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
/******************************** Chat shell **********************************/
|
||||
/******************************************************************************/
|
||||
static int cmd_status(const struct shell *shell, size_t argc, char *argv[])
|
||||
{
|
||||
print_client_status();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cmd_message(const struct shell *shell, size_t argc, char *argv[])
|
||||
{
|
||||
int err;
|
||||
|
||||
if (argc < 2) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
err = bt_mesh_chat_cli_message_send(&chat, argv[1]);
|
||||
if (err) {
|
||||
LOG_WRN("Failed to send message: %d", err);
|
||||
}
|
||||
|
||||
/* Print own messages in the chat. */
|
||||
shell_print(shell, "<you>: %s", argv[1]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cmd_private_message(const struct shell *shell, size_t argc,
|
||||
char *argv[])
|
||||
{
|
||||
uint16_t addr;
|
||||
int err;
|
||||
|
||||
if (argc < 3) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
addr = strtol(argv[1], NULL, 0);
|
||||
|
||||
/* Print own message to the chat. */
|
||||
shell_print(shell, "%x: %s\n", addr, argv[2]);
|
||||
|
||||
err = bt_mesh_chat_cli_private_message_send(&chat, addr, argv[2]);
|
||||
if (err) {
|
||||
LOG_WRN("Failed to publish message: %d", err);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cmd_presence_set(const struct shell *shell, size_t argc,
|
||||
char *argv[])
|
||||
{
|
||||
size_t i;
|
||||
|
||||
if (argc < 2) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(presence_string); i++) {
|
||||
if (!strcmp(argv[1], presence_string[i])) {
|
||||
enum bt_mesh_chat_cli_presence presence;
|
||||
int err;
|
||||
|
||||
presence = i;
|
||||
|
||||
err = bt_mesh_chat_cli_presence_set(&chat, presence);
|
||||
if (err) {
|
||||
LOG_WRN("Failed to update presence: %d", err);
|
||||
}
|
||||
|
||||
/* Print own presence in the chat. */
|
||||
shell_print(shell, "You are now %s",
|
||||
presence_string[presence]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
shell_print(shell,
|
||||
"Unknown presence status: %s. Possible presence statuses:",
|
||||
argv[1]);
|
||||
for (i = 0; i < ARRAY_SIZE(presence_string); i++) {
|
||||
shell_print(shell, "%s", presence_string[i]);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cmd_presence_get(const struct shell *shell, size_t argc,
|
||||
char *argv[])
|
||||
{
|
||||
uint16_t addr;
|
||||
int err;
|
||||
|
||||
if (argc < 2) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
addr = strtol(argv[1], NULL, 0);
|
||||
|
||||
err = bt_mesh_chat_cli_presence_get(&chat, addr);
|
||||
if (err) {
|
||||
LOG_WRN("Failed to publish message: %d", err);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
SHELL_STATIC_SUBCMD_SET_CREATE(presence_cmds,
|
||||
SHELL_CMD_ARG(set, NULL,
|
||||
"Set presence of the current client <presence: available, away, dnd or inactive>",
|
||||
cmd_presence_set, 2, 0),
|
||||
SHELL_CMD_ARG(get, NULL,
|
||||
"Get presence status of the remote node <node>",
|
||||
cmd_presence_get, 2, 0),
|
||||
SHELL_SUBCMD_SET_END
|
||||
);
|
||||
|
||||
static int cmd_presence(const struct shell *shell, size_t argc, char *argv[])
|
||||
{
|
||||
if (argc == 1) {
|
||||
shell_help(shell);
|
||||
/* shell returns 1 when help is printed */
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (argc != 3) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
SHELL_STATIC_SUBCMD_SET_CREATE(chat_cmds,
|
||||
SHELL_CMD_ARG(status, NULL, "Print client status", cmd_status, 1, 0),
|
||||
SHELL_CMD(presence, &presence_cmds, "Presence commands", cmd_presence),
|
||||
SHELL_CMD_ARG(private, NULL,
|
||||
"Send a private text message to a client <node> <message>",
|
||||
cmd_private_message, 3, 0),
|
||||
SHELL_CMD_ARG(msg, NULL, "Send a text message to the chat <message>",
|
||||
cmd_message, 2, 0),
|
||||
SHELL_SUBCMD_SET_END
|
||||
);
|
||||
|
||||
static int cmd_chat(const struct shell *shell, size_t argc, char **argv)
|
||||
{
|
||||
if (argc == 1) {
|
||||
shell_help(shell);
|
||||
/* shell returns 1 when help is printed */
|
||||
return 1;
|
||||
}
|
||||
|
||||
shell_error(shell, "%s unknown parameter: %s", argv[0], argv[1]);
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
SHELL_CMD_ARG_REGISTER(chat, &chat_cmds, "Bluetooth Mesh Chat Client commands",
|
||||
cmd_chat, 1, 1);
|
||||
|
||||
|
||||
static struct k_work_delayable message_timer;
|
||||
|
||||
static uint32_t msg_counter = 0;
|
||||
|
||||
static uint16_t get_node_address(void)
|
||||
{
|
||||
uint16_t addr = bt_mesh_model_elem(chat.model)->rt->addr;
|
||||
LOG_INF("Node unicast address: 0x%04x", addr);
|
||||
return addr;
|
||||
}
|
||||
|
||||
static bool has_publish_address(void)
|
||||
{
|
||||
const struct bt_mesh_model *model = chat.model;
|
||||
if (model && model->pub && model->pub->addr != BT_MESH_ADDR_UNASSIGNED) {
|
||||
LOG_INF("Publish address: 0x%04x", model->pub->addr);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static void send_periodic_message(struct k_work *work)
|
||||
{
|
||||
if (!has_publish_address()) {
|
||||
LOG_INF("No publish address assigned yet");
|
||||
k_work_reschedule(&message_timer, K_SECONDS(5));
|
||||
return;
|
||||
}
|
||||
|
||||
const char fixed_message[255]; // change the size as needed for payload
|
||||
uint16_t target_addr = 0x0105;
|
||||
|
||||
snprintf(fixed_message, sizeof(fixed_message),
|
||||
"%lu 0x%04x dammavalamsarathchandrasrivatsandammavalamsarathchandrasrivatsandammavalamsarathchandrasrivatsandammavalamsarathchandrasrivatsandammavalamsarathchandrasrivatsandammavalamsarathchandrasrivatsandammavalamsarathchandradammavalamsarathchandrasrivatsandammavalamsarathchandrasrivatsandammavalamsarathchandrasrivatsandammavalamsarathchandrasrivatsandammavalamsarathchandrasrivatsa", msg_counter, get_node_address());
|
||||
|
||||
|
||||
// First attempt
|
||||
message_acknowledged = false;
|
||||
int err = bt_mesh_chat_cli_private_message_send(&chat, target_addr, fixed_message);
|
||||
if (err) {
|
||||
LOG_WRN("First attempt failed, retrying...");
|
||||
k_sleep(K_MSEC(10000));
|
||||
|
||||
// Second attempt
|
||||
message_acknowledged = false;
|
||||
err = bt_mesh_chat_cli_private_message_send(&chat, target_addr, fixed_message);
|
||||
}
|
||||
else
|
||||
msg_counter++;
|
||||
|
||||
|
||||
if (message_acknowledged) {
|
||||
shell_print(chat_shell, "Message delivered successfully");
|
||||
}
|
||||
|
||||
k_work_reschedule(&message_timer, K_SECONDS(20));
|
||||
}
|
||||
|
||||
|
||||
// change array size and constant value for payload in 519 & 523.
|
||||
// change publish time value in line 545
|
||||
// comment lines 562 & 563 for receiver nodes 105
|
||||
// uncomment lines 562 & 563 for transmitter nodes 120,121,122,123,124
|
||||
//
|
||||
|
||||
/******************************************************************************/
|
||||
/******************************** Public API **********************************/
|
||||
/******************************************************************************/
|
||||
const struct bt_mesh_comp *model_handler_init(void)
|
||||
{
|
||||
k_work_init_delayable(&attention_blink_work, attention_blink);
|
||||
|
||||
// k_work_init_delayable(&message_timer, send_periodic_message);
|
||||
// k_work_schedule(&message_timer, K_NO_WAIT);
|
||||
|
||||
chat_shell = shell_backend_uart_get_ptr();
|
||||
printk(">>> Bluetooth Mesh Chat sample <<<\n");
|
||||
|
||||
|
||||
|
||||
return ∁
|
||||
}
|
Loading…
Reference in New Issue
Block a user