mirror of
https://github.com/espressif/esp-idf.git
synced 2026-10-02 03:00:34 +03:00
feat(ble_iso): Split ISO related files into components/bt/esp_ble_iso
This commit is contained in:
@@ -0,0 +1,118 @@
|
||||
/** @file
|
||||
* @brief Internal APIs for Bluetooth connection handling.
|
||||
*/
|
||||
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015 Intel Corporation
|
||||
* SPDX-FileCopyrightText: 2021 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <zephyr/bluetooth/iso.h>
|
||||
|
||||
typedef enum __packed {
|
||||
BT_CONN_DISCONNECTED, /* Disconnected, conn is completely down */
|
||||
BT_CONN_DISCONNECT_COMPLETE, /* Received disconn comp event, transition to DISCONNECTED */
|
||||
|
||||
BT_CONN_INITIATING, /* Central connection establishment */
|
||||
|
||||
BT_CONN_CONNECTED, /* Peripheral or Central connected */
|
||||
BT_CONN_DISCONNECTING, /* Peripheral or Central issued disconnection command */
|
||||
} bt_conn_state_t;
|
||||
|
||||
struct bt_conn_le {
|
||||
bt_addr_le_t dst;
|
||||
|
||||
uint16_t interval;
|
||||
|
||||
/** @brief Remote LE features
|
||||
*
|
||||
* Available after `atomic_test_bit(conn->flags, BT_CONN_LE_FEATURES_EXCHANGED)`.
|
||||
* Signaled by bt_conn_cb.remote_info_available().
|
||||
*/
|
||||
uint8_t features[8];
|
||||
|
||||
struct bt_keys *keys;
|
||||
};
|
||||
|
||||
struct bt_conn_iso {
|
||||
/* Reference to ACL Connection */
|
||||
struct bt_conn *acl;
|
||||
|
||||
/* Reference to the struct bt_iso_chan */
|
||||
struct bt_iso_chan *chan;
|
||||
|
||||
/** Stored information about the ISO stream */
|
||||
struct bt_iso_info info;
|
||||
};
|
||||
|
||||
typedef void (*bt_conn_tx_cb_t)(struct bt_conn *conn, void *user_data, int err);
|
||||
|
||||
struct bt_conn_rx {
|
||||
/* Index into the bt_conn storage array */
|
||||
uint8_t index;
|
||||
|
||||
/** Connection handle */
|
||||
uint16_t handle;
|
||||
};
|
||||
|
||||
struct bt_conn {
|
||||
uint16_t handle;
|
||||
enum bt_conn_type type;
|
||||
uint8_t role;
|
||||
|
||||
/* Which local identity address this connection uses */
|
||||
uint8_t id;
|
||||
|
||||
bt_security_t sec_level;
|
||||
uint8_t encrypt;
|
||||
|
||||
/* Connection error or reason for disconnect */
|
||||
uint8_t err;
|
||||
|
||||
bt_conn_state_t state;
|
||||
uint16_t rx_len;
|
||||
struct net_buf *rx;
|
||||
|
||||
/* Active L2CAP channels */
|
||||
sys_slist_t channels;
|
||||
|
||||
union {
|
||||
struct bt_conn_le le;
|
||||
struct bt_conn_iso iso;
|
||||
};
|
||||
|
||||
/* Get (and clears for ACL conns) callback and user-data for `buf`. */
|
||||
void (*get_and_clear_cb)(struct bt_conn *conn, struct net_buf *buf,
|
||||
bt_conn_tx_cb_t *cb, void **ud);
|
||||
};
|
||||
|
||||
/* Cleanup ISO references */
|
||||
void bt_iso_cleanup_acl(struct bt_conn *iso_conn);
|
||||
|
||||
void bt_iso_reset(void);
|
||||
|
||||
/* Allocate new connection object */
|
||||
struct bt_conn *bt_conn_new(struct bt_conn *conns, size_t size);
|
||||
|
||||
/* Look up an existing connection */
|
||||
struct bt_conn *bt_conn_lookup_handle(uint16_t handle, enum bt_conn_type type);
|
||||
|
||||
/* Check if the connection is with the given peer. */
|
||||
bool bt_conn_is_peer_addr_le(const struct bt_conn *conn, uint8_t id,
|
||||
const bt_addr_le_t *peer);
|
||||
|
||||
/* Helpers for identifying & looking up connections based on the index to
|
||||
* the connection list. This is useful for O(1) lookups, but can't be used
|
||||
* e.g. as the handle since that's assigned to us by the controller.
|
||||
*/
|
||||
#define BT_CONN_INDEX_INVALID 0xff
|
||||
|
||||
/* Set connection object in certain state and perform action related to state */
|
||||
void bt_conn_set_state(struct bt_conn *conn, bt_conn_state_t state);
|
||||
@@ -0,0 +1,109 @@
|
||||
/* hci_core.h - Bluetooth HCI core access */
|
||||
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2021 Nordic Semiconductor ASA
|
||||
* SPDX-FileCopyrightText: 2015-2016 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
/* bt_dev flags: the flags defined here represent BT controller state */
|
||||
enum {
|
||||
/** The application either explicitly or implicitly instructed the stack to scan
|
||||
* for advertisers.
|
||||
*
|
||||
* Examples of such cases
|
||||
* - Explicit scanning, @ref BT_LE_SCAN_USER_EXPLICIT_SCAN.
|
||||
* - The application instructed the stack to automatically connect if a given device
|
||||
* is detected.
|
||||
* - The application wants to connect to a peer device using private addresses, but
|
||||
* the controller resolving list is too small. The host will fallback to using
|
||||
* host-based privacy and first scan for the device before it initiates a connection.
|
||||
* - The application wants to synchronize to a periodic advertiser.
|
||||
* The host will implicitly start scanning if it is not already doing so.
|
||||
*
|
||||
* The host needs to keep track of this state to ensure it can restart scanning
|
||||
* when a connection is established/lost, explicit scanning is started or stopped etc.
|
||||
* Also, when the scanner and advertiser share the same identity, the scanner may need
|
||||
* to be restarted upon RPA refresh.
|
||||
*/
|
||||
BT_DEV_SCANNING,
|
||||
|
||||
/* Total number of flags - must be at the end of the enum */
|
||||
BT_DEV_NUM_FLAGS,
|
||||
};
|
||||
|
||||
enum {
|
||||
/* Periodic Advertising parameters has been set in the controller. */
|
||||
BT_PER_ADV_PARAMS_SET,
|
||||
|
||||
BT_ADV_NUM_FLAGS,
|
||||
};
|
||||
|
||||
struct bt_le_ext_adv {
|
||||
/* Advertising handle */
|
||||
uint8_t handle;
|
||||
|
||||
ATOMIC_DEFINE(flags, BT_ADV_NUM_FLAGS);
|
||||
};
|
||||
|
||||
enum {
|
||||
/** Periodic Advertising Sync has been created in the host. */
|
||||
BT_PER_ADV_SYNC_CREATED,
|
||||
|
||||
/** Periodic Advertising Sync is established and can be terminated */
|
||||
BT_PER_ADV_SYNC_SYNCED,
|
||||
|
||||
/** Periodic Advertising Sync is attempting to create sync */
|
||||
BT_PER_ADV_SYNC_SYNCING,
|
||||
|
||||
BT_PER_ADV_SYNC_NUM_FLAGS,
|
||||
};
|
||||
|
||||
struct bt_le_per_adv_sync {
|
||||
/** Periodic Advertiser Address */
|
||||
bt_addr_le_t addr;
|
||||
|
||||
/** Advertiser SID */
|
||||
uint8_t sid;
|
||||
|
||||
/** Sync handle */
|
||||
uint16_t handle;
|
||||
|
||||
/** Periodic advertising interval (N * 1.25 ms) */
|
||||
uint16_t interval;
|
||||
|
||||
/** Advertiser PHY */
|
||||
uint8_t phy;
|
||||
|
||||
/** Flags */
|
||||
ATOMIC_DEFINE(flags, BT_PER_ADV_SYNC_NUM_FLAGS);
|
||||
};
|
||||
|
||||
struct bt_dev_le {
|
||||
/* LE features */
|
||||
uint8_t features[8];
|
||||
};
|
||||
|
||||
/* State tracking for the local Bluetooth controller */
|
||||
struct bt_dev {
|
||||
ATOMIC_DEFINE(flags, BT_DEV_NUM_FLAGS);
|
||||
|
||||
/* LE controller specific features */
|
||||
struct bt_dev_le le;
|
||||
};
|
||||
|
||||
extern struct bt_dev bt_dev;
|
||||
|
||||
/* Data type to store state related with command to be updated
|
||||
* when command completes successfully.
|
||||
*/
|
||||
struct bt_hci_cmd_state_set {
|
||||
/* Dummy */
|
||||
};
|
||||
|
||||
uint8_t bt_get_phy(uint8_t hci_phy);
|
||||
|
||||
bool bt_le_bond_exists(uint8_t id, const bt_addr_le_t *addr);
|
||||
@@ -0,0 +1,126 @@
|
||||
/** @file
|
||||
* @brief Internal APIs for Bluetooth ISO handling.
|
||||
*/
|
||||
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2020 Intel Corporation
|
||||
* SPDX-FileCopyrightText: 2021-2024 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <zephyr/bluetooth/conn.h>
|
||||
#include <zephyr/bluetooth/buf.h>
|
||||
#include <zephyr/bluetooth/iso.h>
|
||||
#include <zephyr/kernel.h>
|
||||
#include <zephyr/net_buf.h>
|
||||
#include <zephyr/sys/atomic.h>
|
||||
#include <zephyr/sys/slist.h>
|
||||
|
||||
enum bt_iso_cig_state {
|
||||
BT_ISO_CIG_STATE_IDLE,
|
||||
BT_ISO_CIG_STATE_CONFIGURED,
|
||||
BT_ISO_CIG_STATE_ACTIVE,
|
||||
BT_ISO_CIG_STATE_INACTIVE
|
||||
};
|
||||
|
||||
struct bt_iso_cig {
|
||||
/** List of ISO channels to setup as CIS (the CIG). */
|
||||
sys_slist_t cis_channels;
|
||||
|
||||
/** Total number of CISes in the CIG. */
|
||||
uint8_t num_cis;
|
||||
|
||||
/** The CIG ID */
|
||||
uint8_t id;
|
||||
|
||||
/** The CIG state
|
||||
*
|
||||
* Refer to BT Core Spec 5.3, Vol 6, Part 6, Figure 4.63
|
||||
*/
|
||||
enum bt_iso_cig_state state;
|
||||
};
|
||||
|
||||
enum {
|
||||
BT_BIG_INITIALIZED,
|
||||
|
||||
/* Creating a BIG as a broadcaster */
|
||||
BT_BIG_PENDING,
|
||||
/* Creating a BIG as a receiver */
|
||||
BT_BIG_SYNCING,
|
||||
/* BIG is busy handling an HCI event.
|
||||
*
|
||||
* Use this to prevent API calls from modifying the BIG while the event is being processed.
|
||||
*/
|
||||
BT_BIG_BUSY,
|
||||
|
||||
BT_BIG_NUM_FLAGS,
|
||||
};
|
||||
|
||||
struct bt_iso_big {
|
||||
/** List of ISO channels to setup as BIS (the BIG). */
|
||||
sys_slist_t bis_channels;
|
||||
|
||||
/** Total number of BISes in the BIG. */
|
||||
uint8_t num_bis;
|
||||
|
||||
/** The BIG handle */
|
||||
uint8_t handle;
|
||||
|
||||
ATOMIC_DEFINE(flags, BT_BIG_NUM_FLAGS);
|
||||
};
|
||||
|
||||
#define iso(buf) ((struct bt_conn_rx *)net_buf_user_data(buf))
|
||||
|
||||
/* Process ISO buffer */
|
||||
void hci_iso(struct net_buf *buf);
|
||||
|
||||
/* Process CIS Established event */
|
||||
void hci_le_cis_established(struct net_buf *buf);
|
||||
void hci_le_cis_established_v2(struct net_buf *buf);
|
||||
|
||||
/* Process CIS Request event */
|
||||
void hci_le_cis_req(struct net_buf *buf);
|
||||
|
||||
/** Process BIG complete event */
|
||||
void hci_le_big_complete(struct net_buf *buf);
|
||||
|
||||
/** Process BIG terminate event */
|
||||
void hci_le_big_terminate(struct net_buf *buf);
|
||||
|
||||
/** Process BIG sync established event */
|
||||
void hci_le_big_sync_established(struct net_buf *buf);
|
||||
|
||||
/** Process BIG sync lost event */
|
||||
void hci_le_big_sync_lost(struct net_buf *buf);
|
||||
|
||||
/* Notify ISO channels of a new connection */
|
||||
void bt_iso_connected(struct bt_conn *iso);
|
||||
|
||||
/* Notify ISO channels of a disconnect event */
|
||||
void bt_iso_disconnected(struct bt_conn *iso);
|
||||
|
||||
#if defined(CONFIG_BT_ISO_LOG_LEVEL_DBG)
|
||||
void bt_iso_chan_set_state_debug(struct bt_iso_chan *chan,
|
||||
enum bt_iso_state state,
|
||||
const char *func, int line);
|
||||
#define bt_iso_chan_set_state(_chan, _state) \
|
||||
bt_iso_chan_set_state_debug(_chan, _state, __func__, __LINE__)
|
||||
#else
|
||||
void bt_iso_chan_set_state(struct bt_iso_chan *chan, enum bt_iso_state state);
|
||||
#endif /* CONFIG_BT_ISO_LOG_LEVEL_DBG */
|
||||
|
||||
/* Process incoming data for a connection */
|
||||
void bt_iso_recv(struct bt_conn *iso, struct net_buf *buf, uint8_t flags);
|
||||
|
||||
/* Whether the HCI ISO data packet contains a timestamp or not.
|
||||
* Per spec, the TS flag can only be set for the first fragment.
|
||||
*/
|
||||
enum bt_iso_timestamp {
|
||||
BT_ISO_TS_ABSENT = 0,
|
||||
BT_ISO_TS_PRESENT,
|
||||
};
|
||||
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2016 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef ZEPHYR_SUBSYS_BLUETOOTH_HOST_KEYS_H_
|
||||
#define ZEPHYR_SUBSYS_BLUETOOTH_HOST_KEYS_H_
|
||||
|
||||
#include <zephyr/bluetooth/bluetooth.h>
|
||||
|
||||
/** @cond INTERNAL_HIDDEN */
|
||||
|
||||
struct bt_ltk {
|
||||
uint8_t rand[8];
|
||||
uint8_t ediv[2];
|
||||
uint8_t val[16];
|
||||
};
|
||||
|
||||
struct bt_keys {
|
||||
uint8_t id;
|
||||
bt_addr_le_t addr;
|
||||
uint16_t keys;
|
||||
struct bt_ltk ltk;
|
||||
};
|
||||
|
||||
/** @endcond */
|
||||
|
||||
#endif /* ZEPHYR_SUBSYS_BLUETOOTH_HOST_KEYS_H_ */
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#include <zephyr/sys/check.h>
|
||||
|
||||
#define CONFIG_LITTLE_ENDIAN 1
|
||||
#define CONFIG_BT_CONN_TX_USER_DATA_SIZE 8
|
||||
|
||||
#define CONFIG_BT_MAX_CONN CONFIG_BT_NIMBLE_MAX_CONNECTIONS
|
||||
#define CONFIG_BT_SMP CONFIG_BT_NIMBLE_SECURITY_ENABLE
|
||||
#define CONFIG_BT_MAX_PAIRED CONFIG_BT_NIMBLE_MAX_BONDS
|
||||
|
||||
#if CONFIG_BT_NIMBLE_MAX_EXT_ADV_INSTANCES
|
||||
#define CONFIG_BT_EXT_ADV_MAX_ADV_SET CONFIG_BT_NIMBLE_MAX_EXT_ADV_INSTANCES
|
||||
#else /* CONFIG_BT_NIMBLE_MAX_EXT_ADV_INSTANCES */
|
||||
#define CONFIG_BT_EXT_ADV_MAX_ADV_SET 0
|
||||
#endif /* CONFIG_BT_NIMBLE_MAX_EXT_ADV_INSTANCES */
|
||||
|
||||
#if CONFIG_BT_NIMBLE_MAX_PERIODIC_SYNCS
|
||||
#define CONFIG_BT_PER_ADV_SYNC_MAX CONFIG_BT_NIMBLE_MAX_PERIODIC_SYNCS
|
||||
#else /* CONFIG_BT_NIMBLE_MAX_PERIODIC_SYNCS */
|
||||
#define CONFIG_BT_PER_ADV_SYNC_MAX 0
|
||||
#endif /* CONFIG_BT_NIMBLE_MAX_PERIODIC_SYNCS */
|
||||
|
||||
#if CONFIG_BT_NIMBLE_PERIODIC_ADV_SYNC_TRANSFER
|
||||
#define CONFIG_BT_PER_ADV_SYNC_TRANSFER_SENDER CONFIG_BT_NIMBLE_PERIODIC_ADV_SYNC_TRANSFER
|
||||
#define CONFIG_BT_PER_ADV_SYNC_TRANSFER_RECEIVER CONFIG_BT_NIMBLE_PERIODIC_ADV_SYNC_TRANSFER
|
||||
#else /* CONFIG_BT_NIMBLE_PERIODIC_ADV_SYNC_TRANSFER */
|
||||
#define CONFIG_BT_PER_ADV_SYNC_TRANSFER_SENDER 0
|
||||
#define CONFIG_BT_PER_ADV_SYNC_TRANSFER_RECEIVER 0
|
||||
#endif /* CONFIG_BT_NIMBLE_PERIODIC_ADV_SYNC_TRANSFER */
|
||||
|
||||
#if CONFIG_BT_ISO_UNICAST && CONFIG_BT_ISO_BROADCAST
|
||||
_Static_assert(CONFIG_BT_ISO_MAX_CHAN <= CONFIG_BT_NIMBLE_ISO_CIS + CONFIG_BT_NIMBLE_ISO_BIS, "Too large ISO channels");
|
||||
#elif CONFIG_BT_ISO_UNICAST && !CONFIG_BT_ISO_BROADCAST
|
||||
_Static_assert(CONFIG_BT_ISO_MAX_CHAN <= CONFIG_BT_NIMBLE_ISO_CIS, "Too large ISO channels");
|
||||
#elif !CONFIG_BT_ISO_UNICAST && CONFIG_BT_ISO_BROADCAST
|
||||
_Static_assert(CONFIG_BT_ISO_MAX_CHAN <= CONFIG_BT_NIMBLE_ISO_BIS, "Too large ISO channels");
|
||||
#else /* CONFIG_BT_ISO_UNICAST && CONFIG_BT_ISO_BROADCAST */
|
||||
_Static_assert(CONFIG_BT_ISO_MAX_CHAN == 0, "Too large ISO channels");
|
||||
#endif /* CONFIG_BT_ISO_UNICAST && CONFIG_BT_ISO_BROADCAST */
|
||||
@@ -0,0 +1,272 @@
|
||||
/** @file
|
||||
* @brief Bluetooth device address definitions and utilities.
|
||||
*/
|
||||
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2019 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#ifndef ZEPHYR_INCLUDE_BLUETOOTH_ADDR_H_
|
||||
#define ZEPHYR_INCLUDE_BLUETOOTH_ADDR_H_
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Bluetooth device address definitions and utilities.
|
||||
* @defgroup bt_addr Device Address
|
||||
* @ingroup bluetooth
|
||||
* @{
|
||||
*/
|
||||
|
||||
#define BT_ADDR_LE_PUBLIC 0x00
|
||||
#define BT_ADDR_LE_RANDOM 0x01
|
||||
#define BT_ADDR_LE_PUBLIC_ID 0x02
|
||||
#define BT_ADDR_LE_RANDOM_ID 0x03
|
||||
#define BT_ADDR_LE_UNRESOLVED 0xFE /* Resolvable Private Address
|
||||
* (Controller unable to resolve)
|
||||
*/
|
||||
#define BT_ADDR_LE_ANONYMOUS 0xFF /* No address provided
|
||||
* (anonymous advertisement)
|
||||
*/
|
||||
|
||||
/** Length in bytes of a standard Bluetooth address */
|
||||
#define BT_ADDR_SIZE 6
|
||||
|
||||
/** Bluetooth Device Address */
|
||||
typedef struct {
|
||||
uint8_t val[BT_ADDR_SIZE];
|
||||
} bt_addr_t;
|
||||
/**/
|
||||
|
||||
/** Length in bytes of an LE Bluetooth address. Not packed, so no sizeof() */
|
||||
#define BT_ADDR_LE_SIZE 7
|
||||
|
||||
/** Bluetooth LE Device Address */
|
||||
typedef struct {
|
||||
uint8_t type;
|
||||
bt_addr_t a;
|
||||
} bt_addr_le_t;
|
||||
|
||||
/* Global Bluetooth address constants defined in bluetooth/common/addr.c */
|
||||
extern const bt_addr_t bt_addr_any;
|
||||
extern const bt_addr_t bt_addr_none;
|
||||
extern const bt_addr_le_t bt_addr_le_any;
|
||||
extern const bt_addr_le_t bt_addr_le_none;
|
||||
|
||||
/** Bluetooth device "any" address, not a valid address */
|
||||
#define BT_ADDR_ANY (&bt_addr_any)
|
||||
/** Bluetooth device "none" address, not a valid address */
|
||||
#define BT_ADDR_NONE (&bt_addr_none)
|
||||
/** Bluetooth LE device "any" address, not a valid address */
|
||||
#define BT_ADDR_LE_ANY (&bt_addr_le_any)
|
||||
/** Bluetooth LE device "none" address, not a valid address */
|
||||
#define BT_ADDR_LE_NONE (&bt_addr_le_none)
|
||||
|
||||
/** @brief Compare Bluetooth device addresses.
|
||||
*
|
||||
* @param a First Bluetooth device address to compare
|
||||
* @param b Second Bluetooth device address to compare
|
||||
*
|
||||
* @return negative value if @a a < @a b, 0 if @a a == @a b, else positive
|
||||
*/
|
||||
static inline int bt_addr_cmp(const bt_addr_t *a, const bt_addr_t *b)
|
||||
{
|
||||
return memcmp(a, b, sizeof(*a));
|
||||
}
|
||||
|
||||
/** @brief Determine equality of two Bluetooth device addresses.
|
||||
*
|
||||
* @retval #true if the two addresses are equal
|
||||
* @retval #false otherwise
|
||||
*/
|
||||
static inline bool bt_addr_eq(const bt_addr_t *a, const bt_addr_t *b)
|
||||
{
|
||||
return bt_addr_cmp(a, b) == 0;
|
||||
}
|
||||
|
||||
/** @brief Compare Bluetooth LE device addresses.
|
||||
*
|
||||
* @param a First Bluetooth LE device address to compare
|
||||
* @param b Second Bluetooth LE device address to compare
|
||||
*
|
||||
* @return negative value if @a a < @a b, 0 if @a a == @a b, else positive
|
||||
*
|
||||
* @sa bt_addr_le_eq
|
||||
*/
|
||||
static inline int bt_addr_le_cmp(const bt_addr_le_t *a, const bt_addr_le_t *b)
|
||||
{
|
||||
return memcmp(a, b, sizeof(*a));
|
||||
}
|
||||
|
||||
/** @brief Determine equality of two Bluetooth LE device addresses.
|
||||
*
|
||||
* The Bluetooth LE addresses are equal if and only if both the types and
|
||||
* the 48-bit addresses are numerically equal.
|
||||
*
|
||||
* @retval #true if the two addresses are equal
|
||||
* @retval #false otherwise
|
||||
*/
|
||||
static inline bool bt_addr_le_eq(const bt_addr_le_t *a, const bt_addr_le_t *b)
|
||||
{
|
||||
return bt_addr_le_cmp(a, b) == 0;
|
||||
}
|
||||
|
||||
/** @brief Copy Bluetooth device address.
|
||||
*
|
||||
* @param dst Bluetooth device address destination buffer.
|
||||
* @param src Bluetooth device address source buffer.
|
||||
*/
|
||||
static inline void bt_addr_copy(bt_addr_t *dst, const bt_addr_t *src)
|
||||
{
|
||||
memcpy(dst, src, sizeof(*dst));
|
||||
}
|
||||
|
||||
/** @brief Copy Bluetooth LE device address.
|
||||
*
|
||||
* @param dst Bluetooth LE device address destination buffer.
|
||||
* @param src Bluetooth LE device address source buffer.
|
||||
*/
|
||||
static inline void bt_addr_le_copy(bt_addr_le_t *dst, const bt_addr_le_t *src)
|
||||
{
|
||||
memcpy(dst, src, sizeof(*dst));
|
||||
}
|
||||
|
||||
/** Check if a Bluetooth LE random address is resolvable private address. */
|
||||
#define BT_ADDR_IS_RPA(a) (((a)->val[5] & 0xc0) == 0x40)
|
||||
/** Check if a Bluetooth LE random address is a non-resolvable private address.
|
||||
*/
|
||||
#define BT_ADDR_IS_NRPA(a) (((a)->val[5] & 0xc0) == 0x00)
|
||||
/** Check if a Bluetooth LE random address is a static address. */
|
||||
#define BT_ADDR_IS_STATIC(a) (((a)->val[5] & 0xc0) == 0xc0)
|
||||
|
||||
/** Set a Bluetooth LE random address as a resolvable private address. */
|
||||
#define BT_ADDR_SET_RPA(a) ((a)->val[5] = (((a)->val[5] & 0x3f) | 0x40))
|
||||
/** Set a Bluetooth LE random address as a non-resolvable private address. */
|
||||
#define BT_ADDR_SET_NRPA(a) ((a)->val[5] &= 0x3f)
|
||||
/** Set a Bluetooth LE random address as a static address. */
|
||||
#define BT_ADDR_SET_STATIC(a) ((a)->val[5] |= 0xc0)
|
||||
|
||||
/** @brief Check if a Bluetooth LE address is a random private resolvable
|
||||
* address.
|
||||
*
|
||||
* @param addr Bluetooth LE device address.
|
||||
*
|
||||
* @return true if address is a random private resolvable address.
|
||||
*/
|
||||
static inline bool bt_addr_le_is_rpa(const bt_addr_le_t *addr)
|
||||
{
|
||||
if (addr->type != BT_ADDR_LE_RANDOM) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return BT_ADDR_IS_RPA(&addr->a);
|
||||
}
|
||||
|
||||
/** @brief Check if a Bluetooth LE address is valid identity address.
|
||||
*
|
||||
* Valid Bluetooth LE identity addresses are either public address or
|
||||
* random static address.
|
||||
*
|
||||
* @param addr Bluetooth LE device address.
|
||||
*
|
||||
* @return true if address is a valid identity address.
|
||||
*/
|
||||
static inline bool bt_addr_le_is_identity(const bt_addr_le_t *addr)
|
||||
{
|
||||
if (addr->type == BT_ADDR_LE_PUBLIC) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return BT_ADDR_IS_STATIC(&addr->a);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Recommended length of user string buffer for Bluetooth address
|
||||
*
|
||||
* @details The recommended length guarantee the output of address
|
||||
* conversion will not lose valuable information about address being
|
||||
* processed.
|
||||
*/
|
||||
#define BT_ADDR_STR_LEN 18
|
||||
|
||||
/**
|
||||
* @brief Recommended length of user string buffer for Bluetooth LE address
|
||||
*
|
||||
* @details The recommended length guarantee the output of address
|
||||
* conversion will not lose valuable information about address being
|
||||
* processed.
|
||||
*/
|
||||
#define BT_ADDR_LE_STR_LEN 30
|
||||
|
||||
/** @brief Converts binary Bluetooth address to string.
|
||||
*
|
||||
* @param addr Address of buffer containing binary Bluetooth address.
|
||||
* @param str Address of user buffer with enough room to store formatted
|
||||
* string containing binary address.
|
||||
* @param len Length of data to be copied to user string buffer. Refer to
|
||||
* BT_ADDR_STR_LEN about recommended value.
|
||||
*
|
||||
* @return Number of successfully formatted bytes from binary address.
|
||||
*/
|
||||
static inline int bt_addr_to_str(const bt_addr_t *addr, char *str, size_t len)
|
||||
{
|
||||
return snprintf(str, len, "%02X:%02X:%02X:%02X:%02X:%02X",
|
||||
addr->val[5], addr->val[4], addr->val[3],
|
||||
addr->val[2], addr->val[1], addr->val[0]);
|
||||
}
|
||||
|
||||
/** @brief Converts binary LE Bluetooth address to string.
|
||||
*
|
||||
* @param addr Address of buffer containing binary LE Bluetooth address.
|
||||
* @param str Address of user buffer with enough room to store
|
||||
* formatted string containing binary LE address.
|
||||
* @param len Length of data to be copied to user string buffer. Refer to
|
||||
* BT_ADDR_LE_STR_LEN about recommended value.
|
||||
*
|
||||
* @return Number of successfully formatted bytes from binary address.
|
||||
*/
|
||||
static inline int bt_addr_le_to_str(const bt_addr_le_t *addr, char *str,
|
||||
size_t len)
|
||||
{
|
||||
char type[10];
|
||||
|
||||
switch (addr->type) {
|
||||
case BT_ADDR_LE_PUBLIC:
|
||||
strcpy(type, "public");
|
||||
break;
|
||||
case BT_ADDR_LE_RANDOM:
|
||||
strcpy(type, "random");
|
||||
break;
|
||||
case BT_ADDR_LE_PUBLIC_ID:
|
||||
strcpy(type, "public-id");
|
||||
break;
|
||||
case BT_ADDR_LE_RANDOM_ID:
|
||||
strcpy(type, "random-id");
|
||||
break;
|
||||
default:
|
||||
snprintf(type, sizeof(type), "0x%02x", addr->type);
|
||||
break;
|
||||
}
|
||||
|
||||
return snprintf(str, len, "%02X:%02X:%02X:%02X:%02X:%02X (%s)",
|
||||
addr->a.val[5], addr->a.val[4], addr->a.val[3],
|
||||
addr->a.val[2], addr->a.val[1], addr->a.val[0], type);
|
||||
}
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* ZEPHYR_INCLUDE_BLUETOOTH_ADDR_H_ */
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,136 @@
|
||||
/** @file
|
||||
* @brief Attribute Protocol handling.
|
||||
*/
|
||||
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2016 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#ifndef ZEPHYR_INCLUDE_BLUETOOTH_ATT_H_
|
||||
#define ZEPHYR_INCLUDE_BLUETOOTH_ATT_H_
|
||||
|
||||
/**
|
||||
* @brief Attribute Protocol (ATT)
|
||||
* @defgroup bt_att Attribute Protocol (ATT)
|
||||
* @ingroup bluetooth
|
||||
* @{
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#include <zephyr/bluetooth/conn.h>
|
||||
#include <zephyr/sys/slist.h>
|
||||
#include <zephyr/sys/util_macro.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Error codes for Error response PDU
|
||||
*
|
||||
* Defined by The Bluetooth Core Specification, Version 5.4, Vol 3, Part F, Section 3.4.1.1
|
||||
*/
|
||||
/** The ATT operation was successful */
|
||||
#define BT_ATT_ERR_SUCCESS 0x00
|
||||
/** The attribute handle given was not valid on the server */
|
||||
#define BT_ATT_ERR_INVALID_HANDLE 0x01
|
||||
/** The attribute cannot be read */
|
||||
#define BT_ATT_ERR_READ_NOT_PERMITTED 0x02
|
||||
/** The attribute cannot be written */
|
||||
#define BT_ATT_ERR_WRITE_NOT_PERMITTED 0x03
|
||||
/** The attribute PDU was invalid */
|
||||
#define BT_ATT_ERR_INVALID_PDU 0x04
|
||||
/** The attribute requires authentication before it can be read or written */
|
||||
#define BT_ATT_ERR_AUTHENTICATION 0x05
|
||||
/** The ATT Server does not support the request received from the client */
|
||||
#define BT_ATT_ERR_NOT_SUPPORTED 0x06
|
||||
/** Offset specified was past the end of the attribute */
|
||||
#define BT_ATT_ERR_INVALID_OFFSET 0x07
|
||||
/** The attribute requires authorization before it can be read or written */
|
||||
#define BT_ATT_ERR_AUTHORIZATION 0x08
|
||||
/** Too many prepare writes have been queued */
|
||||
#define BT_ATT_ERR_PREPARE_QUEUE_FULL 0x09
|
||||
/** No attribute found within the given attribute handle range */
|
||||
#define BT_ATT_ERR_ATTRIBUTE_NOT_FOUND 0x0a
|
||||
/** The attribute cannot be read using the ATT_READ_BLOB_REQ PDU */
|
||||
#define BT_ATT_ERR_ATTRIBUTE_NOT_LONG 0x0b
|
||||
/** The Encryption Key Size used for encrypting this link is too short */
|
||||
#define BT_ATT_ERR_ENCRYPTION_KEY_SIZE 0x0c
|
||||
/** The attribute value length is invalid for the operation */
|
||||
#define BT_ATT_ERR_INVALID_ATTRIBUTE_LEN 0x0d
|
||||
/**
|
||||
* @brief The attribute request that was requested has encountered an error that was unlikely
|
||||
*
|
||||
* The attribute request could therefore not be completed as requested
|
||||
*/
|
||||
#define BT_ATT_ERR_UNLIKELY 0x0e
|
||||
/** The attribute requires encryption before it can be read or written */
|
||||
#define BT_ATT_ERR_INSUFFICIENT_ENCRYPTION 0x0f
|
||||
/**
|
||||
* @brief The attribute type is not a supported grouping attribute
|
||||
*
|
||||
* The attribute type is not a supported grouping attribute as defined by a higher layer
|
||||
* specification.
|
||||
*/
|
||||
#define BT_ATT_ERR_UNSUPPORTED_GROUP_TYPE 0x10
|
||||
/** Insufficient Resources to complete the request */
|
||||
#define BT_ATT_ERR_INSUFFICIENT_RESOURCES 0x11
|
||||
/** The server requests the client to rediscover the database */
|
||||
#define BT_ATT_ERR_DB_OUT_OF_SYNC 0x12
|
||||
/** The attribute parameter value was not allowed */
|
||||
#define BT_ATT_ERR_VALUE_NOT_ALLOWED 0x13
|
||||
|
||||
/* Common Profile Error Codes
|
||||
*
|
||||
* Defined by the Supplement to the Bluetooth Core Specification (CSS), v11, Part B, Section 1.2.
|
||||
*/
|
||||
/** Write Request Rejected */
|
||||
#define BT_ATT_ERR_WRITE_REQ_REJECTED 0xfc
|
||||
/** Client Characteristic Configuration Descriptor Improperly Configured */
|
||||
#define BT_ATT_ERR_CCC_IMPROPER_CONF 0xfd
|
||||
/** Procedure Already in Progress */
|
||||
#define BT_ATT_ERR_PROCEDURE_IN_PROGRESS 0xfe
|
||||
/** Out of Range */
|
||||
#define BT_ATT_ERR_OUT_OF_RANGE 0xff
|
||||
|
||||
/* Version 5.2, Vol 3, Part F, 3.2.9 defines maximum attribute length to 512 */
|
||||
#define BT_ATT_MAX_ATTRIBUTE_LEN 512
|
||||
|
||||
/* Handle 0x0000 is reserved for future use */
|
||||
#define BT_ATT_FIRST_ATTRIBUTE_HANDLE 0x0001
|
||||
/* 0xffff is defined as the maximum, and thus last, valid attribute handle */
|
||||
#define BT_ATT_LAST_ATTRIBUTE_HANDLE 0xffff
|
||||
|
||||
/** @brief Get number of EATT channels connected.
|
||||
*
|
||||
* @param conn The connection to get the number of EATT channels for.
|
||||
*
|
||||
* @return The number of EATT channels connected.
|
||||
* Returns 0 if @p conn is NULL or not connected.
|
||||
*/
|
||||
size_t bt_eatt_count(struct bt_conn *conn);
|
||||
|
||||
/** @brief ATT channel option bit field values.
|
||||
* @note @ref BT_ATT_CHAN_OPT_UNENHANCED_ONLY and @ref BT_ATT_CHAN_OPT_ENHANCED_ONLY are mutually
|
||||
* exclusive and both bits may not be set.
|
||||
*/
|
||||
enum bt_att_chan_opt {
|
||||
/** Both Enhanced and Unenhanced channels can be used */
|
||||
BT_ATT_CHAN_OPT_NONE = 0x0,
|
||||
/** Only Unenhanced channels will be used */
|
||||
BT_ATT_CHAN_OPT_UNENHANCED_ONLY = BIT(0),
|
||||
/** Only Enhanced channels will be used */
|
||||
BT_ATT_CHAN_OPT_ENHANCED_ONLY = BIT(1),
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
#endif /* ZEPHYR_INCLUDE_BLUETOOTH_ATT_H_ */
|
||||
@@ -0,0 +1,635 @@
|
||||
/**
|
||||
* @file
|
||||
* @brief Bluetooth subsystem core APIs.
|
||||
*/
|
||||
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2017 Nordic Semiconductor ASA
|
||||
* SPDX-FileCopyrightText: 2015-2016 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#ifndef ZEPHYR_INCLUDE_BLUETOOTH_BLUETOOTH_H_
|
||||
#define ZEPHYR_INCLUDE_BLUETOOTH_BLUETOOTH_H_
|
||||
|
||||
/**
|
||||
* @brief Bluetooth APIs
|
||||
*
|
||||
* @details The Bluetooth Subsystem Core APIs provide essential functionalities
|
||||
* to use and manage Bluetooth based communication. These APIs include
|
||||
* APIs for Bluetooth stack initialization, device discovery,
|
||||
* connection management, data transmission, profiles and services.
|
||||
* These APIs support both classic Bluetooth and Bluetooth Low Energy
|
||||
* (LE) operations.
|
||||
*
|
||||
* @defgroup bluetooth Bluetooth APIs
|
||||
* @ingroup connectivity
|
||||
* @{
|
||||
*/
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <zephyr/sys/util.h>
|
||||
#include <zephyr/net_buf.h>
|
||||
#include <zephyr/bluetooth/gap.h>
|
||||
#include <zephyr/bluetooth/addr.h>
|
||||
#include <zephyr/bluetooth/crypto.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Generic Access Profile (GAP)
|
||||
*
|
||||
* @details The Generic Access Profile (GAP) defines fundamental Bluetooth
|
||||
* operations, including device discovery, pairing, and connection
|
||||
* management. Zephyr's GAP implementation supports both classic
|
||||
* Bluetooth and Bluetooth Low Energy (LE) functionalities, enabling
|
||||
* roles such as Broadcaster, Observer, Peripheral, and Central. These
|
||||
* roles define the device's behavior in advertising, scanning, and
|
||||
* establishing connections within Bluetooth networks.
|
||||
*
|
||||
* @defgroup bt_gap Generic Access Profile (GAP)
|
||||
* @since 1.0
|
||||
* @version 1.0.0
|
||||
* @ingroup bluetooth
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** Opaque type representing an advertiser. */
|
||||
struct bt_le_ext_adv;
|
||||
|
||||
/** Opaque type representing an periodic advertising sync. */
|
||||
struct bt_le_per_adv_sync;
|
||||
|
||||
/* Don't require everyone to include conn.h */
|
||||
struct bt_conn;
|
||||
|
||||
/* Don't require everyone to include iso.h */
|
||||
struct bt_iso_biginfo;
|
||||
|
||||
/**
|
||||
* @brief Bluetooth data.
|
||||
*
|
||||
* @details Description of different AD Types that can be encoded into advertising data. Used to
|
||||
* form arrays that are passed to the @ref bt_le_adv_start function. The @ref BT_DATA define can
|
||||
* be used as a helpter to declare the elements of an @ref bt_data array.
|
||||
*/
|
||||
struct bt_data {
|
||||
/** Type of scan response data or advertisement data. */
|
||||
uint8_t type;
|
||||
/** Length of scan response data or advertisement data. */
|
||||
uint8_t data_len;
|
||||
/** Pointer to Scan response or advertisement data. */
|
||||
const uint8_t *data;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Helper to declare elements of bt_data arrays
|
||||
*
|
||||
* This macro is mainly for creating an array of struct bt_data
|
||||
* elements which is then passed to e.g. @ref bt_le_adv_start function.
|
||||
*
|
||||
* @param _type Type of advertising data field
|
||||
* @param _data Pointer to the data field payload
|
||||
* @param _data_len Number of octets behind the _data pointer
|
||||
*/
|
||||
#define BT_DATA(_type, _data, _data_len) \
|
||||
{ \
|
||||
.type = (_type), \
|
||||
.data_len = (_data_len), \
|
||||
.data = (const uint8_t *)(_data), \
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Parameters for starting an extended advertising session.
|
||||
*
|
||||
* @details This struct provides the parameters to control the behavior of an extended advertising
|
||||
* session, including the timeout and the number of advertising events to send. The timeout is
|
||||
* specified in units of 10 ms, and the number of events determines how many times the advertising
|
||||
* will be sent before stopping. If either the timeout or number of events is reached, the
|
||||
* advertising session will be stopped, and the application will be notified via the advertiser sent
|
||||
* callback. If both parameters are provided, the advertising session will stop when either limit is
|
||||
* reached.
|
||||
*
|
||||
* @note Used in @ref bt_le_ext_adv_start function.
|
||||
*/
|
||||
struct bt_le_ext_adv_start_param {
|
||||
/**
|
||||
* @brief Maximum advertising set duration (N * 10 ms)
|
||||
*
|
||||
* The advertising set can be automatically disabled after a
|
||||
* certain amount of time has passed since it first appeared on
|
||||
* air.
|
||||
*
|
||||
* Set to zero for no limit. Set in units of 10 ms.
|
||||
*
|
||||
* When the advertising set is automatically disabled because of
|
||||
* this limit, @ref bt_le_ext_adv_cb.sent will be called.
|
||||
*
|
||||
* When using high duty cycle directed connectable advertising
|
||||
* then this parameters must be set to a non-zero value less
|
||||
* than or equal to the maximum of
|
||||
* @ref BT_GAP_ADV_HIGH_DUTY_CYCLE_MAX_TIMEOUT.
|
||||
*
|
||||
* If privacy @kconfig{CONFIG_BT_PRIVACY} is enabled then the
|
||||
* timeout must be less than @kconfig{CONFIG_BT_RPA_TIMEOUT}.
|
||||
*
|
||||
* For background information, see parameter "Duration" in
|
||||
* Bluetooth Core Specification Version 6.0 Vol. 4 Part E,
|
||||
* Section 7.8.56.
|
||||
*/
|
||||
uint16_t timeout;
|
||||
|
||||
/**
|
||||
* @brief Maximum number of extended advertising events to be
|
||||
* sent
|
||||
*
|
||||
* The advertiser can be automatically disabled once the whole
|
||||
* advertisement (i.e. extended advertising event) has been sent
|
||||
* a certain number of times. The number of advertising PDUs
|
||||
* sent may be higher and is not relevant.
|
||||
*
|
||||
* Set to zero for no limit.
|
||||
*
|
||||
* When the advertising set is automatically disabled because of
|
||||
* this limit, @ref bt_le_ext_adv_cb.sent will be called.
|
||||
*
|
||||
* For background information, see parameter
|
||||
* "Max_Extended_Advertising_Events" in Bluetooth Core
|
||||
* Specification Version 6.0 Vol. 4 Part E, Section 7.8.56.
|
||||
*/
|
||||
uint8_t num_events;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Start advertising with the given advertising set
|
||||
*
|
||||
* If the advertiser is limited by either the @p param.timeout or @p param.num_events,
|
||||
* the application will be notified by the @ref bt_le_ext_adv_cb.sent callback once
|
||||
* the limit is reached.
|
||||
* If the advertiser is limited by both the timeout and the number of
|
||||
* advertising events, then the limit that is reached first will stop the
|
||||
* advertiser.
|
||||
*
|
||||
* @note The advertising set @p adv can be created with @ref bt_le_ext_adv_create.
|
||||
*
|
||||
* @param adv Advertising set object.
|
||||
* @param param Advertise start parameters.
|
||||
*/
|
||||
int bt_le_ext_adv_start(struct bt_le_ext_adv *adv,
|
||||
const struct bt_le_ext_adv_start_param *param);
|
||||
|
||||
/** Advertising states. */
|
||||
enum bt_le_ext_adv_state {
|
||||
/** The advertising set has been created but not enabled. */
|
||||
BT_LE_EXT_ADV_STATE_DISABLED,
|
||||
|
||||
/** The advertising set is enabled. */
|
||||
BT_LE_EXT_ADV_STATE_ENABLED,
|
||||
};
|
||||
|
||||
/** Periodic Advertising states. */
|
||||
enum bt_le_per_adv_state {
|
||||
/** Not configured for periodic advertising. */
|
||||
BT_LE_PER_ADV_STATE_NONE,
|
||||
|
||||
/** The advertising set has been configured for periodic advertising, but is not enabled. */
|
||||
BT_LE_PER_ADV_STATE_DISABLED,
|
||||
|
||||
/** Periodic advertising is enabled. */
|
||||
BT_LE_PER_ADV_STATE_ENABLED,
|
||||
};
|
||||
|
||||
/** @brief Advertising set info structure. */
|
||||
struct bt_le_ext_adv_info {
|
||||
/** Advertising Set ID */
|
||||
uint8_t sid;
|
||||
|
||||
/** Current local advertising address used. */
|
||||
const bt_addr_le_t *addr;
|
||||
|
||||
/** Extended advertising state. */
|
||||
enum bt_le_ext_adv_state ext_adv_state;
|
||||
|
||||
/** Periodic advertising state. */
|
||||
enum bt_le_per_adv_state per_adv_state;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Get advertising set info
|
||||
*
|
||||
* @param adv Advertising set object
|
||||
* @param info Advertising set info object. The values in this object are only valid on success.
|
||||
*
|
||||
* @retval 0 Success.
|
||||
* @retval -EINVAL @p adv is not valid advertising set or @p info is NULL.
|
||||
*/
|
||||
int bt_le_ext_adv_get_info(const struct bt_le_ext_adv *adv,
|
||||
struct bt_le_ext_adv_info *info);
|
||||
|
||||
struct bt_le_per_adv_sync_synced_info {
|
||||
/** Advertiser LE address and type. */
|
||||
const bt_addr_le_t *addr;
|
||||
|
||||
/** Advertising Set Identifier, valid range @ref BT_GAP_SID_MIN to @ref BT_GAP_SID_MAX. */
|
||||
uint8_t sid;
|
||||
|
||||
/** Periodic advertising interval (N * 1.25 ms) */
|
||||
uint16_t interval;
|
||||
|
||||
/** Advertiser PHY (see @ref bt_gap_le_phy). */
|
||||
uint8_t phy;
|
||||
|
||||
/**
|
||||
* @brief Peer that transferred the periodic advertising sync
|
||||
*
|
||||
* Will always be NULL when the sync is locally created.
|
||||
*
|
||||
*/
|
||||
struct bt_conn *conn;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Information about the termination of a periodic advertising sync.
|
||||
*
|
||||
* @details This struct provides information about the termination of a periodic advertising sync.
|
||||
* It includes the advertiser’s address and SID, along with the reason for the sync termination.
|
||||
* This information is provided in the callback when the sync is terminated, either due to a
|
||||
* local or remote request, or due to missing data (e.g., out of range or lost sync).
|
||||
*
|
||||
* @note Used in @ref bt_le_per_adv_sync_cb structure.
|
||||
*/
|
||||
struct bt_le_per_adv_sync_term_info {
|
||||
/** Advertiser LE address and type. */
|
||||
const bt_addr_le_t *addr;
|
||||
|
||||
/** Advertising Set Identifier, valid range @ref BT_GAP_SID_MIN to @ref BT_GAP_SID_MAX. */
|
||||
uint8_t sid;
|
||||
|
||||
/** Cause of periodic advertising termination (see the BT_HCI_ERR_* values). */
|
||||
uint8_t reason;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Information about a received periodic advertising report.
|
||||
*
|
||||
* @details This struct holds information about a periodic advertising event that has been received.
|
||||
* It contains details such as the advertiser’s address, SID, transmit power, RSSI, CTE type, and
|
||||
* additional information depending on the configuration (e.g., event counter and subevent in case
|
||||
* of a subevent indication). This information is provided in the callback when periodic advertising
|
||||
* data is received.
|
||||
*
|
||||
* @note Used in @ref bt_le_per_adv_sync_cb structure.
|
||||
*/
|
||||
struct bt_le_per_adv_sync_recv_info {
|
||||
/** Advertiser LE address and type. */
|
||||
const bt_addr_le_t *addr;
|
||||
|
||||
/** Advertising Set Identifier, valid range @ref BT_GAP_SID_MIN to @ref BT_GAP_SID_MAX. */
|
||||
uint8_t sid;
|
||||
|
||||
/** The TX power of the advertisement. */
|
||||
int8_t tx_power;
|
||||
|
||||
/** The RSSI of the advertisement excluding any CTE. */
|
||||
int8_t rssi;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Callback struct for periodic advertising sync events.
|
||||
*
|
||||
* @details This struct defines the callback functions that are invoked for various periodic
|
||||
* advertising sync events. These include when the sync is successfully established, terminated,
|
||||
* when data is received, state changes, BIG info reports, and IQ samples from the periodic
|
||||
* advertising.
|
||||
*
|
||||
* @note Used in @ref bt_le_per_adv_sync_cb_register function.
|
||||
*/
|
||||
|
||||
struct bt_le_per_adv_sync_cb {
|
||||
/**
|
||||
* @brief The periodic advertising has been successfully synced.
|
||||
*
|
||||
* This callback notifies the application that the periodic advertising
|
||||
* set has been successfully synced, and will now start to
|
||||
* receive periodic advertising reports.
|
||||
*
|
||||
* @param sync The periodic advertising sync object.
|
||||
* @param info Information about the sync event.
|
||||
*/
|
||||
void (*synced)(struct bt_le_per_adv_sync *sync,
|
||||
struct bt_le_per_adv_sync_synced_info *info);
|
||||
|
||||
/**
|
||||
* @brief The periodic advertising sync has been terminated.
|
||||
*
|
||||
* This callback notifies the application that the periodic advertising
|
||||
* sync has been terminated, either by local request, remote request or
|
||||
* because due to missing data, e.g. by being out of range or sync.
|
||||
*
|
||||
* @param sync The periodic advertising sync object.
|
||||
* @param info Information about the termination event.
|
||||
*/
|
||||
void (*term)(struct bt_le_per_adv_sync *sync,
|
||||
const struct bt_le_per_adv_sync_term_info *info);
|
||||
|
||||
/**
|
||||
* @brief Periodic advertising data received.
|
||||
*
|
||||
* This callback notifies the application of an periodic advertising
|
||||
* report.
|
||||
*
|
||||
* @param sync The advertising set object.
|
||||
* @param info Information about the periodic advertising event.
|
||||
* @param buf Buffer containing the periodic advertising data.
|
||||
* NULL if the controller failed to receive a subevent
|
||||
* indication. Only happens if
|
||||
* @kconfig{CONFIG_BT_PER_ADV_SYNC_RSP} is enabled.
|
||||
*/
|
||||
void (*recv)(struct bt_le_per_adv_sync *sync,
|
||||
const struct bt_le_per_adv_sync_recv_info *info,
|
||||
struct net_buf_simple *buf);
|
||||
|
||||
/**
|
||||
* @brief BIGInfo advertising report received.
|
||||
*
|
||||
* This callback notifies the application of a BIGInfo advertising report.
|
||||
* This is received if the advertiser is broadcasting isochronous streams in a BIG.
|
||||
* See iso.h for more information.
|
||||
*
|
||||
* @param sync The advertising set object.
|
||||
* @param biginfo The BIGInfo report.
|
||||
*/
|
||||
void (*biginfo)(struct bt_le_per_adv_sync *sync, const struct bt_iso_biginfo *biginfo);
|
||||
|
||||
sys_snode_t node;
|
||||
};
|
||||
|
||||
/** @brief Periodic advertising set info structure. */
|
||||
struct bt_le_per_adv_sync_info {
|
||||
/** Periodic Advertiser Address */
|
||||
bt_addr_le_t addr;
|
||||
|
||||
/** Advertising Set Identifier, valid range @ref BT_GAP_SID_MIN to @ref BT_GAP_SID_MAX. */
|
||||
uint8_t sid;
|
||||
|
||||
/** Periodic advertising interval (N * 1.25 ms) */
|
||||
uint16_t interval;
|
||||
|
||||
/** Advertiser PHY (see @ref bt_gap_le_phy). */
|
||||
uint8_t phy;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Get periodic adv sync information.
|
||||
*
|
||||
* @param per_adv_sync Periodic advertising sync object.
|
||||
* @param info Periodic advertising sync info object
|
||||
*
|
||||
* @return Zero on success or (negative) error code on failure.
|
||||
*/
|
||||
int bt_le_per_adv_sync_get_info(struct bt_le_per_adv_sync *per_adv_sync,
|
||||
struct bt_le_per_adv_sync_info *info);
|
||||
|
||||
/**
|
||||
* @brief Look up an existing periodic advertising sync object by advertiser address.
|
||||
*
|
||||
* @param adv_addr Advertiser address.
|
||||
* @param sid The periodic advertising set ID.
|
||||
*
|
||||
* @return Periodic advertising sync object or NULL if not found.
|
||||
*/
|
||||
struct bt_le_per_adv_sync *bt_le_per_adv_sync_lookup_addr(const bt_addr_le_t *adv_addr,
|
||||
uint8_t sid);
|
||||
|
||||
/**
|
||||
* @brief Register periodic advertising sync callbacks.
|
||||
*
|
||||
* Adds the callback structure to the list of callback structures for periodic
|
||||
* advertising syncs.
|
||||
*
|
||||
* This callback will be called for all periodic advertising sync activity,
|
||||
* such as synced, terminated and when data is received.
|
||||
*
|
||||
* @param cb Callback struct. Must point to memory that remains valid.
|
||||
*
|
||||
* @retval 0 Success.
|
||||
* @retval -EEXIST if @p cb was already registered.
|
||||
*/
|
||||
int bt_le_per_adv_sync_cb_register(struct bt_le_per_adv_sync_cb *cb);
|
||||
|
||||
/** LE scan parameters */
|
||||
struct bt_le_scan_param {
|
||||
/** Scan type. @ref BT_LE_SCAN_TYPE_ACTIVE or @ref BT_LE_SCAN_TYPE_PASSIVE. */
|
||||
uint8_t type;
|
||||
|
||||
/** Bit-field of scanning options. */
|
||||
uint8_t options;
|
||||
|
||||
/** Scan interval (N * 0.625 ms).
|
||||
*
|
||||
* @note When @kconfig{CONFIG_BT_SCAN_AND_INITIATE_IN_PARALLEL} is enabled
|
||||
* and the application wants to scan and connect in parallel,
|
||||
* the Bluetooth Controller may require the scan interval used
|
||||
* for scanning and connection establishment to be equal to
|
||||
* obtain the best performance.
|
||||
*/
|
||||
uint16_t interval;
|
||||
|
||||
/** Scan window (N * 0.625 ms)
|
||||
*
|
||||
* @note When @kconfig{CONFIG_BT_SCAN_AND_INITIATE_IN_PARALLEL} is enabled
|
||||
* and the application wants to scan and connect in parallel,
|
||||
* the Bluetooth Controller may require the scan window used
|
||||
* for scanning and connection establishment to be equal to
|
||||
* obtain the best performance.
|
||||
*/
|
||||
uint16_t window;
|
||||
|
||||
/**
|
||||
* @brief Scan timeout (N * 10 ms)
|
||||
*
|
||||
* Application will be notified by the scan timeout callback.
|
||||
* Set zero to disable timeout.
|
||||
*/
|
||||
uint16_t timeout;
|
||||
|
||||
/**
|
||||
* @brief Scan interval LE Coded PHY (N * 0.625 MS)
|
||||
*
|
||||
* Set zero to use same as LE 1M PHY scan interval.
|
||||
*/
|
||||
uint16_t interval_coded;
|
||||
|
||||
/**
|
||||
* @brief Scan window LE Coded PHY (N * 0.625 MS)
|
||||
*
|
||||
* Set zero to use same as LE 1M PHY scan window.
|
||||
*/
|
||||
uint16_t window_coded;
|
||||
};
|
||||
|
||||
/** LE advertisement and scan response packet information */
|
||||
struct bt_le_scan_recv_info {
|
||||
/**
|
||||
* @brief Advertiser LE address and type.
|
||||
*
|
||||
* If advertiser is anonymous then this address will be
|
||||
* @ref BT_ADDR_LE_ANY.
|
||||
*/
|
||||
const bt_addr_le_t *addr;
|
||||
|
||||
/** Advertising Set Identifier, valid range @ref BT_GAP_SID_MIN to @ref BT_GAP_SID_MAX. */
|
||||
uint8_t sid;
|
||||
|
||||
/** Strength of advertiser signal. */
|
||||
int8_t rssi;
|
||||
|
||||
/** Transmit power of the advertiser. */
|
||||
int8_t tx_power;
|
||||
|
||||
/**
|
||||
* @brief Advertising packet type.
|
||||
*
|
||||
* Uses the @ref bt_gap_adv_type value.
|
||||
*
|
||||
* May indicate that this is a scan response if the type is
|
||||
* @ref BT_GAP_ADV_TYPE_SCAN_RSP.
|
||||
*/
|
||||
uint8_t adv_type;
|
||||
|
||||
/**
|
||||
* @brief Advertising packet properties bitfield.
|
||||
*
|
||||
* Uses the @ref bt_gap_adv_prop values.
|
||||
* May indicate that this is a scan response if the value contains the
|
||||
* @ref BT_GAP_ADV_PROP_SCAN_RESPONSE bit.
|
||||
*
|
||||
*/
|
||||
uint16_t adv_props;
|
||||
|
||||
/**
|
||||
* @brief Periodic advertising interval (N * 1.25 ms).
|
||||
*
|
||||
* If 0 there is no periodic advertising.
|
||||
*/
|
||||
uint16_t interval;
|
||||
|
||||
/** Primary advertising channel PHY. */
|
||||
uint8_t primary_phy;
|
||||
|
||||
/** Secondary advertising channel PHY. */
|
||||
uint8_t secondary_phy;
|
||||
};
|
||||
|
||||
/** Listener context for (LE) scanning. */
|
||||
struct bt_le_scan_cb {
|
||||
|
||||
/**
|
||||
* @brief Advertisement packet and scan response received callback.
|
||||
*
|
||||
* @param info Advertiser packet and scan response information.
|
||||
* @param buf Buffer containing advertiser data.
|
||||
*/
|
||||
void (*recv)(const struct bt_le_scan_recv_info *info,
|
||||
struct net_buf_simple *buf);
|
||||
|
||||
sys_snode_t node;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Start (LE) scanning
|
||||
*
|
||||
* Start LE scanning with given parameters and provide results through
|
||||
* the specified callback.
|
||||
*
|
||||
* @note The LE scanner by default does not use the Identity Address of the
|
||||
* local device when @kconfig{CONFIG_BT_PRIVACY} is disabled. This is to
|
||||
* prevent the active scanner from disclosing the identity address information
|
||||
* when requesting additional information from advertisers.
|
||||
* In order to enable directed advertiser reports then
|
||||
* @kconfig{CONFIG_BT_SCAN_WITH_IDENTITY} must be enabled.
|
||||
*
|
||||
* @note Setting the `param.timeout` parameter is not supported when
|
||||
* @kconfig{CONFIG_BT_PRIVACY} is enabled, when the param.type is @ref
|
||||
* BT_LE_SCAN_TYPE_ACTIVE. Supplying a non-zero timeout will result in an
|
||||
* -EINVAL error code.
|
||||
*
|
||||
* @param param Scan parameters.
|
||||
* @param cb Callback to notify scan results. May be NULL if callback
|
||||
* registration through @ref bt_le_scan_cb_register is preferred.
|
||||
*
|
||||
* @return Zero on success or error code otherwise, positive in case of
|
||||
* protocol error or negative (POSIX) in case of stack internal error.
|
||||
* @retval -EBUSY if the scanner is already being started in a different thread.
|
||||
*/
|
||||
int bt_le_scan_start(const struct bt_le_scan_param *param, void *cb);
|
||||
|
||||
/**
|
||||
* @brief Stop (LE) scanning.
|
||||
*
|
||||
* Stops ongoing LE scanning.
|
||||
*
|
||||
* @return Zero on success or error code otherwise, positive in case of
|
||||
* protocol error or negative (POSIX) in case of stack internal error.
|
||||
*/
|
||||
int bt_le_scan_stop(void);
|
||||
|
||||
/**
|
||||
* @brief Register scanner packet callbacks.
|
||||
*
|
||||
* Adds the callback structure to the list of callback structures that monitors
|
||||
* scanner activity.
|
||||
*
|
||||
* This callback will be called for all scanner activity.
|
||||
*
|
||||
* @param cb Callback struct. Must point to memory that remains valid.
|
||||
*
|
||||
* @retval 0 Success.
|
||||
* @retval -EEXIST if @p cb was already registered.
|
||||
*/
|
||||
int bt_le_scan_cb_register(struct bt_le_scan_cb *cb);
|
||||
|
||||
/**
|
||||
* @brief Unregister scanner packet callbacks.
|
||||
*
|
||||
* Remove the callback structure from the list of scanner callbacks.
|
||||
*
|
||||
* @param cb Callback struct. Must point to memory that remains valid.
|
||||
*/
|
||||
void bt_le_scan_cb_unregister(struct bt_le_scan_cb *cb);
|
||||
|
||||
/** Information about a bond with a remote device. */
|
||||
struct bt_bond_info {
|
||||
/** Address of the remote device. */
|
||||
bt_addr_le_t addr;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Iterate through all existing bonds.
|
||||
*
|
||||
* @param id Local identity handle (typically @ref BT_ID_DEFAULT). Corresponds to the
|
||||
* identity address used in iteration.
|
||||
* @param func Function to call for each bond.
|
||||
* @param user_data Data to pass to the callback function.
|
||||
*/
|
||||
void bt_foreach_bond(uint8_t id, void (*func)(const struct bt_bond_info *info,
|
||||
void *user_data),
|
||||
void *user_data);
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
#endif /* ZEPHYR_INCLUDE_BLUETOOTH_BLUETOOTH_H_ */
|
||||
@@ -0,0 +1,55 @@
|
||||
/** @file
|
||||
* @brief Bluetooth data buffer API
|
||||
*/
|
||||
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2016 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef ZEPHYR_INCLUDE_BLUETOOTH_BUF_H_
|
||||
#define ZEPHYR_INCLUDE_BLUETOOTH_BUF_H_
|
||||
|
||||
/**
|
||||
* @brief Data buffers
|
||||
* @defgroup bt_buf Data buffers
|
||||
* @ingroup bluetooth
|
||||
* @{
|
||||
*/
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <zephyr/kernel.h>
|
||||
#include <zephyr/net_buf.h>
|
||||
#include <zephyr/bluetooth/hci.h>
|
||||
#include <zephyr/sys/util.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Headroom reserved in buffers, primarily for HCI transport encoding purposes */
|
||||
#define BT_BUF_RESERVE 1
|
||||
|
||||
/** Helper to include reserved HCI data in buffer calculations */
|
||||
#define BT_BUF_SIZE(size) (BT_BUF_RESERVE + (size))
|
||||
|
||||
/** Helper to calculate needed buffer size for HCI ACL packets */
|
||||
#define BT_BUF_ACL_SIZE(size) BT_BUF_SIZE(BT_HCI_ACL_HDR_SIZE + (size))
|
||||
|
||||
/** Helper to calculate needed buffer size for HCI ISO packets. */
|
||||
#define BT_BUF_ISO_SIZE(size) BT_BUF_SIZE(BT_HCI_ISO_HDR_SIZE + \
|
||||
BT_HCI_ISO_SDU_TS_HDR_SIZE + \
|
||||
(size))
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* ZEPHYR_INCLUDE_BLUETOOTH_BUF_H_ */
|
||||
@@ -0,0 +1,189 @@
|
||||
/** @file
|
||||
* @brief Bluetooth byteorder API
|
||||
*/
|
||||
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef ZEPHYR_INCLUDE_BLUETOOTH_BYTEORDER_H_
|
||||
#define ZEPHYR_INCLUDE_BLUETOOTH_BYTEORDER_H_
|
||||
|
||||
/**
|
||||
* @brief Byteorder
|
||||
* @defgroup bt_byteorder Byteorder
|
||||
* @ingroup bluetooth
|
||||
* @{
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** @brief Encode 16-bit value into array values in little-endian format.
|
||||
*
|
||||
* Helper macro to encode 16-bit values into comma separated values.
|
||||
*
|
||||
* @note @p _v is evaluated 2 times.
|
||||
*
|
||||
* @param _v 16-bit integer in host endianness.
|
||||
*
|
||||
* @return The comma separated values for the 16-bit value.
|
||||
*/
|
||||
#define BT_BYTES_LIST_LE16(_v) \
|
||||
(((_v) >> 0) & 0xFFU), \
|
||||
(((_v) >> 8) & 0xFFU) \
|
||||
|
||||
/** @brief Encode 24-bit value into array values in little-endian format.
|
||||
*
|
||||
* Helper macro to encode 24-bit values into comma separated values.
|
||||
*
|
||||
* @note @p _v is evaluated 3 times.
|
||||
*
|
||||
* @param _v 24-bit integer in host endianness.
|
||||
*
|
||||
* @return The comma separated values for the 24-bit value.
|
||||
*/
|
||||
#define BT_BYTES_LIST_LE24(_v) \
|
||||
BT_BYTES_LIST_LE16(_v), \
|
||||
(((_v) >> 16) & 0xFFU) \
|
||||
|
||||
/** @brief Encode 32-bit value into array values in little-endian format.
|
||||
*
|
||||
* Helper macro to encode 32-bit values into comma separated values.
|
||||
*
|
||||
* @note @p _v is evaluated 4 times.
|
||||
*
|
||||
* @param _v 32-bit integer in host endianness.
|
||||
*
|
||||
* @return The comma separated values for the 32-bit value.
|
||||
*/
|
||||
#define BT_BYTES_LIST_LE32(_v) \
|
||||
BT_BYTES_LIST_LE24(_v), \
|
||||
(((_v) >> 24) & 0xFFU) \
|
||||
|
||||
/** @brief Encode 40-bit value into array values in little-endian format.
|
||||
*
|
||||
* Helper macro to encode 40-bit values into comma separated values.
|
||||
*
|
||||
* @note @p _v is evaluated 5 times.
|
||||
*
|
||||
* @param _v 40-bit integer in host endianness.
|
||||
*
|
||||
* @return The comma separated values for the 40-bit value.
|
||||
*/
|
||||
#define BT_BYTES_LIST_LE40(_v) \
|
||||
BT_BYTES_LIST_LE24(_v), \
|
||||
BT_BYTES_LIST_LE16((_v) >> 24) \
|
||||
|
||||
/** @brief Encode 48-bit value into array values in little-endian format.
|
||||
*
|
||||
* Helper macro to encode 48-bit values into comma separated values.
|
||||
*
|
||||
* @note @p _v is evaluated 6 times.
|
||||
*
|
||||
* @param _v 48-bit integer in host endianness.
|
||||
*
|
||||
* @return The comma separated values for the 48-bit value.
|
||||
*/
|
||||
#define BT_BYTES_LIST_LE48(_v) \
|
||||
BT_BYTES_LIST_LE32(_v), \
|
||||
BT_BYTES_LIST_LE16((_v) >> 32) \
|
||||
|
||||
/** @brief Encode 64-bit value into array values in little-endian format.
|
||||
*
|
||||
* Helper macro to encode 64-bit values into comma separated values.
|
||||
*
|
||||
* @note @p _v is evaluated 8 times.
|
||||
*
|
||||
* @param _v 64-bit integer in host endianness.
|
||||
*
|
||||
* @return The comma separated values for the 64-bit value.
|
||||
*/
|
||||
#define BT_BYTES_LIST_LE64(_v) \
|
||||
BT_BYTES_LIST_LE32(_v), \
|
||||
BT_BYTES_LIST_LE32((_v) >> 32) \
|
||||
|
||||
/** @brief Encode 16-bit value into array values in big-endian format.
|
||||
*
|
||||
* Helper macro to encode 16-bit values into comma separated values.
|
||||
*
|
||||
* @note @p _v is evaluated 2 times.
|
||||
*
|
||||
* @param _v 16-bit integer in host endianness.
|
||||
*
|
||||
* @return The comma separated values for the 16-bit value.
|
||||
*/
|
||||
#define BT_BYTES_LIST_BE16(_v) (((_v) >> 8) & 0xFFU), (((_v) >> 0) & 0xFFU)
|
||||
|
||||
/** @brief Encode 24-bit value into array values in big-endian format.
|
||||
*
|
||||
* Helper macro to encode 24-bit values into comma separated values.
|
||||
*
|
||||
* @note @p _v is evaluated 3 times.
|
||||
*
|
||||
* @param _v 24-bit integer in host endianness.
|
||||
*
|
||||
* @return The comma separated values for the 24-bit value.
|
||||
*/
|
||||
#define BT_BYTES_LIST_BE24(_v) (((_v) >> 16) & 0xFFU), BT_BYTES_LIST_BE16(_v)
|
||||
|
||||
/** @brief Encode 32-bit value into array values in big-endian format.
|
||||
*
|
||||
* Helper macro to encode 32-bit values into comma separated values.
|
||||
*
|
||||
* @note @p _v is evaluated 4 times.
|
||||
*
|
||||
* @param _v 32-bit integer in host endianness.
|
||||
*
|
||||
* @return The comma separated values for the 32-bit value.
|
||||
*/
|
||||
#define BT_BYTES_LIST_BE32(_v) (((_v) >> 24) & 0xFFU), BT_BYTES_LIST_BE24(_v)
|
||||
|
||||
/** @brief Encode 40-bit value into array values in big-endian format.
|
||||
*
|
||||
* Helper macro to encode 40-bit values into comma separated values.
|
||||
*
|
||||
* @note @p _v is evaluated 5 times.
|
||||
*
|
||||
* @param _v 40-bit integer in host endianness.
|
||||
*
|
||||
* @return The comma separated values for the 40-bit value.
|
||||
*/
|
||||
#define BT_BYTES_LIST_BE40(_v) BT_BYTES_LIST_BE16((_v) >> 24), BT_BYTES_LIST_BE24(_v)
|
||||
|
||||
/** @brief Encode 48-bit value into array values in big-endian format.
|
||||
*
|
||||
* Helper macro to encode 48-bit values into comma separated values.
|
||||
*
|
||||
* @note @p _v is evaluated 6 times.
|
||||
*
|
||||
* @param _v 48-bit integer in host endianness.
|
||||
*
|
||||
* @return The comma separated values for the 48-bit value.
|
||||
*/
|
||||
#define BT_BYTES_LIST_BE48(_v) BT_BYTES_LIST_BE16((_v) >> 32), BT_BYTES_LIST_BE32(_v)
|
||||
|
||||
/** @brief Encode 64-bit value into array values in big-endian format.
|
||||
*
|
||||
* Helper macro to encode 64-bit values into comma separated values.
|
||||
*
|
||||
* @note @p _v is evaluated 8 times.
|
||||
*
|
||||
* @param _v 64-bit integer in host endianness.
|
||||
*
|
||||
* @return The comma separated values for the 64-bit value.
|
||||
*/
|
||||
#define BT_BYTES_LIST_BE64(_v) BT_BYTES_LIST_BE32((_v) >> 32), BT_BYTES_LIST_BE32(_v)
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* ZEPHYR_INCLUDE_BLUETOOTH_BYTEORDER_H_ */
|
||||
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <zephyr/bluetooth/bluetooth.h>
|
||||
#include <zephyr/bluetooth/uuid.h>
|
||||
|
||||
/* NOTE: These helper functions always encodes into the same buffer storage.
|
||||
* It is the responsibility of the user of this function to copy the information
|
||||
* in this string if needed.
|
||||
*
|
||||
* NOTE: These functions are not thread-safe!
|
||||
*/
|
||||
const char *bt_hex(const void *buf, size_t len);
|
||||
const char *bt_addr_str(const bt_addr_t *addr);
|
||||
const char *bt_addr_le_str(const bt_addr_le_t *addr);
|
||||
const char *bt_uuid_str(const struct bt_uuid *uuid);
|
||||
@@ -0,0 +1,487 @@
|
||||
/** @file
|
||||
* @brief Bluetooth connection handling
|
||||
*/
|
||||
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2016 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#ifndef ZEPHYR_INCLUDE_BLUETOOTH_CONN_H_
|
||||
#define ZEPHYR_INCLUDE_BLUETOOTH_CONN_H_
|
||||
|
||||
/**
|
||||
* @brief Connection management
|
||||
* @defgroup bt_conn Connection management
|
||||
* @ingroup bluetooth
|
||||
* @{
|
||||
*/
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <zephyr/bluetooth/bluetooth.h>
|
||||
#include <zephyr/bluetooth/hci_types.h>
|
||||
#include <zephyr/bluetooth/addr.h>
|
||||
#include <zephyr/bluetooth/gap.h>
|
||||
#include <zephyr/sys/iterable_sections.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** Opaque type representing a connection to a remote device */
|
||||
struct bt_conn;
|
||||
|
||||
/** Connection Type */
|
||||
enum __packed bt_conn_type {
|
||||
/** No Connection Type (free slot marker) */
|
||||
BT_CONN_TYPE_NONE = 0,
|
||||
/** LE Connection Type */
|
||||
BT_CONN_TYPE_LE = BIT(0),
|
||||
/** ISO Connection Type */
|
||||
BT_CONN_TYPE_ISO = BIT(3),
|
||||
/** All Connection Type */
|
||||
BT_CONN_TYPE_ALL = BT_CONN_TYPE_LE | BT_CONN_TYPE_ISO,
|
||||
};
|
||||
|
||||
/** @brief Increment a connection's reference count.
|
||||
*
|
||||
* Increment the reference count of a connection object.
|
||||
*
|
||||
* @note Will return NULL if the reference count is zero.
|
||||
*
|
||||
* @param conn Connection object.
|
||||
*
|
||||
* @return Connection object with incremented reference count, or NULL if the
|
||||
* reference count is zero.
|
||||
*/
|
||||
struct bt_conn *bt_conn_ref(struct bt_conn *conn);
|
||||
|
||||
/** @brief Decrement a connection's reference count.
|
||||
*
|
||||
* Decrement the reference count of a connection object.
|
||||
*
|
||||
* @param conn Connection object.
|
||||
*/
|
||||
void bt_conn_unref(struct bt_conn *conn);
|
||||
|
||||
/** @brief Iterate through all bt_conn objects.
|
||||
*
|
||||
* Iterates through all bt_conn objects that are alive in the Host allocator.
|
||||
*
|
||||
* To find established connections, combine this with @ref bt_conn_get_info.
|
||||
* Check that @ref bt_conn_info.state is @ref BT_CONN_STATE_CONNECTED.
|
||||
*
|
||||
* Thread safety: This API is thread safe, but it does not guarantee a
|
||||
* sequentially-consistent view for objects allocated during the current
|
||||
* invocation of this API. E.g. If preempted while allocations A then B then C
|
||||
* happen then results may include A and C but miss B.
|
||||
*
|
||||
* @param type Connection Type
|
||||
* @param func Function to call for each connection.
|
||||
* @param data Data to pass to the callback function.
|
||||
*/
|
||||
void bt_conn_foreach(enum bt_conn_type type,
|
||||
void (*func)(struct bt_conn *conn, void *data),
|
||||
void *data);
|
||||
|
||||
/** @brief Get destination (peer) address of a connection.
|
||||
*
|
||||
* @param conn Connection object.
|
||||
*
|
||||
* @return Destination address if @p conn is a valid @ref BT_CONN_TYPE_LE connection
|
||||
*/
|
||||
const bt_addr_le_t *bt_conn_get_dst(const struct bt_conn *conn);
|
||||
|
||||
/** @brief Get array index of a connection
|
||||
*
|
||||
* This function is used to map bt_conn to index of an array of
|
||||
* connections. The array has CONFIG_BT_MAX_CONN elements.
|
||||
*
|
||||
* @param conn Connection object.
|
||||
*
|
||||
* @return Index of the connection object.
|
||||
* The range of the returned value is 0..CONFIG_BT_MAX_CONN-1
|
||||
*/
|
||||
uint8_t bt_conn_index(const struct bt_conn *conn);
|
||||
|
||||
/** LE Connection Info Structure */
|
||||
struct bt_conn_le_info {
|
||||
/** Destination (Remote) Identity Address or remote Resolvable Private
|
||||
* Address (RPA) before identity has been resolved.
|
||||
*/
|
||||
const bt_addr_le_t *dst;
|
||||
uint16_t interval; /**< Connection interval */
|
||||
};
|
||||
|
||||
/** @brief Convert connection interval to milliseconds
|
||||
*
|
||||
* Multiply by 1.25 to get milliseconds.
|
||||
*
|
||||
* Note that this may be inaccurate, as something like 7.5 ms cannot be
|
||||
* accurately presented with integers.
|
||||
*/
|
||||
#define BT_CONN_INTERVAL_TO_MS(interval) ((interval) * 5U / 4U)
|
||||
|
||||
/** @brief Convert connection interval to microseconds
|
||||
*
|
||||
* Multiply by 1250 to get microseconds.
|
||||
*/
|
||||
#define BT_CONN_INTERVAL_TO_US(interval) ((interval) * 1250U)
|
||||
|
||||
enum {
|
||||
BT_CONN_ROLE_CENTRAL = 0,
|
||||
BT_CONN_ROLE_PERIPHERAL = 1,
|
||||
};
|
||||
|
||||
enum bt_conn_state {
|
||||
/** Channel disconnected */
|
||||
BT_CONN_STATE_DISCONNECTED,
|
||||
/** Channel in connecting state */
|
||||
BT_CONN_STATE_CONNECTING,
|
||||
/** Channel connected and ready for upper layer traffic on it */
|
||||
BT_CONN_STATE_CONNECTED,
|
||||
/** Channel in disconnecting state */
|
||||
BT_CONN_STATE_DISCONNECTING,
|
||||
};
|
||||
|
||||
/** Security level. */
|
||||
typedef enum __packed {
|
||||
/** Level 0: Only for BR/EDR special cases, like SDP */
|
||||
BT_SECURITY_L0,
|
||||
/** Level 1: No encryption and no authentication. */
|
||||
BT_SECURITY_L1,
|
||||
/** Level 2: Encryption and no authentication (no MITM). */
|
||||
BT_SECURITY_L2,
|
||||
/** Level 3: Encryption and authentication (MITM). */
|
||||
BT_SECURITY_L3,
|
||||
/** Level 4: Authenticated Secure Connections and 128-bit key. */
|
||||
BT_SECURITY_L4,
|
||||
/** Bit to force new pairing procedure, bit-wise OR with requested
|
||||
* security level.
|
||||
*/
|
||||
BT_SECURITY_FORCE_PAIR = BIT(7),
|
||||
} bt_security_t;
|
||||
|
||||
/** Security Info Flags. */
|
||||
enum bt_security_flag {
|
||||
/** Paired with Secure Connections. */
|
||||
BT_SECURITY_FLAG_SC = BIT(0),
|
||||
/** Paired with Out of Band method. */
|
||||
BT_SECURITY_FLAG_OOB = BIT(1),
|
||||
};
|
||||
|
||||
/** Security Info Structure. */
|
||||
struct bt_security_info {
|
||||
/** Security Level. */
|
||||
bt_security_t level;
|
||||
/** Encryption Key Size. */
|
||||
uint8_t enc_key_size;
|
||||
/** Flags. */
|
||||
enum bt_security_flag flags;
|
||||
};
|
||||
|
||||
/** Connection Info Structure */
|
||||
struct bt_conn_info {
|
||||
/** Connection Type. */
|
||||
enum bt_conn_type type;
|
||||
/** Connection Role. */
|
||||
uint8_t role;
|
||||
/** Which local identity the connection was created with */
|
||||
uint8_t id;
|
||||
/** LE Connection specific Info. */
|
||||
struct bt_conn_le_info le;
|
||||
/** Connection state. */
|
||||
enum bt_conn_state state;
|
||||
/** Security specific info. */
|
||||
struct bt_security_info security;
|
||||
};
|
||||
|
||||
/** @brief Get connection info
|
||||
*
|
||||
* @param conn Connection object.
|
||||
* @param info Connection info object.
|
||||
*
|
||||
* @return Zero on success or (negative) error code on failure.
|
||||
*/
|
||||
int bt_conn_get_info(const struct bt_conn *conn, struct bt_conn_info *info);
|
||||
|
||||
/** @brief Disconnect from a remote device or cancel pending connection.
|
||||
*
|
||||
* Disconnect an active connection with the specified reason code or cancel
|
||||
* pending outgoing connection.
|
||||
*
|
||||
* The disconnect reason for a normal disconnect should be:
|
||||
* @ref BT_HCI_ERR_REMOTE_USER_TERM_CONN.
|
||||
*
|
||||
* The following disconnect reasons are accepted:
|
||||
* - @ref BT_HCI_ERR_AUTH_FAIL
|
||||
* - @ref BT_HCI_ERR_REMOTE_USER_TERM_CONN
|
||||
* - @ref BT_HCI_ERR_REMOTE_LOW_RESOURCES
|
||||
* - @ref BT_HCI_ERR_REMOTE_POWER_OFF
|
||||
* - @ref BT_HCI_ERR_UNSUPP_REMOTE_FEATURE
|
||||
* - @ref BT_HCI_ERR_PAIRING_NOT_SUPPORTED
|
||||
* - @ref BT_HCI_ERR_UNACCEPT_CONN_PARAM
|
||||
*
|
||||
* @param conn Connection to disconnect.
|
||||
* @param reason Reason code for the disconnection.
|
||||
*
|
||||
* @return Zero on success or (negative) error code on failure.
|
||||
*/
|
||||
int bt_conn_disconnect(struct bt_conn *conn, uint8_t reason);
|
||||
|
||||
/** @brief Set security level for a connection.
|
||||
*
|
||||
* This function enable security (encryption) for a connection. If the device
|
||||
* has bond information for the peer with sufficiently strong key encryption
|
||||
* will be enabled. If the connection is already encrypted with sufficiently
|
||||
* strong key this function does nothing.
|
||||
*
|
||||
* If the device has no bond information for the peer and is not already paired
|
||||
* then the pairing procedure will be initiated. Note that @p sec has no effect
|
||||
* on the security level selected for the pairing process. The selection is
|
||||
* instead controlled by the values of the registered @ref bt_conn_auth_cb. If
|
||||
* the device has bond information or is already paired and the keys are too
|
||||
* weak then the pairing procedure will be initiated.
|
||||
*
|
||||
* This function may return an error if the required level of security defined using
|
||||
* @p sec is not possible to achieve due to local or remote device limitation
|
||||
* (e.g., input output capabilities), or if the maximum number of paired devices
|
||||
* has been reached.
|
||||
*
|
||||
* This function may return an error if the pairing procedure has already been
|
||||
* initiated by the local device or the peer device.
|
||||
*
|
||||
* @note When @kconfig{CONFIG_BT_SMP_SC_ONLY} is enabled then the security
|
||||
* level will always be level 4.
|
||||
*
|
||||
* @note When @kconfig{CONFIG_BT_SMP_OOB_LEGACY_PAIR_ONLY} is enabled then the
|
||||
* security level will always be level 3.
|
||||
*
|
||||
* @note When @ref BT_SECURITY_FORCE_PAIR within @p sec is enabled then the pairing
|
||||
* procedure will always be initiated.
|
||||
*
|
||||
* @param conn Connection object.
|
||||
* @param sec Requested minimum security level.
|
||||
*
|
||||
* @return 0 on success or negative error
|
||||
*/
|
||||
int bt_conn_set_security(struct bt_conn *conn, bt_security_t sec);
|
||||
|
||||
enum bt_security_err {
|
||||
/** Security procedure successful. */
|
||||
BT_SECURITY_ERR_SUCCESS,
|
||||
|
||||
/** Authentication failed. */
|
||||
BT_SECURITY_ERR_AUTH_FAIL,
|
||||
|
||||
/** PIN or encryption key is missing. */
|
||||
BT_SECURITY_ERR_PIN_OR_KEY_MISSING,
|
||||
|
||||
/** OOB data is not available. */
|
||||
BT_SECURITY_ERR_OOB_NOT_AVAILABLE,
|
||||
|
||||
/** The requested security level could not be reached. */
|
||||
BT_SECURITY_ERR_AUTH_REQUIREMENT,
|
||||
|
||||
/** Pairing is not supported */
|
||||
BT_SECURITY_ERR_PAIR_NOT_SUPPORTED,
|
||||
|
||||
/** Pairing is not allowed. */
|
||||
BT_SECURITY_ERR_PAIR_NOT_ALLOWED,
|
||||
|
||||
/** Invalid parameters. */
|
||||
BT_SECURITY_ERR_INVALID_PARAM,
|
||||
|
||||
/** Distributed Key Rejected */
|
||||
BT_SECURITY_ERR_KEY_REJECTED,
|
||||
|
||||
/** Pairing failed but the exact reason could not be specified. */
|
||||
BT_SECURITY_ERR_UNSPECIFIED,
|
||||
};
|
||||
|
||||
/** @brief Connection callback structure.
|
||||
*
|
||||
* This structure is used for tracking the state of a connection.
|
||||
* It is registered with the help of the bt_conn_cb_register() API.
|
||||
* It's permissible to register multiple instances of this @ref bt_conn_cb
|
||||
* type, in case different modules of an application are interested in
|
||||
* tracking the connection state. If a callback is not of interest for
|
||||
* an instance, it may be set to NULL and will as a consequence not be
|
||||
* used for that instance.
|
||||
*/
|
||||
struct bt_conn_cb {
|
||||
/** @brief A new connection has been established.
|
||||
*
|
||||
* This callback notifies the application of a new connection.
|
||||
* In case the err parameter is non-zero it means that the
|
||||
* connection establishment failed.
|
||||
*
|
||||
* @note If the connection was established from an advertising set then
|
||||
* the advertising set cannot be restarted directly from this
|
||||
* callback. Instead use the connected callback of the
|
||||
* advertising set.
|
||||
*
|
||||
* @param conn New connection object.
|
||||
* @param err HCI error. Zero for success, non-zero otherwise.
|
||||
*
|
||||
* @p err can mean either of the following:
|
||||
* - @ref BT_HCI_ERR_UNKNOWN_CONN_ID Creating the connection started by
|
||||
* @ref bt_conn_le_create was canceled either by the user through
|
||||
* @ref bt_conn_disconnect or by the timeout in the host through
|
||||
* @ref bt_conn_le_create_param timeout parameter, which defaults to
|
||||
* @kconfig{CONFIG_BT_CREATE_CONN_TIMEOUT} seconds.
|
||||
* - @p BT_HCI_ERR_ADV_TIMEOUT High duty cycle directed connectable
|
||||
* advertiser started by @ref bt_le_adv_start failed to be connected
|
||||
* within the timeout.
|
||||
*/
|
||||
void (*connected)(struct bt_conn *conn, uint8_t err);
|
||||
|
||||
/** @brief A connection has been disconnected.
|
||||
*
|
||||
* This callback notifies the application that a connection
|
||||
* has been disconnected.
|
||||
*
|
||||
* When this callback is called the stack still has one reference to
|
||||
* the connection object. If the application in this callback tries to
|
||||
* start either a connectable advertiser or create a new connection
|
||||
* this might fail because there are no free connection objects
|
||||
* available.
|
||||
* To avoid this issue it is recommended to either start connectable
|
||||
* advertise or create a new connection using @ref k_work_submit or
|
||||
* increase @kconfig{CONFIG_BT_MAX_CONN}.
|
||||
*
|
||||
* @param conn Connection object.
|
||||
* @param reason BT_HCI_ERR_* reason for the disconnection.
|
||||
*/
|
||||
void (*disconnected)(struct bt_conn *conn, uint8_t reason);
|
||||
|
||||
/** @brief Remote Identity Address has been resolved.
|
||||
*
|
||||
* This callback notifies the application that a remote
|
||||
* Identity Address has been resolved
|
||||
*
|
||||
* @param conn Connection object.
|
||||
* @param rpa Resolvable Private Address.
|
||||
* @param identity Identity Address.
|
||||
*/
|
||||
void (*identity_resolved)(struct bt_conn *conn,
|
||||
const bt_addr_le_t *rpa,
|
||||
const bt_addr_le_t *identity);
|
||||
|
||||
/** @brief The security level of a connection has changed.
|
||||
*
|
||||
* This callback notifies the application that the security of a
|
||||
* connection has changed.
|
||||
*
|
||||
* The security level of the connection can either have been increased
|
||||
* or remain unchanged. An increased security level means that the
|
||||
* pairing procedure has been performed or the bond information from
|
||||
* a previous connection has been applied. If the security level
|
||||
* remains unchanged this means that the encryption key has been
|
||||
* refreshed for the connection.
|
||||
*
|
||||
* @param conn Connection object.
|
||||
* @param level New security level of the connection.
|
||||
* @param err Security error. Zero for success, non-zero otherwise.
|
||||
*/
|
||||
void (*security_changed)(struct bt_conn *conn, bt_security_t level,
|
||||
enum bt_security_err err);
|
||||
|
||||
/** @internal Internally used field for list handling */
|
||||
sys_snode_t _node;
|
||||
};
|
||||
|
||||
/** @brief Register connection callbacks.
|
||||
*
|
||||
* Register callbacks to monitor the state of connections.
|
||||
*
|
||||
* @param cb Callback struct. Must point to memory that remains valid.
|
||||
*
|
||||
* @retval 0 Success.
|
||||
* @retval -EEXIST if @p cb was already registered.
|
||||
*/
|
||||
int bt_conn_cb_register(struct bt_conn_cb *cb);
|
||||
int bt_conn_cb_register_safe(struct bt_conn_cb *cb);
|
||||
|
||||
/**
|
||||
* @brief Unregister connection callbacks.
|
||||
*
|
||||
* Unregister the state of connections callbacks.
|
||||
*
|
||||
* @param cb Callback struct point to memory that remains valid.
|
||||
*
|
||||
* @retval 0 Success
|
||||
* @retval -EINVAL If @p cb is NULL
|
||||
* @retval -ENOENT if @p cb was not registered
|
||||
*/
|
||||
int bt_conn_cb_unregister(struct bt_conn_cb *cb);
|
||||
|
||||
/**
|
||||
* @brief Register a callback structure for connection events.
|
||||
*
|
||||
* @param _name Name of callback structure.
|
||||
*/
|
||||
#define BT_CONN_CB_DEFINE(_name) \
|
||||
static STRUCT_SECTION_ITERABLE(bt_conn_cb, \
|
||||
_CONCAT(bt_conn_cb_, \
|
||||
_name))
|
||||
|
||||
/** Authenticated pairing information callback structure */
|
||||
struct bt_conn_auth_info_cb {
|
||||
/** @brief notify that pairing procedure was complete.
|
||||
*
|
||||
* This callback notifies the application that the pairing procedure
|
||||
* has been completed.
|
||||
*
|
||||
* @param conn Connection object.
|
||||
* @param bonded Bond information has been distributed during the
|
||||
* pairing procedure.
|
||||
*/
|
||||
void (*pairing_complete)(struct bt_conn *conn, bool bonded);
|
||||
|
||||
/** @brief Notify that bond has been deleted.
|
||||
*
|
||||
* This callback notifies the application that the bond information
|
||||
* for the remote peer has been deleted
|
||||
*
|
||||
* @param id Which local identity had the bond.
|
||||
* @param peer Remote address.
|
||||
*/
|
||||
void (*bond_deleted)(uint8_t id, const bt_addr_le_t *peer);
|
||||
|
||||
/** Internally used field for list handling */
|
||||
sys_snode_t node;
|
||||
};
|
||||
|
||||
/** @brief Register authentication information callbacks.
|
||||
*
|
||||
* Register callbacks to get authenticated pairing information. Multiple
|
||||
* registrations can be done.
|
||||
*
|
||||
* @param cb Callback struct.
|
||||
*
|
||||
* @return Zero on success or negative error code otherwise
|
||||
*/
|
||||
int bt_conn_auth_info_cb_register(struct bt_conn_auth_info_cb *cb);
|
||||
|
||||
/** @brief Unregister authentication information callbacks.
|
||||
*
|
||||
* Unregister callbacks to stop getting authenticated pairing information.
|
||||
*
|
||||
* @param cb Callback struct.
|
||||
*
|
||||
* @return Zero on success or negative error code otherwise
|
||||
*/
|
||||
int bt_conn_auth_info_cb_unregister(struct bt_conn_auth_info_cb *cb);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
#endif /* ZEPHYR_INCLUDE_BLUETOOTH_CONN_H_ */
|
||||
@@ -0,0 +1,65 @@
|
||||
/** @file
|
||||
* @brief Bluetooth subsystem crypto APIs.
|
||||
*/
|
||||
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2017-2020 Nordic Semiconductor ASA
|
||||
* SPDX-FileCopyrightText: 2015-2017 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef ZEPHYR_INCLUDE_BLUETOOTH_CRYPTO_H_
|
||||
#define ZEPHYR_INCLUDE_BLUETOOTH_CRYPTO_H_
|
||||
|
||||
/**
|
||||
* @brief Cryptography
|
||||
* @defgroup bt_crypto Cryptography
|
||||
* @ingroup bluetooth
|
||||
* @{
|
||||
*/
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** @brief Generate random data.
|
||||
*
|
||||
* A random number generation helper which utilizes the Bluetooth
|
||||
* controller's own RNG.
|
||||
*
|
||||
* @param buf Buffer to insert the random data
|
||||
* @param len Length of random data to generate
|
||||
*
|
||||
* @return Zero on success or error code otherwise, positive in case
|
||||
* of protocol error or negative (POSIX) in case of stack internal error
|
||||
*/
|
||||
int bt_rand(void *buf, size_t len);
|
||||
|
||||
/** @brief AES encrypt little-endian data.
|
||||
*
|
||||
* An AES encrypt helper is used to request the Bluetooth controller's own
|
||||
* hardware to encrypt the plaintext using the key and returns the encrypted
|
||||
* data.
|
||||
*
|
||||
* @param key 128 bit LS byte first key for the encryption of the plaintext
|
||||
* @param plaintext 128 bit LS byte first plaintext data block to be encrypted
|
||||
* @param enc_data 128 bit LS byte first encrypted data block
|
||||
*
|
||||
* @return Zero on success or error code otherwise.
|
||||
*/
|
||||
int bt_encrypt_le(const uint8_t key[16], const uint8_t plaintext[16],
|
||||
uint8_t enc_data[16]);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
#endif /* ZEPHYR_INCLUDE_BLUETOOTH_CRYPTO_H_ */
|
||||
@@ -0,0 +1,152 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef __BT_CRYPTO_H
|
||||
#define __BT_CRYPTO_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <zephyr/bluetooth/bluetooth.h>
|
||||
|
||||
/**
|
||||
* @brief Cypher based Message Authentication Code (CMAC) with AES 128 bit
|
||||
*
|
||||
* Defined in Core Vol. 3, part H 2.2.5.
|
||||
*
|
||||
* @param[in] key 128-bit key
|
||||
* @param[in] in message to be authenticated
|
||||
* @param[in] len length of the message in octets
|
||||
* @param[out] out message authentication code
|
||||
*
|
||||
* @retval 0 Computation was successful. @p res contains the result.
|
||||
* @retval -EIO Computation failed.
|
||||
*/
|
||||
int bt_crypto_aes_cmac(const uint8_t *key, const uint8_t *in, size_t len, uint8_t *out);
|
||||
|
||||
/**
|
||||
* @brief Cryptographic Toolbox f4
|
||||
*
|
||||
* Defined in Core Vol. 3, part H 2.2.6.
|
||||
*
|
||||
* @param[in] u 256-bit
|
||||
* @param[in] v 256-bit
|
||||
* @param[in] x 128-bit key
|
||||
* @param[in] z 8-bit
|
||||
* @param[out] res
|
||||
*
|
||||
* @retval 0 Computation was successful. @p res contains the result.
|
||||
* @retval -EIO Computation failed.
|
||||
*/
|
||||
int bt_crypto_f4(const uint8_t *u, const uint8_t *v, const uint8_t *x, uint8_t z, uint8_t res[16]);
|
||||
|
||||
/**
|
||||
* @brief Cryptographic Toolbox f5
|
||||
*
|
||||
* Defined in Core Vol. 3, part H 2.2.7.
|
||||
*
|
||||
* @param[in] w 256-bit
|
||||
* @param[in] n1 128-bit
|
||||
* @param[in] n2 128-bit
|
||||
* @param[in] a1 56-bit
|
||||
* @param[in] a2 56-bit
|
||||
* @param[out] mackey most significant 128-bit of the result
|
||||
* @param[out] ltk least significant 128-bit of the result
|
||||
*
|
||||
* @retval 0 Computation was successful. @p res contains the result.
|
||||
* @retval -EIO Computation failed.
|
||||
*/
|
||||
int bt_crypto_f5(const uint8_t *w, const uint8_t *n1, const uint8_t *n2, const bt_addr_le_t *a1,
|
||||
const bt_addr_le_t *a2, uint8_t *mackey, uint8_t *ltk);
|
||||
|
||||
/**
|
||||
* @brief Cryptographic Toolbox f6
|
||||
*
|
||||
* Defined in Core Vol. 3, part H 2.2.8.
|
||||
*
|
||||
* @param[in] w 128-bit
|
||||
* @param[in] n1 128-bit
|
||||
* @param[in] n2 128-bit
|
||||
* @param[in] r 128-bit
|
||||
* @param[in] iocap 24-bit
|
||||
* @param[in] a1 56-bit
|
||||
* @param[in] a2 56-bit
|
||||
* @param[out] check
|
||||
*
|
||||
* @retval 0 Computation was successful. @p res contains the result.
|
||||
* @retval -EIO Computation failed.
|
||||
*/
|
||||
int bt_crypto_f6(const uint8_t *w, const uint8_t *n1, const uint8_t *n2, const uint8_t *r,
|
||||
const uint8_t *iocap, const bt_addr_le_t *a1, const bt_addr_le_t *a2,
|
||||
uint8_t *check);
|
||||
|
||||
/**
|
||||
* @brief Cryptographic Toolbox g2
|
||||
|
||||
* Defined in Core Vol. 3, part H 2.2.9.
|
||||
*
|
||||
* @param[in] u 256-bit
|
||||
* @param[in] v 256-bit
|
||||
* @param[in] x 128-bit
|
||||
* @param[in] y 128-bit
|
||||
* @param[out] passkey
|
||||
*
|
||||
* @retval 0 Computation was successful. @p res contains the result.
|
||||
* @retval -EIO Computation failed.
|
||||
*/
|
||||
int bt_crypto_g2(const uint8_t u[32], const uint8_t v[32], const uint8_t x[16], const uint8_t y[16],
|
||||
uint32_t *passkey);
|
||||
|
||||
/**
|
||||
* @brief Cryptographic Toolbox h6
|
||||
*
|
||||
* Link key conversion defined in Core Vol. 3, part H 2.2.10.
|
||||
*
|
||||
* @param[in] w 128-bit key
|
||||
* @param[in] key_id 32-bit
|
||||
* @param[out] res 128-bit
|
||||
*
|
||||
* @retval 0 Computation was successful. @p res contains the result.
|
||||
* @retval -EIO Computation failed.
|
||||
*/
|
||||
int bt_crypto_h6(const uint8_t w[16], const uint8_t key_id[4], uint8_t res[16]);
|
||||
|
||||
/**
|
||||
* @brief Cryptographic Toolbox h7
|
||||
*
|
||||
* Link key conversion defined in Core Vol. 3, part H 2.2.11.
|
||||
*
|
||||
* @param[in] salt 128-bit key
|
||||
* @param[in] w 128-bit input of the AES-CMAC function
|
||||
* @param[out] res 128-bit
|
||||
*
|
||||
* @retval 0 Computation was successful. @p res contains the result.
|
||||
* @retval -EIO Computation failed.
|
||||
*/
|
||||
int bt_crypto_h7(const uint8_t salt[16], const uint8_t w[16], uint8_t res[16]);
|
||||
|
||||
/**
|
||||
* @brief Cryptographic Toolbox function h8
|
||||
*
|
||||
* Defined in Core Vol. 6, part E 1.1.1.
|
||||
*
|
||||
* @note This function is purely a shorthand for the calculation. The parameters
|
||||
* are therefore intentionally not assigned meaning.
|
||||
*
|
||||
* Pseudocode: `aes_cmac(key=aes_cmac(key=s, plaintext=k), plaintext=key_id)`
|
||||
*
|
||||
* @param[in] k (128-bit number in big endian)
|
||||
* @param[in] s (128-bit number in big endian)
|
||||
* @param[in] key_id (32-bit number in big endian)
|
||||
* @param[out] res (128-bit number in big endian)
|
||||
*
|
||||
* @retval 0 Computation was successful. @p res contains the result.
|
||||
* @retval -EIO Computation failed.
|
||||
*/
|
||||
int bt_crypto_h8(const uint8_t k[16], const uint8_t s[16], const uint8_t key_id[4],
|
||||
uint8_t res[16]);
|
||||
|
||||
#endif /* __BT_CRYPTO_H */
|
||||
@@ -0,0 +1,351 @@
|
||||
/** @file
|
||||
* @brief Bluetooth Generic Access Profile defines and Assigned Numbers.
|
||||
*/
|
||||
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2019 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef ZEPHYR_INCLUDE_BLUETOOTH_GAP_H_
|
||||
#define ZEPHYR_INCLUDE_BLUETOOTH_GAP_H_
|
||||
|
||||
#include <zephyr/bluetooth/assigned_numbers.h>
|
||||
#include <zephyr/bluetooth/byteorder.h>
|
||||
#include <zephyr/sys/util_macro.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Bluetooth Generic Access Profile defines and Assigned Numbers.
|
||||
* @defgroup bt_gap_defines Defines and Assigned Numbers
|
||||
* @ingroup bt_gap
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @name Company Identifiers (see Bluetooth Assigned Numbers)
|
||||
* @{
|
||||
*/
|
||||
#define BT_COMP_ID_LF 0x05f1 /**< The Linux Foundation */
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @name Defined GAP timers
|
||||
* @{
|
||||
*/
|
||||
#define BT_GAP_SCAN_FAST_INTERVAL_MIN 0x0030 /* 30 ms */
|
||||
#define BT_GAP_SCAN_FAST_INTERVAL 0x0060 /* 60 ms */
|
||||
#define BT_GAP_SCAN_FAST_WINDOW 0x0030 /* 30 ms */
|
||||
#define BT_GAP_SCAN_SLOW_INTERVAL_1 0x0800 /* 1.28 s */
|
||||
#define BT_GAP_SCAN_SLOW_WINDOW_1 0x0012 /* 11.25 ms */
|
||||
#define BT_GAP_SCAN_SLOW_INTERVAL_2 0x1000 /* 2.56 s */
|
||||
#define BT_GAP_SCAN_SLOW_WINDOW_2 0x0012 /* 11.25 ms */
|
||||
#define BT_GAP_ADV_FAST_INT_MIN_1 0x0030 /* 30 ms */
|
||||
#define BT_GAP_ADV_FAST_INT_MAX_1 0x0060 /* 60 ms */
|
||||
#define BT_GAP_ADV_FAST_INT_MIN_2 0x00a0 /* 100 ms */
|
||||
#define BT_GAP_ADV_FAST_INT_MAX_2 0x00f0 /* 150 ms */
|
||||
#define BT_GAP_ADV_SLOW_INT_MIN 0x0640 /* 1 s */
|
||||
#define BT_GAP_ADV_SLOW_INT_MAX 0x0780 /* 1.2 s */
|
||||
#define BT_GAP_PER_ADV_FAST_INT_MIN_1 0x0018 /* 30 ms */
|
||||
#define BT_GAP_PER_ADV_FAST_INT_MAX_1 0x0030 /* 60 ms */
|
||||
#define BT_GAP_PER_ADV_FAST_INT_MIN_2 0x0050 /* 100 ms */
|
||||
#define BT_GAP_PER_ADV_FAST_INT_MAX_2 0x0078 /* 150 ms */
|
||||
#define BT_GAP_PER_ADV_SLOW_INT_MIN 0x0320 /* 1 s */
|
||||
#define BT_GAP_PER_ADV_SLOW_INT_MAX 0x03C0 /* 1.2 s */
|
||||
#define BT_GAP_INIT_CONN_INT_MIN 0x0018 /* 30 ms */
|
||||
#define BT_GAP_INIT_CONN_INT_MAX 0x0028 /* 50 ms */
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/** LE PHY types */
|
||||
enum bt_gap_le_phy {
|
||||
/** Convenience macro for when no PHY is set. */
|
||||
BT_GAP_LE_PHY_NONE = 0,
|
||||
/** LE 1M PHY */
|
||||
BT_GAP_LE_PHY_1M = BIT(0),
|
||||
/** LE 2M PHY */
|
||||
BT_GAP_LE_PHY_2M = BIT(1),
|
||||
/** LE Coded PHY, coding scheme not specified */
|
||||
BT_GAP_LE_PHY_CODED = BIT(2),
|
||||
/** LE Coded S=8 PHY. Only used for advertising reports
|
||||
* when Kconfig BT_EXT_ADV_CODING_SELECTION is enabled.
|
||||
*/
|
||||
BT_GAP_LE_PHY_CODED_S8 = BIT(3),
|
||||
/** LE Coded S=2 PHY. Only used for advertising reports
|
||||
* when Kconfig BT_EXT_ADV_CODING_SELECTION is enabled.
|
||||
*/
|
||||
BT_GAP_LE_PHY_CODED_S2 = BIT(4),
|
||||
};
|
||||
|
||||
/** Advertising PDU types */
|
||||
enum bt_gap_adv_type {
|
||||
/** Scannable and connectable advertising. */
|
||||
BT_GAP_ADV_TYPE_ADV_IND = 0x00,
|
||||
/** Directed connectable advertising. */
|
||||
BT_GAP_ADV_TYPE_ADV_DIRECT_IND = 0x01,
|
||||
/** Non-connectable and scannable advertising. */
|
||||
BT_GAP_ADV_TYPE_ADV_SCAN_IND = 0x02,
|
||||
/** Non-connectable and non-scannable advertising. */
|
||||
BT_GAP_ADV_TYPE_ADV_NONCONN_IND = 0x03,
|
||||
/** Additional advertising data requested by an active scanner. */
|
||||
BT_GAP_ADV_TYPE_SCAN_RSP = 0x04,
|
||||
/** Extended advertising, see advertising properties. */
|
||||
BT_GAP_ADV_TYPE_EXT_ADV = 0x05,
|
||||
};
|
||||
|
||||
/** Advertising PDU properties */
|
||||
enum bt_gap_adv_prop {
|
||||
/** Connectable advertising. */
|
||||
BT_GAP_ADV_PROP_CONNECTABLE = BIT(0),
|
||||
/** Scannable advertising. */
|
||||
BT_GAP_ADV_PROP_SCANNABLE = BIT(1),
|
||||
/** Directed advertising. */
|
||||
BT_GAP_ADV_PROP_DIRECTED = BIT(2),
|
||||
/** Additional advertising data requested by an active scanner. */
|
||||
BT_GAP_ADV_PROP_SCAN_RESPONSE = BIT(3),
|
||||
/** Extended advertising. */
|
||||
BT_GAP_ADV_PROP_EXT_ADV = BIT(4),
|
||||
};
|
||||
|
||||
/** Maximum advertising data length. */
|
||||
#define BT_GAP_ADV_MAX_ADV_DATA_LEN 31
|
||||
/** Maximum extended advertising data length.
|
||||
*
|
||||
* @note The maximum advertising data length that can be sent by an extended
|
||||
* advertiser is defined by the controller.
|
||||
*/
|
||||
#define BT_GAP_ADV_MAX_EXT_ADV_DATA_LEN 1650
|
||||
|
||||
#define BT_GAP_TX_POWER_INVALID 0x7f
|
||||
#define BT_GAP_RSSI_INVALID 0x7f
|
||||
#define BT_GAP_SID_INVALID 0xff
|
||||
#define BT_GAP_NO_TIMEOUT 0x0000
|
||||
|
||||
/* The maximum allowed high duty cycle directed advertising timeout, 1.28
|
||||
* seconds in 10 ms unit.
|
||||
*/
|
||||
#define BT_GAP_ADV_HIGH_DUTY_CYCLE_MAX_TIMEOUT 128
|
||||
|
||||
/** Default data length */
|
||||
#define BT_GAP_DATA_LEN_DEFAULT 0x001b /* 27 bytes */
|
||||
/** Maximum data length */
|
||||
#define BT_GAP_DATA_LEN_MAX 0x00fb /* 251 bytes */
|
||||
|
||||
/** Default data time */
|
||||
#define BT_GAP_DATA_TIME_DEFAULT 0x0148 /* 328 us */
|
||||
/** Maximum data time */
|
||||
#define BT_GAP_DATA_TIME_MAX 0x4290 /* 17040 us */
|
||||
|
||||
/** Minimum advertising set number */
|
||||
#define BT_GAP_SID_MIN 0x00
|
||||
/** Maximum advertising set number */
|
||||
#define BT_GAP_SID_MAX 0x0F
|
||||
/** Maximum number of consecutive periodic advertisement events that can be
|
||||
* skipped after a successful receive.
|
||||
*/
|
||||
#define BT_GAP_PER_ADV_MAX_SKIP 0x01F3
|
||||
/** Minimum Periodic Advertising Timeout (N * 10 ms) */
|
||||
#define BT_GAP_PER_ADV_MIN_TIMEOUT 0x000A /* 100 ms */
|
||||
/** Maximum Periodic Advertising Timeout (N * 10 ms) */
|
||||
#define BT_GAP_PER_ADV_MAX_TIMEOUT 0x4000 /* 163.84 s */
|
||||
/** Minimum Periodic Advertising Interval (N * 1.25 ms) */
|
||||
#define BT_GAP_PER_ADV_MIN_INTERVAL 0x0006 /* 7.5 ms */
|
||||
/** Maximum Periodic Advertising Interval (N * 1.25 ms) */
|
||||
#define BT_GAP_PER_ADV_MAX_INTERVAL 0xFFFF /* 81.91875 s */
|
||||
|
||||
/**
|
||||
* @brief Convert periodic advertising interval (N * 0.625 ms) to microseconds
|
||||
*
|
||||
* Value range of @p _interval is @ref BT_LE_ADV_INTERVAL_MIN to @ref BT_LE_ADV_INTERVAL_MAX
|
||||
*/
|
||||
#define BT_GAP_ADV_INTERVAL_TO_US(_interval) ((uint32_t)((_interval) * 625U))
|
||||
|
||||
/**
|
||||
* @brief Convert periodic advertising interval (N * 0.625 ms) to milliseconds
|
||||
*
|
||||
* Value range of @p _interval is @ref BT_LE_ADV_INTERVAL_MIN to @ref BT_LE_ADV_INTERVAL_MAX
|
||||
*
|
||||
* @note When intervals cannot be represented in milliseconds, this will round down.
|
||||
* For example BT_GAP_ADV_INTERVAL_TO_MS(0x0021) will become 20 ms instead of 20.625 ms
|
||||
*/
|
||||
#define BT_GAP_ADV_INTERVAL_TO_MS(_interval) (BT_GAP_ADV_INTERVAL_TO_US(_interval) / USEC_PER_MSEC)
|
||||
|
||||
/**
|
||||
* @brief Convert isochronous interval (N * 1.25 ms) to microseconds
|
||||
*
|
||||
* Value range of @p _interval is @ref BT_HCI_ISO_INTERVAL_MIN to @ref BT_HCI_ISO_INTERVAL_MAX
|
||||
*/
|
||||
#define BT_GAP_ISO_INTERVAL_TO_US(_interval) ((uint32_t)((_interval) * 1250U))
|
||||
|
||||
/**
|
||||
* @brief Convert isochronous interval (N * 1.25 ms) to milliseconds
|
||||
*
|
||||
* Value range of @p _interval is @ref BT_HCI_ISO_INTERVAL_MIN to @ref BT_HCI_ISO_INTERVAL_MAX
|
||||
*
|
||||
* @note When intervals cannot be represented in milliseconds, this will round down.
|
||||
* For example BT_GAP_ISO_INTERVAL_TO_MS(0x0005) will become 6 ms instead of 6.25 ms
|
||||
*/
|
||||
#define BT_GAP_ISO_INTERVAL_TO_MS(_interval) (BT_GAP_ISO_INTERVAL_TO_US(_interval) / USEC_PER_MSEC)
|
||||
|
||||
/** @brief Convert periodic advertising interval (N * 1.25 ms) to microseconds *
|
||||
*
|
||||
* Value range of @p _interval is @ref BT_HCI_LE_PER_ADV_INTERVAL_MIN to @ref
|
||||
* BT_HCI_LE_PER_ADV_INTERVAL_MAX
|
||||
*/
|
||||
#define BT_GAP_PER_ADV_INTERVAL_TO_US(_interval) ((uint32_t)((_interval) * 1250U))
|
||||
|
||||
/**
|
||||
* @brief Convert periodic advertising interval (N * 1.25 ms) to milliseconds
|
||||
*
|
||||
* @note When intervals cannot be represented in milliseconds, this will round down.
|
||||
* For example BT_GAP_PER_ADV_INTERVAL_TO_MS(0x0009) will become 11 ms instead of 11.25 ms
|
||||
*/
|
||||
#define BT_GAP_PER_ADV_INTERVAL_TO_MS(_interval) \
|
||||
(BT_GAP_PER_ADV_INTERVAL_TO_US(_interval) / 1000U)
|
||||
|
||||
/** @brief Peripheral sleep clock accuracy (SCA) in ppm (parts per million) */
|
||||
enum bt_gap_sca {
|
||||
BT_GAP_SCA_UNKNOWN = 0, /**< Unknown */
|
||||
BT_GAP_SCA_251_500 = 0, /**< 251 ppm to 500 ppm */
|
||||
BT_GAP_SCA_151_250 = 1, /**< 151 ppm to 250 ppm */
|
||||
BT_GAP_SCA_101_150 = 2, /**< 101 ppm to 150 ppm */
|
||||
BT_GAP_SCA_76_100 = 3, /**< 76 ppm to 100 ppm */
|
||||
BT_GAP_SCA_51_75 = 4, /**< 51 ppm to 75 ppm */
|
||||
BT_GAP_SCA_31_50 = 5, /**< 31 ppm to 50 ppm */
|
||||
BT_GAP_SCA_21_30 = 6, /**< 21 ppm to 30 ppm */
|
||||
BT_GAP_SCA_0_20 = 7, /**< 0 ppm to 20 ppm */
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Encode 40 least significant bits of 64-bit LE Supported Features into array values
|
||||
* in little-endian format.
|
||||
*
|
||||
* Helper macro to encode 40 least significant bits of 64-bit LE Supported Features value into
|
||||
* advertising data. The number of bits that are encoded is a number of LE Supported Features
|
||||
* defined by BT 5.3 Core specification.
|
||||
*
|
||||
* Example of how to encode the `0x000000DFF00DF00D` into advertising data.
|
||||
*
|
||||
* @code
|
||||
* BT_DATA_BYTES(BT_DATA_LE_SUPPORTED_FEATURES, BT_LE_SUPP_FEAT_40_ENCODE(0x000000DFF00DF00D))
|
||||
* @endcode
|
||||
*
|
||||
* @param w64 LE Supported Features value (64-bits)
|
||||
*
|
||||
* @return The comma separated values for LE Supported Features value that
|
||||
* may be used directly as an argument for @ref BT_DATA_BYTES.
|
||||
*/
|
||||
#define BT_LE_SUPP_FEAT_40_ENCODE(w64) BT_BYTES_LIST_LE40(w64)
|
||||
|
||||
/** @brief Encode 4 least significant bytes of 64-bit LE Supported Features into
|
||||
* 4 bytes long array of values in little-endian format.
|
||||
*
|
||||
* Helper macro to encode 64-bit LE Supported Features value into advertising
|
||||
* data. The macro encodes 4 least significant bytes into advertising data.
|
||||
* Other 4 bytes are not encoded.
|
||||
*
|
||||
* Example of how to encode the `0x000000DFF00DF00D` into advertising data.
|
||||
*
|
||||
* @code
|
||||
* BT_DATA_BYTES(BT_DATA_LE_SUPPORTED_FEATURES, BT_LE_SUPP_FEAT_32_ENCODE(0x000000DFF00DF00D))
|
||||
* @endcode
|
||||
*
|
||||
* @param w64 LE Supported Features value (64-bits)
|
||||
*
|
||||
* @return The comma separated values for LE Supported Features value that
|
||||
* may be used directly as an argument for @ref BT_DATA_BYTES.
|
||||
*/
|
||||
#define BT_LE_SUPP_FEAT_32_ENCODE(w64) BT_BYTES_LIST_LE32(w64)
|
||||
|
||||
/**
|
||||
* @brief Encode 3 least significant bytes of 64-bit LE Supported Features into
|
||||
* 3 bytes long array of values in little-endian format.
|
||||
*
|
||||
* Helper macro to encode 64-bit LE Supported Features value into advertising
|
||||
* data. The macro encodes 3 least significant bytes into advertising data.
|
||||
* Other 5 bytes are not encoded.
|
||||
*
|
||||
* Example of how to encode the `0x000000DFF00DF00D` into advertising data.
|
||||
*
|
||||
* @code
|
||||
* BT_DATA_BYTES(BT_DATA_LE_SUPPORTED_FEATURES, BT_LE_SUPP_FEAT_24_ENCODE(0x000000DFF00DF00D))
|
||||
* @endcode
|
||||
*
|
||||
* @param w64 LE Supported Features value (64-bits)
|
||||
*
|
||||
* @return The comma separated values for LE Supported Features value that
|
||||
* may be used directly as an argument for @ref BT_DATA_BYTES.
|
||||
*/
|
||||
#define BT_LE_SUPP_FEAT_24_ENCODE(w64) BT_BYTES_LIST_LE24(w64)
|
||||
|
||||
/**
|
||||
* @brief Encode 2 least significant bytes of 64-bit LE Supported Features into
|
||||
* 2 bytes long array of values in little-endian format.
|
||||
*
|
||||
* Helper macro to encode 64-bit LE Supported Features value into advertising
|
||||
* data. The macro encodes 3 least significant bytes into advertising data.
|
||||
* Other 6 bytes are not encoded.
|
||||
*
|
||||
* Example of how to encode the `0x000000DFF00DF00D` into advertising data.
|
||||
*
|
||||
* @code
|
||||
* BT_DATA_BYTES(BT_DATA_LE_SUPPORTED_FEATURES, BT_LE_SUPP_FEAT_16_ENCODE(0x000000DFF00DF00D))
|
||||
* @endcode
|
||||
*
|
||||
* @param w64 LE Supported Features value (64-bits)
|
||||
*
|
||||
* @return The comma separated values for LE Supported Features value that
|
||||
* may be used directly as an argument for @ref BT_DATA_BYTES.
|
||||
*/
|
||||
#define BT_LE_SUPP_FEAT_16_ENCODE(w64) BT_BYTES_LIST_LE16(w64)
|
||||
|
||||
/**
|
||||
* @brief Encode the least significant byte of 64-bit LE Supported Features into
|
||||
* single byte long array.
|
||||
*
|
||||
* Helper macro to encode 64-bit LE Supported Features value into advertising
|
||||
* data. The macro encodes the least significant byte into advertising data.
|
||||
* Other 7 bytes are not encoded.
|
||||
*
|
||||
* Example of how to encode the `0x000000DFF00DF00D` into advertising data.
|
||||
*
|
||||
* @code
|
||||
* BT_DATA_BYTES(BT_DATA_LE_SUPPORTED_FEATURES, BT_LE_SUPP_FEAT_8_ENCODE(0x000000DFF00DF00D))
|
||||
* @endcode
|
||||
*
|
||||
* @param w64 LE Supported Features value (64-bits)
|
||||
*
|
||||
* @return The value of least significant byte of LE Supported Features value
|
||||
* that may be used directly as an argument for @ref BT_DATA_BYTES.
|
||||
*/
|
||||
#define BT_LE_SUPP_FEAT_8_ENCODE(w64) \
|
||||
(((w64) >> 0) & 0xFF)
|
||||
|
||||
/**
|
||||
* @brief Validate whether LE Supported Features value does not use bits that are reserved for
|
||||
* future use.
|
||||
*
|
||||
* Helper macro to check if @p w64 has zeros as bits 40-63. The macro is compliant with BT 5.3
|
||||
* Core Specification where bits 0-40 has assigned values. In case of invalid value, build time
|
||||
* error is reported.
|
||||
*/
|
||||
#define BT_LE_SUPP_FEAT_VALIDATE(w64) \
|
||||
BUILD_ASSERT(!((w64) & (~BIT64_MASK(40))), \
|
||||
"RFU bit in LE Supported Features are not zeros.")
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* ZEPHYR_INCLUDE_BLUETOOTH_GAP_H_ */
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,92 @@
|
||||
/* hci.h - Bluetooth Host Control Interface definitions */
|
||||
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2016 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#ifndef ZEPHYR_INCLUDE_BLUETOOTH_HCI_H_
|
||||
#define ZEPHYR_INCLUDE_BLUETOOTH_HCI_H_
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <zephyr/bluetooth/bluetooth.h>
|
||||
#include <zephyr/net_buf.h>
|
||||
#include <zephyr/bluetooth/addr.h>
|
||||
#include <zephyr/bluetooth/conn.h>
|
||||
#include <zephyr/bluetooth/hci_types.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** Converts a HCI error to string.
|
||||
*
|
||||
* The error codes are described in the Bluetooth Core specification,
|
||||
* Vol 1, Part F, Section 2.
|
||||
*
|
||||
* The HCI documentation found in Vol 4, Part E,
|
||||
* describes when the different error codes are used.
|
||||
*
|
||||
* See also the defined BT_HCI_ERR_* macros.
|
||||
*
|
||||
* @return The string representation of the HCI error code.
|
||||
* If @kconfig{CONFIG_BT_HCI_ERR_TO_STR} is not enabled,
|
||||
* this just returns the empty string
|
||||
*/
|
||||
static inline const char *bt_hci_err_to_str(uint8_t hci_err)
|
||||
{
|
||||
ARG_UNUSED(hci_err);
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
/** Allocate a HCI command buffer.
|
||||
*
|
||||
* This function allocates a new buffer for a HCI command. It is given
|
||||
* the OpCode (encoded e.g. using the BT_OP macro) and the total length
|
||||
* of the parameters. Upon successful return the buffer is ready to have
|
||||
* the parameters encoded into it.
|
||||
*
|
||||
* @deprecated Use bt_hci_cmd_alloc() instead.
|
||||
*
|
||||
* @param opcode Command OpCode.
|
||||
* @param param_len Length of command parameters.
|
||||
*
|
||||
* @return Newly allocated buffer.
|
||||
*/
|
||||
struct net_buf *bt_hci_cmd_create(uint16_t opcode, uint8_t param_len);
|
||||
|
||||
/** Send a HCI command synchronously.
|
||||
*
|
||||
* This function is used for sending a HCI command synchronously. It can
|
||||
* either be called for a buffer created using bt_hci_cmd_create(), or
|
||||
* if the command has no parameters a NULL can be passed instead.
|
||||
*
|
||||
* The function will block until a Command Status or a Command Complete
|
||||
* event is returned. If either of these have a non-zero status the function
|
||||
* will return a negative error code and the response reference will not
|
||||
* be set. If the command completed successfully and a non-NULL rsp parameter
|
||||
* was given, this parameter will be set to point to a buffer containing
|
||||
* the response parameters.
|
||||
*
|
||||
* @param opcode Command OpCode.
|
||||
* @param buf Command buffer or NULL (if no parameters).
|
||||
* @param rsp Place to store a reference to the command response. May
|
||||
* be NULL if the caller is not interested in the response
|
||||
* parameters. If non-NULL is passed the caller is responsible
|
||||
* for calling net_buf_unref() on the buffer when done parsing
|
||||
* it.
|
||||
*
|
||||
* @return 0 on success or negative error value on failure.
|
||||
*/
|
||||
int bt_hci_cmd_send_sync(uint16_t opcode, struct net_buf *buf,
|
||||
struct net_buf **rsp);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* ZEPHYR_INCLUDE_BLUETOOTH_HCI_H_ */
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,603 @@
|
||||
/** @file
|
||||
* @brief Bluetooth L2CAP handling
|
||||
*/
|
||||
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2016 Intel Corporation
|
||||
* SPDX-FileCopyrightText: 2023 Nordic Semiconductor
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#ifndef ZEPHYR_INCLUDE_BLUETOOTH_L2CAP_H_
|
||||
#define ZEPHYR_INCLUDE_BLUETOOTH_L2CAP_H_
|
||||
|
||||
/**
|
||||
* @brief L2CAP
|
||||
* @defgroup bt_l2cap L2CAP
|
||||
* @ingroup bluetooth
|
||||
* @{
|
||||
*/
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <zephyr/sys/atomic.h>
|
||||
#include <zephyr/bluetooth/buf.h>
|
||||
#include <zephyr/bluetooth/conn.h>
|
||||
#include <zephyr/bluetooth/hci.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** L2CAP PDU header size, used for buffer size calculations */
|
||||
#define BT_L2CAP_HDR_SIZE 4
|
||||
|
||||
/** Maximum Transmission Unit (MTU) for an outgoing L2CAP PDU. */
|
||||
#define BT_L2CAP_TX_MTU (CONFIG_BT_L2CAP_TX_MTU)
|
||||
|
||||
/** Maximum Transmission Unit (MTU) for an incoming L2CAP PDU. */
|
||||
#define BT_L2CAP_RX_MTU (CONFIG_BT_L2CAP_RX_MTU - BT_L2CAP_HDR_SIZE)
|
||||
|
||||
/** @brief Helper to calculate needed buffer size for L2CAP PDUs.
|
||||
* Useful for creating buffer pools.
|
||||
*
|
||||
* @param mtu Needed L2CAP PDU MTU.
|
||||
*
|
||||
* @return Needed buffer size to match the requested L2CAP PDU MTU.
|
||||
*/
|
||||
#define BT_L2CAP_BUF_SIZE(mtu) BT_BUF_ACL_SIZE(BT_L2CAP_HDR_SIZE + (mtu))
|
||||
|
||||
/** L2CAP SDU header size, used for buffer size calculations */
|
||||
#define BT_L2CAP_SDU_HDR_SIZE 2
|
||||
|
||||
/** @brief Maximum Transmission Unit for an unsegmented outgoing L2CAP SDU.
|
||||
*
|
||||
* The Maximum Transmission Unit for an outgoing L2CAP SDU when sent without
|
||||
* segmentation, i.e. a single L2CAP SDU will fit inside a single L2CAP PDU.
|
||||
*
|
||||
* The MTU for outgoing L2CAP SDUs with segmentation is defined by the
|
||||
* size of the application buffer pool.
|
||||
*/
|
||||
#define BT_L2CAP_SDU_TX_MTU (BT_L2CAP_TX_MTU - BT_L2CAP_SDU_HDR_SIZE)
|
||||
|
||||
/** @brief Maximum Transmission Unit for an unsegmented incoming L2CAP SDU.
|
||||
*
|
||||
* The Maximum Transmission Unit for an incoming L2CAP SDU when sent without
|
||||
* segmentation, i.e. a single L2CAP SDU will fit inside a single L2CAP PDU.
|
||||
*
|
||||
* The MTU for incoming L2CAP SDUs with segmentation is defined by the
|
||||
* size of the application buffer pool. The application will have to define
|
||||
* an alloc_buf callback for the channel in order to support receiving
|
||||
* segmented L2CAP SDUs.
|
||||
*/
|
||||
#define BT_L2CAP_SDU_RX_MTU (BT_L2CAP_RX_MTU - BT_L2CAP_SDU_HDR_SIZE)
|
||||
|
||||
/**
|
||||
*
|
||||
* @brief Helper to calculate needed buffer size for L2CAP SDUs.
|
||||
* Useful for creating buffer pools.
|
||||
*
|
||||
* @param mtu Required BT_L2CAP_*_SDU.
|
||||
*
|
||||
* @return Needed buffer size to match the requested L2CAP SDU MTU.
|
||||
*/
|
||||
#define BT_L2CAP_SDU_BUF_SIZE(mtu) BT_L2CAP_BUF_SIZE(BT_L2CAP_SDU_HDR_SIZE + (mtu))
|
||||
|
||||
struct bt_l2cap_chan;
|
||||
|
||||
/** @typedef bt_l2cap_chan_destroy_t
|
||||
* @brief Channel destroy callback
|
||||
*
|
||||
* @param chan Channel object.
|
||||
*/
|
||||
typedef void (*bt_l2cap_chan_destroy_t)(struct bt_l2cap_chan *chan);
|
||||
|
||||
/** @brief Life-span states of L2CAP CoC channel.
|
||||
*
|
||||
* Used only by internal APIs dealing with setting channel to proper state
|
||||
* depending on operational context.
|
||||
*
|
||||
* A channel enters the @ref BT_L2CAP_CONNECTING state upon @ref
|
||||
* bt_l2cap_chan_connect, @ref bt_l2cap_ecred_chan_connect or upon returning
|
||||
* from @ref bt_l2cap_server.accept.
|
||||
*
|
||||
* When a channel leaves the @ref BT_L2CAP_CONNECTING state, @ref
|
||||
* bt_l2cap_chan_ops.connected is called.
|
||||
*/
|
||||
typedef enum bt_l2cap_chan_state {
|
||||
/** Channel disconnected */
|
||||
BT_L2CAP_DISCONNECTED,
|
||||
/** Channel in connecting state */
|
||||
BT_L2CAP_CONNECTING,
|
||||
/** Channel in config state, BR/EDR specific */
|
||||
BT_L2CAP_CONFIG,
|
||||
/** Channel ready for upper layer traffic on it */
|
||||
BT_L2CAP_CONNECTED,
|
||||
/** Channel in disconnecting state */
|
||||
BT_L2CAP_DISCONNECTING,
|
||||
|
||||
} __packed bt_l2cap_chan_state_t;
|
||||
|
||||
/** @brief Status of L2CAP channel. */
|
||||
typedef enum bt_l2cap_chan_status {
|
||||
/** Channel can send at least one PDU */
|
||||
BT_L2CAP_STATUS_OUT,
|
||||
|
||||
/** @brief Channel shutdown status
|
||||
*
|
||||
* Once this status is notified it means the channel will no longer be
|
||||
* able to transmit or receive data.
|
||||
*/
|
||||
BT_L2CAP_STATUS_SHUTDOWN,
|
||||
|
||||
/** @brief Channel encryption pending status */
|
||||
BT_L2CAP_STATUS_ENCRYPT_PENDING,
|
||||
|
||||
/* Total number of status - must be at the end of the enum */
|
||||
BT_L2CAP_NUM_STATUS,
|
||||
} __packed bt_l2cap_chan_status_t;
|
||||
|
||||
/** @brief L2CAP Channel structure. */
|
||||
struct bt_l2cap_chan {
|
||||
/** Channel connection reference */
|
||||
struct bt_conn *conn;
|
||||
/** Channel operations reference */
|
||||
const struct bt_l2cap_chan_ops *ops;
|
||||
sys_snode_t node;
|
||||
bt_l2cap_chan_destroy_t destroy;
|
||||
|
||||
ATOMIC_DEFINE(status, BT_L2CAP_NUM_STATUS);
|
||||
};
|
||||
|
||||
/** @brief LE L2CAP Endpoint structure. */
|
||||
struct bt_l2cap_le_endpoint {
|
||||
/** Endpoint Channel Identifier (CID) */
|
||||
uint16_t cid;
|
||||
/** Endpoint Maximum Transmission Unit */
|
||||
uint16_t mtu;
|
||||
/** Endpoint Maximum PDU payload Size */
|
||||
uint16_t mps;
|
||||
/** Endpoint credits */
|
||||
atomic_t credits;
|
||||
};
|
||||
|
||||
/** @brief LE L2CAP Channel structure. */
|
||||
struct bt_l2cap_le_chan {
|
||||
/** Common L2CAP channel reference object */
|
||||
struct bt_l2cap_chan chan;
|
||||
/** @brief Channel Receiving Endpoint.
|
||||
*
|
||||
* If the application has set an alloc_buf channel callback for the
|
||||
* channel to support receiving segmented L2CAP SDUs the application
|
||||
* should initialize the MTU of the Receiving Endpoint. Otherwise the
|
||||
* MTU of the receiving endpoint will be initialized to
|
||||
* @ref BT_L2CAP_SDU_RX_MTU by the stack.
|
||||
*
|
||||
* This is the source of the MTU, MPS and credit values when sending
|
||||
* L2CAP_LE_CREDIT_BASED_CONNECTION_REQ/RSP and
|
||||
* L2CAP_CONFIGURATION_REQ.
|
||||
*/
|
||||
struct bt_l2cap_le_endpoint rx;
|
||||
|
||||
/** Pending RX MTU on ECFC reconfigure, used internally by stack */
|
||||
uint16_t pending_rx_mtu;
|
||||
|
||||
/** Channel Transmission Endpoint.
|
||||
*
|
||||
* This is an image of the remote's rx.
|
||||
*
|
||||
* The MTU and MPS is controlled by the remote by
|
||||
* L2CAP_LE_CREDIT_BASED_CONNECTION_REQ/RSP or L2CAP_CONFIGURATION_REQ.
|
||||
*/
|
||||
struct bt_l2cap_le_endpoint tx;
|
||||
/** Channel Transmission queue
|
||||
*
|
||||
* Internal
|
||||
*
|
||||
* SDUs/PDUs given to @ref bt_l2cap_chan_send and @c bt_l2cap_send_pdu
|
||||
* are stored here until they are sent to the Controller.
|
||||
*
|
||||
* The SDU header is prepended to SDUs before they are stored here. The
|
||||
* head of this list (the next data to be sent) may be just the
|
||||
* remaining part of an already partially transmitted SDU/PDU due to
|
||||
* L2CAP segmentation and fragmentation.
|
||||
*
|
||||
* This is the outbox for a single channel. Channels may be serviced in
|
||||
* any order. The transmission order does not follow the sequence of
|
||||
* @ref bt_l2cap_chan_send calls across channels.
|
||||
*
|
||||
* There may be more data here than the channel currently has credits
|
||||
* for. The transmission will wait until credits are available.
|
||||
*
|
||||
* Callbacks given to @ref bt_l2cap_chan_send are stored in the
|
||||
* user_data of the buffer. These callbacks must be invoked when the
|
||||
* Controller gives a Number of Buffers Complete Event for the last
|
||||
* L2CAP PDU of the buffer or when the channel is disconnected.
|
||||
*/
|
||||
struct k_fifo tx_queue;
|
||||
/** Segment SDU packet from upper layer */
|
||||
struct net_buf *_sdu;
|
||||
uint16_t _sdu_len;
|
||||
uint16_t _sdu_len_done;
|
||||
|
||||
struct k_work rx_work;
|
||||
struct k_fifo rx_queue;
|
||||
|
||||
bt_l2cap_chan_state_t state;
|
||||
/** Remote PSM to be connected */
|
||||
uint16_t psm;
|
||||
/** Helps match request context during CoC */
|
||||
uint8_t ident;
|
||||
bt_security_t required_sec_level;
|
||||
|
||||
/* Response Timeout eXpired (RTX) timer */
|
||||
struct k_work_delayable rtx_work;
|
||||
struct k_work_sync rtx_sync;
|
||||
|
||||
/** @internal To be used with @ref bt_conn.upper_data_ready */
|
||||
sys_snode_t _pdu_ready;
|
||||
/** @internal Holds the length of the current PDU/segment */
|
||||
size_t _pdu_remaining;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Helper macro getting container object of type bt_l2cap_le_chan
|
||||
* address having the same container chan member address as object in question.
|
||||
*
|
||||
* @param _ch Address of object of bt_l2cap_chan type
|
||||
*
|
||||
* @return Address of in memory bt_l2cap_le_chan object type containing
|
||||
* the address of in question object.
|
||||
*/
|
||||
#define BT_L2CAP_LE_CHAN(_ch) CONTAINER_OF(_ch, struct bt_l2cap_le_chan, chan)
|
||||
|
||||
/** @brief L2CAP Channel operations structure.
|
||||
*
|
||||
* The object has to stay valid and constant for the lifetime of the channel.
|
||||
*/
|
||||
struct bt_l2cap_chan_ops {
|
||||
/** @brief Channel connected callback
|
||||
*
|
||||
* If this callback is provided it will be called whenever the
|
||||
* connection completes.
|
||||
*
|
||||
* @param chan The channel that has been connected
|
||||
*/
|
||||
void (*connected)(struct bt_l2cap_chan *chan);
|
||||
|
||||
/** @brief Channel disconnected callback
|
||||
*
|
||||
* If this callback is provided it will be called whenever the
|
||||
* channel is disconnected, including when a connection gets
|
||||
* rejected.
|
||||
*
|
||||
* @param chan The channel that has been Disconnected
|
||||
*/
|
||||
void (*disconnected)(struct bt_l2cap_chan *chan);
|
||||
|
||||
/** @brief Channel encrypt_change callback
|
||||
*
|
||||
* If this callback is provided it will be called whenever the
|
||||
* security level changed (indirectly link encryption done) or
|
||||
* authentication procedure fails. In both cases security initiator
|
||||
* and responder got the final status (HCI status) passed by
|
||||
* related to encryption and authentication events from local host's
|
||||
* controller.
|
||||
*
|
||||
* @param chan The channel which has made encryption status changed.
|
||||
* @param status HCI status of performed security procedure caused
|
||||
* by channel security requirements. The value is populated
|
||||
* by HCI layer and set to 0 when success and to non-zero (reference to
|
||||
* HCI Error Codes) when security/authentication failed.
|
||||
*/
|
||||
void (*encrypt_change)(struct bt_l2cap_chan *chan, uint8_t hci_status);
|
||||
|
||||
/** @brief Channel alloc_seg callback
|
||||
*
|
||||
* If this callback is provided the channel will use it to allocate
|
||||
* buffers to store segments. This avoids wasting big SDU buffers with
|
||||
* potentially much smaller PDUs. If this callback is supplied, it must
|
||||
* return a valid buffer.
|
||||
*
|
||||
* @param chan The channel requesting a buffer.
|
||||
*
|
||||
* @return Allocated buffer.
|
||||
*/
|
||||
struct net_buf *(*alloc_seg)(struct bt_l2cap_chan *chan);
|
||||
|
||||
/** @brief Channel alloc_buf callback
|
||||
*
|
||||
* If this callback is provided the channel will use it to allocate
|
||||
* buffers to store incoming data. Channels that requires segmentation
|
||||
* must set this callback.
|
||||
* If the application has not set a callback the L2CAP SDU MTU will be
|
||||
* truncated to @ref BT_L2CAP_SDU_RX_MTU.
|
||||
*
|
||||
* @param chan The channel requesting a buffer.
|
||||
*
|
||||
* @return Allocated buffer.
|
||||
*/
|
||||
struct net_buf *(*alloc_buf)(struct bt_l2cap_chan *chan);
|
||||
|
||||
/** @brief Channel recv callback
|
||||
*
|
||||
* @param chan The channel receiving data.
|
||||
* @param buf Buffer containing incoming data.
|
||||
*
|
||||
* @note This callback is mandatory, unless
|
||||
* @kconfig{CONFIG_BT_L2CAP_SEG_RECV} is enabled and seg_recv is
|
||||
* supplied.
|
||||
*
|
||||
* If the application returns @c -EINPROGRESS, the application takes
|
||||
* ownership of the reference in @p buf. (I.e. This pointer value can
|
||||
* simply be given to @ref bt_l2cap_chan_recv_complete without any
|
||||
* calls @ref net_buf_ref or @ref net_buf_unref.)
|
||||
*
|
||||
* @return 0 in case of success or negative value in case of error.
|
||||
* @return -EINPROGRESS in case where user has to confirm once the data
|
||||
* has been processed by calling
|
||||
* @ref bt_l2cap_chan_recv_complete passing back
|
||||
* the buffer received with its original user_data
|
||||
* which contains the number of segments/credits
|
||||
* used by the packet.
|
||||
*/
|
||||
int (*recv)(struct bt_l2cap_chan *chan, struct net_buf *buf);
|
||||
|
||||
/** @brief Channel sent callback
|
||||
*
|
||||
* This callback will be called once the controller marks the SDU
|
||||
* as completed. When the controller does so is implementation
|
||||
* dependent. It could be after the SDU is enqueued for transmission,
|
||||
* or after it is sent on air.
|
||||
*
|
||||
* @param chan The channel which has sent data.
|
||||
*/
|
||||
void (*sent)(struct bt_l2cap_chan *chan);
|
||||
|
||||
/** @brief Channel status callback
|
||||
*
|
||||
* If this callback is provided it will be called whenever the
|
||||
* channel status changes.
|
||||
*
|
||||
* @param chan The channel which status changed
|
||||
* @param status The channel status
|
||||
*/
|
||||
void (*status)(struct bt_l2cap_chan *chan, atomic_t *status);
|
||||
|
||||
/* @brief Channel released callback
|
||||
*
|
||||
* If this callback is set it is called when the stack has release all
|
||||
* references to the channel object.
|
||||
*/
|
||||
void (*released)(struct bt_l2cap_chan *chan);
|
||||
|
||||
/** @brief Channel reconfigured callback
|
||||
*
|
||||
* If this callback is provided it will be called whenever peer or
|
||||
* local device requested reconfiguration. Application may check
|
||||
* updated MTU and MPS values by inspecting chan->le endpoints.
|
||||
*
|
||||
* @param chan The channel which was reconfigured
|
||||
*/
|
||||
void (*reconfigured)(struct bt_l2cap_chan *chan);
|
||||
|
||||
/** @brief Handle L2CAP segments directly
|
||||
*
|
||||
* This is an alternative to @ref bt_l2cap_chan_ops.recv. They cannot
|
||||
* be used together.
|
||||
*
|
||||
* This is called immediately for each received segment.
|
||||
*
|
||||
* Unlike with @ref bt_l2cap_chan_ops.recv, flow control is explicit.
|
||||
* Each time this handler is invoked, the remote has permanently used
|
||||
* up one credit. Use @ref bt_l2cap_chan_give_credits to give credits.
|
||||
*
|
||||
* The start of an SDU is marked by `seg_offset == 0`. The end of an
|
||||
* SDU is marked by `seg_offset + seg->len == sdu_len`.
|
||||
*
|
||||
* The stack guarantees that:
|
||||
* - The sender had the credit.
|
||||
* - The SDU length does not exceed MTU.
|
||||
* - The segment length does not exceed MPS.
|
||||
*
|
||||
* Additionally, the L2CAP protocol is such that:
|
||||
* - Segments come in order.
|
||||
* - SDUs cannot be interleaved or aborted halfway.
|
||||
*
|
||||
* @note With this alternative API, the application is responsible for
|
||||
* setting the RX MTU and MPS. The MPS must not exceed @ref BT_L2CAP_RX_MTU.
|
||||
*
|
||||
* @param chan The receiving channel.
|
||||
* @param sdu_len Byte length of the SDU this segment is part of.
|
||||
* @param seg_offset The byte offset of this segment in the SDU.
|
||||
* @param seg The segment payload.
|
||||
*/
|
||||
void (*seg_recv)(struct bt_l2cap_chan *chan, size_t sdu_len,
|
||||
off_t seg_offset, struct net_buf_simple *seg);
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Headroom needed for outgoing L2CAP PDUs.
|
||||
*/
|
||||
#define BT_L2CAP_CHAN_SEND_RESERVE (BT_L2CAP_BUF_SIZE(0))
|
||||
|
||||
/**
|
||||
* @brief Headroom needed for outgoing L2CAP SDUs.
|
||||
*/
|
||||
#define BT_L2CAP_SDU_CHAN_SEND_RESERVE (BT_L2CAP_SDU_BUF_SIZE(0))
|
||||
|
||||
/** @brief L2CAP Server structure. */
|
||||
struct bt_l2cap_server {
|
||||
/** @brief Server PSM.
|
||||
*
|
||||
* For LE, possible values:
|
||||
* 0 A dynamic value will be auto-allocated when
|
||||
* bt_l2cap_server_register() is called.
|
||||
*
|
||||
* 0x0001-0x007f Standard, Bluetooth SIG-assigned fixed values.
|
||||
*
|
||||
* 0x0080-0x00ff Dynamically allocated. May be pre-set by the
|
||||
* application before server registration (not
|
||||
* recommended however), or auto-allocated by the
|
||||
* stack if the app gave 0 as the value.
|
||||
*
|
||||
* For BR, possible values:
|
||||
*
|
||||
* The PSM field is at least two octets in length. All PSM values shall have the least
|
||||
* significant bit of the most significant octet equal to 0 and the least significant bit
|
||||
* of all other octets equal to 1.
|
||||
*
|
||||
* 0 A dynamic value will be auto-allocated when
|
||||
* bt_l2cap_br_server_register() is called.
|
||||
*
|
||||
* 0x0001-0x0eff Standard, Bluetooth SIG-assigned fixed values.
|
||||
*
|
||||
* > 0x1000 Dynamically allocated. May be pre-set by the
|
||||
* application before server registration (not
|
||||
* recommended however), or auto-allocated by the
|
||||
* stack if the app gave 0 as the value.
|
||||
*/
|
||||
uint16_t psm;
|
||||
|
||||
/** Required minimum security level */
|
||||
bt_security_t sec_level;
|
||||
|
||||
/** @brief Server accept callback
|
||||
*
|
||||
* This callback is called whenever a new incoming connection requires
|
||||
* authorization.
|
||||
*
|
||||
* @warning It is the responsibility of this callback to zero out the
|
||||
* parent of the chan object.
|
||||
*
|
||||
* @param conn The connection that is requesting authorization
|
||||
* @param server Pointer to the server structure this callback relates to
|
||||
* @param chan Pointer to received the allocated channel
|
||||
*
|
||||
* @return 0 in case of success or negative value in case of error.
|
||||
* @return -ENOMEM if no available space for new channel.
|
||||
* @return -EACCES if application did not authorize the connection.
|
||||
* @return -EPERM if encryption key size is too short.
|
||||
*/
|
||||
int (*accept)(struct bt_conn *conn, struct bt_l2cap_server *server,
|
||||
struct bt_l2cap_chan **chan);
|
||||
|
||||
sys_snode_t node;
|
||||
};
|
||||
|
||||
/** @brief Register L2CAP server.
|
||||
*
|
||||
* Register L2CAP server for a PSM, each new connection is authorized using
|
||||
* the accept() callback which in case of success shall allocate the channel
|
||||
* structure to be used by the new connection.
|
||||
*
|
||||
* For fixed, SIG-assigned PSMs (in the range 0x0001-0x007f) the PSM should
|
||||
* be assigned to server->psm before calling this API. For dynamic PSMs
|
||||
* (in the range 0x0080-0x00ff) server->psm may be pre-set to a given value
|
||||
* (this is however not recommended) or be left as 0, in which case upon
|
||||
* return a newly allocated value will have been assigned to it. For
|
||||
* dynamically allocated values the expectation is that it's exposed through
|
||||
* a GATT service, and that's how L2CAP clients discover how to connect to
|
||||
* the server.
|
||||
*
|
||||
* @param server Server structure.
|
||||
*
|
||||
* @return 0 in case of success or negative value in case of error.
|
||||
*/
|
||||
int bt_l2cap_server_register(struct bt_l2cap_server *server);
|
||||
|
||||
/** @brief Connect L2CAP channel
|
||||
*
|
||||
* Connect L2CAP channel by PSM, once the connection is completed channel
|
||||
* connected() callback will be called. If the connection is rejected
|
||||
* disconnected() callback is called instead.
|
||||
* Channel object passed (over an address of it) as second parameter shouldn't
|
||||
* be instantiated in application as standalone. Instead of, application should
|
||||
* create transport dedicated L2CAP objects, i.e. type of bt_l2cap_le_chan for
|
||||
* LE and/or type of bt_l2cap_br_chan for BR/EDR. Then pass to this API
|
||||
* the location (address) of bt_l2cap_chan type object which is a member
|
||||
* of both transport dedicated objects.
|
||||
*
|
||||
* @warning It is the responsibility of the caller to zero out the
|
||||
* parent of the chan object.
|
||||
*
|
||||
* @param conn Connection object.
|
||||
* @param chan Channel object.
|
||||
* @param psm Channel PSM to connect to.
|
||||
*
|
||||
* @return 0 in case of success or negative value in case of error.
|
||||
*/
|
||||
int bt_l2cap_chan_connect(struct bt_conn *conn, struct bt_l2cap_chan *chan,
|
||||
uint16_t psm);
|
||||
|
||||
/** @brief Disconnect L2CAP channel
|
||||
*
|
||||
* Disconnect L2CAP channel, if the connection is pending it will be
|
||||
* canceled and as a result the channel disconnected() callback is called.
|
||||
* Regarding to input parameter, to get details see reference description
|
||||
* to bt_l2cap_chan_connect() API above.
|
||||
*
|
||||
* @param chan Channel object.
|
||||
*
|
||||
* @return 0 in case of success or negative value in case of error.
|
||||
*/
|
||||
int bt_l2cap_chan_disconnect(struct bt_l2cap_chan *chan);
|
||||
|
||||
/** @brief Send data to L2CAP channel
|
||||
*
|
||||
* Send data from buffer to the channel. For dynamic channels; if credits are
|
||||
* not available, buf will be queued and sent as and when credits are received
|
||||
* from peer.
|
||||
*
|
||||
* Network buffer fragments (ie `buf->frags`) are not supported.
|
||||
*
|
||||
* When sending L2CAP data over an BR/EDR connection or a fixed L2CAP channel,
|
||||
* the application is sending L2CAP PDUs. The application is required to have
|
||||
* reserved @ref BT_L2CAP_CHAN_SEND_RESERVE bytes in the buffer before sending.
|
||||
* The application should use the BT_L2CAP_BUF_SIZE() helper to correctly size
|
||||
* the buffers for the for the outgoing buffer pool.
|
||||
*
|
||||
* When sending L2CAP data over a dynamic L2CAP channel, the application is
|
||||
* sending L2CAP SDUs. The application shall reserve
|
||||
* @ref BT_L2CAP_SDU_CHAN_SEND_RESERVE bytes in the buffer before sending.
|
||||
* The application can use the BT_L2CAP_SDU_BUF_SIZE() helper to correctly size
|
||||
* the buffer to account for the reserved headroom.
|
||||
*
|
||||
* When segmenting an L2CAP SDU into L2CAP PDUs the stack will first attempt to
|
||||
* allocate buffers from the channel's `alloc_seg` callback and will fallback
|
||||
* on the stack's global buffer pool (sized
|
||||
* @kconfig{CONFIG_BT_L2CAP_TX_BUF_COUNT}).
|
||||
*
|
||||
* @warning The buffer's user_data _will_ be overwritten by this function. Do
|
||||
* not store anything in it. As soon as a call to this function has been made,
|
||||
* consider ownership of user_data transferred into the stack.
|
||||
*
|
||||
* @note Buffer ownership is transferred to the stack in case of success, in
|
||||
* case of an error the caller retains the ownership of the buffer.
|
||||
*
|
||||
* @param chan The channel to send the data to. See @ref bt_l2cap_chan_connect
|
||||
* for more details.
|
||||
* @param buf Buffer containing the data.
|
||||
*
|
||||
* @return 0 in case of success or negative value in case of error.
|
||||
* @return -EINVAL if `buf` or `chan` is NULL.
|
||||
* @return -EINVAL if `chan` is not either BR/EDR or LE based.
|
||||
* @return -EINVAL if buffer doesn't have enough bytes reserved to fit header.
|
||||
* @return -EINVAL if buffer's reference counter != 1
|
||||
* @return -EMSGSIZE if `buf` is larger than `chan`'s MTU.
|
||||
* @return -ENOTCONN if underlying conn is disconnected.
|
||||
* @return -ESHUTDOWN if L2CAP channel is disconnected.
|
||||
* @return -other (from lower layers) if chan is BR/EDR.
|
||||
*/
|
||||
int bt_l2cap_chan_send(struct bt_l2cap_chan *chan, struct net_buf *buf);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
#endif /* ZEPHYR_INCLUDE_BLUETOOTH_L2CAP_H_ */
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,161 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2016 Wind River Systems, Inc.
|
||||
* SPDX-FileContributor: 2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <zephyr/sys/slist.h>
|
||||
#include <zephyr/logging/log.h>
|
||||
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/queue.h"
|
||||
#include "freertos/semphr.h"
|
||||
#include "toolchain.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Mutex */
|
||||
|
||||
#define K_MUTEX_FOREVER portMAX_DELAY
|
||||
|
||||
struct k_mutex {
|
||||
SemaphoreHandle_t handle;
|
||||
};
|
||||
|
||||
static inline void k_mutex_create(struct k_mutex *mutex)
|
||||
{
|
||||
assert(mutex);
|
||||
assert(mutex->handle == NULL);
|
||||
|
||||
mutex->handle = xSemaphoreCreateRecursiveMutex();
|
||||
assert(mutex->handle);
|
||||
}
|
||||
|
||||
static inline void k_mutex_delete(struct k_mutex *mutex)
|
||||
{
|
||||
assert(mutex);
|
||||
assert(mutex->handle);
|
||||
|
||||
vSemaphoreDelete(mutex->handle);
|
||||
mutex->handle = NULL;
|
||||
}
|
||||
|
||||
static inline int k_mutex_lock(struct k_mutex *mutex, uint32_t timeout)
|
||||
{
|
||||
assert(mutex);
|
||||
assert(mutex->handle);
|
||||
|
||||
if (xSemaphoreTakeRecursive(mutex->handle, timeout) != pdTRUE) {
|
||||
LOG_ERR("KMutexLockFail");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int k_mutex_unlock(struct k_mutex *mutex)
|
||||
{
|
||||
assert(mutex);
|
||||
assert(mutex->handle);
|
||||
|
||||
if (xSemaphoreGiveRecursive(mutex->handle) != pdTRUE) {
|
||||
LOG_ERR("KMutexUnlockFail");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Timer */
|
||||
|
||||
typedef uint32_t k_timeout_t;
|
||||
|
||||
#define K_NO_WAIT 0
|
||||
#define K_FOREVER (-1)
|
||||
|
||||
#define MSEC_PER_SEC 1000
|
||||
#define K_USEC(t) (t)
|
||||
#define K_MSEC(ms) (ms)
|
||||
#define K_SECONDS(s) K_MSEC((s) * MSEC_PER_SEC)
|
||||
#define K_MINUTES(m) K_SECONDS((m) * 60)
|
||||
#define K_HOURS(h) K_MINUTES((h) * 60)
|
||||
|
||||
struct k_work;
|
||||
|
||||
typedef void (*k_work_handler_t)(struct k_work *work);
|
||||
|
||||
struct k_work {
|
||||
void *timer;
|
||||
k_work_handler_t handler;
|
||||
int64_t timeout_us;
|
||||
void *user_data;
|
||||
};
|
||||
|
||||
struct k_work_sync {
|
||||
struct k_work work;
|
||||
};
|
||||
|
||||
struct k_work_delayable {
|
||||
struct k_work work;
|
||||
};
|
||||
|
||||
#define K_WORK_DEFINE(work, work_handler) \
|
||||
struct k_work work = { \
|
||||
.handler = work_handler, \
|
||||
}
|
||||
|
||||
#define K_WORK_DELAYABLE_DEFINE(dwork, work_handler) \
|
||||
struct k_work_delayable dwork = { \
|
||||
.work.handler = work_handler, \
|
||||
}
|
||||
|
||||
#define K_TIMEOUT_EQ(a, b) ((a) == (b))
|
||||
|
||||
typedef void (*k_work_handler_t)(struct k_work *work);
|
||||
|
||||
int k_work_submit(struct k_work *work);
|
||||
|
||||
bool k_work_is_pending(struct k_work *work);
|
||||
|
||||
void k_work_init(struct k_work *work, k_work_handler_t handler);
|
||||
|
||||
struct k_work_delayable *k_work_delayable_from_work(struct k_work *work);
|
||||
|
||||
void k_work_init_delayable(struct k_work_delayable *dwork,
|
||||
k_work_handler_t handler);
|
||||
|
||||
void k_work_deinit_delayable(struct k_work_delayable *dwork);
|
||||
|
||||
int k_work_cancel_delayable(struct k_work_delayable *dwork);
|
||||
|
||||
bool k_work_cancel_delayable_sync(struct k_work_delayable *dwork,
|
||||
struct k_work_sync *sync);
|
||||
|
||||
int k_work_schedule(struct k_work_delayable *dwork, k_timeout_t delay);
|
||||
|
||||
int k_work_reschedule(struct k_work_delayable *dwork, k_timeout_t delay);
|
||||
|
||||
int k_work_schedule_periodic(struct k_work_delayable *dwork, k_timeout_t period_ms);
|
||||
|
||||
k_timeout_t k_work_delayable_remaining_get(struct k_work_delayable *dwork);
|
||||
|
||||
/* Slist */
|
||||
|
||||
struct k_fifo {
|
||||
sys_slist_t slist;
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,121 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2018 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef ZEPHYR_INCLUDE_LOGGING_LOG_H_
|
||||
#define ZEPHYR_INCLUDE_LOGGING_LOG_H_
|
||||
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#include "esp_log.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern int ets_printf(const char *fmt, ...);
|
||||
|
||||
#define LOG_MODULE_REGISTER(...)
|
||||
|
||||
#define LOG_MODULE_DECLARE(...)
|
||||
|
||||
#define BT_ISO_LOG_COLOR_BLACK "30"
|
||||
#define BT_ISO_LOG_COLOR_RED "31"
|
||||
#define BT_ISO_LOG_COLOR_GREEN "32"
|
||||
#define BT_ISO_LOG_COLOR_YELLOW "33"
|
||||
#define BT_ISO_LOG_COLOR_BLUE "34"
|
||||
#define BT_ISO_LOG_COLOR_PURPLE "35"
|
||||
#define BT_ISO_LOG_COLOR_CYAN "36"
|
||||
#define BT_ISO_LOG_COLOR_WHITE "37"
|
||||
#define BT_ISO_LOG_COLOR(COLOR) "\033[0;" COLOR "m"
|
||||
#define BT_ISO_LOG_BOLD(COLOR) "\033[1;" COLOR "m"
|
||||
#define BT_ISO_LOG_RESET_COLOR "\033[0m"
|
||||
#define BT_ISO_LOG_COLOR_E BT_ISO_LOG_COLOR(BT_ISO_LOG_COLOR_RED)
|
||||
#define BT_ISO_LOG_COLOR_W BT_ISO_LOG_COLOR(BT_ISO_LOG_COLOR_YELLOW)
|
||||
#define BT_ISO_LOG_COLOR_I BT_ISO_LOG_COLOR(BT_ISO_LOG_COLOR_GREEN)
|
||||
#define BT_ISO_LOG_COLOR_D BT_ISO_LOG_COLOR(BT_ISO_LOG_COLOR_WHITE)
|
||||
#define BT_ISO_LOG_COLOR_V BT_ISO_LOG_COLOR(BT_ISO_LOG_COLOR_WHITE)
|
||||
|
||||
#define BT_ISO_LOG_ERROR 1
|
||||
#define BT_ISO_LOG_WARN 2
|
||||
#define BT_ISO_LOG_INFO 3
|
||||
#define BT_ISO_LOG_DEBUG 4
|
||||
#define BT_ISO_LOG_VERBOSE 5
|
||||
|
||||
#define BT_AUDIO_LOG_ERROR BT_ISO_LOG_ERROR
|
||||
#define BT_AUDIO_LOG_WARN BT_ISO_LOG_WARN
|
||||
#define BT_AUDIO_LOG_INFO BT_ISO_LOG_INFO
|
||||
#define BT_AUDIO_LOG_DEBUG BT_ISO_LOG_DEBUG
|
||||
#define BT_AUDIO_LOG_VERBOSE BT_ISO_LOG_VERBOSE
|
||||
|
||||
#define BT_ISO_LOG_TAG "ISO"
|
||||
|
||||
#define BT_ISO_LOGE(tag, format, ...) \
|
||||
esp_log_write(ESP_LOG_ERROR, tag, LOG_FORMAT(E, format), \
|
||||
esp_log_timestamp(), tag, ##__VA_ARGS__);
|
||||
|
||||
#define BT_ISO_LOGW(tag, format, ...) \
|
||||
esp_log_write(ESP_LOG_WARN, tag, LOG_FORMAT(W, format), \
|
||||
esp_log_timestamp(), tag, ##__VA_ARGS__);
|
||||
|
||||
#define BT_ISO_LOGI(tag, format, ...) \
|
||||
esp_log_write(ESP_LOG_INFO, tag, LOG_FORMAT(I, format), \
|
||||
esp_log_timestamp(), tag, ##__VA_ARGS__);
|
||||
|
||||
#define BT_ISO_LOGD(tag, format, ...) \
|
||||
esp_log_write(ESP_LOG_INFO, tag, LOG_FORMAT(D, format), \
|
||||
esp_log_timestamp(), tag, ##__VA_ARGS__);
|
||||
|
||||
#if CONFIG_BT_ISO_NO_LOG
|
||||
#define LOG_ERR(fmt, args...)
|
||||
#define LOG_WRN(fmt, args...)
|
||||
#define LOG_INF(fmt, args...)
|
||||
#define LOG_DBG(fmt, args...)
|
||||
#else /* CONFIG_BT_ISO_NO_LOG */
|
||||
#if (CONFIG_BT_ISO_LOG_LEVEL >= BT_ISO_LOG_ERROR)
|
||||
#define LOG_ERR(fmt, args...) BT_ISO_LOGE(BT_ISO_LOG_TAG, fmt, ## args)
|
||||
#else /* (CONFIG_BT_ISO_LOG_LEVEL >= BT_ISO_LOG_ERROR) */
|
||||
#define LOG_ERR(fmt, args...)
|
||||
#endif /* (CONFIG_BT_ISO_LOG_LEVEL >= BT_ISO_LOG_ERROR) */
|
||||
|
||||
#if (CONFIG_BT_ISO_LOG_LEVEL >= BT_ISO_LOG_WARN)
|
||||
#define LOG_WRN(fmt, args...) BT_ISO_LOGW(BT_ISO_LOG_TAG, fmt, ## args)
|
||||
#else /* (CONFIG_BT_ISO_LOG_LEVEL >= BT_ISO_LOG_WARN) */
|
||||
#define LOG_WRN(fmt, args...)
|
||||
#endif /* (CONFIG_BT_ISO_LOG_LEVEL >= BT_ISO_LOG_WARN) */
|
||||
|
||||
#if (CONFIG_BT_ISO_LOG_LEVEL >= BT_ISO_LOG_INFO)
|
||||
#define LOG_INF(fmt, args...) BT_ISO_LOGI(BT_ISO_LOG_TAG, fmt, ## args)
|
||||
#else /* (CONFIG_BT_ISO_LOG_LEVEL >= BT_ISO_LOG_INFO) */
|
||||
#define LOG_INF(fmt, args...)
|
||||
#endif /* (CONFIG_BT_ISO_LOG_LEVEL >= BT_ISO_LOG_INFO) */
|
||||
|
||||
#if (CONFIG_BT_ISO_LOG_LEVEL >= BT_ISO_LOG_DEBUG)
|
||||
#define LOG_DBG(fmt, args...) BT_ISO_LOGD(BT_ISO_LOG_TAG, fmt, ## args)
|
||||
#else /* (CONFIG_BT_ISO_LOG_LEVEL >= BT_ISO_LOG_DEBUG) */
|
||||
#define LOG_DBG(fmt, args...)
|
||||
#endif /* (CONFIG_BT_ISO_LOG_LEVEL >= BT_ISO_LOG_DEBUG) */
|
||||
#endif /* CONFIG_BT_ISO_NO_LOG */
|
||||
|
||||
#define NET_BUF_ERR(fmt, args...) /* TBD */
|
||||
#define NET_BUF_WARN(fmt, args...) /* TBD */
|
||||
#define NET_BUF_INFO(fmt, args...) /* TBD */
|
||||
#define NET_BUF_DBG(fmt, args...) /* TBD */
|
||||
#define NET_BUF_ASSERT assert
|
||||
|
||||
#define NET_BUF_SIMPLE_ERR(fmt, args...) /* TBD */
|
||||
#define NET_BUF_SIMPLE_WARN(fmt, args...) /* TBD */
|
||||
#define NET_BUF_SIMPLE_INFO(fmt, args...) /* TBD */
|
||||
#define NET_BUF_SIMPLE_DBG(fmt, args...) /* TBD */
|
||||
#define NET_BUF_SIMPLE_ASSERT assert
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* ZEPHYR_INCLUDE_LOGGING_LOG_H_ */
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2011-2014 Wind River Systems, Inc.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef ZEPHYR_INCLUDE_SYS_ASSERT_H_
|
||||
#define ZEPHYR_INCLUDE_SYS_ASSERT_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <assert.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define __ASSERT_NO_MSG(test) assert(test)
|
||||
|
||||
#define __ASSERT(test, fmt, ...) assert(test)
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* ZEPHYR_INCLUDE_SYS_ASSERT_H_ */
|
||||
@@ -0,0 +1,162 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 1997-2015 Wind River Systems, Inc.
|
||||
* SPDX-FileCopyrightText: 2021 Intel Corporation
|
||||
* SPDX-FileCopyrightText: 2023 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef ZEPHYR_INCLUDE_SYS_ATOMIC_H_
|
||||
#define ZEPHYR_INCLUDE_SYS_ATOMIC_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <zephyr/sys/util.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef uint32_t atomic_t;
|
||||
typedef atomic_t atomic_val_t;
|
||||
typedef void *atomic_ptr_t;
|
||||
typedef atomic_ptr_t atomic_ptr_val_t;
|
||||
|
||||
#define ATOMIC_INIT(i) (i)
|
||||
#define ATOMIC_PTR_INIT(p) (p)
|
||||
#define ATOMIC_BITS (sizeof(atomic_val_t) * 8)
|
||||
#define ATOMIC_MASK(bit) BIT((unsigned long)(bit) & (ATOMIC_BITS - 1U))
|
||||
#define ATOMIC_ELEM(addr, bit) ((addr) + ((bit) / ATOMIC_BITS))
|
||||
#define ATOMIC_BITMAP_SIZE(num_bits) (ROUND_UP(num_bits, ATOMIC_BITS) / ATOMIC_BITS)
|
||||
#define ATOMIC_DEFINE(name, num_bits) atomic_t name[ATOMIC_BITMAP_SIZE(num_bits)]
|
||||
|
||||
static inline bool atomic_cas(atomic_t *target,
|
||||
atomic_val_t old_value,
|
||||
atomic_val_t new_value)
|
||||
{
|
||||
if (*target != old_value) {
|
||||
return false;
|
||||
}
|
||||
|
||||
*target = new_value;
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline atomic_val_t atomic_inc(atomic_t *target)
|
||||
{
|
||||
atomic_val_t ret = 0;
|
||||
|
||||
ret = *target;
|
||||
(*target)++;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline atomic_val_t atomic_dec(atomic_t *target)
|
||||
{
|
||||
atomic_val_t ret = 0;
|
||||
|
||||
ret = *target;
|
||||
(*target)--;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline atomic_val_t atomic_get(const atomic_t *target)
|
||||
{
|
||||
return *target;
|
||||
}
|
||||
|
||||
static inline atomic_val_t atomic_set(atomic_t *target, atomic_val_t value)
|
||||
{
|
||||
atomic_val_t ret = 0;
|
||||
|
||||
ret = *target;
|
||||
*target = value;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline atomic_val_t atomic_clear(atomic_t *target)
|
||||
{
|
||||
return atomic_set(target, 0);
|
||||
}
|
||||
|
||||
static inline atomic_val_t atomic_or(atomic_t *target, atomic_val_t value)
|
||||
{
|
||||
atomic_val_t ret = 0;
|
||||
|
||||
ret = *target;
|
||||
*target |= value;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline atomic_val_t atomic_and(atomic_t *target, atomic_val_t value)
|
||||
{
|
||||
atomic_val_t ret = 0;
|
||||
|
||||
ret = *target;
|
||||
*target &= value;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline void atomic_set_bit_to(atomic_t *target, int bit, bool val)
|
||||
{
|
||||
atomic_val_t mask = ATOMIC_MASK(bit);
|
||||
|
||||
if (val) {
|
||||
(void)atomic_or(ATOMIC_ELEM(target, bit), mask);
|
||||
} else {
|
||||
(void)atomic_and(ATOMIC_ELEM(target, bit), ~mask);
|
||||
}
|
||||
}
|
||||
|
||||
static inline bool atomic_test_bit(const atomic_t *target, int bit)
|
||||
{
|
||||
atomic_val_t val = atomic_get(ATOMIC_ELEM(target, bit));
|
||||
|
||||
return (1 & (val >> (bit & (ATOMIC_BITS - 1)))) != 0;
|
||||
}
|
||||
|
||||
static inline void atomic_set_bit(atomic_t *target, int bit)
|
||||
{
|
||||
atomic_val_t mask = ATOMIC_MASK(bit);
|
||||
|
||||
(void)atomic_or(ATOMIC_ELEM(target, bit), mask);
|
||||
}
|
||||
|
||||
static inline void atomic_clear_bit(atomic_t *target, int bit)
|
||||
{
|
||||
atomic_val_t mask = ATOMIC_MASK(bit);
|
||||
|
||||
(void)atomic_and(ATOMIC_ELEM(target, bit), ~mask);
|
||||
}
|
||||
|
||||
static inline bool atomic_test_and_set_bit(atomic_t *target, int bit)
|
||||
{
|
||||
atomic_val_t mask = ATOMIC_MASK(bit);
|
||||
atomic_val_t old;
|
||||
|
||||
old = atomic_or(ATOMIC_ELEM(target, bit), mask);
|
||||
|
||||
return (old & mask) != 0;
|
||||
}
|
||||
|
||||
static inline bool atomic_test_and_clear_bit(atomic_t *target, int bit)
|
||||
{
|
||||
atomic_val_t mask = ATOMIC_MASK(bit);
|
||||
atomic_val_t old;
|
||||
|
||||
old = atomic_and(ATOMIC_ELEM(target, bit), ~mask);
|
||||
|
||||
return (old & mask) != 0;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* ZEPHYR_INCLUDE_SYS_ATOMIC_H_ */
|
||||
@@ -0,0 +1,852 @@
|
||||
/** @file
|
||||
* @brief Byte order helpers.
|
||||
*/
|
||||
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2016 Intel Corporation.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef ZEPHYR_INCLUDE_SYS_BYTEORDER_H_
|
||||
#define ZEPHYR_INCLUDE_SYS_BYTEORDER_H_
|
||||
|
||||
#include <zephyr/types.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include <zephyr/sys/__assert.h>
|
||||
#include <zephyr/sys/util_macro.h>
|
||||
#include <zephyr/toolchain.h>
|
||||
|
||||
#define BSWAP_16(x) ((uint16_t) ((((x) >> 8) & 0xff) | (((x) & 0xff) << 8)))
|
||||
#define BSWAP_24(x) ((uint32_t) ((((x) >> 16) & 0xff) | \
|
||||
(((x)) & 0xff00) | \
|
||||
(((x) & 0xff) << 16)))
|
||||
#define BSWAP_32(x) ((uint32_t) ((((x) >> 24) & 0xff) | \
|
||||
(((x) >> 8) & 0xff00) | \
|
||||
(((x) & 0xff00) << 8) | \
|
||||
(((x) & 0xff) << 24)))
|
||||
#define BSWAP_40(x) ((uint64_t) ((((x) >> 32) & 0xff) | \
|
||||
(((x) >> 16) & 0xff00) | \
|
||||
(((x)) & 0xff0000) | \
|
||||
(((x) & 0xff00) << 16) | \
|
||||
(((x) & 0xff) << 32)))
|
||||
#define BSWAP_48(x) ((uint64_t) ((((x) >> 40) & 0xff) | \
|
||||
(((x) >> 24) & 0xff00) | \
|
||||
(((x) >> 8) & 0xff0000) | \
|
||||
(((x) & 0xff0000) << 8) | \
|
||||
(((x) & 0xff00) << 24) | \
|
||||
(((x) & 0xff) << 40)))
|
||||
#define BSWAP_64(x) ((uint64_t) ((((x) >> 56) & 0xff) | \
|
||||
(((x) >> 40) & 0xff00) | \
|
||||
(((x) >> 24) & 0xff0000) | \
|
||||
(((x) >> 8) & 0xff000000) | \
|
||||
(((x) & 0xff000000) << 8) | \
|
||||
(((x) & 0xff0000) << 24) | \
|
||||
(((x) & 0xff00) << 40) | \
|
||||
(((x) & 0xff) << 56)))
|
||||
|
||||
/** @def sys_le16_to_cpu
|
||||
* @brief Convert 16-bit integer from little-endian to host endianness.
|
||||
*
|
||||
* @param val 16-bit integer in little-endian format.
|
||||
*
|
||||
* @return 16-bit integer in host endianness.
|
||||
*/
|
||||
|
||||
/** @def sys_cpu_to_le16
|
||||
* @brief Convert 16-bit integer from host endianness to little-endian.
|
||||
*
|
||||
* @param val 16-bit integer in host endianness.
|
||||
*
|
||||
* @return 16-bit integer in little-endian format.
|
||||
*/
|
||||
|
||||
/** @def sys_le24_to_cpu
|
||||
* @brief Convert 24-bit integer from little-endian to host endianness.
|
||||
*
|
||||
* @param val 24-bit integer in little-endian format.
|
||||
*
|
||||
* @return 24-bit integer in host endianness.
|
||||
*/
|
||||
|
||||
/** @def sys_cpu_to_le24
|
||||
* @brief Convert 24-bit integer from host endianness to little-endian.
|
||||
*
|
||||
* @param val 24-bit integer in host endianness.
|
||||
*
|
||||
* @return 24-bit integer in little-endian format.
|
||||
*/
|
||||
|
||||
/** @def sys_le32_to_cpu
|
||||
* @brief Convert 32-bit integer from little-endian to host endianness.
|
||||
*
|
||||
* @param val 32-bit integer in little-endian format.
|
||||
*
|
||||
* @return 32-bit integer in host endianness.
|
||||
*/
|
||||
|
||||
/** @def sys_cpu_to_le32
|
||||
* @brief Convert 32-bit integer from host endianness to little-endian.
|
||||
*
|
||||
* @param val 32-bit integer in host endianness.
|
||||
*
|
||||
* @return 32-bit integer in little-endian format.
|
||||
*/
|
||||
|
||||
/** @def sys_le48_to_cpu
|
||||
* @brief Convert 48-bit integer from little-endian to host endianness.
|
||||
*
|
||||
* @param val 48-bit integer in little-endian format.
|
||||
*
|
||||
* @return 48-bit integer in host endianness.
|
||||
*/
|
||||
|
||||
/** @def sys_cpu_to_le48
|
||||
* @brief Convert 48-bit integer from host endianness to little-endian.
|
||||
*
|
||||
* @param val 48-bit integer in host endianness.
|
||||
*
|
||||
* @return 48-bit integer in little-endian format.
|
||||
*/
|
||||
|
||||
/** @def sys_be16_to_cpu
|
||||
* @brief Convert 16-bit integer from big-endian to host endianness.
|
||||
*
|
||||
* @param val 16-bit integer in big-endian format.
|
||||
*
|
||||
* @return 16-bit integer in host endianness.
|
||||
*/
|
||||
|
||||
/** @def sys_cpu_to_be16
|
||||
* @brief Convert 16-bit integer from host endianness to big-endian.
|
||||
*
|
||||
* @param val 16-bit integer in host endianness.
|
||||
*
|
||||
* @return 16-bit integer in big-endian format.
|
||||
*/
|
||||
|
||||
/** @def sys_be24_to_cpu
|
||||
* @brief Convert 24-bit integer from big-endian to host endianness.
|
||||
*
|
||||
* @param val 24-bit integer in big-endian format.
|
||||
*
|
||||
* @return 24-bit integer in host endianness.
|
||||
*/
|
||||
|
||||
/** @def sys_cpu_to_be24
|
||||
* @brief Convert 24-bit integer from host endianness to big-endian.
|
||||
*
|
||||
* @param val 24-bit integer in host endianness.
|
||||
*
|
||||
* @return 24-bit integer in big-endian format.
|
||||
*/
|
||||
|
||||
/** @def sys_be32_to_cpu
|
||||
* @brief Convert 32-bit integer from big-endian to host endianness.
|
||||
*
|
||||
* @param val 32-bit integer in big-endian format.
|
||||
*
|
||||
* @return 32-bit integer in host endianness.
|
||||
*/
|
||||
|
||||
/** @def sys_cpu_to_be32
|
||||
* @brief Convert 32-bit integer from host endianness to big-endian.
|
||||
*
|
||||
* @param val 32-bit integer in host endianness.
|
||||
*
|
||||
* @return 32-bit integer in big-endian format.
|
||||
*/
|
||||
|
||||
/** @def sys_be48_to_cpu
|
||||
* @brief Convert 48-bit integer from big-endian to host endianness.
|
||||
*
|
||||
* @param val 48-bit integer in big-endian format.
|
||||
*
|
||||
* @return 48-bit integer in host endianness.
|
||||
*/
|
||||
|
||||
/** @def sys_cpu_to_be48
|
||||
* @brief Convert 48-bit integer from host endianness to big-endian.
|
||||
*
|
||||
* @param val 48-bit integer in host endianness.
|
||||
*
|
||||
* @return 48-bit integer in big-endian format.
|
||||
*/
|
||||
|
||||
/** @def sys_uint16_to_array
|
||||
* @brief Convert 16-bit unsigned integer to byte array.
|
||||
*
|
||||
* @details Byte order aware macro to treat an unsigned integer
|
||||
* as an array, rather than an integer literal. For example,
|
||||
* `0x0123` would be converted to `{0x01, 0x23}` for big endian
|
||||
* machines, and `{0x23, 0x01}` for little endian machines.
|
||||
*
|
||||
* @param val 16-bit unsigned integer.
|
||||
*
|
||||
* @return 16-bit unsigned integer as byte array.
|
||||
*/
|
||||
|
||||
/** @def sys_uint32_to_array
|
||||
* @brief Convert 32-bit unsigned integer to byte array.
|
||||
*
|
||||
* @details Byte order aware macro to treat an unsigned integer
|
||||
* as an array, rather than an integer literal. For example,
|
||||
* `0x01234567` would be converted to `{0x01, 0x23, 0x45, 0x67}`
|
||||
* for big endian machines, and `{0x67, 0x45, 0x23, 0x01}` for
|
||||
* little endian machines.
|
||||
*
|
||||
* @param val 32-bit unsigned integer.
|
||||
*
|
||||
* @return 32-bit unsigned integer as byte array.
|
||||
*/
|
||||
|
||||
/** @def sys_uint64_to_array
|
||||
* @brief Convert 64-bit unsigned integer to byte array.
|
||||
*
|
||||
* @details Byte order aware macro to treat an unsigned integer
|
||||
* as an array, rather than an integer literal. For example,
|
||||
* `0x0123456789abcdef` would be converted to
|
||||
* `{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef}`
|
||||
* for big endian machines, and
|
||||
* `{0xef, 0xcd, 0xab, 0x89, 0x67, 0x45, 0x23, 0x01}` for
|
||||
* little endian machines.
|
||||
*
|
||||
* @param val 64-bit unsigned integer.
|
||||
*
|
||||
* @return 64-bit unsigned integer as byte array.
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_LITTLE_ENDIAN
|
||||
#define sys_le16_to_cpu(val) (val)
|
||||
#define sys_cpu_to_le16(val) (val)
|
||||
#define sys_le24_to_cpu(val) (val)
|
||||
#define sys_cpu_to_le24(val) (val)
|
||||
#define sys_le32_to_cpu(val) (val)
|
||||
#define sys_cpu_to_le32(val) (val)
|
||||
#define sys_le40_to_cpu(val) (val)
|
||||
#define sys_cpu_to_le40(val) (val)
|
||||
#define sys_le48_to_cpu(val) (val)
|
||||
#define sys_cpu_to_le48(val) (val)
|
||||
#define sys_le64_to_cpu(val) (val)
|
||||
#define sys_cpu_to_le64(val) (val)
|
||||
#define sys_be16_to_cpu(val) BSWAP_16(val)
|
||||
#define sys_cpu_to_be16(val) BSWAP_16(val)
|
||||
#define sys_be24_to_cpu(val) BSWAP_24(val)
|
||||
#define sys_cpu_to_be24(val) BSWAP_24(val)
|
||||
#define sys_be32_to_cpu(val) BSWAP_32(val)
|
||||
#define sys_cpu_to_be32(val) BSWAP_32(val)
|
||||
#define sys_be40_to_cpu(val) BSWAP_40(val)
|
||||
#define sys_cpu_to_be40(val) BSWAP_40(val)
|
||||
#define sys_be48_to_cpu(val) BSWAP_48(val)
|
||||
#define sys_cpu_to_be48(val) BSWAP_48(val)
|
||||
#define sys_be64_to_cpu(val) BSWAP_64(val)
|
||||
#define sys_cpu_to_be64(val) BSWAP_64(val)
|
||||
|
||||
#define sys_uint16_to_array(val) { \
|
||||
((val) & 0xff), \
|
||||
(((val) >> 8) & 0xff)}
|
||||
|
||||
#define sys_uint32_to_array(val) { \
|
||||
((val) & 0xff), \
|
||||
(((val) >> 8) & 0xff), \
|
||||
(((val) >> 16) & 0xff), \
|
||||
(((val) >> 24) & 0xff)}
|
||||
|
||||
#define sys_uint64_to_array(val) { \
|
||||
((val) & 0xff), \
|
||||
(((val) >> 8) & 0xff), \
|
||||
(((val) >> 16) & 0xff), \
|
||||
(((val) >> 24) & 0xff), \
|
||||
(((val) >> 32) & 0xff), \
|
||||
(((val) >> 40) & 0xff), \
|
||||
(((val) >> 48) & 0xff), \
|
||||
(((val) >> 56) & 0xff)}
|
||||
|
||||
#else
|
||||
#define sys_le16_to_cpu(val) BSWAP_16(val)
|
||||
#define sys_cpu_to_le16(val) BSWAP_16(val)
|
||||
#define sys_le24_to_cpu(val) BSWAP_24(val)
|
||||
#define sys_cpu_to_le24(val) BSWAP_24(val)
|
||||
#define sys_le32_to_cpu(val) BSWAP_32(val)
|
||||
#define sys_cpu_to_le32(val) BSWAP_32(val)
|
||||
#define sys_le40_to_cpu(val) BSWAP_40(val)
|
||||
#define sys_cpu_to_le40(val) BSWAP_40(val)
|
||||
#define sys_le48_to_cpu(val) BSWAP_48(val)
|
||||
#define sys_cpu_to_le48(val) BSWAP_48(val)
|
||||
#define sys_le64_to_cpu(val) BSWAP_64(val)
|
||||
#define sys_cpu_to_le64(val) BSWAP_64(val)
|
||||
#define sys_be16_to_cpu(val) (val)
|
||||
#define sys_cpu_to_be16(val) (val)
|
||||
#define sys_be24_to_cpu(val) (val)
|
||||
#define sys_cpu_to_be24(val) (val)
|
||||
#define sys_be32_to_cpu(val) (val)
|
||||
#define sys_cpu_to_be32(val) (val)
|
||||
#define sys_be40_to_cpu(val) (val)
|
||||
#define sys_cpu_to_be40(val) (val)
|
||||
#define sys_be48_to_cpu(val) (val)
|
||||
#define sys_cpu_to_be48(val) (val)
|
||||
#define sys_be64_to_cpu(val) (val)
|
||||
#define sys_cpu_to_be64(val) (val)
|
||||
|
||||
#define sys_uint16_to_array(val) { \
|
||||
(((val) >> 8) & 0xff), \
|
||||
((val) & 0xff)}
|
||||
|
||||
#define sys_uint32_to_array(val) { \
|
||||
(((val) >> 24) & 0xff), \
|
||||
(((val) >> 16) & 0xff), \
|
||||
(((val) >> 8) & 0xff), \
|
||||
((val) & 0xff)}
|
||||
|
||||
#define sys_uint64_to_array(val) { \
|
||||
(((val) >> 56) & 0xff), \
|
||||
(((val) >> 48) & 0xff), \
|
||||
(((val) >> 40) & 0xff), \
|
||||
(((val) >> 32) & 0xff), \
|
||||
(((val) >> 24) & 0xff), \
|
||||
(((val) >> 16) & 0xff), \
|
||||
(((val) >> 8) & 0xff), \
|
||||
((val) & 0xff)}
|
||||
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Put a 16-bit integer as big-endian to arbitrary location.
|
||||
*
|
||||
* Put a 16-bit integer, originally in host endianness, to a
|
||||
* potentially unaligned memory location in big-endian format.
|
||||
*
|
||||
* @param val 16-bit integer in host endianness.
|
||||
* @param dst Destination memory address to store the result.
|
||||
*/
|
||||
static inline void sys_put_be16(uint16_t val, uint8_t dst[2])
|
||||
{
|
||||
dst[0] = val >> 8;
|
||||
dst[1] = val;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Put a 24-bit integer as big-endian to arbitrary location.
|
||||
*
|
||||
* Put a 24-bit integer, originally in host endianness, to a
|
||||
* potentially unaligned memory location in big-endian format.
|
||||
*
|
||||
* @param val 24-bit integer in host endianness.
|
||||
* @param dst Destination memory address to store the result.
|
||||
*/
|
||||
static inline void sys_put_be24(uint32_t val, uint8_t dst[3])
|
||||
{
|
||||
dst[0] = val >> 16;
|
||||
sys_put_be16(val, &dst[1]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Put a 32-bit integer as big-endian to arbitrary location.
|
||||
*
|
||||
* Put a 32-bit integer, originally in host endianness, to a
|
||||
* potentially unaligned memory location in big-endian format.
|
||||
*
|
||||
* @param val 32-bit integer in host endianness.
|
||||
* @param dst Destination memory address to store the result.
|
||||
*/
|
||||
static inline void sys_put_be32(uint32_t val, uint8_t dst[4])
|
||||
{
|
||||
sys_put_be16(val >> 16, dst);
|
||||
sys_put_be16(val, &dst[2]);
|
||||
}
|
||||
/**
|
||||
* @brief Put a 40-bit integer as big-endian to arbitrary location.
|
||||
*
|
||||
* Put a 40-bit integer, originally in host endianness, to a
|
||||
* potentially unaligned memory location in big-endian format.
|
||||
*
|
||||
* @param val 40-bit integer in host endianness.
|
||||
* @param dst Destination memory address to store the result.
|
||||
*/
|
||||
static inline void sys_put_be40(uint64_t val, uint8_t dst[5])
|
||||
{
|
||||
dst[0] = val >> 32;
|
||||
sys_put_be32(val, &dst[1]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Put a 48-bit integer as big-endian to arbitrary location.
|
||||
*
|
||||
* Put a 48-bit integer, originally in host endianness, to a
|
||||
* potentially unaligned memory location in big-endian format.
|
||||
*
|
||||
* @param val 48-bit integer in host endianness.
|
||||
* @param dst Destination memory address to store the result.
|
||||
*/
|
||||
static inline void sys_put_be48(uint64_t val, uint8_t dst[6])
|
||||
{
|
||||
sys_put_be16(val >> 32, dst);
|
||||
sys_put_be32(val, &dst[2]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Put a 64-bit integer as big-endian to arbitrary location.
|
||||
*
|
||||
* Put a 64-bit integer, originally in host endianness, to a
|
||||
* potentially unaligned memory location in big-endian format.
|
||||
*
|
||||
* @param val 64-bit integer in host endianness.
|
||||
* @param dst Destination memory address to store the result.
|
||||
*/
|
||||
static inline void sys_put_be64(uint64_t val, uint8_t dst[8])
|
||||
{
|
||||
sys_put_be32(val >> 32, dst);
|
||||
sys_put_be32(val, &dst[4]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Put a 16-bit integer as little-endian to arbitrary location.
|
||||
*
|
||||
* Put a 16-bit integer, originally in host endianness, to a
|
||||
* potentially unaligned memory location in little-endian format.
|
||||
*
|
||||
* @param val 16-bit integer in host endianness.
|
||||
* @param dst Destination memory address to store the result.
|
||||
*/
|
||||
static inline void sys_put_le16(uint16_t val, uint8_t dst[2])
|
||||
{
|
||||
dst[0] = val;
|
||||
dst[1] = val >> 8;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Put a 24-bit integer as little-endian to arbitrary location.
|
||||
*
|
||||
* Put a 24-bit integer, originally in host endianness, to a
|
||||
* potentially unaligned memory location in little-endian format.
|
||||
*
|
||||
* @param val 24-bit integer in host endianness.
|
||||
* @param dst Destination memory address to store the result.
|
||||
*/
|
||||
static inline void sys_put_le24(uint32_t val, uint8_t dst[3])
|
||||
{
|
||||
sys_put_le16(val, dst);
|
||||
dst[2] = val >> 16;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Put a 32-bit integer as little-endian to arbitrary location.
|
||||
*
|
||||
* Put a 32-bit integer, originally in host endianness, to a
|
||||
* potentially unaligned memory location in little-endian format.
|
||||
*
|
||||
* @param val 32-bit integer in host endianness.
|
||||
* @param dst Destination memory address to store the result.
|
||||
*/
|
||||
static inline void sys_put_le32(uint32_t val, uint8_t dst[4])
|
||||
{
|
||||
sys_put_le16(val, dst);
|
||||
sys_put_le16(val >> 16, &dst[2]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Put a 40-bit integer as little-endian to arbitrary location.
|
||||
*
|
||||
* Put a 40-bit integer, originally in host endianness, to a
|
||||
* potentially unaligned memory location in little-endian format.
|
||||
*
|
||||
* @param val 40-bit integer in host endianness.
|
||||
* @param dst Destination memory address to store the result.
|
||||
*/
|
||||
static inline void sys_put_le40(uint64_t val, uint8_t dst[5])
|
||||
{
|
||||
sys_put_le32(val, dst);
|
||||
dst[4] = val >> 32;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Put a 48-bit integer as little-endian to arbitrary location.
|
||||
*
|
||||
* Put a 48-bit integer, originally in host endianness, to a
|
||||
* potentially unaligned memory location in little-endian format.
|
||||
*
|
||||
* @param val 48-bit integer in host endianness.
|
||||
* @param dst Destination memory address to store the result.
|
||||
*/
|
||||
static inline void sys_put_le48(uint64_t val, uint8_t dst[6])
|
||||
{
|
||||
sys_put_le32(val, dst);
|
||||
sys_put_le16(val >> 32, &dst[4]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Put a 64-bit integer as little-endian to arbitrary location.
|
||||
*
|
||||
* Put a 64-bit integer, originally in host endianness, to a
|
||||
* potentially unaligned memory location in little-endian format.
|
||||
*
|
||||
* @param val 64-bit integer in host endianness.
|
||||
* @param dst Destination memory address to store the result.
|
||||
*/
|
||||
static inline void sys_put_le64(uint64_t val, uint8_t dst[8])
|
||||
{
|
||||
sys_put_le32(val, dst);
|
||||
sys_put_le32(val >> 32, &dst[4]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get a 16-bit integer stored in big-endian format.
|
||||
*
|
||||
* Get a 16-bit integer, stored in big-endian format in a potentially
|
||||
* unaligned memory location, and convert it to the host endianness.
|
||||
*
|
||||
* @param src Location of the big-endian 16-bit integer to get.
|
||||
*
|
||||
* @return 16-bit integer in host endianness.
|
||||
*/
|
||||
static inline uint16_t sys_get_be16(const uint8_t src[2])
|
||||
{
|
||||
return ((uint16_t)src[0] << 8) | src[1];
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get a 24-bit integer stored in big-endian format.
|
||||
*
|
||||
* Get a 24-bit integer, stored in big-endian format in a potentially
|
||||
* unaligned memory location, and convert it to the host endianness.
|
||||
*
|
||||
* @param src Location of the big-endian 24-bit integer to get.
|
||||
*
|
||||
* @return 24-bit integer in host endianness.
|
||||
*/
|
||||
static inline uint32_t sys_get_be24(const uint8_t src[3])
|
||||
{
|
||||
return ((uint32_t)src[0] << 16) | sys_get_be16(&src[1]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get a 32-bit integer stored in big-endian format.
|
||||
*
|
||||
* Get a 32-bit integer, stored in big-endian format in a potentially
|
||||
* unaligned memory location, and convert it to the host endianness.
|
||||
*
|
||||
* @param src Location of the big-endian 32-bit integer to get.
|
||||
*
|
||||
* @return 32-bit integer in host endianness.
|
||||
*/
|
||||
static inline uint32_t sys_get_be32(const uint8_t src[4])
|
||||
{
|
||||
return ((uint32_t)sys_get_be16(&src[0]) << 16) | sys_get_be16(&src[2]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get a 40-bit integer stored in big-endian format.
|
||||
*
|
||||
* Get a 40-bit integer, stored in big-endian format in a potentially
|
||||
* unaligned memory location, and convert it to the host endianness.
|
||||
*
|
||||
* @param src Location of the big-endian 40-bit integer to get.
|
||||
*
|
||||
* @return 40-bit integer in host endianness.
|
||||
*/
|
||||
static inline uint64_t sys_get_be40(const uint8_t src[5])
|
||||
{
|
||||
return ((uint64_t)sys_get_be32(&src[0]) << 8) | src[4];
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get a 48-bit integer stored in big-endian format.
|
||||
*
|
||||
* Get a 48-bit integer, stored in big-endian format in a potentially
|
||||
* unaligned memory location, and convert it to the host endianness.
|
||||
*
|
||||
* @param src Location of the big-endian 48-bit integer to get.
|
||||
*
|
||||
* @return 48-bit integer in host endianness.
|
||||
*/
|
||||
static inline uint64_t sys_get_be48(const uint8_t src[6])
|
||||
{
|
||||
return ((uint64_t)sys_get_be32(&src[0]) << 16) | sys_get_be16(&src[4]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get a 64-bit integer stored in big-endian format.
|
||||
*
|
||||
* Get a 64-bit integer, stored in big-endian format in a potentially
|
||||
* unaligned memory location, and convert it to the host endianness.
|
||||
*
|
||||
* @param src Location of the big-endian 64-bit integer to get.
|
||||
*
|
||||
* @return 64-bit integer in host endianness.
|
||||
*/
|
||||
static inline uint64_t sys_get_be64(const uint8_t src[8])
|
||||
{
|
||||
return ((uint64_t)sys_get_be32(&src[0]) << 32) | sys_get_be32(&src[4]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get a 16-bit integer stored in little-endian format.
|
||||
*
|
||||
* Get a 16-bit integer, stored in little-endian format in a potentially
|
||||
* unaligned memory location, and convert it to the host endianness.
|
||||
*
|
||||
* @param src Location of the little-endian 16-bit integer to get.
|
||||
*
|
||||
* @return 16-bit integer in host endianness.
|
||||
*/
|
||||
static inline uint16_t sys_get_le16(const uint8_t src[2])
|
||||
{
|
||||
return ((uint16_t)src[1] << 8) | src[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get a 24-bit integer stored in little-endian format.
|
||||
*
|
||||
* Get a 24-bit integer, stored in little-endian format in a potentially
|
||||
* unaligned memory location, and convert it to the host endianness.
|
||||
*
|
||||
* @param src Location of the little-endian 24-bit integer to get.
|
||||
*
|
||||
* @return 24-bit integer in host endianness.
|
||||
*/
|
||||
static inline uint32_t sys_get_le24(const uint8_t src[3])
|
||||
{
|
||||
return ((uint32_t)src[2] << 16) | sys_get_le16(&src[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get a 32-bit integer stored in little-endian format.
|
||||
*
|
||||
* Get a 32-bit integer, stored in little-endian format in a potentially
|
||||
* unaligned memory location, and convert it to the host endianness.
|
||||
*
|
||||
* @param src Location of the little-endian 32-bit integer to get.
|
||||
*
|
||||
* @return 32-bit integer in host endianness.
|
||||
*/
|
||||
static inline uint32_t sys_get_le32(const uint8_t src[4])
|
||||
{
|
||||
return ((uint32_t)sys_get_le16(&src[2]) << 16) | sys_get_le16(&src[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get a 40-bit integer stored in little-endian format.
|
||||
*
|
||||
* Get a 40-bit integer, stored in little-endian format in a potentially
|
||||
* unaligned memory location, and convert it to the host endianness.
|
||||
*
|
||||
* @param src Location of the little-endian 40-bit integer to get.
|
||||
*
|
||||
* @return 40-bit integer in host endianness.
|
||||
*/
|
||||
static inline uint64_t sys_get_le40(const uint8_t src[5])
|
||||
{
|
||||
return ((uint64_t)sys_get_le32(&src[1]) << 8) | src[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get a 48-bit integer stored in little-endian format.
|
||||
*
|
||||
* Get a 48-bit integer, stored in little-endian format in a potentially
|
||||
* unaligned memory location, and convert it to the host endianness.
|
||||
*
|
||||
* @param src Location of the little-endian 48-bit integer to get.
|
||||
*
|
||||
* @return 48-bit integer in host endianness.
|
||||
*/
|
||||
static inline uint64_t sys_get_le48(const uint8_t src[6])
|
||||
{
|
||||
return ((uint64_t)sys_get_le32(&src[2]) << 16) | sys_get_le16(&src[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get a 64-bit integer stored in little-endian format.
|
||||
*
|
||||
* Get a 64-bit integer, stored in little-endian format in a potentially
|
||||
* unaligned memory location, and convert it to the host endianness.
|
||||
*
|
||||
* @param src Location of the little-endian 64-bit integer to get.
|
||||
*
|
||||
* @return 64-bit integer in host endianness.
|
||||
*/
|
||||
static inline uint64_t sys_get_le64(const uint8_t src[8])
|
||||
{
|
||||
return ((uint64_t)sys_get_le32(&src[4]) << 32) | sys_get_le32(&src[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Swap one buffer content into another
|
||||
*
|
||||
* Copy the content of src buffer into dst buffer in reversed order,
|
||||
* i.e.: src[n] will be put in dst[end-n]
|
||||
* Where n is an index and 'end' the last index in both arrays.
|
||||
* The 2 memory pointers must be pointing to different areas, and have
|
||||
* a minimum size of given length.
|
||||
*
|
||||
* @param dst A valid pointer on a memory area where to copy the data in
|
||||
* @param src A valid pointer on a memory area where to copy the data from
|
||||
* @param length Size of both dst and src memory areas
|
||||
*/
|
||||
static inline void sys_memcpy_swap(void *dst, const void *src, size_t length)
|
||||
{
|
||||
uint8_t *pdst = (uint8_t *)dst;
|
||||
const uint8_t *psrc = (const uint8_t *)src;
|
||||
|
||||
__ASSERT(((psrc < pdst && (psrc + length) <= pdst) ||
|
||||
(psrc > pdst && (pdst + length) <= psrc)),
|
||||
"Source and destination buffers must not overlap");
|
||||
|
||||
psrc += length - 1;
|
||||
|
||||
for (; length > 0; length--) {
|
||||
*pdst++ = *psrc--;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Swap buffer content
|
||||
*
|
||||
* In-place memory swap, where final content will be reversed.
|
||||
* I.e.: buf[n] will be put in buf[end-n]
|
||||
* Where n is an index and 'end' the last index of buf.
|
||||
*
|
||||
* @param buf A valid pointer on a memory area to swap
|
||||
* @param length Size of buf memory area
|
||||
*/
|
||||
static inline void sys_mem_swap(void *buf, size_t length)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < (length / 2); i++) {
|
||||
uint8_t tmp = ((uint8_t *)buf)[i];
|
||||
|
||||
((uint8_t *)buf)[i] = ((uint8_t *)buf)[length - 1 - i];
|
||||
((uint8_t *)buf)[length - 1 - i] = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Convert buffer from little-endian to host endianness.
|
||||
*
|
||||
* @param buf A valid pointer on a memory area to convert from little-endian to host endianness.
|
||||
* @param length Size of buf memory area
|
||||
*/
|
||||
static inline void sys_le_to_cpu(void *buf, size_t length)
|
||||
{
|
||||
if (IS_ENABLED(CONFIG_BIG_ENDIAN)) {
|
||||
sys_mem_swap(buf, length);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Convert buffer from host endianness to little-endian.
|
||||
*
|
||||
* @param buf A valid pointer on a memory area to convert from host endianness to little-endian.
|
||||
* @param length Size of buf memory area
|
||||
*/
|
||||
static inline void sys_cpu_to_le(void *buf, size_t length)
|
||||
{
|
||||
if (IS_ENABLED(CONFIG_BIG_ENDIAN)) {
|
||||
sys_mem_swap(buf, length);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Convert buffer from big-endian to host endianness.
|
||||
*
|
||||
* @param buf A valid pointer on a memory area to convert from big-endian to host endianness.
|
||||
* @param length Size of buf memory area
|
||||
*/
|
||||
static inline void sys_be_to_cpu(void *buf, size_t length)
|
||||
{
|
||||
if (IS_ENABLED(CONFIG_LITTLE_ENDIAN)) {
|
||||
sys_mem_swap(buf, length);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Convert buffer from host endianness to big-endian.
|
||||
*
|
||||
* @param buf A valid pointer on a memory area to convert from host endianness to big-endian.
|
||||
* @param length Size of buf memory area
|
||||
*/
|
||||
static inline void sys_cpu_to_be(void *buf, size_t length)
|
||||
{
|
||||
if (IS_ENABLED(CONFIG_LITTLE_ENDIAN)) {
|
||||
sys_mem_swap(buf, length);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Put a buffer as little-endian to arbitrary location.
|
||||
*
|
||||
* Put a buffer originally in host endianness, to a
|
||||
* potentially unaligned memory location in little-endian format.
|
||||
*
|
||||
* @param dst A valid pointer on a memory area where to copy the data in
|
||||
* @param src A valid pointer on a memory area where to copy the data from
|
||||
* @param length Size of both dst and src memory areas
|
||||
*/
|
||||
static inline void sys_put_le(void *dst, const void *src, size_t length)
|
||||
{
|
||||
if (IS_ENABLED(CONFIG_LITTLE_ENDIAN)) {
|
||||
(void)memcpy(dst, src, length);
|
||||
} else {
|
||||
sys_memcpy_swap(dst, src, length);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Put a buffer as big-endian to arbitrary location.
|
||||
*
|
||||
* Put a buffer originally in host endianness, to a
|
||||
* potentially unaligned memory location in big-endian format.
|
||||
*
|
||||
* @param dst A valid pointer on a memory area where to copy the data in
|
||||
* @param src A valid pointer on a memory area where to copy the data from
|
||||
* @param length Size of both dst and src memory areas
|
||||
*/
|
||||
static inline void sys_put_be(void *dst, const void *src, size_t length)
|
||||
{
|
||||
if (IS_ENABLED(CONFIG_LITTLE_ENDIAN)) {
|
||||
sys_memcpy_swap(dst, src, length);
|
||||
} else {
|
||||
(void)memcpy(dst, src, length);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get a buffer stored in little-endian format.
|
||||
*
|
||||
* Get a buffer, stored in little-endian format in a potentially
|
||||
* unaligned memory location, and convert it to the host endianness.
|
||||
*
|
||||
* @param dst A valid pointer on a memory area where to copy the data in
|
||||
* @param src A valid pointer on a memory area where to copy the data from
|
||||
* @param length Size of both dst and src memory areas
|
||||
*/
|
||||
static inline void sys_get_le(void *dst, const void *src, size_t length)
|
||||
{
|
||||
if (IS_ENABLED(CONFIG_LITTLE_ENDIAN)) {
|
||||
(void)memcpy(dst, src, length);
|
||||
} else {
|
||||
sys_memcpy_swap(dst, src, length);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get a buffer stored in big-endian format.
|
||||
*
|
||||
* Get a buffer, stored in big-endian format in a potentially
|
||||
* unaligned memory location, and convert it to the host endianness.
|
||||
*
|
||||
* @param dst A valid pointer on a memory area where to copy the data in
|
||||
* @param src A valid pointer on a memory area where to copy the data from
|
||||
* @param length Size of both dst and src memory areas
|
||||
*/
|
||||
static inline void sys_get_be(void *dst, const void *src, size_t length)
|
||||
{
|
||||
if (IS_ENABLED(CONFIG_LITTLE_ENDIAN)) {
|
||||
sys_memcpy_swap(dst, src, length);
|
||||
} else {
|
||||
(void)memcpy(dst, src, length);
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* ZEPHYR_INCLUDE_SYS_BYTEORDER_H_ */
|
||||
@@ -0,0 +1,9 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2019 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#define CHECKIF(expr) if (expr)
|
||||
@@ -0,0 +1,531 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2018 Workaround GmbH.
|
||||
* SPDX-FileCopyrightText: 2017 Intel Corporation.
|
||||
* SPDX-FileCopyrightText: 2017 Nordic Semiconductor ASA
|
||||
* SPDX-FileCopyrightText: 2015 Runtime Inc
|
||||
* SPDX-FileCopyrightText: 2018 Google LLC.
|
||||
* SPDX-FileCopyrightText: 2022 Meta
|
||||
* SPDX-FileCopyrightText: 2024 Intercreate, Inc.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
/** @file
|
||||
* @brief CRC computation function
|
||||
*/
|
||||
|
||||
#ifndef ZEPHYR_INCLUDE_SYS_CRC_H_
|
||||
#define ZEPHYR_INCLUDE_SYS_CRC_H_
|
||||
|
||||
#include <zephyr/types.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#include <zephyr/sys/__assert.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Initial value expected to be used at the beginning of the crc8_ccitt
|
||||
* computation.
|
||||
*/
|
||||
#define CRC8_CCITT_INITIAL_VALUE 0xFF
|
||||
#define CRC8_ROHC_INITIAL_VALUE 0xFF
|
||||
|
||||
/* Initial value expected to be used at the beginning of the OpenPGP CRC-24 computation. */
|
||||
#define CRC24_PGP_INITIAL_VALUE 0x00B704CEU
|
||||
/*
|
||||
* The CRC-24 value is stored on a 32-bit value, only the 3 least significant bytes
|
||||
* are meaningful. Use the following mask to only keep the CRC-24 value.
|
||||
*/
|
||||
#define CRC24_FINAL_VALUE_MASK 0x00FFFFFFU
|
||||
|
||||
/**
|
||||
* @defgroup checksum Checksum
|
||||
* @ingroup os_services
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup crc CRC
|
||||
* @ingroup checksum
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief CRC polynomial definitions
|
||||
* @anchor CRC_POLYNOMIAL
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** CRC4 polynomial */
|
||||
#define CRC4_POLY 0x3
|
||||
|
||||
/** CRC4_TI polynomial */
|
||||
#define CRC4_REFLECT_POLY 0xC
|
||||
|
||||
/** CRC7_BE polynomial */
|
||||
#define CRC7_BE_POLY 0x09
|
||||
|
||||
/** CRC8 polynomial */
|
||||
#define CRC8_POLY 0x07
|
||||
|
||||
/** CRC8_CCITT polynomial */
|
||||
#define CRC8_REFLECT_POLY 0xE0
|
||||
|
||||
/** CRC8_ROHC polynomial */
|
||||
#define CRC16_POLY 0x8005
|
||||
|
||||
/** CRC16_ANSI polynomial */
|
||||
#define CRC16_REFLECT_POLY 0xA001
|
||||
|
||||
/** CRC16_CCITT polynomial */
|
||||
#define CRC16_CCITT_POLY 0x1021
|
||||
|
||||
/** CRC16_ITU_T polynomial */
|
||||
#define CRC24_PGP_POLY 0x01864CFBU
|
||||
|
||||
/** CRC32_C polynomial */
|
||||
#define CRC32_IEEE_POLY 0x04C11DB7U
|
||||
|
||||
/** CRC32C polynomial */
|
||||
#define CRC32C_POLY 0x1EDC6F41U
|
||||
|
||||
/** CRC32_K_4_2 polynomial */
|
||||
#define CRC32K_4_2_POLY 0x93A409EBU
|
||||
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @brief CRC algorithm enumeration
|
||||
*
|
||||
* These values should be used with the @ref crc dispatch function.
|
||||
*/
|
||||
enum crc_type {
|
||||
CRC4, /**< Use @ref crc4 */
|
||||
CRC4_TI, /**< Use @ref crc4_ti */
|
||||
CRC7_BE, /**< Use @ref crc7_be */
|
||||
CRC8, /**< Use @ref crc8 */
|
||||
CRC8_CCITT, /**< Use @ref crc8_ccitt */
|
||||
CRC8_ROHC, /**< Use @ref crc8_rohc */
|
||||
CRC16, /**< Use @ref crc16 */
|
||||
CRC16_ANSI, /**< Use @ref crc16_ansi */
|
||||
CRC16_CCITT, /**< Use @ref crc16_ccitt */
|
||||
CRC16_ITU_T, /**< Use @ref crc16_itu_t */
|
||||
CRC24_PGP, /**< Use @ref crc24_pgp */
|
||||
CRC32_C, /**< Use @ref crc32_c */
|
||||
CRC32_IEEE, /**< Use @ref crc32_ieee */
|
||||
CRC32_K_4_2, /**< Use @ref crc32_k_4_2_update */
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Generic function for computing a CRC-16 without input or output
|
||||
* reflection.
|
||||
*
|
||||
* Compute CRC-16 by passing in the address of the input, the input length
|
||||
* and polynomial used in addition to the initial value. This is O(n*8) where n
|
||||
* is the length of the buffer provided. No reflection is performed.
|
||||
*
|
||||
* @note If you are planning to use a CRC based on poly 0x1012 the functions
|
||||
* crc16_itu_t() is faster and thus recommended over this one.
|
||||
*
|
||||
* @param poly The polynomial to use omitting the leading x^16
|
||||
* coefficient
|
||||
* @param seed Initial value for the CRC computation
|
||||
* @param src Input bytes for the computation
|
||||
* @param len Length of the input in bytes
|
||||
*
|
||||
* @return The computed CRC16 value (without any XOR applied to it)
|
||||
*/
|
||||
uint16_t crc16(uint16_t poly, uint16_t seed, const uint8_t *src, size_t len);
|
||||
|
||||
/**
|
||||
* @brief Generic function for computing a CRC-16 with input and output
|
||||
* reflection.
|
||||
*
|
||||
* Compute CRC-16 by passing in the address of the input, the input length
|
||||
* and polynomial used in addition to the initial value. This is O(n*8) where n
|
||||
* is the length of the buffer provided. Both input and output are reflected.
|
||||
*
|
||||
* @note If you are planning to use a CRC based on poly 0x1012 the function
|
||||
* crc16_ccitt() is faster and thus recommended over this one.
|
||||
*
|
||||
* The following checksums can, among others, be calculated by this function,
|
||||
* depending on the value provided for the initial seed and the value the final
|
||||
* calculated CRC is XORed with:
|
||||
*
|
||||
* - CRC-16/ANSI, CRC-16/MODBUS, CRC-16/USB, CRC-16/IBM
|
||||
* https://reveng.sourceforge.io/crc-catalogue/16.htm#crc.cat.crc-16-modbus
|
||||
* poly: 0x8005 (0xA001) initial seed: 0xffff, xor output: 0x0000
|
||||
*
|
||||
* @param poly The polynomial to use omitting the leading x^16
|
||||
* coefficient. Important: please reflect the poly. For example,
|
||||
* use 0xA001 instead of 0x8005 for CRC-16-MODBUS.
|
||||
* @param seed Initial value for the CRC computation
|
||||
* @param src Input bytes for the computation
|
||||
* @param len Length of the input in bytes
|
||||
*
|
||||
* @return The computed CRC16 value (without any XOR applied to it)
|
||||
*/
|
||||
uint16_t crc16_reflect(uint16_t poly, uint16_t seed, const uint8_t *src, size_t len);
|
||||
/**
|
||||
* @brief Generic function for computing CRC 8
|
||||
*
|
||||
* Compute CRC 8 by passing in the address of the input, the input length
|
||||
* and polynomial used in addition to the initial value.
|
||||
*
|
||||
* @param src Input bytes for the computation
|
||||
* @param len Length of the input in bytes
|
||||
* @param polynomial The polynomial to use omitting the leading x^8
|
||||
* coefficient
|
||||
* @param initial_value Initial value for the CRC computation
|
||||
* @param reversed Should we use reflected/reversed values or not
|
||||
*
|
||||
* @return The computed CRC8 value
|
||||
*/
|
||||
uint8_t crc8(const uint8_t *src, size_t len, uint8_t polynomial, uint8_t initial_value,
|
||||
bool reversed);
|
||||
|
||||
/**
|
||||
* @brief Compute the checksum of a buffer with polynomial 0x1021, reflecting
|
||||
* input and output.
|
||||
*
|
||||
* This function is able to calculate any CRC that uses 0x1021 as it polynomial
|
||||
* and requires reflecting both the input and the output. It is a fast variant
|
||||
* that runs in O(n) time, where n is the length of the input buffer.
|
||||
*
|
||||
* The following checksums can, among others, be calculated by this function,
|
||||
* depending on the value provided for the initial seed and the value the final
|
||||
* calculated CRC is XORed with:
|
||||
*
|
||||
* - CRC-16/CCITT, CRC-16/CCITT-TRUE, CRC-16/KERMIT
|
||||
* https://reveng.sourceforge.io/crc-catalogue/16.htm#crc.cat.crc-16-kermit
|
||||
* initial seed: 0x0000, xor output: 0x0000
|
||||
*
|
||||
* - CRC-16/X-25, CRC-16/IBM-SDLC, CRC-16/ISO-HDLC
|
||||
* https://reveng.sourceforge.io/crc-catalogue/16.htm#crc.cat.crc-16-ibm-sdlc
|
||||
* initial seed: 0xffff, xor output: 0xffff
|
||||
*
|
||||
* @note To calculate the CRC across non-contiguous blocks use the return
|
||||
* value from block N-1 as the seed for block N.
|
||||
*
|
||||
* See ITU-T Recommendation V.41 (November 1988).
|
||||
*
|
||||
* @param seed Value to seed the CRC with
|
||||
* @param src Input bytes for the computation
|
||||
* @param len Length of the input in bytes
|
||||
*
|
||||
* @return The computed CRC16 value (without any XOR applied to it)
|
||||
*/
|
||||
uint16_t crc16_ccitt(uint16_t seed, const uint8_t *src, size_t len);
|
||||
|
||||
/**
|
||||
* @brief Compute the checksum of a buffer with polynomial 0x1021, no
|
||||
* reflection of input or output.
|
||||
*
|
||||
* This function is able to calculate any CRC that uses 0x1021 as it polynomial
|
||||
* and requires no reflection on both the input and the output. It is a fast
|
||||
* variant that runs in O(n) time, where n is the length of the input buffer.
|
||||
*
|
||||
* The following checksums can, among others, be calculated by this function,
|
||||
* depending on the value provided for the initial seed and the value the final
|
||||
* calculated CRC is XORed with:
|
||||
*
|
||||
* - CRC-16/XMODEM, CRC-16/ACORN, CRC-16/LTE
|
||||
* https://reveng.sourceforge.io/crc-catalogue/16.htm#crc.cat.crc-16-xmodem
|
||||
* initial seed: 0x0000, xor output: 0x0000
|
||||
*
|
||||
* - CRC16/CCITT-FALSE, CRC-16/IBM-3740, CRC-16/AUTOSAR
|
||||
* https://reveng.sourceforge.io/crc-catalogue/16.htm#crc.cat.crc-16-ibm-3740
|
||||
* initial seed: 0xffff, xor output: 0x0000
|
||||
*
|
||||
* - CRC-16/GSM
|
||||
* https://reveng.sourceforge.io/crc-catalogue/16.htm#crc.cat.crc-16-gsm
|
||||
* initial seed: 0x0000, xor output: 0xffff
|
||||
*
|
||||
* @note To calculate the CRC across non-contiguous blocks use the return
|
||||
* value from block N-1 as the seed for block N.
|
||||
*
|
||||
* See ITU-T Recommendation V.41 (November 1988) (MSB first).
|
||||
*
|
||||
* @param seed Value to seed the CRC with
|
||||
* @param src Input bytes for the computation
|
||||
* @param len Length of the input in bytes
|
||||
*
|
||||
* @return The computed CRC16 value (without any XOR applied to it)
|
||||
*/
|
||||
uint16_t crc16_itu_t(uint16_t seed, const uint8_t *src, size_t len);
|
||||
|
||||
/**
|
||||
* @brief Compute the ANSI (or Modbus) variant of CRC-16
|
||||
*
|
||||
* The ANSI variant of CRC-16 uses 0x8005 (0xA001 reflected) as its polynomial
|
||||
* with the initial * value set to 0xffff.
|
||||
*
|
||||
* @param src Input bytes for the computation
|
||||
* @param len Length of the input in bytes
|
||||
*
|
||||
* @return The computed CRC16 value
|
||||
*/
|
||||
static inline uint16_t crc16_ansi(const uint8_t *src, size_t len)
|
||||
{
|
||||
return crc16_reflect(0xA001, 0xffff, src, len);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Generate IEEE conform CRC32 checksum.
|
||||
*
|
||||
* @param data Pointer to data on which the CRC should be calculated.
|
||||
* @param len Data length.
|
||||
*
|
||||
* @return CRC32 value.
|
||||
*
|
||||
*/
|
||||
uint32_t crc32_ieee(const uint8_t *data, size_t len);
|
||||
|
||||
/**
|
||||
* @brief Update an IEEE conforming CRC32 checksum.
|
||||
*
|
||||
* @param crc CRC32 checksum that needs to be updated.
|
||||
* @param data Pointer to data on which the CRC should be calculated.
|
||||
* @param len Data length.
|
||||
*
|
||||
* @return CRC32 value.
|
||||
*
|
||||
*/
|
||||
uint32_t crc32_ieee_update(uint32_t crc, const uint8_t *data, size_t len);
|
||||
|
||||
/**
|
||||
* @brief Calculate CRC32C (Castagnoli) checksum.
|
||||
*
|
||||
* @param crc CRC32C checksum that needs to be updated.
|
||||
* @param data Pointer to data on which the CRC should be calculated.
|
||||
* @param len Data length.
|
||||
* @param first_pkt Whether this is the first packet in the stream.
|
||||
* @param last_pkt Whether this is the last packet in the stream.
|
||||
*
|
||||
* @return CRC32 value.
|
||||
*
|
||||
*/
|
||||
uint32_t crc32_c(uint32_t crc, const uint8_t *data,
|
||||
size_t len, bool first_pkt, bool last_pkt);
|
||||
|
||||
/**
|
||||
* @brief Update a CRC-32K/4.2 (*op) (Koopman) checksum. This is a good HD=4
|
||||
* checksum up to 2,147,483,615 bits and HD=5/6 up to 6,167 bits.
|
||||
*
|
||||
* Hamming Distance and properties:
|
||||
*
|
||||
* - Polynomial: 0x93a409eb
|
||||
* - reflect-in: false
|
||||
* - initial value (xor-in): provided by caller as crc argument (0xFFFFFFFF is OK)
|
||||
* - reflect-out: false
|
||||
* - xor-out: 0
|
||||
* - HD=4 @ 2,147,483,615 bits
|
||||
* - HD=5 @ 6,167 bits
|
||||
* - HD=6 @ 6,167 bits
|
||||
* - HD=7 @ 148 bits
|
||||
*
|
||||
* Reference: https://users.ece.cmu.edu/~koopman/crc/crc32.html
|
||||
*
|
||||
* @param crc CRC32 checksum that needs to be updated.
|
||||
* @param data Pointer to data on which the CRC should be calculated.
|
||||
* @param len Data length.
|
||||
*
|
||||
* @return CRC32 value.
|
||||
*/
|
||||
uint32_t crc32_k_4_2_update(uint32_t crc, const uint8_t *data, size_t len);
|
||||
|
||||
/**
|
||||
* @brief Compute CCITT variant of CRC 8
|
||||
*
|
||||
* Normal CCITT variant of CRC 8 is using 0x07.
|
||||
*
|
||||
* @param initial_value Initial value for the CRC computation
|
||||
* @param buf Input bytes for the computation
|
||||
* @param len Length of the input in bytes
|
||||
*
|
||||
* @return The computed CRC8 value
|
||||
*/
|
||||
uint8_t crc8_ccitt(uint8_t initial_value, const void *buf, size_t len);
|
||||
|
||||
/**
|
||||
* @brief Compute ROHC variant of CRC 8
|
||||
*
|
||||
* ROHC (Robust Header Compression) variant of CRC 8.
|
||||
* Uses 0x07 as the polynomial with reflection.
|
||||
*
|
||||
* @param initial_value Initial value for the CRC computation
|
||||
* @param buf Input bytes for the computation
|
||||
* @param len Length of the input in bytes
|
||||
*
|
||||
* @return The computed CRC8 value
|
||||
*/
|
||||
uint8_t crc8_rohc(uint8_t initial_value, const void *buf, size_t len);
|
||||
|
||||
/**
|
||||
* @brief Compute the CRC-7 checksum of a buffer.
|
||||
*
|
||||
* See JESD84-A441. Used by the MMC protocol. Uses 0x09 as the
|
||||
* polynomial with no reflection. The CRC is left
|
||||
* justified, so bit 7 of the result is bit 6 of the CRC.
|
||||
*
|
||||
* @param seed Value to seed the CRC with
|
||||
* @param src Input bytes for the computation
|
||||
* @param len Length of the input in bytes
|
||||
*
|
||||
* @return The computed CRC7 value
|
||||
*/
|
||||
uint8_t crc7_be(uint8_t seed, const uint8_t *src, size_t len);
|
||||
|
||||
/**
|
||||
* @brief Compute the CRC-4 checksum of a buffer.
|
||||
*
|
||||
* Used by the TMAG5170 sensor. Uses 0x03 as the
|
||||
* polynomial with no reflection. 4 most significant
|
||||
* bits of the CRC result will be set to zero.
|
||||
*
|
||||
* @param seed Value to seed the CRC with
|
||||
* @param src Input bytes for the computation
|
||||
* @param len Length of the input in bytes
|
||||
*
|
||||
* @return The computed CRC4 value
|
||||
*/
|
||||
uint8_t crc4_ti(uint8_t seed, const uint8_t *src, size_t len);
|
||||
|
||||
/**
|
||||
* @brief Generic function for computing CRC 4
|
||||
*
|
||||
* Compute CRC 4 by passing in the address of the input, the input length
|
||||
* and polynomial used in addition to the initial value. The input buffer
|
||||
* must be aligned to a whole byte. It is guaranteed that 4 most significant
|
||||
* bits of the result will be set to zero.
|
||||
*
|
||||
* @param src Input bytes for the computation
|
||||
* @param len Length of the input in bytes
|
||||
* @param polynomial The polynomial to use omitting the leading x^4
|
||||
* coefficient
|
||||
* @param initial_value Initial value for the CRC computation
|
||||
* @param reversed Should we use reflected/reversed values or not
|
||||
*
|
||||
* @return The computed CRC4 value
|
||||
*/
|
||||
uint8_t crc4(const uint8_t *src, size_t len, uint8_t polynomial, uint8_t initial_value,
|
||||
bool reversed);
|
||||
|
||||
/**
|
||||
* @brief Generate an OpenPGP CRC-24 checksum as defined in RFC 4880 section 6.1.
|
||||
*
|
||||
* @param data A pointer to the data on which the CRC will be calculated.
|
||||
* @param len Data length in bytes.
|
||||
*
|
||||
* @return The CRC-24 value.
|
||||
*/
|
||||
uint32_t crc24_pgp(const uint8_t *data, size_t len);
|
||||
|
||||
/**
|
||||
* @brief Update an OpenPGP CRC-24 checksum.
|
||||
*
|
||||
* @param crc The CRC-24 checksum that needs to be updated. The full 32-bit value of the CRC needs
|
||||
* to be used between calls, do not mask the value to keep only the last 24 bits.
|
||||
* @param data A pointer to the data on which the CRC will be calculated.
|
||||
* @param len Data length in bytes.
|
||||
*
|
||||
* @return The CRC-24 value. When the last buffer of data has been processed, mask the value
|
||||
* with CRC24_FINAL_VALUE_MASK to keep only the meaningful 24 bits of the CRC result.
|
||||
*/
|
||||
uint32_t crc24_pgp_update(uint32_t crc, const uint8_t *data, size_t len);
|
||||
|
||||
/**
|
||||
* @brief Calculate an RTCM3 CRC24Q frame checksum
|
||||
*
|
||||
* @param[in] data RTCM3 Frame
|
||||
* @param[in] len Frame length in bytes.
|
||||
*
|
||||
* @return 0 if the data-frame contains a checksum and it matches.
|
||||
* @return Result if data-frame does not contain checksum.
|
||||
*/
|
||||
uint32_t crc24q_rtcm3(const uint8_t *data, size_t len);
|
||||
|
||||
/**
|
||||
* @brief Compute a CRC checksum, in a generic way.
|
||||
*
|
||||
* This is a dispatch function that calls the individual CRC routine
|
||||
* determined by @p type.
|
||||
*
|
||||
* For 7, 8, 16 and 24-bit CRCs, the relevant @p seed and @p poly values should
|
||||
* be passed in via the least-significant byte(s).
|
||||
*
|
||||
* Similarly, for 7, 8, 16 and 24-bit CRCs, the relevant result is stored in the
|
||||
* least-significant byte(s) of the returned value.
|
||||
*
|
||||
* @param type CRC algorithm to use.
|
||||
* @param src Input bytes for the computation
|
||||
* @param len Length of the input in bytes
|
||||
* @param seed Seed or existing CRC value to update
|
||||
* @param poly The polynomial to use omitting the leading coefficient
|
||||
* @param reflect Should we use reflected/reversed values or not
|
||||
* @param first Whether this is the first packet in the stream.
|
||||
* @param last Whether this is the last packet in the stream.
|
||||
* @return uint32_t the computed CRC value
|
||||
*/
|
||||
static inline uint32_t crc_by_type(enum crc_type type, const uint8_t *src, size_t len,
|
||||
uint32_t seed, uint32_t poly, bool reflect, bool first,
|
||||
bool last)
|
||||
{
|
||||
switch (type) {
|
||||
case CRC4:
|
||||
return crc4(src, len, poly, seed, reflect);
|
||||
case CRC4_TI:
|
||||
return crc4_ti(seed, src, len);
|
||||
case CRC7_BE:
|
||||
return crc7_be(seed, src, len);
|
||||
case CRC8:
|
||||
return crc8(src, len, poly, seed, reflect);
|
||||
case CRC8_CCITT:
|
||||
return crc8_ccitt(seed, src, len);
|
||||
case CRC8_ROHC:
|
||||
return crc8_rohc(seed, src, len);
|
||||
case CRC16:
|
||||
if (reflect) {
|
||||
return crc16_reflect(poly, seed, src, len);
|
||||
} else {
|
||||
return crc16(poly, seed, src, len);
|
||||
}
|
||||
case CRC16_ANSI:
|
||||
return crc16_ansi(src, len);
|
||||
case CRC16_CCITT:
|
||||
return crc16_ccitt(seed, src, len);
|
||||
case CRC16_ITU_T:
|
||||
return crc16_itu_t(seed, src, len);
|
||||
case CRC24_PGP: {
|
||||
uint32_t crc = crc24_pgp_update(seed, src, len);
|
||||
|
||||
if (last) {
|
||||
crc &= CRC24_FINAL_VALUE_MASK;
|
||||
}
|
||||
return crc;
|
||||
}
|
||||
case CRC32_C:
|
||||
return crc32_c(seed, src, len, first, last);
|
||||
case CRC32_IEEE:
|
||||
return crc32_ieee_update(seed, src, len);
|
||||
case CRC32_K_4_2:
|
||||
return crc32_k_4_2_update(seed, src, len);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
__ASSERT_NO_MSG(false);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,581 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2013-2015 Wind River Systems, Inc.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @defgroup doubly-linked-list_apis Doubly-linked list
|
||||
* @ingroup datastructure_apis
|
||||
*
|
||||
* @brief Doubly-linked list implementation
|
||||
*
|
||||
* Doubly-linked list implementation using inline macros/functions.
|
||||
* This API is not thread safe, and thus if a list is used across threads,
|
||||
* calls to functions must be protected with synchronization primitives.
|
||||
*
|
||||
* The lists are expected to be initialized such that both the head and tail
|
||||
* pointers point to the list itself. Initializing the lists in such a fashion
|
||||
* simplifies the adding and removing of nodes to/from the list.
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
#ifndef ZEPHYR_INCLUDE_SYS_DLIST_H_
|
||||
#define ZEPHYR_INCLUDE_SYS_DLIST_H_
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct _dnode {
|
||||
union {
|
||||
struct _dnode *head; /* ptr to head of list (sys_dlist_t) */
|
||||
struct _dnode *next; /* ptr to next node (sys_dnode_t) */
|
||||
};
|
||||
union {
|
||||
struct _dnode *tail; /* ptr to tail of list (sys_dlist_t) */
|
||||
struct _dnode *prev; /* ptr to previous node (sys_dnode_t) */
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Doubly-linked list structure.
|
||||
*/
|
||||
typedef struct _dnode sys_dlist_t;
|
||||
/**
|
||||
* @brief Doubly-linked list node structure.
|
||||
*/
|
||||
typedef struct _dnode sys_dnode_t;
|
||||
|
||||
/**
|
||||
* @brief Provide the primitive to iterate on a list
|
||||
* Note: the loop is unsafe and thus __dn should not be removed
|
||||
*
|
||||
* User _MUST_ add the loop statement curly braces enclosing its own code:
|
||||
*
|
||||
* SYS_DLIST_FOR_EACH_NODE(l, n) {
|
||||
* <user code>
|
||||
* }
|
||||
*
|
||||
* This and other SYS_DLIST_*() macros are not thread safe.
|
||||
*
|
||||
* @param __dl A pointer on a sys_dlist_t to iterate on
|
||||
* @param __dn A sys_dnode_t pointer to peek each node of the list
|
||||
*/
|
||||
#define SYS_DLIST_FOR_EACH_NODE(__dl, __dn) \
|
||||
for (__dn = sys_dlist_peek_head(__dl); __dn != NULL; \
|
||||
__dn = sys_dlist_peek_next(__dl, __dn))
|
||||
|
||||
/**
|
||||
* @brief Provide the primitive to iterate on a list, from a node in the list
|
||||
* Note: the loop is unsafe and thus __dn should not be removed
|
||||
*
|
||||
* User _MUST_ add the loop statement curly braces enclosing its own code:
|
||||
*
|
||||
* SYS_DLIST_ITERATE_FROM_NODE(l, n) {
|
||||
* <user code>
|
||||
* }
|
||||
*
|
||||
* Like SYS_DLIST_FOR_EACH_NODE(), but __dn already contains a node in the list
|
||||
* where to start searching for the next entry from. If NULL, it starts from
|
||||
* the head.
|
||||
*
|
||||
* This and other SYS_DLIST_*() macros are not thread safe.
|
||||
*
|
||||
* @param __dl A pointer on a sys_dlist_t to iterate on
|
||||
* @param __dn A sys_dnode_t pointer to peek each node of the list;
|
||||
* it contains the starting node, or NULL to start from the head
|
||||
*/
|
||||
#define SYS_DLIST_ITERATE_FROM_NODE(__dl, __dn) \
|
||||
for (__dn = __dn ? sys_dlist_peek_next_no_check(__dl, __dn) \
|
||||
: sys_dlist_peek_head(__dl); \
|
||||
__dn != NULL; \
|
||||
__dn = sys_dlist_peek_next(__dl, __dn))
|
||||
|
||||
/**
|
||||
* @brief Provide the primitive to safely iterate on a list
|
||||
* Note: __dn can be removed, it will not break the loop.
|
||||
*
|
||||
* User _MUST_ add the loop statement curly braces enclosing its own code:
|
||||
*
|
||||
* SYS_DLIST_FOR_EACH_NODE_SAFE(l, n, s) {
|
||||
* <user code>
|
||||
* }
|
||||
*
|
||||
* This and other SYS_DLIST_*() macros are not thread safe.
|
||||
*
|
||||
* @param __dl A pointer on a sys_dlist_t to iterate on
|
||||
* @param __dn A sys_dnode_t pointer to peek each node of the list
|
||||
* @param __dns A sys_dnode_t pointer for the loop to run safely
|
||||
*/
|
||||
#define SYS_DLIST_FOR_EACH_NODE_SAFE(__dl, __dn, __dns) \
|
||||
for ((__dn) = sys_dlist_peek_head(__dl), \
|
||||
(__dns) = sys_dlist_peek_next((__dl), (__dn)); \
|
||||
(__dn) != NULL; (__dn) = (__dns), \
|
||||
(__dns) = sys_dlist_peek_next(__dl, __dn))
|
||||
|
||||
/**
|
||||
* @brief Provide the primitive to resolve the container of a list node
|
||||
* Note: it is safe to use with NULL pointer nodes
|
||||
*
|
||||
* @param __dn A pointer on a sys_dnode_t to get its container
|
||||
* @param __cn Container struct type pointer
|
||||
* @param __n The field name of sys_dnode_t within the container struct
|
||||
*/
|
||||
#define SYS_DLIST_CONTAINER(__dn, __cn, __n) \
|
||||
(((__dn) != NULL) ? CONTAINER_OF(__dn, __typeof__(*(__cn)), __n) : NULL)
|
||||
/**
|
||||
* @brief Provide the primitive to peek container of the list head
|
||||
*
|
||||
* @param __dl A pointer on a sys_dlist_t to peek
|
||||
* @param __cn Container struct type pointer
|
||||
* @param __n The field name of sys_dnode_t within the container struct
|
||||
*/
|
||||
#define SYS_DLIST_PEEK_HEAD_CONTAINER(__dl, __cn, __n) \
|
||||
SYS_DLIST_CONTAINER(sys_dlist_peek_head(__dl), __cn, __n)
|
||||
|
||||
/**
|
||||
* @brief Provide the primitive to peek the next container
|
||||
*
|
||||
* @param __dl A pointer on a sys_dlist_t to peek
|
||||
* @param __cn Container struct type pointer
|
||||
* @param __n The field name of sys_dnode_t within the container struct
|
||||
*/
|
||||
#define SYS_DLIST_PEEK_NEXT_CONTAINER(__dl, __cn, __n) \
|
||||
(((__cn) != NULL) ? \
|
||||
SYS_DLIST_CONTAINER(sys_dlist_peek_next((__dl), &((__cn)->__n)), \
|
||||
__cn, __n) : NULL)
|
||||
|
||||
/**
|
||||
* @brief Provide the primitive to iterate on a list under a container
|
||||
* Note: the loop is unsafe and thus __cn should not be detached
|
||||
*
|
||||
* User _MUST_ add the loop statement curly braces enclosing its own code:
|
||||
*
|
||||
* SYS_DLIST_FOR_EACH_CONTAINER(l, c, n) {
|
||||
* <user code>
|
||||
* }
|
||||
*
|
||||
* @param __dl A pointer on a sys_dlist_t to iterate on
|
||||
* @param __cn A container struct type pointer to peek each entry of the list
|
||||
* @param __n The field name of sys_dnode_t within the container struct
|
||||
*/
|
||||
#define SYS_DLIST_FOR_EACH_CONTAINER(__dl, __cn, __n) \
|
||||
for ((__cn) = SYS_DLIST_PEEK_HEAD_CONTAINER(__dl, __cn, __n); \
|
||||
(__cn) != NULL; \
|
||||
(__cn) = SYS_DLIST_PEEK_NEXT_CONTAINER(__dl, __cn, __n))
|
||||
|
||||
/**
|
||||
* @brief Provide the primitive to safely iterate on a list under a container
|
||||
* Note: __cn can be detached, it will not break the loop.
|
||||
*
|
||||
* User _MUST_ add the loop statement curly braces enclosing its own code:
|
||||
*
|
||||
* SYS_DLIST_FOR_EACH_CONTAINER_SAFE(l, c, cn, n) {
|
||||
* <user code>
|
||||
* }
|
||||
*
|
||||
* @param __dl A pointer on a sys_dlist_t to iterate on
|
||||
* @param __cn A container struct type pointer to peek each entry of the list
|
||||
* @param __cns A container struct type pointer for the loop to run safely
|
||||
* @param __n The field name of sys_dnode_t within the container struct
|
||||
*/
|
||||
#define SYS_DLIST_FOR_EACH_CONTAINER_SAFE(__dl, __cn, __cns, __n) \
|
||||
for ((__cn) = SYS_DLIST_PEEK_HEAD_CONTAINER(__dl, __cn, __n), \
|
||||
(__cns) = SYS_DLIST_PEEK_NEXT_CONTAINER(__dl, __cn, __n); \
|
||||
(__cn) != NULL; (__cn) = (__cns), \
|
||||
(__cns) = SYS_DLIST_PEEK_NEXT_CONTAINER(__dl, __cn, __n))
|
||||
|
||||
/**
|
||||
* @brief initialize list to its empty state
|
||||
*
|
||||
* @param list the doubly-linked list
|
||||
*/
|
||||
|
||||
static inline void sys_dlist_init(sys_dlist_t *list)
|
||||
{
|
||||
list->head = (sys_dnode_t *)list;
|
||||
list->tail = (sys_dnode_t *)list;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Static initializer for a doubly-linked list
|
||||
*/
|
||||
#define SYS_DLIST_STATIC_INIT(ptr_to_list) { {(ptr_to_list)}, {(ptr_to_list)} }
|
||||
|
||||
/**
|
||||
* @brief initialize node to its state when not in a list
|
||||
*
|
||||
* @param node the node
|
||||
*/
|
||||
|
||||
static inline void sys_dnode_init(sys_dnode_t *node)
|
||||
{
|
||||
node->next = NULL;
|
||||
node->prev = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief check if a node is a member of any list
|
||||
*
|
||||
* @param node the node
|
||||
*
|
||||
* @return true if node is linked into a list, false if it is not
|
||||
*/
|
||||
|
||||
static inline bool sys_dnode_is_linked(const sys_dnode_t *node)
|
||||
{
|
||||
return node->next != NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief check if a node is the list's head
|
||||
*
|
||||
* @param list the doubly-linked list to operate on
|
||||
* @param node the node to check
|
||||
*
|
||||
* @return true if node is the head, false otherwise
|
||||
*/
|
||||
|
||||
static inline bool sys_dlist_is_head(const sys_dlist_t *list, const sys_dnode_t *node)
|
||||
{
|
||||
return list->head == node;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief check if a node is the list's tail
|
||||
*
|
||||
* @param list the doubly-linked list to operate on
|
||||
* @param node the node to check
|
||||
*
|
||||
* @return true if node is the tail, false otherwise
|
||||
*/
|
||||
|
||||
static inline bool sys_dlist_is_tail(const sys_dlist_t *list, const sys_dnode_t *node)
|
||||
{
|
||||
return list->tail == node;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief check if the list is empty
|
||||
*
|
||||
* @param list the doubly-linked list to operate on
|
||||
*
|
||||
* @return true if empty, false otherwise
|
||||
*/
|
||||
|
||||
static inline bool sys_dlist_is_empty(const sys_dlist_t *list)
|
||||
{
|
||||
return list->head == list;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief check if more than one node present
|
||||
*
|
||||
* This and other sys_dlist_*() functions are not thread safe.
|
||||
*
|
||||
* @param list the doubly-linked list to operate on
|
||||
*
|
||||
* @return true if multiple nodes, false otherwise
|
||||
*/
|
||||
|
||||
static inline bool sys_dlist_has_multiple_nodes(const sys_dlist_t *list)
|
||||
{
|
||||
return list->head != list->tail;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief get a reference to the head item in the list
|
||||
*
|
||||
* @param list the doubly-linked list to operate on
|
||||
*
|
||||
* @return a pointer to the head element, NULL if list is empty
|
||||
*/
|
||||
|
||||
static inline sys_dnode_t *sys_dlist_peek_head(const sys_dlist_t *list)
|
||||
{
|
||||
return sys_dlist_is_empty(list) ? NULL : list->head;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief get a reference to the head item in the list
|
||||
*
|
||||
* The list must be known to be non-empty.
|
||||
*
|
||||
* @param list the doubly-linked list to operate on
|
||||
*
|
||||
* @return a pointer to the head element
|
||||
*/
|
||||
|
||||
static inline sys_dnode_t *sys_dlist_peek_head_not_empty(const sys_dlist_t *list)
|
||||
{
|
||||
return list->head;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief get a reference to the next item in the list, node is not NULL
|
||||
*
|
||||
* Faster than sys_dlist_peek_next() if node is known not to be NULL.
|
||||
*
|
||||
* @param list the doubly-linked list to operate on
|
||||
* @param node the node from which to get the next element in the list
|
||||
*
|
||||
* @return a pointer to the next element from a node, NULL if node is the tail
|
||||
*/
|
||||
|
||||
static inline sys_dnode_t *sys_dlist_peek_next_no_check(const sys_dlist_t *list,
|
||||
const sys_dnode_t *node)
|
||||
{
|
||||
return (node == list->tail) ? NULL : node->next;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief get a reference to the next item in the list
|
||||
*
|
||||
* @param list the doubly-linked list to operate on
|
||||
* @param node the node from which to get the next element in the list
|
||||
*
|
||||
* @return a pointer to the next element from a node, NULL if node is the tail
|
||||
* or NULL (when node comes from reading the head of an empty list).
|
||||
*/
|
||||
|
||||
static inline sys_dnode_t *sys_dlist_peek_next(const sys_dlist_t *list,
|
||||
const sys_dnode_t *node)
|
||||
{
|
||||
return (node != NULL) ? sys_dlist_peek_next_no_check(list, node) : NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief get a reference to the previous item in the list, node is not NULL
|
||||
*
|
||||
* Faster than sys_dlist_peek_prev() if node is known not to be NULL.
|
||||
*
|
||||
* @param list the doubly-linked list to operate on
|
||||
* @param node the node from which to get the previous element in the list
|
||||
*
|
||||
* @return a pointer to the previous element from a node, NULL if node is the
|
||||
* tail
|
||||
*/
|
||||
|
||||
static inline sys_dnode_t *sys_dlist_peek_prev_no_check(const sys_dlist_t *list,
|
||||
const sys_dnode_t *node)
|
||||
{
|
||||
return (node == list->head) ? NULL : node->prev;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief get a reference to the previous item in the list
|
||||
*
|
||||
* @param list the doubly-linked list to operate on
|
||||
* @param node the node from which to get the previous element in the list
|
||||
*
|
||||
* @return a pointer to the previous element from a node, NULL if node is the
|
||||
* tail or NULL (when node comes from reading the head of an empty
|
||||
* list).
|
||||
*/
|
||||
|
||||
static inline sys_dnode_t *sys_dlist_peek_prev(const sys_dlist_t *list,
|
||||
const sys_dnode_t *node)
|
||||
{
|
||||
return (node != NULL) ? sys_dlist_peek_prev_no_check(list, node) : NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief get a reference to the tail item in the list
|
||||
*
|
||||
* @param list the doubly-linked list to operate on
|
||||
*
|
||||
* @return a pointer to the tail element, NULL if list is empty
|
||||
*/
|
||||
|
||||
static inline sys_dnode_t *sys_dlist_peek_tail(const sys_dlist_t *list)
|
||||
{
|
||||
return sys_dlist_is_empty(list) ? NULL : list->tail;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief add node to tail of list
|
||||
*
|
||||
* This and other sys_dlist_*() functions are not thread safe.
|
||||
*
|
||||
* @param list the doubly-linked list to operate on
|
||||
* @param node the element to append
|
||||
*/
|
||||
|
||||
static inline void sys_dlist_append(sys_dlist_t *list, sys_dnode_t *node)
|
||||
{
|
||||
sys_dnode_t *const tail = list->tail;
|
||||
|
||||
node->next = list;
|
||||
node->prev = tail;
|
||||
|
||||
tail->next = node;
|
||||
list->tail = node;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief add node to head of list
|
||||
*
|
||||
* This and other sys_dlist_*() functions are not thread safe.
|
||||
*
|
||||
* @param list the doubly-linked list to operate on
|
||||
* @param node the element to append
|
||||
*/
|
||||
|
||||
static inline void sys_dlist_prepend(sys_dlist_t *list, sys_dnode_t *node)
|
||||
{
|
||||
sys_dnode_t *const head = list->head;
|
||||
|
||||
node->next = head;
|
||||
node->prev = list;
|
||||
|
||||
head->prev = node;
|
||||
list->head = node;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Insert a node into a list
|
||||
*
|
||||
* Insert a node before a specified node in a dlist.
|
||||
*
|
||||
* @param successor the position before which "node" will be inserted
|
||||
* @param node the element to insert
|
||||
*/
|
||||
static inline void sys_dlist_insert(sys_dnode_t *successor, sys_dnode_t *node)
|
||||
{
|
||||
sys_dnode_t *const prev = successor->prev;
|
||||
|
||||
node->prev = prev;
|
||||
node->next = successor;
|
||||
prev->next = node;
|
||||
successor->prev = node;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief insert node at position
|
||||
*
|
||||
* Insert a node in a location depending on a external condition. The cond()
|
||||
* function checks if the node is to be inserted _before_ the current node
|
||||
* against which it is checked.
|
||||
* This and other sys_dlist_*() functions are not thread safe.
|
||||
*
|
||||
* @param list the doubly-linked list to operate on
|
||||
* @param node the element to insert
|
||||
* @param cond a function that determines if the current node is the correct
|
||||
* insert point
|
||||
* @param data parameter to cond()
|
||||
*/
|
||||
|
||||
static inline void sys_dlist_insert_at(sys_dlist_t *list, sys_dnode_t *node,
|
||||
int (*cond)(sys_dnode_t *node, void *data), void *data)
|
||||
{
|
||||
if (sys_dlist_is_empty(list)) {
|
||||
sys_dlist_append(list, node);
|
||||
} else {
|
||||
sys_dnode_t *pos = sys_dlist_peek_head(list);
|
||||
|
||||
while ((pos != NULL) && (cond(pos, data) == 0)) {
|
||||
pos = sys_dlist_peek_next(list, pos);
|
||||
}
|
||||
if (pos != NULL) {
|
||||
sys_dlist_insert(pos, node);
|
||||
} else {
|
||||
sys_dlist_append(list, node);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief remove a specific node from a list
|
||||
*
|
||||
* Like :c:func:`sys_dlist_remove()`, this routine removes a specific node
|
||||
* from a list. However, unlike :c:func:`sys_dlist_remove()`, this routine
|
||||
* does not re-initialize the removed node. One significant implication of
|
||||
* this difference is that the function :c:func`sys_dnode_is_linked()` will
|
||||
* not work on a dequeued node.
|
||||
*
|
||||
* The list is implicit from the node. The node must be part of a list.
|
||||
* This and other sys_dlist_*() functions are not thread safe.
|
||||
*
|
||||
* @param node the node to dequeue
|
||||
*/
|
||||
static inline void sys_dlist_dequeue(sys_dnode_t *node)
|
||||
{
|
||||
sys_dnode_t *const prev = node->prev;
|
||||
sys_dnode_t *const next = node->next;
|
||||
|
||||
prev->next = next;
|
||||
next->prev = prev;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief remove a specific node from a list
|
||||
*
|
||||
* The list is implicit from the node. The node must be part of a list.
|
||||
* This and other sys_dlist_*() functions are not thread safe.
|
||||
*
|
||||
* @param node the node to remove
|
||||
*/
|
||||
|
||||
static inline void sys_dlist_remove(sys_dnode_t *node)
|
||||
{
|
||||
sys_dnode_t *const prev = node->prev;
|
||||
sys_dnode_t *const next = node->next;
|
||||
|
||||
prev->next = next;
|
||||
next->prev = prev;
|
||||
sys_dnode_init(node);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief get the first node in a list
|
||||
*
|
||||
* This and other sys_dlist_*() functions are not thread safe.
|
||||
*
|
||||
* @param list the doubly-linked list to operate on
|
||||
*
|
||||
* @return the first node in the list, NULL if list is empty
|
||||
*/
|
||||
|
||||
static inline sys_dnode_t *sys_dlist_get(sys_dlist_t *list)
|
||||
{
|
||||
sys_dnode_t *node = NULL;
|
||||
|
||||
if (!sys_dlist_is_empty(list)) {
|
||||
node = list->head;
|
||||
sys_dlist_remove(node);
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Compute the size of the given list in O(n) time
|
||||
*
|
||||
* @param list A pointer on the list
|
||||
*
|
||||
* @return an integer equal to the size of the list, or 0 if empty
|
||||
*/
|
||||
static inline size_t sys_dlist_len(const sys_dlist_t *list)
|
||||
{
|
||||
size_t len = 0;
|
||||
sys_dnode_t *node = NULL;
|
||||
|
||||
SYS_DLIST_FOR_EACH_NODE(list, node) {
|
||||
len++;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
/** @} */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* ZEPHYR_INCLUDE_SYS_DLIST_H_ */
|
||||
@@ -0,0 +1,10 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2020 Intel Corporation
|
||||
* SPDX-FileCopyrightText: 2023 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#define STRUCT_SECTION_ITERABLE(struct_type, varname) struct struct_type varname
|
||||
@@ -0,0 +1,273 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2016 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef ZEPHYR_INCLUDE_SYS_LIST_GEN_H_
|
||||
#define ZEPHYR_INCLUDE_SYS_LIST_GEN_H_
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
#include <zephyr/sys/util.h>
|
||||
|
||||
#define Z_GENLIST_FOR_EACH_NODE(__lname, __l, __sn) \
|
||||
for ((__sn) = sys_ ## __lname ## _peek_head(__l); (__sn) != NULL; \
|
||||
(__sn) = sys_ ## __lname ## _peek_next(__sn))
|
||||
|
||||
#define Z_GENLIST_ITERATE_FROM_NODE(__lname, __l, __sn) \
|
||||
for ((__sn) = (__sn) ? sys_ ## __lname ## _peek_next_no_check(__sn) \
|
||||
: sys_ ## __lname ## _peek_head(__l); \
|
||||
(__sn) != NULL; \
|
||||
(__sn) = sys_ ## __lname ## _peek_next(__sn))
|
||||
|
||||
#define Z_GENLIST_FOR_EACH_NODE_SAFE(__lname, __l, __sn, __sns) \
|
||||
for ((__sn) = sys_ ## __lname ## _peek_head(__l), \
|
||||
(__sns) = sys_ ## __lname ## _peek_next(__sn); \
|
||||
(__sn) != NULL ; (__sn) = (__sns), \
|
||||
(__sns) = sys_ ## __lname ## _peek_next(__sn))
|
||||
|
||||
#define Z_GENLIST_CONTAINER(__ln, __cn, __n) \
|
||||
((__ln) ? CONTAINER_OF((__ln), __typeof__(*(__cn)), __n) : NULL)
|
||||
|
||||
#define Z_GENLIST_PEEK_HEAD_CONTAINER(__lname, __l, __cn, __n) \
|
||||
Z_GENLIST_CONTAINER(sys_ ## __lname ## _peek_head(__l), __cn, __n)
|
||||
|
||||
#define Z_GENLIST_PEEK_TAIL_CONTAINER(__lname, __l, __cn, __n) \
|
||||
Z_GENLIST_CONTAINER(sys_ ## __lname ## _peek_tail(__l), __cn, __n)
|
||||
|
||||
#define Z_GENLIST_PEEK_NEXT_CONTAINER(__lname, __cn, __n) \
|
||||
((__cn) ? Z_GENLIST_CONTAINER( \
|
||||
sys_ ## __lname ## _peek_next(&((__cn)->__n)), \
|
||||
__cn, __n) : NULL)
|
||||
|
||||
#define Z_GENLIST_FOR_EACH_CONTAINER(__lname, __l, __cn, __n) \
|
||||
for ((__cn) = Z_GENLIST_PEEK_HEAD_CONTAINER(__lname, __l, __cn, \
|
||||
__n); \
|
||||
(__cn) != NULL; \
|
||||
(__cn) = Z_GENLIST_PEEK_NEXT_CONTAINER(__lname, __cn, __n))
|
||||
|
||||
#define Z_GENLIST_FOR_EACH_CONTAINER_SAFE(__lname, __l, __cn, __cns, __n) \
|
||||
for ((__cn) = Z_GENLIST_PEEK_HEAD_CONTAINER(__lname, __l, __cn, __n), \
|
||||
(__cns) = Z_GENLIST_PEEK_NEXT_CONTAINER(__lname, __cn, __n); \
|
||||
(__cn) != NULL; (__cn) = (__cns), \
|
||||
(__cns) = Z_GENLIST_PEEK_NEXT_CONTAINER(__lname, __cn, __n))
|
||||
|
||||
#define Z_GENLIST_IS_EMPTY(__lname) \
|
||||
static inline bool \
|
||||
sys_ ## __lname ## _is_empty(const sys_ ## __lname ## _t *list) \
|
||||
{ \
|
||||
return (sys_ ## __lname ## _peek_head(list) == NULL); \
|
||||
}
|
||||
|
||||
#define Z_GENLIST_PEEK_NEXT_NO_CHECK(__lname, __nname) \
|
||||
static inline sys_ ## __nname ## _t * \
|
||||
sys_ ## __lname ## _peek_next_no_check(const sys_ ## __nname ## _t *node) \
|
||||
{ \
|
||||
return z_ ## __nname ## _next_peek(node); \
|
||||
}
|
||||
|
||||
#define Z_GENLIST_PEEK_NEXT(__lname, __nname) \
|
||||
static inline sys_ ## __nname ## _t * \
|
||||
sys_ ## __lname ## _peek_next(const sys_ ## __nname ## _t *node) \
|
||||
{ \
|
||||
return (node != NULL) ? \
|
||||
sys_ ## __lname ## _peek_next_no_check(node) : \
|
||||
NULL; \
|
||||
}
|
||||
|
||||
#define Z_GENLIST_PREPEND(__lname, __nname) \
|
||||
static inline void \
|
||||
sys_ ## __lname ## _prepend(sys_ ## __lname ## _t *list, \
|
||||
sys_ ## __nname ## _t *node) \
|
||||
{ \
|
||||
z_ ## __nname ## _next_set(node, \
|
||||
sys_ ## __lname ## _peek_head(list)); \
|
||||
z_ ## __lname ## _head_set(list, node); \
|
||||
\
|
||||
if (sys_ ## __lname ## _peek_tail(list) == NULL) { \
|
||||
z_ ## __lname ## _tail_set(list, \
|
||||
sys_ ## __lname ## _peek_head(list)); \
|
||||
} \
|
||||
}
|
||||
|
||||
#define Z_GENLIST_APPEND(__lname, __nname) \
|
||||
static inline void \
|
||||
sys_ ## __lname ## _append(sys_ ## __lname ## _t *list, \
|
||||
sys_ ## __nname ## _t *node) \
|
||||
{ \
|
||||
z_ ## __nname ## _next_set(node, NULL); \
|
||||
\
|
||||
if (sys_ ## __lname ## _peek_tail(list) == NULL) { \
|
||||
z_ ## __lname ## _tail_set(list, node); \
|
||||
z_ ## __lname ## _head_set(list, node); \
|
||||
} else { \
|
||||
z_ ## __nname ## _next_set( \
|
||||
sys_ ## __lname ## _peek_tail(list), \
|
||||
node); \
|
||||
z_ ## __lname ## _tail_set(list, node); \
|
||||
} \
|
||||
}
|
||||
|
||||
#define Z_GENLIST_APPEND_LIST(__lname, __nname) \
|
||||
static inline void \
|
||||
sys_ ## __lname ## _append_list(sys_ ## __lname ## _t *list, \
|
||||
void *head, void *tail) \
|
||||
{ \
|
||||
if (head != NULL && tail != NULL) { \
|
||||
if (sys_ ## __lname ## _peek_tail(list) == NULL) { \
|
||||
z_ ## __lname ## _head_set(list, \
|
||||
(sys_ ## __nname ## _t *)head); \
|
||||
} else { \
|
||||
z_ ## __nname ## _next_set( \
|
||||
sys_ ## __lname ## _peek_tail(list), \
|
||||
(sys_ ## __nname ## _t *)head); \
|
||||
} \
|
||||
z_ ## __lname ## _tail_set(list, \
|
||||
(sys_ ## __nname ## _t *)tail); \
|
||||
} \
|
||||
}
|
||||
|
||||
#define Z_GENLIST_MERGE_LIST(__lname, __nname) \
|
||||
static inline void \
|
||||
sys_ ## __lname ## _merge_ ## __lname ( \
|
||||
sys_ ## __lname ## _t *list, \
|
||||
sys_ ## __lname ## _t *list_to_append) \
|
||||
{ \
|
||||
sys_ ## __nname ## _t *head, *tail; \
|
||||
head = sys_ ## __lname ## _peek_head(list_to_append); \
|
||||
tail = sys_ ## __lname ## _peek_tail(list_to_append); \
|
||||
sys_ ## __lname ## _append_list(list, head, tail); \
|
||||
sys_ ## __lname ## _init(list_to_append); \
|
||||
}
|
||||
|
||||
#define Z_GENLIST_INSERT(__lname, __nname) \
|
||||
static inline void \
|
||||
sys_ ## __lname ## _insert(sys_ ## __lname ## _t *list, \
|
||||
sys_ ## __nname ## _t *prev, \
|
||||
sys_ ## __nname ## _t *node) \
|
||||
{ \
|
||||
if (prev == NULL) { \
|
||||
sys_ ## __lname ## _prepend(list, node); \
|
||||
} else if (z_ ## __nname ## _next_peek(prev) == NULL) { \
|
||||
sys_ ## __lname ## _append(list, node); \
|
||||
} else { \
|
||||
z_ ## __nname ## _next_set(node, \
|
||||
z_ ## __nname ## _next_peek(prev)); \
|
||||
z_ ## __nname ## _next_set(prev, node); \
|
||||
} \
|
||||
}
|
||||
|
||||
#define Z_GENLIST_GET_NOT_EMPTY(__lname, __nname) \
|
||||
static inline sys_ ## __nname ## _t * \
|
||||
sys_ ## __lname ## _get_not_empty(sys_ ## __lname ## _t *list) \
|
||||
{ \
|
||||
sys_ ## __nname ## _t *node = \
|
||||
sys_ ## __lname ## _peek_head(list); \
|
||||
\
|
||||
z_ ## __lname ## _head_set(list, \
|
||||
z_ ## __nname ## _next_peek(node)); \
|
||||
if (sys_ ## __lname ## _peek_tail(list) == node) { \
|
||||
z_ ## __lname ## _tail_set(list, \
|
||||
sys_ ## __lname ## _peek_head(list)); \
|
||||
} \
|
||||
\
|
||||
return node; \
|
||||
}
|
||||
|
||||
#define Z_GENLIST_GET(__lname, __nname) \
|
||||
static inline sys_ ## __nname ## _t * \
|
||||
sys_ ## __lname ## _get(sys_ ## __lname ## _t *list) \
|
||||
{ \
|
||||
return sys_ ## __lname ## _is_empty(list) ? NULL : \
|
||||
sys_ ## __lname ## _get_not_empty(list); \
|
||||
}
|
||||
|
||||
#define Z_GENLIST_REMOVE(__lname, __nname) \
|
||||
static inline void \
|
||||
sys_ ## __lname ## _remove(sys_ ## __lname ## _t *list, \
|
||||
sys_ ## __nname ## _t *prev_node, \
|
||||
sys_ ## __nname ## _t *node) \
|
||||
{ \
|
||||
if (prev_node == NULL) { \
|
||||
z_ ## __lname ## _head_set(list, \
|
||||
z_ ## __nname ## _next_peek(node)); \
|
||||
\
|
||||
/* Was node also the tail? */ \
|
||||
if (sys_ ## __lname ## _peek_tail(list) == node) { \
|
||||
z_ ## __lname ## _tail_set(list, \
|
||||
sys_ ## __lname ## _peek_head(list)); \
|
||||
} \
|
||||
} else { \
|
||||
z_ ## __nname ## _next_set(prev_node, \
|
||||
z_ ## __nname ## _next_peek(node)); \
|
||||
\
|
||||
/* Was node the tail? */ \
|
||||
if (sys_ ## __lname ## _peek_tail(list) == node) { \
|
||||
z_ ## __lname ## _tail_set(list, \
|
||||
prev_node); \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
z_ ## __nname ## _next_set(node, NULL); \
|
||||
}
|
||||
|
||||
#define Z_GENLIST_FIND_AND_REMOVE(__lname, __nname) \
|
||||
static inline bool \
|
||||
sys_ ## __lname ## _find_and_remove(sys_ ## __lname ## _t *list, \
|
||||
sys_ ## __nname ## _t *node) \
|
||||
{ \
|
||||
sys_ ## __nname ## _t *prev = NULL; \
|
||||
sys_ ## __nname ## _t *test; \
|
||||
\
|
||||
Z_GENLIST_FOR_EACH_NODE(__lname, list, test) { \
|
||||
if (test == node) { \
|
||||
sys_ ## __lname ## _remove(list, prev, \
|
||||
node); \
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
prev = test; \
|
||||
} \
|
||||
\
|
||||
return false; \
|
||||
}
|
||||
|
||||
#define Z_GENLIST_FIND(__lname, __nname) \
|
||||
static inline bool sys_##__lname##_find( \
|
||||
const sys_##__lname##_t *list, const sys_##__nname##_t *node, \
|
||||
sys_##__nname##_t **prev) \
|
||||
{ \
|
||||
sys_##__nname##_t *current = NULL; \
|
||||
sys_##__nname##_t *previous = NULL; \
|
||||
\
|
||||
Z_GENLIST_FOR_EACH_NODE(__lname, list, current) { \
|
||||
if (current == node) { \
|
||||
if (prev != NULL) { \
|
||||
*prev = previous; \
|
||||
} \
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
previous = current; \
|
||||
} \
|
||||
\
|
||||
if (prev != NULL) { \
|
||||
*prev = previous; \
|
||||
} \
|
||||
\
|
||||
return false; \
|
||||
}
|
||||
|
||||
#define Z_GENLIST_LEN(__lname, __nname) \
|
||||
static inline size_t sys_##__lname##_len(const sys_##__lname##_t * list) \
|
||||
{ \
|
||||
size_t len = 0; \
|
||||
static sys_##__nname##_t * node; \
|
||||
Z_GENLIST_FOR_EACH_NODE(__lname, list, node) { \
|
||||
len++; \
|
||||
} \
|
||||
return len; \
|
||||
}
|
||||
|
||||
#endif /* ZEPHYR_INCLUDE_SYS_LIST_GEN_H_ */
|
||||
@@ -0,0 +1,452 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2016 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @defgroup single-linked-list_apis Single-linked list
|
||||
* @ingroup datastructure_apis
|
||||
*
|
||||
* @brief Single-linked list implementation.
|
||||
*
|
||||
* Single-linked list implementation using inline macros/functions.
|
||||
* This API is not thread safe, and thus if a list is used across threads,
|
||||
* calls to functions must be protected with synchronization primitives.
|
||||
* @{
|
||||
*/
|
||||
|
||||
#ifndef ZEPHYR_INCLUDE_SYS_SLIST_H_
|
||||
#define ZEPHYR_INCLUDE_SYS_SLIST_H_
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
#include "list_gen.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** @cond INTERNAL_HIDDEN */
|
||||
struct _snode {
|
||||
struct _snode *next;
|
||||
};
|
||||
/** @endcond */
|
||||
|
||||
/** Single-linked list node structure. */
|
||||
typedef struct _snode sys_snode_t;
|
||||
|
||||
/** @cond INTERNAL_HIDDEN */
|
||||
struct _slist {
|
||||
sys_snode_t *head;
|
||||
sys_snode_t *tail;
|
||||
};
|
||||
/** @endcond */
|
||||
|
||||
/** Single-linked list structure. */
|
||||
typedef struct _slist sys_slist_t;
|
||||
|
||||
/**
|
||||
* @brief Provide the primitive to iterate on a list
|
||||
* Note: the loop is unsafe and thus __sn should not be removed
|
||||
*
|
||||
* User _MUST_ add the loop statement curly braces enclosing its own code:
|
||||
*
|
||||
* SYS_SLIST_FOR_EACH_NODE(l, n) {
|
||||
* <user code>
|
||||
* }
|
||||
*
|
||||
* This and other SYS_SLIST_*() macros are not thread safe.
|
||||
*
|
||||
* @param __sl A pointer on a sys_slist_t to iterate on
|
||||
* @param __sn A sys_snode_t pointer to peek each node of the list
|
||||
*/
|
||||
#define SYS_SLIST_FOR_EACH_NODE(__sl, __sn) \
|
||||
Z_GENLIST_FOR_EACH_NODE(slist, __sl, __sn)
|
||||
|
||||
/**
|
||||
* @brief Provide the primitive to iterate on a list, from a node in the list
|
||||
* Note: the loop is unsafe and thus __sn should not be removed
|
||||
*
|
||||
* User _MUST_ add the loop statement curly braces enclosing its own code:
|
||||
*
|
||||
* SYS_SLIST_ITERATE_FROM_NODE(l, n) {
|
||||
* <user code>
|
||||
* }
|
||||
*
|
||||
* Like SYS_SLIST_FOR_EACH_NODE(), but __dn already contains a node in the list
|
||||
* where to start searching for the next entry from. If NULL, it starts from
|
||||
* the head.
|
||||
*
|
||||
* This and other SYS_SLIST_*() macros are not thread safe.
|
||||
*
|
||||
* @param __sl A pointer on a sys_slist_t to iterate on
|
||||
* @param __sn A sys_snode_t pointer to peek each node of the list
|
||||
* it contains the starting node, or NULL to start from the head
|
||||
*/
|
||||
#define SYS_SLIST_ITERATE_FROM_NODE(__sl, __sn) \
|
||||
Z_GENLIST_ITERATE_FROM_NODE(slist, __sl, __sn)
|
||||
|
||||
/**
|
||||
* @brief Provide the primitive to safely iterate on a list
|
||||
* Note: __sn can be removed, it will not break the loop.
|
||||
*
|
||||
* User _MUST_ add the loop statement curly braces enclosing its own code:
|
||||
*
|
||||
* SYS_SLIST_FOR_EACH_NODE_SAFE(l, n, s) {
|
||||
* <user code>
|
||||
* }
|
||||
*
|
||||
* This and other SYS_SLIST_*() macros are not thread safe.
|
||||
*
|
||||
* @param __sl A pointer on a sys_slist_t to iterate on
|
||||
* @param __sn A sys_snode_t pointer to peek each node of the list
|
||||
* @param __sns A sys_snode_t pointer for the loop to run safely
|
||||
*/
|
||||
#define SYS_SLIST_FOR_EACH_NODE_SAFE(__sl, __sn, __sns) \
|
||||
Z_GENLIST_FOR_EACH_NODE_SAFE(slist, __sl, __sn, __sns)
|
||||
|
||||
/**
|
||||
* @brief Provide the primitive to resolve the container of a list node
|
||||
* Note: it is safe to use with NULL pointer nodes
|
||||
*
|
||||
* @param __ln A pointer on a sys_node_t to get its container
|
||||
* @param __cn Container struct type pointer
|
||||
* @param __n The field name of sys_node_t within the container struct
|
||||
*/
|
||||
#define SYS_SLIST_CONTAINER(__ln, __cn, __n) \
|
||||
Z_GENLIST_CONTAINER(__ln, __cn, __n)
|
||||
|
||||
/**
|
||||
* @brief Provide the primitive to peek container of the list head
|
||||
*
|
||||
* @param __sl A pointer on a sys_slist_t to peek
|
||||
* @param __cn Container struct type pointer
|
||||
* @param __n The field name of sys_node_t within the container struct
|
||||
*/
|
||||
#define SYS_SLIST_PEEK_HEAD_CONTAINER(__sl, __cn, __n) \
|
||||
Z_GENLIST_PEEK_HEAD_CONTAINER(slist, __sl, __cn, __n)
|
||||
|
||||
/**
|
||||
* @brief Provide the primitive to peek container of the list tail
|
||||
*
|
||||
* @param __sl A pointer on a sys_slist_t to peek
|
||||
* @param __cn Container struct type pointer
|
||||
* @param __n The field name of sys_node_t within the container struct
|
||||
*/
|
||||
#define SYS_SLIST_PEEK_TAIL_CONTAINER(__sl, __cn, __n) \
|
||||
Z_GENLIST_PEEK_TAIL_CONTAINER(slist, __sl, __cn, __n)
|
||||
|
||||
/**
|
||||
* @brief Provide the primitive to peek the next container
|
||||
*
|
||||
* @param __cn Container struct type pointer
|
||||
* @param __n The field name of sys_node_t within the container struct
|
||||
*/
|
||||
#define SYS_SLIST_PEEK_NEXT_CONTAINER(__cn, __n) \
|
||||
Z_GENLIST_PEEK_NEXT_CONTAINER(slist, __cn, __n)
|
||||
|
||||
/**
|
||||
* @brief Provide the primitive to iterate on a list under a container
|
||||
* Note: the loop is unsafe and thus __cn should not be detached
|
||||
*
|
||||
* User _MUST_ add the loop statement curly braces enclosing its own code:
|
||||
*
|
||||
* SYS_SLIST_FOR_EACH_CONTAINER(l, c, n) {
|
||||
* <user code>
|
||||
* }
|
||||
*
|
||||
* @param __sl A pointer on a sys_slist_t to iterate on
|
||||
* @param __cn A pointer to peek each entry of the list
|
||||
* @param __n The field name of sys_node_t within the container struct
|
||||
*/
|
||||
#define SYS_SLIST_FOR_EACH_CONTAINER(__sl, __cn, __n) \
|
||||
Z_GENLIST_FOR_EACH_CONTAINER(slist, __sl, __cn, __n)
|
||||
|
||||
/**
|
||||
* @brief Provide the primitive to safely iterate on a list under a container
|
||||
* Note: __cn can be detached, it will not break the loop.
|
||||
*
|
||||
* User _MUST_ add the loop statement curly braces enclosing its own code:
|
||||
*
|
||||
* SYS_SLIST_FOR_EACH_NODE_SAFE(l, c, cn, n) {
|
||||
* <user code>
|
||||
* }
|
||||
*
|
||||
* @param __sl A pointer on a sys_slist_t to iterate on
|
||||
* @param __cn A pointer to peek each entry of the list
|
||||
* @param __cns A pointer for the loop to run safely
|
||||
* @param __n The field name of sys_node_t within the container struct
|
||||
*/
|
||||
#define SYS_SLIST_FOR_EACH_CONTAINER_SAFE(__sl, __cn, __cns, __n) \
|
||||
Z_GENLIST_FOR_EACH_CONTAINER_SAFE(slist, __sl, __cn, __cns, __n)
|
||||
|
||||
/*
|
||||
* Required function definitions for the list_gen.h interface
|
||||
*
|
||||
* These are the only functions that do not treat the list/node pointers
|
||||
* as completely opaque types.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Initialize a list
|
||||
*
|
||||
* @param list A pointer on the list to initialize
|
||||
*/
|
||||
static inline void sys_slist_init(sys_slist_t *list)
|
||||
{
|
||||
list->head = NULL;
|
||||
list->tail = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Statically initialize a single-linked list
|
||||
* @param ptr_to_list A pointer on the list to initialize
|
||||
*/
|
||||
#define SYS_SLIST_STATIC_INIT(ptr_to_list) {NULL, NULL}
|
||||
|
||||
static inline sys_snode_t *z_snode_next_peek(const sys_snode_t *node)
|
||||
{
|
||||
return node->next;
|
||||
}
|
||||
|
||||
static inline void z_snode_next_set(sys_snode_t *parent, sys_snode_t *child)
|
||||
{
|
||||
parent->next = child;
|
||||
}
|
||||
|
||||
static inline void z_slist_head_set(sys_slist_t *list, sys_snode_t *node)
|
||||
{
|
||||
list->head = node;
|
||||
}
|
||||
|
||||
static inline void z_slist_tail_set(sys_slist_t *list, sys_snode_t *node)
|
||||
{
|
||||
list->tail = node;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Peek the first node from the list
|
||||
*
|
||||
* @param list A point on the list to peek the first node from
|
||||
*
|
||||
* @return A pointer on the first node of the list (or NULL if none)
|
||||
*/
|
||||
static inline sys_snode_t *sys_slist_peek_head(const sys_slist_t *list)
|
||||
{
|
||||
return list->head;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Peek the last node from the list
|
||||
*
|
||||
* @param list A point on the list to peek the last node from
|
||||
*
|
||||
* @return A pointer on the last node of the list (or NULL if none)
|
||||
*/
|
||||
static inline sys_snode_t *sys_slist_peek_tail(const sys_slist_t *list)
|
||||
{
|
||||
return list->tail;
|
||||
}
|
||||
|
||||
/*
|
||||
* Derived, generated APIs
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Test if the given list is empty
|
||||
*
|
||||
* @param list A pointer on the list to test
|
||||
*
|
||||
* @return a boolean, true if it's empty, false otherwise
|
||||
*/
|
||||
static inline bool sys_slist_is_empty(const sys_slist_t *list);
|
||||
|
||||
Z_GENLIST_IS_EMPTY(slist)
|
||||
|
||||
/**
|
||||
* @brief Peek the next node from current node, node is not NULL
|
||||
*
|
||||
* Faster then sys_slist_peek_next() if node is known not to be NULL.
|
||||
*
|
||||
* @param node A pointer on the node where to peek the next node
|
||||
*
|
||||
* @return a pointer on the next node (or NULL if none)
|
||||
*/
|
||||
static inline sys_snode_t *sys_slist_peek_next_no_check(const sys_snode_t *node);
|
||||
|
||||
Z_GENLIST_PEEK_NEXT_NO_CHECK(slist, snode)
|
||||
|
||||
/**
|
||||
* @brief Peek the next node from current node
|
||||
*
|
||||
* @param node A pointer on the node where to peek the next node
|
||||
*
|
||||
* @return a pointer on the next node (or NULL if none)
|
||||
*/
|
||||
static inline sys_snode_t *sys_slist_peek_next(const sys_snode_t *node);
|
||||
|
||||
Z_GENLIST_PEEK_NEXT(slist, snode)
|
||||
|
||||
/**
|
||||
* @brief Prepend a node to the given list
|
||||
*
|
||||
* This and other sys_slist_*() functions are not thread safe.
|
||||
*
|
||||
* @param list A pointer on the list to affect
|
||||
* @param node A pointer on the node to prepend
|
||||
*/
|
||||
static inline void sys_slist_prepend(sys_slist_t *list,
|
||||
sys_snode_t *node);
|
||||
|
||||
Z_GENLIST_PREPEND(slist, snode)
|
||||
|
||||
/**
|
||||
* @brief Append a node to the given list
|
||||
*
|
||||
* This and other sys_slist_*() functions are not thread safe.
|
||||
*
|
||||
* @param list A pointer on the list to affect
|
||||
* @param node A pointer on the node to append
|
||||
*/
|
||||
static inline void sys_slist_append(sys_slist_t *list,
|
||||
sys_snode_t *node);
|
||||
|
||||
Z_GENLIST_APPEND(slist, snode)
|
||||
|
||||
/**
|
||||
* @brief Append a list to the given list
|
||||
*
|
||||
* Append a singly-linked, NULL-terminated list consisting of nodes containing
|
||||
* the pointer to the next node as the first element of a node, to @a list.
|
||||
* This and other sys_slist_*() functions are not thread safe.
|
||||
*
|
||||
* @param list A pointer on the list to affect
|
||||
* @param head A pointer to the first element of the list to append
|
||||
* @param tail A pointer to the last element of the list to append
|
||||
*/
|
||||
static inline void sys_slist_append_list(sys_slist_t *list,
|
||||
void *head, void *tail);
|
||||
|
||||
Z_GENLIST_APPEND_LIST(slist, snode)
|
||||
|
||||
/**
|
||||
* @brief merge two slists, appending the second one to the first
|
||||
*
|
||||
* When the operation is completed, the appending list is empty.
|
||||
* This and other sys_slist_*() functions are not thread safe.
|
||||
*
|
||||
* @param list A pointer on the list to affect
|
||||
* @param list_to_append A pointer to the list to append.
|
||||
*/
|
||||
static inline void sys_slist_merge_slist(sys_slist_t *list,
|
||||
sys_slist_t *list_to_append);
|
||||
|
||||
Z_GENLIST_MERGE_LIST(slist, snode)
|
||||
|
||||
/**
|
||||
* @brief Insert a node to the given list
|
||||
*
|
||||
* This and other sys_slist_*() functions are not thread safe.
|
||||
*
|
||||
* @param list A pointer on the list to affect
|
||||
* @param prev A pointer on the previous node
|
||||
* @param node A pointer on the node to insert
|
||||
*/
|
||||
static inline void sys_slist_insert(sys_slist_t *list,
|
||||
sys_snode_t *prev,
|
||||
sys_snode_t *node);
|
||||
|
||||
Z_GENLIST_INSERT(slist, snode)
|
||||
|
||||
/**
|
||||
* @brief Fetch and remove the first node of the given list
|
||||
*
|
||||
* List must be known to be non-empty.
|
||||
* This and other sys_slist_*() functions are not thread safe.
|
||||
*
|
||||
* @param list A pointer on the list to affect
|
||||
*
|
||||
* @return A pointer to the first node of the list
|
||||
*/
|
||||
static inline sys_snode_t *sys_slist_get_not_empty(sys_slist_t *list);
|
||||
|
||||
Z_GENLIST_GET_NOT_EMPTY(slist, snode)
|
||||
|
||||
/**
|
||||
* @brief Fetch and remove the first node of the given list
|
||||
*
|
||||
* This and other sys_slist_*() functions are not thread safe.
|
||||
*
|
||||
* @param list A pointer on the list to affect
|
||||
*
|
||||
* @return A pointer to the first node of the list (or NULL if empty)
|
||||
*/
|
||||
static inline sys_snode_t *sys_slist_get(sys_slist_t *list);
|
||||
|
||||
Z_GENLIST_GET(slist, snode)
|
||||
|
||||
/**
|
||||
* @brief Remove a node
|
||||
*
|
||||
* This and other sys_slist_*() functions are not thread safe.
|
||||
*
|
||||
* @param list A pointer on the list to affect
|
||||
* @param prev_node A pointer on the previous node
|
||||
* (can be NULL, which means the node is the list's head)
|
||||
* @param node A pointer on the node to remove
|
||||
*/
|
||||
static inline void sys_slist_remove(sys_slist_t *list,
|
||||
sys_snode_t *prev_node,
|
||||
sys_snode_t *node);
|
||||
|
||||
Z_GENLIST_REMOVE(slist, snode)
|
||||
|
||||
/**
|
||||
* @brief Find and remove a node from a list
|
||||
*
|
||||
* This and other sys_slist_*() functions are not thread safe.
|
||||
*
|
||||
* @param list A pointer on the list to affect
|
||||
* @param node A pointer on the node to remove from the list
|
||||
*
|
||||
* @return true if node was removed
|
||||
*/
|
||||
static inline bool sys_slist_find_and_remove(sys_slist_t *list,
|
||||
sys_snode_t *node);
|
||||
|
||||
/**
|
||||
* @brief Find if a node is already linked in a singly linked list
|
||||
*
|
||||
* This and other sys_slist_*() functions are not thread safe.
|
||||
*
|
||||
* @param list A pointer to the list to check
|
||||
* @param node A pointer to the node to search in the list
|
||||
* @param[out] prev A pointer to the previous node
|
||||
*
|
||||
* @return true if node was found in the list, false otherwise
|
||||
*/
|
||||
static inline bool sys_slist_find(const sys_slist_t *list, const sys_snode_t *node,
|
||||
sys_snode_t **prev);
|
||||
Z_GENLIST_FIND(slist, snode)
|
||||
|
||||
/**
|
||||
* @brief Compute the size of the given list in O(n) time
|
||||
*
|
||||
* @param list A pointer on the list
|
||||
*
|
||||
* @return an integer equal to the size of the list, or 0 if empty
|
||||
*/
|
||||
static inline size_t sys_slist_len(const sys_slist_t *list);
|
||||
|
||||
Z_GENLIST_LEN(slist, snode)
|
||||
|
||||
/** @} */
|
||||
Z_GENLIST_FIND_AND_REMOVE(slist, snode)
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* ZEPHYR_INCLUDE_SYS_SLIST_H_ */
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,201 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2011-2014 Wind River Systems, Inc.
|
||||
* SPDX-FileCopyrightText: 2020 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @brief Misc utilities
|
||||
*
|
||||
* Repetitive or obscure helper macros needed by sys/util.h.
|
||||
*/
|
||||
|
||||
#ifndef ZEPHYR_INCLUDE_SYS_UTIL_INTERNAL_H_
|
||||
#define ZEPHYR_INCLUDE_SYS_UTIL_INTERNAL_H_
|
||||
|
||||
#include "util_loops.h"
|
||||
|
||||
/* IS_ENABLED() helpers */
|
||||
|
||||
/* This is called from IS_ENABLED(), and sticks on a "_XXXX" prefix,
|
||||
* it will now be "_XXXX1" if config_macro is "1", or just "_XXXX" if it's
|
||||
* undefined.
|
||||
* ENABLED: Z_IS_ENABLED2(_XXXX1)
|
||||
* DISABLED Z_IS_ENABLED2(_XXXX)
|
||||
*/
|
||||
#define Z_IS_ENABLED1(config_macro) Z_IS_ENABLED2(_XXXX##config_macro)
|
||||
|
||||
/* Here's the core trick, we map "_XXXX1" to "_YYYY," (i.e. a string
|
||||
* with a trailing comma), so it has the effect of making this a
|
||||
* two-argument tuple to the preprocessor only in the case where the
|
||||
* value is defined to "1"
|
||||
* ENABLED: _YYYY, <--- note comma!
|
||||
* DISABLED: _XXXX
|
||||
*/
|
||||
#define _XXXX1 _YYYY,
|
||||
|
||||
/* Then we append an extra argument to fool the gcc preprocessor into
|
||||
* accepting it as a varargs macro.
|
||||
* arg1 arg2 arg3
|
||||
* ENABLED: Z_IS_ENABLED3(_YYYY, 1, 0)
|
||||
* DISABLED Z_IS_ENABLED3(_XXXX 1, 0)
|
||||
*/
|
||||
#define Z_IS_ENABLED2(one_or_two_args) Z_IS_ENABLED3(one_or_two_args 1, 0)
|
||||
|
||||
/* And our second argument is thus now cooked to be 1 in the case
|
||||
* where the value is defined to 1, and 0 if not:
|
||||
*/
|
||||
#define Z_IS_ENABLED3(ignore_this, val, ...) val
|
||||
|
||||
/* Implementation of IS_EQ(). Returns 1 if _0 and _1 are the same integer from
|
||||
* 0 to 4096, 0 otherwise.
|
||||
*/
|
||||
#define Z_IS_EQ(_0, _1) Z_HAS_COMMA(Z_CAT4(Z_IS_, _0, _EQ_, _1)())
|
||||
|
||||
/* Used internally by COND_CODE_1 and COND_CODE_0. */
|
||||
#define Z_COND_CODE_1(_flag, _if_1_code, _else_code) \
|
||||
__COND_CODE(_XXXX##_flag, _if_1_code, _else_code)
|
||||
#define Z_COND_CODE_0(_flag, _if_0_code, _else_code) \
|
||||
__COND_CODE(_ZZZZ##_flag, _if_0_code, _else_code)
|
||||
#define _ZZZZ0 _YYYY,
|
||||
#define __COND_CODE(one_or_two_args, _if_code, _else_code) \
|
||||
__GET_ARG2_DEBRACKET(one_or_two_args _if_code, _else_code)
|
||||
|
||||
/* Gets second argument and removes brackets around that argument. It
|
||||
* is expected that the parameter is provided in brackets/parentheses.
|
||||
*/
|
||||
#define __GET_ARG2_DEBRACKET(ignore_this, val, ...) __DEBRACKET val
|
||||
|
||||
/* Used to remove brackets from around a single argument. */
|
||||
#define __DEBRACKET(...) __VA_ARGS__
|
||||
|
||||
/* Used by IS_EMPTY() */
|
||||
/* reference: https://gustedt.wordpress.com/2010/06/08/detect-empty-macro-arguments/ */
|
||||
#define Z_HAS_COMMA(...) \
|
||||
NUM_VA_ARGS_LESS_1_IMPL(__VA_ARGS__, 1, 1, 1, 1, 1, 1, 1, 1, \
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0)
|
||||
#define Z_TRIGGER_PARENTHESIS_(...) ,
|
||||
#define Z_IS_EMPTY_(...) \
|
||||
Z_IS_EMPTY__( \
|
||||
Z_HAS_COMMA(__VA_ARGS__), \
|
||||
Z_HAS_COMMA(Z_TRIGGER_PARENTHESIS_ __VA_ARGS__), \
|
||||
Z_HAS_COMMA(__VA_ARGS__ (/*empty*/)), \
|
||||
Z_HAS_COMMA(Z_TRIGGER_PARENTHESIS_ __VA_ARGS__ (/*empty*/)))
|
||||
#define Z_CAT4(_0, _1, _2, _3) _0 ## _1 ## _2 ## _3
|
||||
#define Z_CAT5(_0, _1, _2, _3, _4) _0 ## _1 ## _2 ## _3 ## _4
|
||||
#define Z_IS_EMPTY__(_0, _1, _2, _3) \
|
||||
Z_HAS_COMMA(Z_CAT5(Z_IS_EMPTY_CASE_, _0, _1, _2, _3))
|
||||
#define Z_IS_EMPTY_CASE_0001 ,
|
||||
|
||||
/* Used by LIST_DROP_EMPTY() */
|
||||
/* Adding ',' after each element would add empty element at the end of
|
||||
* list, which is hard to remove, so instead precede each element with ',',
|
||||
* this way first element is empty, and this one is easy to drop.
|
||||
*/
|
||||
#define Z_LIST_ADD_ELEM(e) EMPTY, e
|
||||
#define Z_LIST_DROP_FIRST(...) GET_ARGS_LESS_N(1, __VA_ARGS__)
|
||||
#define Z_LIST_NO_EMPTIES(e) \
|
||||
COND_CODE_1(IS_EMPTY(e), (), (Z_LIST_ADD_ELEM(e)))
|
||||
|
||||
#define UTIL_CAT(a, ...) UTIL_PRIMITIVE_CAT(a, __VA_ARGS__)
|
||||
#define UTIL_PRIMITIVE_CAT(a, ...) a##__VA_ARGS__
|
||||
#define UTIL_CHECK_N(x, n, ...) n
|
||||
#define UTIL_CHECK(...) UTIL_CHECK_N(__VA_ARGS__, 0,)
|
||||
#define UTIL_NOT(x) UTIL_CHECK(UTIL_PRIMITIVE_CAT(UTIL_NOT_, x))
|
||||
#define UTIL_NOT_0 ~, 1,
|
||||
#define UTIL_COMPL(b) UTIL_PRIMITIVE_CAT(UTIL_COMPL_, b)
|
||||
#define UTIL_COMPL_0 1
|
||||
#define UTIL_COMPL_1 0
|
||||
#define UTIL_BOOL(x) UTIL_COMPL(UTIL_NOT(x))
|
||||
|
||||
#define UTIL_EVAL(...) __VA_ARGS__
|
||||
#define UTIL_EXPAND(...) __VA_ARGS__
|
||||
#define UTIL_REPEAT(...) UTIL_LISTIFY(__VA_ARGS__)
|
||||
|
||||
#define _CONCAT_0(arg, ...) arg
|
||||
#define _CONCAT_1(arg, ...) UTIL_CAT(arg, _CONCAT_0(__VA_ARGS__))
|
||||
#define _CONCAT_2(arg, ...) UTIL_CAT(arg, _CONCAT_1(__VA_ARGS__))
|
||||
#define _CONCAT_3(arg, ...) UTIL_CAT(arg, _CONCAT_2(__VA_ARGS__))
|
||||
#define _CONCAT_4(arg, ...) UTIL_CAT(arg, _CONCAT_3(__VA_ARGS__))
|
||||
#define _CONCAT_5(arg, ...) UTIL_CAT(arg, _CONCAT_4(__VA_ARGS__))
|
||||
#define _CONCAT_6(arg, ...) UTIL_CAT(arg, _CONCAT_5(__VA_ARGS__))
|
||||
#define _CONCAT_7(arg, ...) UTIL_CAT(arg, _CONCAT_6(__VA_ARGS__))
|
||||
|
||||
/* Implementation details for NUM_VA_ARGS_LESS_1 */
|
||||
#define NUM_VA_ARGS_LESS_1_IMPL( \
|
||||
_ignored, \
|
||||
_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, \
|
||||
_11, _12, _13, _14, _15, _16, _17, _18, _19, _20, \
|
||||
_21, _22, _23, _24, _25, _26, _27, _28, _29, _30, \
|
||||
_31, _32, _33, _34, _35, _36, _37, _38, _39, _40, \
|
||||
_41, _42, _43, _44, _45, _46, _47, _48, _49, _50, \
|
||||
_51, _52, _53, _54, _55, _56, _57, _58, _59, _60, \
|
||||
_61, _62, N, ...) N
|
||||
|
||||
/* Used by MACRO_MAP_CAT */
|
||||
#define MACRO_MAP_CAT_(...) \
|
||||
/* To make sure it works also for 2 arguments in total */ \
|
||||
MACRO_MAP_CAT_N(NUM_VA_ARGS_LESS_1(__VA_ARGS__), __VA_ARGS__)
|
||||
#define MACRO_MAP_CAT_N_(N, ...) UTIL_CAT(MACRO_MC_, N)(__VA_ARGS__,)
|
||||
#define MACRO_MC_0(...)
|
||||
#define MACRO_MC_1(m, a, ...) m(a)
|
||||
#define MACRO_MC_2(m, a, ...) UTIL_CAT(m(a), MACRO_MC_1(m, __VA_ARGS__,))
|
||||
#define MACRO_MC_3(m, a, ...) UTIL_CAT(m(a), MACRO_MC_2(m, __VA_ARGS__,))
|
||||
#define MACRO_MC_4(m, a, ...) UTIL_CAT(m(a), MACRO_MC_3(m, __VA_ARGS__,))
|
||||
#define MACRO_MC_5(m, a, ...) UTIL_CAT(m(a), MACRO_MC_4(m, __VA_ARGS__,))
|
||||
#define MACRO_MC_6(m, a, ...) UTIL_CAT(m(a), MACRO_MC_5(m, __VA_ARGS__,))
|
||||
#define MACRO_MC_7(m, a, ...) UTIL_CAT(m(a), MACRO_MC_6(m, __VA_ARGS__,))
|
||||
#define MACRO_MC_8(m, a, ...) UTIL_CAT(m(a), MACRO_MC_7(m, __VA_ARGS__,))
|
||||
#define MACRO_MC_9(m, a, ...) UTIL_CAT(m(a), MACRO_MC_8(m, __VA_ARGS__,))
|
||||
#define MACRO_MC_10(m, a, ...) UTIL_CAT(m(a), MACRO_MC_9(m, __VA_ARGS__,))
|
||||
#define MACRO_MC_11(m, a, ...) UTIL_CAT(m(a), MACRO_MC_10(m, __VA_ARGS__,))
|
||||
#define MACRO_MC_12(m, a, ...) UTIL_CAT(m(a), MACRO_MC_11(m, __VA_ARGS__,))
|
||||
#define MACRO_MC_13(m, a, ...) UTIL_CAT(m(a), MACRO_MC_12(m, __VA_ARGS__,))
|
||||
#define MACRO_MC_14(m, a, ...) UTIL_CAT(m(a), MACRO_MC_13(m, __VA_ARGS__,))
|
||||
#define MACRO_MC_15(m, a, ...) UTIL_CAT(m(a), MACRO_MC_14(m, __VA_ARGS__,))
|
||||
|
||||
/* Used by Z_IS_EQ */
|
||||
#include "util_internal_is_eq.h"
|
||||
|
||||
/*
|
||||
* Generic sparse list of odd numbers (check the implementation of
|
||||
* GPIO_DT_RESERVED_RANGES_NGPIOS as a usage example)
|
||||
*/
|
||||
#define Z_SPARSE_LIST_ODD_NUMBERS \
|
||||
EMPTY, 1, EMPTY, 3, EMPTY, 5, EMPTY, 7, \
|
||||
EMPTY, 9, EMPTY, 11, EMPTY, 13, EMPTY, 15, \
|
||||
EMPTY, 17, EMPTY, 19, EMPTY, 21, EMPTY, 23, \
|
||||
EMPTY, 25, EMPTY, 27, EMPTY, 29, EMPTY, 31, \
|
||||
EMPTY, 33, EMPTY, 35, EMPTY, 37, EMPTY, 39, \
|
||||
EMPTY, 41, EMPTY, 43, EMPTY, 45, EMPTY, 47, \
|
||||
EMPTY, 49, EMPTY, 51, EMPTY, 53, EMPTY, 55, \
|
||||
EMPTY, 57, EMPTY, 59, EMPTY, 61, EMPTY, 63
|
||||
|
||||
/*
|
||||
* Generic sparse list of even numbers (check the implementation of
|
||||
* GPIO_DT_RESERVED_RANGES_NGPIOS as a usage example)
|
||||
*/
|
||||
#define Z_SPARSE_LIST_EVEN_NUMBERS \
|
||||
0, EMPTY, 2, EMPTY, 4, EMPTY, 6, EMPTY, \
|
||||
8, EMPTY, 10, EMPTY, 12, EMPTY, 14, EMPTY, \
|
||||
16, EMPTY, 18, EMPTY, 20, EMPTY, 22, EMPTY, \
|
||||
24, EMPTY, 26, EMPTY, 28, EMPTY, 30, EMPTY, \
|
||||
32, EMPTY, 34, EMPTY, 36, EMPTY, 38, EMPTY, \
|
||||
40, EMPTY, 42, EMPTY, 44, EMPTY, 46, EMPTY, \
|
||||
48, EMPTY, 50, EMPTY, 52, EMPTY, 54, EMPTY, \
|
||||
56, EMPTY, 58, EMPTY, 60, EMPTY, 62, EMPTY
|
||||
|
||||
/* Used by UTIL_INC */
|
||||
#include "util_internal_util_inc.h"
|
||||
|
||||
/* Used by UTIL_DEC */
|
||||
#include "util_internal_util_dec.h"
|
||||
|
||||
/* Used by UTIL_X2 */
|
||||
#include "util_internal_util_x2.h"
|
||||
|
||||
#endif /* ZEPHYR_INCLUDE_SYS_UTIL_INTERNAL_H_ */
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,733 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2011-2014 Wind River Systems, Inc.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @brief Macro utilities
|
||||
*
|
||||
* Macro utilities are the public interface for C/C++ code and device tree
|
||||
* related implementation. In general, C/C++ will include <sys/util.h>
|
||||
* instead this file directly. For device tree implementation, this file
|
||||
* should be include instead <sys/util_internal.h>
|
||||
*/
|
||||
|
||||
#ifndef ZEPHYR_INCLUDE_SYS_UTIL_MACROS_H_
|
||||
#define ZEPHYR_INCLUDE_SYS_UTIL_MACROS_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @addtogroup sys-util
|
||||
* @{
|
||||
*/
|
||||
|
||||
/*
|
||||
* Most of the eldritch implementation details for all the macrobatics
|
||||
* below (APIs like IS_ENABLED(), COND_CODE_1(), etc.) are hidden away
|
||||
* in this file.
|
||||
*/
|
||||
#include <zephyr/sys/util_internal.h>
|
||||
|
||||
#ifndef BIT
|
||||
#if defined(_ASMLANGUAGE)
|
||||
#define BIT(n) (1 << (n))
|
||||
#else
|
||||
/**
|
||||
* @brief Unsigned integer with bit position @p n set (signed in
|
||||
* assembly language).
|
||||
*/
|
||||
#define BIT(n) (1UL << (n))
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef BIT64
|
||||
/** @brief 64-bit unsigned integer with bit position @p _n set. */
|
||||
#define BIT64(_n) (1ULL << (_n))
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Set or clear a bit depending on a boolean value
|
||||
*
|
||||
* The argument @p var is a variable whose value is written to as a
|
||||
* side effect.
|
||||
*
|
||||
* @param var Variable to be altered
|
||||
* @param bit Bit number
|
||||
* @param set if 0, clears @p bit in @p var; any other value sets @p bit
|
||||
*/
|
||||
#define WRITE_BIT(var, bit, set) \
|
||||
((var) = (set) ? ((var) | BIT(bit)) : ((var) & ~BIT(bit)))
|
||||
|
||||
/**
|
||||
* @brief Bit mask with bits 0 through <tt>n-1</tt> (inclusive) set,
|
||||
* or 0 if @p n is 0.
|
||||
*/
|
||||
#define BIT_MASK(n) (BIT(n) - 1UL)
|
||||
|
||||
/**
|
||||
* @brief 64-bit bit mask with bits 0 through <tt>n-1</tt> (inclusive) set,
|
||||
* or 0 if @p n is 0.
|
||||
*/
|
||||
#define BIT64_MASK(n) (BIT64(n) - 1ULL)
|
||||
|
||||
/** @brief Check if a @p x is a power of two */
|
||||
#define IS_POWER_OF_TWO(x) (((x) != 0U) && (((x) & ((x) - 1U)) == 0U))
|
||||
|
||||
/**
|
||||
* @brief Check if bits are set continuously from the specified bit
|
||||
*
|
||||
* The macro is not dependent on the bit-width.
|
||||
*
|
||||
* @param m Check whether the bits are set continuously or not.
|
||||
* @param s Specify the lowest bit for that is continuously set bits.
|
||||
*/
|
||||
#define IS_SHIFTED_BIT_MASK(m, s) (!(((m) >> (s)) & (((m) >> (s)) + 1U)))
|
||||
|
||||
/**
|
||||
* @brief Check if bits are set continuously from the LSB.
|
||||
*
|
||||
* @param m Check whether the bits are set continuously from LSB.
|
||||
*/
|
||||
#define IS_BIT_MASK(m) IS_SHIFTED_BIT_MASK(m, 0)
|
||||
|
||||
/**
|
||||
* @brief Check if bit is set in a value
|
||||
*
|
||||
* @param value Value that contain checked bit
|
||||
* @param bit Bit number
|
||||
*/
|
||||
#define IS_BIT_SET(value, bit) ((((value) >> (bit)) & (0x1)) != 0)
|
||||
|
||||
/** @brief Extract the Least Significant Bit from @p value. */
|
||||
#define LSB_GET(value) ((value) & -(value))
|
||||
|
||||
/**
|
||||
* @brief Extract a bitfield element from @p value corresponding to
|
||||
* the field mask @p mask.
|
||||
*/
|
||||
#define FIELD_GET(mask, value) (((value) & (mask)) / LSB_GET(mask))
|
||||
|
||||
/**
|
||||
* @brief Prepare a bitfield element using @p value with @p mask representing
|
||||
* its field position and width. The result should be combined
|
||||
* with other fields using a logical OR.
|
||||
*/
|
||||
#define FIELD_PREP(mask, value) (((value) * LSB_GET(mask)) & (mask))
|
||||
|
||||
/**
|
||||
* @brief Check for macro definition in compiler-visible expressions
|
||||
*
|
||||
* This trick was pioneered in Linux as the config_enabled() macro. It
|
||||
* has the effect of taking a macro value that may be defined to "1"
|
||||
* or may not be defined at all and turning it into a literal
|
||||
* expression that can be handled by the C compiler instead of just
|
||||
* the preprocessor. It is often used with a @p CONFIG_FOO macro which
|
||||
* may be defined to 1 via Kconfig, or left undefined.
|
||||
*
|
||||
* That is, it works similarly to <tt>\#if defined(CONFIG_FOO)</tt>
|
||||
* except that its expansion is a C expression. Thus, much <tt>\#ifdef</tt>
|
||||
* usage can be replaced with equivalents like:
|
||||
*
|
||||
* if (IS_ENABLED(CONFIG_FOO)) {
|
||||
* do_something_with_foo
|
||||
* }
|
||||
*
|
||||
* This is cleaner since the compiler can generate errors and warnings
|
||||
* for @p do_something_with_foo even when @p CONFIG_FOO is undefined.
|
||||
*
|
||||
* Note: Use of IS_ENABLED in a <tt>\#if</tt> statement is discouraged
|
||||
* as it doesn't provide any benefit vs plain <tt>\#if defined()</tt>
|
||||
*
|
||||
* @param config_macro Macro to check
|
||||
* @return 1 if @p config_macro is defined to 1, 0 otherwise (including
|
||||
* if @p config_macro is not defined)
|
||||
*/
|
||||
#define IS_ENABLED(config_macro) Z_IS_ENABLED1(config_macro)
|
||||
/* INTERNAL: the first pass above is just to expand any existing
|
||||
* macros, we need the macro value to be e.g. a literal "1" at
|
||||
* expansion time in the next macro, not "(1)", etc... Standard
|
||||
* recursive expansion does not work.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Insert code depending on whether @p _flag expands to 1 or not.
|
||||
*
|
||||
* This relies on similar tricks as IS_ENABLED(), but as the result of
|
||||
* @p _flag expansion, results in either @p _if_1_code or @p
|
||||
* _else_code is expanded.
|
||||
*
|
||||
* To prevent the preprocessor from treating commas as argument
|
||||
* separators, the @p _if_1_code and @p _else_code expressions must be
|
||||
* inside brackets/parentheses: <tt>()</tt>. These are stripped away
|
||||
* during macro expansion.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* COND_CODE_1(CONFIG_FLAG, (uint32_t x;), (there_is_no_flag();))
|
||||
*
|
||||
* If @p CONFIG_FLAG is defined to 1, this expands to:
|
||||
*
|
||||
* uint32_t x;
|
||||
*
|
||||
* It expands to <tt>there_is_no_flag();</tt> otherwise.
|
||||
*
|
||||
* This could be used as an alternative to:
|
||||
*
|
||||
* #if defined(CONFIG_FLAG) && (CONFIG_FLAG == 1)
|
||||
* #define MAYBE_DECLARE(x) uint32_t x
|
||||
* #else
|
||||
* #define MAYBE_DECLARE(x) there_is_no_flag()
|
||||
* #endif
|
||||
*
|
||||
* MAYBE_DECLARE(x);
|
||||
*
|
||||
* However, the advantage of COND_CODE_1() is that code is resolved in
|
||||
* place where it is used, while the @p \#if method defines @p
|
||||
* MAYBE_DECLARE on two lines and requires it to be invoked again on a
|
||||
* separate line. This makes COND_CODE_1() more concise and also
|
||||
* sometimes more useful when used within another macro's expansion.
|
||||
*
|
||||
* @note @p _flag can be the result of preprocessor expansion, e.g.
|
||||
* an expression involving <tt>NUM_VA_ARGS_LESS_1(...)</tt>.
|
||||
* However, @p _if_1_code is only expanded if @p _flag expands
|
||||
* to the integer literal 1. Integer expressions that evaluate
|
||||
* to 1, e.g. after doing some arithmetic, will not work.
|
||||
*
|
||||
* @param _flag evaluated flag
|
||||
* @param _if_1_code result if @p _flag expands to 1; must be in parentheses
|
||||
* @param _else_code result otherwise; must be in parentheses
|
||||
*/
|
||||
#define COND_CODE_1(_flag, _if_1_code, _else_code) \
|
||||
Z_COND_CODE_1(_flag, _if_1_code, _else_code)
|
||||
|
||||
/**
|
||||
* @brief Like COND_CODE_1() except tests if @p _flag is 0.
|
||||
*
|
||||
* This is like COND_CODE_1(), except that it tests whether @p _flag
|
||||
* expands to the integer literal 0. It expands to @p _if_0_code if
|
||||
* so, and @p _else_code otherwise; both of these must be enclosed in
|
||||
* parentheses.
|
||||
*
|
||||
* @param _flag evaluated flag
|
||||
* @param _if_0_code result if @p _flag expands to 0; must be in parentheses
|
||||
* @param _else_code result otherwise; must be in parentheses
|
||||
* @see COND_CODE_1()
|
||||
*/
|
||||
#define COND_CODE_0(_flag, _if_0_code, _else_code) \
|
||||
Z_COND_CODE_0(_flag, _if_0_code, _else_code)
|
||||
|
||||
/**
|
||||
* @brief Insert code if @p _flag is defined and equals 1.
|
||||
*
|
||||
* Like COND_CODE_1(), this expands to @p _code if @p _flag is defined to 1;
|
||||
* it expands to nothing otherwise.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* IF_ENABLED(CONFIG_FLAG, (uint32_t foo;))
|
||||
*
|
||||
* If @p CONFIG_FLAG is defined to 1, this expands to:
|
||||
*
|
||||
* uint32_t foo;
|
||||
*
|
||||
* and to nothing otherwise.
|
||||
*
|
||||
* It can be considered as a more compact alternative to:
|
||||
*
|
||||
* #if defined(CONFIG_FLAG) && (CONFIG_FLAG == 1)
|
||||
* uint32_t foo;
|
||||
* #endif
|
||||
*
|
||||
* @param _flag evaluated flag
|
||||
* @param _code result if @p _flag expands to 1; must be in parentheses
|
||||
*/
|
||||
#define IF_ENABLED(_flag, _code) \
|
||||
COND_CODE_1(_flag, _code, ())
|
||||
|
||||
/**
|
||||
* @brief Insert code if @p _flag is not defined as 1.
|
||||
*
|
||||
* This expands to nothing if @p _flag is defined and equal to 1;
|
||||
* it expands to @p _code otherwise.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* IF_DISABLED(CONFIG_FLAG, (uint32_t foo;))
|
||||
*
|
||||
* If @p CONFIG_FLAG isn't defined or different than 1, this expands to:
|
||||
*
|
||||
* uint32_t foo;
|
||||
*
|
||||
* and to nothing otherwise.
|
||||
*
|
||||
* IF_DISABLED does the opposite of IF_ENABLED.
|
||||
*
|
||||
* @param _flag evaluated flag
|
||||
* @param _code result if @p _flag does not expand to 1; must be in parentheses
|
||||
*/
|
||||
#define IF_DISABLED(_flag, _code) \
|
||||
COND_CODE_1(_flag, (), _code)
|
||||
|
||||
/**
|
||||
* @brief Check if a macro has a replacement expression
|
||||
*
|
||||
* If @p a is a macro defined to a nonempty value, this will return
|
||||
* true, otherwise it will return false. It only works with defined
|
||||
* macros, so an additional @p \#ifdef test may be needed in some cases.
|
||||
*
|
||||
* This macro may be used with COND_CODE_1() and COND_CODE_0() while
|
||||
* processing `__VA_ARGS__` to avoid processing empty arguments.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* #define EMPTY
|
||||
* #define NON_EMPTY 1
|
||||
* #undef UNDEFINED
|
||||
* IS_EMPTY(EMPTY)
|
||||
* IS_EMPTY(NON_EMPTY)
|
||||
* IS_EMPTY(UNDEFINED)
|
||||
* #if defined(EMPTY) && IS_EMPTY(EMPTY) == true
|
||||
* some_conditional_code
|
||||
* #endif
|
||||
*
|
||||
* In above examples, the invocations of IS_EMPTY(...) return @p true,
|
||||
* @p false, and @p true; @p some_conditional_code is included.
|
||||
*
|
||||
* @param ... macro to check for emptiness (may be `__VA_ARGS__`)
|
||||
*/
|
||||
#define IS_EMPTY(...) Z_IS_EMPTY_(__VA_ARGS__)
|
||||
|
||||
/**
|
||||
* @brief Like <tt>a == b</tt>, but does evaluation and
|
||||
* short-circuiting at C preprocessor time.
|
||||
*
|
||||
* This however only works for integer literal from 0 to 4096 (literals with U suffix,
|
||||
* e.g. 0U are also included).
|
||||
*
|
||||
* Examples:
|
||||
*
|
||||
* IS_EQ(1, 1) -> 1
|
||||
* IS_EQ(1U, 1U) -> 1
|
||||
* IS_EQ(1U, 1) -> 1
|
||||
* IS_EQ(1, 1U) -> 1
|
||||
* IS_EQ(1, 0) -> 0
|
||||
*
|
||||
* @param a Integer literal (can be with U suffix)
|
||||
* @param b Integer literal
|
||||
*
|
||||
*/
|
||||
#define IS_EQ(a, b) Z_IS_EQ(a, b)
|
||||
|
||||
/**
|
||||
* @brief Remove empty arguments from list.
|
||||
*
|
||||
* During macro expansion, `__VA_ARGS__` and other preprocessor
|
||||
* generated lists may contain empty elements, e.g.:
|
||||
*
|
||||
* #define LIST ,a,b,,d,
|
||||
*
|
||||
* Using EMPTY to show each empty element, LIST contains:
|
||||
*
|
||||
* EMPTY, a, b, EMPTY, d
|
||||
*
|
||||
* When processing such lists, e.g. using FOR_EACH(), all empty elements
|
||||
* will be processed, and may require filtering out.
|
||||
* To make that process easier, it is enough to invoke LIST_DROP_EMPTY
|
||||
* which will remove all empty elements.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* LIST_DROP_EMPTY(LIST)
|
||||
*
|
||||
* expands to:
|
||||
*
|
||||
* a, b, d
|
||||
*
|
||||
* @param ... list to be processed
|
||||
*/
|
||||
#define LIST_DROP_EMPTY(...) \
|
||||
Z_LIST_DROP_FIRST(FOR_EACH(Z_LIST_NO_EMPTIES, (), __VA_ARGS__))
|
||||
|
||||
/**
|
||||
* @brief Macro with an empty expansion
|
||||
*
|
||||
* This trivial definition is provided for readability when a macro
|
||||
* should expand to an empty result, which e.g. is sometimes needed to
|
||||
* silence checkpatch.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* #define LIST_ITEM(n) , item##n
|
||||
*
|
||||
* The above would cause checkpatch to complain, but:
|
||||
*
|
||||
* #define LIST_ITEM(n) EMPTY, item##n
|
||||
*
|
||||
* would not.
|
||||
*/
|
||||
#define EMPTY
|
||||
|
||||
/**
|
||||
* @brief Macro that expands to its argument
|
||||
*
|
||||
* This is useful in macros like @c FOR_EACH() when there is no
|
||||
* transformation required on the list elements.
|
||||
*
|
||||
* @param V any value
|
||||
*/
|
||||
#define IDENTITY(V) V
|
||||
|
||||
/**
|
||||
* @brief Get nth argument from argument list.
|
||||
*
|
||||
* @param N Argument index to fetch. Counter from 1.
|
||||
* @param ... Variable list of arguments from which one argument is returned.
|
||||
*
|
||||
* @return Nth argument.
|
||||
*/
|
||||
#define GET_ARG_N(N, ...) UTIL_CAT(Z_GET_ARG_, N)(__VA_ARGS__)
|
||||
|
||||
/**
|
||||
* @brief Strips n first arguments from the argument list.
|
||||
*
|
||||
* @param N Number of arguments to discard.
|
||||
* @param ... Variable list of arguments.
|
||||
*
|
||||
* @return argument list without N first arguments.
|
||||
*/
|
||||
#define GET_ARGS_LESS_N(N, ...) UTIL_CAT(Z_GET_ARGS_LESS_, N)(__VA_ARGS__)
|
||||
|
||||
/**
|
||||
* @brief Like <tt>a || b</tt>, but does evaluation and
|
||||
* short-circuiting at C preprocessor time.
|
||||
*
|
||||
* This is not the same as the binary @p || operator; in particular,
|
||||
* @p a should expand to an integer literal 0 or 1. However, @p b
|
||||
* can be any value.
|
||||
*
|
||||
* This can be useful when @p b is an expression that would cause a
|
||||
* build error when @p a is 1.
|
||||
*/
|
||||
#define UTIL_OR(a, b) COND_CODE_1(UTIL_BOOL(a), (a), (b))
|
||||
|
||||
/**
|
||||
* @brief Like <tt>a && b</tt>, but does evaluation and
|
||||
* short-circuiting at C preprocessor time.
|
||||
*
|
||||
* This is not the same as the binary @p &&, however; in particular,
|
||||
* @p a should expand to an integer literal 0 or 1. However, @p b
|
||||
* can be any value.
|
||||
*
|
||||
* This can be useful when @p b is an expression that would cause a
|
||||
* build error when @p a is 0.
|
||||
*/
|
||||
#define UTIL_AND(a, b) COND_CODE_1(UTIL_BOOL(a), (b), (0))
|
||||
|
||||
/**
|
||||
* @brief UTIL_INC(x) for an integer literal x from 0 to 4095 expands to an
|
||||
* integer literal whose value is x+1.
|
||||
*
|
||||
* @see UTIL_DEC(x)
|
||||
*/
|
||||
#define UTIL_INC(x) UTIL_PRIMITIVE_CAT(Z_UTIL_INC_, x)
|
||||
|
||||
/**
|
||||
* @brief UTIL_DEC(x) for an integer literal x from 0 to 4095 expands to an
|
||||
* integer literal whose value is x-1.
|
||||
*
|
||||
* @see UTIL_INC(x)
|
||||
*/
|
||||
#define UTIL_DEC(x) UTIL_PRIMITIVE_CAT(Z_UTIL_DEC_, x)
|
||||
|
||||
/**
|
||||
* @brief UTIL_X2(y) for an integer literal y from 0 to 4095 expands to an
|
||||
* integer literal whose value is 2y.
|
||||
*/
|
||||
#define UTIL_X2(y) UTIL_PRIMITIVE_CAT(Z_UTIL_X2_, y)
|
||||
|
||||
/**
|
||||
* @brief Generates a sequence of code with configurable separator.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* #define FOO(i, _) MY_PWM ## i
|
||||
* { LISTIFY(PWM_COUNT, FOO, (,)) }
|
||||
*
|
||||
* The above two lines expand to:
|
||||
*
|
||||
* { MY_PWM0 , MY_PWM1 }
|
||||
*
|
||||
* @param LEN The length of the sequence. Must be an integer literal less
|
||||
* than 4095.
|
||||
* @param F A macro function that accepts at least two arguments:
|
||||
* <tt>F(i, ...)</tt>. @p F is called repeatedly in the expansion.
|
||||
* Its first argument @p i is the index in the sequence, and
|
||||
* the variable list of arguments passed to LISTIFY are passed
|
||||
* through to @p F.
|
||||
*
|
||||
* @param sep Separator (e.g. comma or semicolon). Must be in parentheses;
|
||||
* this is required to enable providing a comma as separator.
|
||||
*
|
||||
* @note Calling LISTIFY with undefined arguments has undefined
|
||||
* behavior.
|
||||
*/
|
||||
#define LISTIFY(LEN, F, sep, ...) UTIL_CAT(Z_UTIL_LISTIFY_, LEN)(F, sep, __VA_ARGS__)
|
||||
|
||||
/**
|
||||
* @brief Call a macro @p F on each provided argument with a given
|
||||
* separator between each call.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* #define F(x) int a##x
|
||||
* FOR_EACH(F, (;), 4, 5, 6);
|
||||
*
|
||||
* This expands to:
|
||||
*
|
||||
* int a4;
|
||||
* int a5;
|
||||
* int a6;
|
||||
*
|
||||
* @param F Macro to invoke
|
||||
* @param sep Separator (e.g. comma or semicolon). Must be in parentheses;
|
||||
* this is required to enable providing a comma as separator.
|
||||
* @param ... Variable argument list. The macro @p F is invoked as
|
||||
* <tt>F(element)</tt> for each element in the list.
|
||||
*/
|
||||
#define FOR_EACH(F, sep, ...) \
|
||||
Z_FOR_EACH(F, sep, REVERSE_ARGS(__VA_ARGS__))
|
||||
|
||||
/**
|
||||
* @brief Like FOR_EACH(), but with a terminator instead of a separator,
|
||||
* and drops empty elements from the argument list
|
||||
*
|
||||
* The @p sep argument to <tt>FOR_EACH(F, (sep), a, b)</tt> is a
|
||||
* separator which is placed between calls to @p F, like this:
|
||||
*
|
||||
* FOR_EACH(F, (sep), a, b) // F(a) sep F(b)
|
||||
* // ^^^ no sep here!
|
||||
*
|
||||
* By contrast, the @p term argument to <tt>FOR_EACH_NONEMPTY_TERM(F, (term),
|
||||
* a, b)</tt> is added after each time @p F appears in the expansion:
|
||||
*
|
||||
* FOR_EACH_NONEMPTY_TERM(F, (term), a, b) // F(a) term F(b) term
|
||||
* // ^^^^
|
||||
*
|
||||
* Further, any empty elements are dropped:
|
||||
*
|
||||
* FOR_EACH_NONEMPTY_TERM(F, (term), a, EMPTY, b) // F(a) term F(b) term
|
||||
*
|
||||
* This is more convenient in some cases, because FOR_EACH_NONEMPTY_TERM()
|
||||
* expands to nothing when given an empty argument list, and it's
|
||||
* often cumbersome to write a macro @p F that does the right thing
|
||||
* even when given an empty argument.
|
||||
*
|
||||
* One example is when `__VA_ARGS__` may or may not be empty,
|
||||
* and the results are embedded in a larger initializer:
|
||||
*
|
||||
* #define SQUARE(x) ((x)*(x))
|
||||
*
|
||||
* int my_array[] = {
|
||||
* FOR_EACH_NONEMPTY_TERM(SQUARE, (,), FOO(...))
|
||||
* FOR_EACH_NONEMPTY_TERM(SQUARE, (,), BAR(...))
|
||||
* FOR_EACH_NONEMPTY_TERM(SQUARE, (,), BAZ(...))
|
||||
* };
|
||||
*
|
||||
* This is more convenient than:
|
||||
*
|
||||
* 1. figuring out whether the @p FOO, @p BAR, and @p BAZ expansions
|
||||
* are empty and adding a comma manually (or not) between FOR_EACH()
|
||||
* calls
|
||||
* 2. rewriting SQUARE so it reacts appropriately when "x" is empty
|
||||
* (which would be necessary if e.g. @p FOO expands to nothing)
|
||||
*
|
||||
* @param F Macro to invoke on each nonempty element of the variable
|
||||
* arguments
|
||||
* @param term Terminator (e.g. comma or semicolon) placed after each
|
||||
* invocation of F. Must be in parentheses; this is required
|
||||
* to enable providing a comma as separator.
|
||||
* @param ... Variable argument list. The macro @p F is invoked as
|
||||
* <tt>F(element)</tt> for each nonempty element in the list.
|
||||
*/
|
||||
#define FOR_EACH_NONEMPTY_TERM(F, term, ...) \
|
||||
COND_CODE_0( \
|
||||
/* are there zero non-empty arguments ? */ \
|
||||
NUM_VA_ARGS_LESS_1(LIST_DROP_EMPTY(__VA_ARGS__, _)), \
|
||||
/* if so, expand to nothing */ \
|
||||
(), \
|
||||
/* otherwise, expand to: */ \
|
||||
(/* FOR_EACH() on nonempty elements, */ \
|
||||
FOR_EACH(F, term, LIST_DROP_EMPTY(__VA_ARGS__)) \
|
||||
/* plus a final terminator */ \
|
||||
__DEBRACKET term \
|
||||
))
|
||||
|
||||
/**
|
||||
* @brief Call macro @p F on each provided argument, with the argument's index
|
||||
* as an additional parameter.
|
||||
*
|
||||
* This is like FOR_EACH(), except @p F should be a macro which takes two
|
||||
* arguments: <tt>F(index, variable_arg)</tt>.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* #define F(idx, x) int a##idx = x
|
||||
* FOR_EACH_IDX(F, (;), 4, 5, 6);
|
||||
*
|
||||
* This expands to:
|
||||
*
|
||||
* int a0 = 4;
|
||||
* int a1 = 5;
|
||||
* int a2 = 6;
|
||||
*
|
||||
* @param F Macro to invoke
|
||||
* @param sep Separator (e.g. comma or semicolon). Must be in parentheses;
|
||||
* this is required to enable providing a comma as separator.
|
||||
* @param ... Variable argument list. The macro @p F is invoked as
|
||||
* <tt>F(index, element)</tt> for each element in the list.
|
||||
*/
|
||||
#define FOR_EACH_IDX(F, sep, ...) \
|
||||
Z_FOR_EACH_IDX(F, sep, REVERSE_ARGS(__VA_ARGS__))
|
||||
|
||||
/**
|
||||
* @brief Call macro @p F on each provided argument, with an additional fixed
|
||||
* argument as a parameter.
|
||||
*
|
||||
* This is like FOR_EACH(), except @p F should be a macro which takes two
|
||||
* arguments: <tt>F(variable_arg, fixed_arg)</tt>.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* static void func(int val, void *dev);
|
||||
* FOR_EACH_FIXED_ARG(func, (;), dev, 4, 5, 6);
|
||||
*
|
||||
* This expands to:
|
||||
*
|
||||
* func(4, dev);
|
||||
* func(5, dev);
|
||||
* func(6, dev);
|
||||
*
|
||||
* @param F Macro to invoke
|
||||
* @param sep Separator (e.g. comma or semicolon). Must be in parentheses;
|
||||
* this is required to enable providing a comma as separator.
|
||||
* @param fixed_arg Fixed argument passed to @p F as the second macro parameter.
|
||||
* @param ... Variable argument list. The macro @p F is invoked as
|
||||
* <tt>F(element, fixed_arg)</tt> for each element in the list.
|
||||
*/
|
||||
#define FOR_EACH_FIXED_ARG(F, sep, fixed_arg, ...) \
|
||||
Z_FOR_EACH_FIXED_ARG(F, sep, fixed_arg, REVERSE_ARGS(__VA_ARGS__))
|
||||
|
||||
/**
|
||||
* @brief Calls macro @p F for each variable argument with an index and fixed
|
||||
* argument
|
||||
*
|
||||
* This is like the combination of FOR_EACH_IDX() with FOR_EACH_FIXED_ARG().
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* #define F(idx, x, fixed_arg) int fixed_arg##idx = x
|
||||
* FOR_EACH_IDX_FIXED_ARG(F, (;), a, 4, 5, 6);
|
||||
*
|
||||
* This expands to:
|
||||
*
|
||||
* int a0 = 4;
|
||||
* int a1 = 5;
|
||||
* int a2 = 6;
|
||||
*
|
||||
* @param F Macro to invoke
|
||||
* @param sep Separator (e.g. comma or semicolon). Must be in parentheses;
|
||||
* This is required to enable providing a comma as separator.
|
||||
* @param fixed_arg Fixed argument passed to @p F as the third macro parameter.
|
||||
* @param ... Variable list of arguments. The macro @p F is invoked as
|
||||
* <tt>F(index, element, fixed_arg)</tt> for each element in
|
||||
* the list.
|
||||
*/
|
||||
#define FOR_EACH_IDX_FIXED_ARG(F, sep, fixed_arg, ...) \
|
||||
Z_FOR_EACH_IDX_FIXED_ARG(F, sep, fixed_arg, REVERSE_ARGS(__VA_ARGS__))
|
||||
|
||||
/** @brief Reverse arguments order.
|
||||
*
|
||||
* @param ... Variable argument list.
|
||||
*/
|
||||
#define REVERSE_ARGS(...) \
|
||||
Z_FOR_EACH_ENGINE(Z_FOR_EACH_EXEC, (,), Z_BYPASS, _, __VA_ARGS__)
|
||||
|
||||
/**
|
||||
* @brief Number of arguments in the variable arguments list minus one.
|
||||
*
|
||||
* @note Supports up to 64 arguments.
|
||||
*
|
||||
* @param ... List of arguments
|
||||
* @return Number of variadic arguments in the argument list, minus one
|
||||
*/
|
||||
#define NUM_VA_ARGS_LESS_1(...) \
|
||||
NUM_VA_ARGS_LESS_1_IMPL(__VA_ARGS__, 63, 62, 61, \
|
||||
60, 59, 58, 57, 56, 55, 54, 53, 52, 51, \
|
||||
50, 49, 48, 47, 46, 45, 44, 43, 42, 41, \
|
||||
40, 39, 38, 37, 36, 35, 34, 33, 32, 31, \
|
||||
30, 29, 28, 27, 26, 25, 24, 23, 22, 21, \
|
||||
20, 19, 18, 17, 16, 15, 14, 13, 12, 11, \
|
||||
10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, ~)
|
||||
|
||||
/**
|
||||
* @brief Number of arguments in the variable arguments list.
|
||||
*
|
||||
* @note Supports up to 63 arguments.
|
||||
*
|
||||
* @param ... List of arguments
|
||||
* @return Number of variadic arguments in the argument list
|
||||
*/
|
||||
#define NUM_VA_ARGS(...) \
|
||||
COND_CODE_1(IS_EMPTY(__VA_ARGS__), (0), (UTIL_INC(NUM_VA_ARGS_LESS_1(__VA_ARGS__))))
|
||||
|
||||
/**
|
||||
* @brief Mapping macro that pastes results together
|
||||
*
|
||||
* This is similar to FOR_EACH() in that it invokes a macro repeatedly
|
||||
* on each element of `__VA_ARGS__`. However, unlike FOR_EACH(),
|
||||
* MACRO_MAP_CAT() pastes the results together into a single token.
|
||||
*
|
||||
* For example, with this macro FOO:
|
||||
*
|
||||
* #define FOO(x) item_##x##_
|
||||
*
|
||||
* <tt>MACRO_MAP_CAT(FOO, a, b, c),</tt> expands to the token:
|
||||
*
|
||||
* item_a_item_b_item_c_
|
||||
*
|
||||
* @param ... Macro to expand on each argument, followed by its
|
||||
* arguments. (The macro should take exactly one argument.)
|
||||
* @return The results of expanding the macro on each argument, all pasted
|
||||
* together
|
||||
*/
|
||||
#define MACRO_MAP_CAT(...) MACRO_MAP_CAT_(__VA_ARGS__)
|
||||
|
||||
/**
|
||||
* @brief Mapping macro that pastes a fixed number of results together
|
||||
*
|
||||
* Similar to @ref MACRO_MAP_CAT(), but expects a fixed number of
|
||||
* arguments. If more arguments are given than are expected, the rest
|
||||
* are ignored.
|
||||
*
|
||||
* @param N Number of arguments to map
|
||||
* @param ... Macro to expand on each argument, followed by its
|
||||
* arguments. (The macro should take exactly one argument.)
|
||||
* @return The results of expanding the macro on each argument, all pasted
|
||||
* together
|
||||
*/
|
||||
#define MACRO_MAP_CAT_N(N, ...) MACRO_MAP_CAT_N_(N, __VA_ARGS__)
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* ZEPHYR_INCLUDE_SYS_UTIL_MACROS_H_ */
|
||||
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: The Zephyr Project Contributors
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @brief UTF-8 utilities
|
||||
*
|
||||
* Misc UTF-8 utilities.
|
||||
*/
|
||||
|
||||
#ifndef ZEPHYR_INCLUDE_SYS_UTIL_UFT8_H_
|
||||
#define ZEPHYR_INCLUDE_SYS_UTIL_UFT8_H_
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @addtogroup sys-util
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Properly truncate a NULL-terminated UTF-8 string
|
||||
*
|
||||
* Take a NULL-terminated UTF-8 string and ensure that if the string has been
|
||||
* truncated (by setting the NULL terminator) earlier by other means, that
|
||||
* the string ends with a properly formatted UTF-8 character (1-4 bytes).
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* @code{.c}
|
||||
* char test_str[] = "€€€";
|
||||
* char trunc_utf8[8];
|
||||
*
|
||||
* printf("Original : %s\n", test_str); // €€€
|
||||
* strncpy(trunc_utf8, test_str, sizeof(trunc_utf8));
|
||||
* trunc_utf8[sizeof(trunc_utf8) - 1] = '\0';
|
||||
* printf("Bad : %s\n", trunc_utf8); // €€�
|
||||
* utf8_trunc(trunc_utf8);
|
||||
* printf("Truncated: %s\n", trunc_utf8); // €€
|
||||
* @endcode
|
||||
*
|
||||
* @param utf8_str NULL-terminated string
|
||||
*
|
||||
* @return Pointer to the @p utf8_str
|
||||
*/
|
||||
char *utf8_trunc(char *utf8_str);
|
||||
|
||||
/**
|
||||
* @brief Copies a UTF-8 encoded string from @p src to @p dst
|
||||
*
|
||||
* The resulting @p dst will always be NULL terminated if @p n is larger than 0,
|
||||
* and the @p dst string will always be properly UTF-8 truncated.
|
||||
*
|
||||
* @param dst The destination of the UTF-8 string.
|
||||
* @param src The source string
|
||||
* @param n The size of the @p dst buffer. Maximum number of characters copied
|
||||
* is @p n - 1. If 0 nothing will be done, and the @p dst will not be
|
||||
* NULL terminated.
|
||||
*
|
||||
* @return Pointer to the @p dst
|
||||
*/
|
||||
char *utf8_lcpy(char *dst, const char *src, size_t n);
|
||||
|
||||
/**
|
||||
* @brief Counts the characters in a UTF-8 encoded string @p s
|
||||
*
|
||||
* Counts the number of UTF-8 characters (code points) in a null-terminated string.
|
||||
* This function steps through each UTF-8 sequence by checking leading byte patterns.
|
||||
* It does not fully validate UTF-8 correctness, only counts characters.
|
||||
*
|
||||
* @param s The input string
|
||||
*
|
||||
* @return Number of UTF-8 characters in @p s on success or (negative) error code
|
||||
* otherwise.
|
||||
*/
|
||||
int utf8_count_chars(const char *s);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
#endif /* ZEPHYR_INCLUDE_SYS_UTIL_UFT8_H_ */
|
||||
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2010-2014 Wind River Systems, Inc.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "esp_compiler.h"
|
||||
|
||||
#include <zephyr/types.h>
|
||||
#include <zephyr/sys/atomic.h>
|
||||
|
||||
#define SYS_INIT(init_fn, level, prio) int init_fn ## _v2(void) { return init_fn(); }
|
||||
|
||||
#ifndef BUILD_ASSERT
|
||||
#define BUILD_ASSERT(EXPR, MSG...) _Static_assert(EXPR, ## MSG)
|
||||
#endif
|
||||
|
||||
#ifndef _DO_CONCAT
|
||||
#define _DO_CONCAT(x, y) x ## y
|
||||
#endif
|
||||
|
||||
#ifndef _CONCAT
|
||||
#define _CONCAT(x, y) _DO_CONCAT(x, y)
|
||||
#endif
|
||||
|
||||
#ifndef ARG_UNUSED
|
||||
#define ARG_UNUSED(x) (void)(x)
|
||||
#endif
|
||||
|
||||
#ifndef __fallthrough
|
||||
#define __fallthrough __attribute__((fallthrough))
|
||||
#endif
|
||||
|
||||
#ifndef __packed
|
||||
#define __packed __attribute__((__packed__))
|
||||
#endif
|
||||
|
||||
#ifndef _LIB_ONLY
|
||||
#define _LIB_ONLY /* Used to mark functions only used by BLE Audio LIB */
|
||||
#endif
|
||||
|
||||
#ifndef _IDF_ONLY
|
||||
#define _IDF_ONLY /* Used to mark functions only used by BLE Audio IDF */
|
||||
#endif
|
||||
|
||||
#ifndef _LIB_IDF
|
||||
#define _LIB_IDF /* Used to mark functions used by BLE Audio LIB and IDF */
|
||||
#endif
|
||||
|
||||
#ifndef _NOT_USED
|
||||
#define _NOT_USED /* Used to mark functions currently not used */
|
||||
#endif
|
||||
|
||||
static inline unsigned int find_msb_set(uint32_t op)
|
||||
{
|
||||
if (op == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 32 - __builtin_clz(op);
|
||||
}
|
||||
|
||||
static inline unsigned int find_lsb_set(uint32_t op)
|
||||
{
|
||||
return __builtin_ffs(op);
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
/* Dummy file just for compiling */
|
||||
Reference in New Issue
Block a user