From 095d93bd11cd48a88d64b8729f6039a487a3600d Mon Sep 17 00:00:00 2001 From: ShenWeilong Date: Fri, 27 Mar 2026 19:56:34 +0800 Subject: [PATCH] feat(nimble): Added npl for btdm sofware arch --- nimble/host/src/ble_hs.c | 2 +- nimble/host/src/ble_hs_periodic_sync.c | 3 +- porting/nimble/include/os/endian.h | 113 ++- porting/nimble/include/os/os_mbuf.h | 650 +++++++++++++++++- porting/npl/esp-idf/README.md | 2 + .../esp-idf/include/nimble/nimble_npl_os.h | 318 +++++++++ .../include/nimble/nimble_port_freertos.h | 26 + .../npl/esp-idf/src/nimble_port_freertos.c | 83 +++ 8 files changed, 1170 insertions(+), 27 deletions(-) create mode 100644 porting/npl/esp-idf/README.md create mode 100644 porting/npl/esp-idf/include/nimble/nimble_npl_os.h create mode 100644 porting/npl/esp-idf/include/nimble/nimble_port_freertos.h create mode 100644 porting/npl/esp-idf/src/nimble_port_freertos.c diff --git a/nimble/host/src/ble_hs.c b/nimble/host/src/ble_hs.c index b0aa535a0..ca7377093 100644 --- a/nimble/host/src/ble_hs.c +++ b/nimble/host/src/ble_hs.c @@ -715,7 +715,7 @@ ble_hs_enqueue_hci_event(uint8_t *hci_evt) ev = os_memblock_get(&ble_hs_hci_ev_pool); - if (ev && ble_hs_evq->eventq) { + if (ev) { memset (ev, 0, sizeof *ev); ble_npl_event_init(ev, ble_hs_event_rx_hci_ev, hci_evt); ble_npl_eventq_put(ble_hs_evq, ev); diff --git a/nimble/host/src/ble_hs_periodic_sync.c b/nimble/host/src/ble_hs_periodic_sync.c index c13684181..88a04506d 100644 --- a/nimble/host/src/ble_hs_periodic_sync.c +++ b/nimble/host/src/ble_hs_periodic_sync.c @@ -104,8 +104,7 @@ ble_hs_periodic_sync_free(struct ble_hs_periodic_sync *psync) return; } - if ((psync->lost_ev).event != NULL) - ble_npl_event_deinit(&psync->lost_ev); + ble_npl_event_deinit(&psync->lost_ev); #if MYNEWT_VAL(BLE_HS_DEBUG) memset(psync, 0xff, sizeof *psync); diff --git a/porting/nimble/include/os/endian.h b/porting/nimble/include/os/endian.h index cc95f653c..f1aa342c8 100644 --- a/porting/nimble/include/os/endian.h +++ b/porting/nimble/include/os/endian.h @@ -207,6 +207,117 @@ extern "C" { #endif #if SOC_ESP_NIMBLE_CONTROLLER && CONFIG_BT_CONTROLLER_ENABLED +#if CONFIG_BT_DUAL_MODE_ARCH +#include "btdm_endian.h" + +static inline void +put_le16(void *buf, uint16_t x) +{ + btdm_put_le16(buf, x); +} + +static inline void +put_le24(void *buf, uint32_t x) +{ + btdm_put_le24(buf, x); +} + +static inline void +put_le32(void *buf, uint32_t x) +{ + btdm_put_le32(buf, x); +} + +static inline void +put_le64(void *buf, uint64_t x) +{ + btdm_put_le64(buf, x); +} + +static inline uint16_t +get_le16(const void *buf) +{ + return btdm_get_le16(buf); +} + +static inline uint32_t +get_le24(const void *buf) +{ + return btdm_get_le24(buf); +} + +static inline uint32_t +get_le32(const void *buf) +{ + return btdm_get_le32(buf); +} + +static inline uint64_t +get_le64(const void *buf) +{ + return btdm_get_le64(buf); +} + +static inline void +put_be16(void *buf, uint16_t x) +{ + btdm_put_be16(buf, x); +} + +static inline void +put_be24(void *buf, uint32_t x) +{ + btdm_put_be24(buf, x); +} + +static inline void +put_be32(void *buf, uint32_t x) +{ + btdm_put_be32(buf, x); +} + +static inline void +put_be64(void *buf, uint64_t x) +{ + btdm_put_be64(buf, x); +} + +static inline uint16_t +get_be16(const void *buf) +{ + return btdm_get_be16(buf); +} + +static inline uint32_t +get_be24(const void *buf) +{ + return btdm_get_be24(buf); +} + +static inline uint32_t +get_be32(const void *buf) +{ + return btdm_get_be32(buf); +} + +static inline uint64_t +get_be64(const void *buf) +{ + return btdm_get_be64(buf); +} + +static inline void +swap_in_place(void *buf, int len) +{ + btdm_swap_in_place(buf, len); +} + +static inline void +swap_buf(uint8_t *dst, const uint8_t *src, int len) +{ + btdm_swap_buf(dst, src, len); +} +#else // CONFIG_BT_DUAL_MODE_ARCH void r_put_le16(void *buf, uint16_t x); #define put_le16 r_put_le16 @@ -260,7 +371,7 @@ void r_swap_in_place(void *buf, int len); void r_swap_buf(uint8_t *dst, const uint8_t *src, int len); #define swap_buf r_swap_buf - +#endif // CONFIG_BT_DUAL_MODE_ARCH #else void put_le16(void *buf, uint16_t x); diff --git a/porting/nimble/include/os/os_mbuf.h b/porting/nimble/include/os/os_mbuf.h index 83e16c4cb..5775c526e 100644 --- a/porting/nimble/include/os/os_mbuf.h +++ b/porting/nimble/include/os/os_mbuf.h @@ -182,24 +182,24 @@ struct os_mqueue { /** @cond INTERNAL_HIDDEN */ +#if SOC_ESP_NIMBLE_CONTROLLER && CONFIG_BT_CONTROLLER_ENABLED +#if CONFIG_BT_DUAL_MODE_ARCH +#include "ble_mbuf.h" + +/* Reuse the controller's APIs. Make sure that we have the same structure. */ +static_assert(sizeof(struct os_mbuf_pool) == sizeof(struct ble_mbuf_pool), + "Error: size of os_mbuf_pool"); +static_assert(sizeof(struct os_mbuf_pkthdr) == sizeof(struct ble_mbuf_pkthdr), + "Error: size of os_mbuf_pkthdr"); +static_assert(sizeof(struct os_mbuf) == sizeof(struct ble_mbuf), "Error: size of os_mbuf"); + /* * Called by OS_MBUF_LEADINGSPACE() macro */ static inline uint16_t _os_mbuf_leadingspace(struct os_mbuf *om) { - uint16_t startoff; - uint16_t leadingspace; - - startoff = 0; - if (OS_MBUF_IS_PKTHDR(om)) { - startoff = om->om_pkthdr_len; - } - - leadingspace = (uint16_t) (OS_MBUF_DATA(om, uint8_t *) - - ((uint8_t *) &om->om_databuf[0] + startoff)); - - return (leadingspace); + return _ble_mbuf_leadingspace((struct ble_mbuf *)om); } /** @endcond */ @@ -216,19 +216,11 @@ _os_mbuf_leadingspace(struct os_mbuf *om) */ #define OS_MBUF_LEADINGSPACE(__om) _os_mbuf_leadingspace(__om) - -/** @cond INTERNAL_HIDDEN */ - /* Called by OS_MBUF_TRAILINGSPACE() macro. */ static inline uint16_t _os_mbuf_trailingspace(struct os_mbuf *om) { - struct os_mbuf_pool *omp; - - omp = om->om_omp; - - return (&om->om_databuf[0] + omp->omp_databuf_len) - - (om->om_data + om->om_len); + return _ble_mbuf_trailingspace((struct ble_mbuf *)om); } /** @endcond */ @@ -244,8 +236,557 @@ _os_mbuf_trailingspace(struct os_mbuf *om) */ #define OS_MBUF_TRAILINGSPACE(__om) _os_mbuf_trailingspace(__om) +/** + * MSYS is a system level mbuf registry. Allows the system to share + * packet buffers amongst the various networking stacks that can be running + * simultaeneously. + * + * Mbuf pools are created in the system initialization code, and then when + * a mbuf is allocated out of msys, it will try and find the best fit based + * upon estimated mbuf size. + * + * os_msys_register() registers a mbuf pool with MSYS, and allows MSYS to + * allocate mbufs out of it. + * + * @param new_pool The pool to register with MSYS + * + * @return 0 on success, non-zero on failure + */ +static inline int +os_msys_register(struct os_mbuf_pool *mp) +{ + return ble_msys_register((struct ble_mbuf_pool *)mp); +} + +/** + * Allocate a mbuf from msys. Based upon the data size requested, + * os_msys_get() will choose the mbuf pool that has the best fit. + * + * @param dsize The estimated size of the data being stored in the mbuf + * @param leadingspace The amount of leadingspace to allocate in the mbuf + * + * @return A freshly allocated mbuf on success, NULL on failure. + */ +static inline struct os_mbuf * +os_msys_get(uint16_t dsize, uint16_t leadingspace) +{ + return (struct os_mbuf *)ble_msys_get(dsize, leadingspace); +} + +/** + * De-registers all mbuf pools from msys. + */ +static inline void +os_msys_reset(void) +{ + ble_msys_reset(); +} + +/** + * Allocate a packet header structure from the MSYS pool. See + * os_msys_register() for a description of MSYS. + * + * @param dsize The estimated size of the data being stored in the mbuf + * @param user_hdr_len The length to allocate for the packet header structure + * + * @return A freshly allocated mbuf on success, NULL on failure. + */ +static inline struct os_mbuf * +os_msys_get_pkthdr(uint16_t dsize, uint16_t user_hdr_len) +{ + return (struct os_mbuf *)ble_msys_get_pkthdr(dsize, user_hdr_len); +} + +/** + * Count the number of blocks in all the mbuf pools that are allocated. + * + * @return total number of blocks allocated in Msys + */ +static inline int +os_msys_count(void) +{ + return ble_msys_count(); +} + +/** + * Return the number of free blocks in Msys + * + * @return Number of free blocks available in Msys + */ +static inline int +os_msys_num_free(void) +{ + return ble_msys_num_free(); +} + +/** + * Initialize a pool of mbufs. + * + * @param omp The mbuf pool to initialize + * @param mp The memory pool that will hold this mbuf pool + * @param buf_len The length of the buffer itself. + * @param nbufs The number of buffers in the pool + * + * @return 0 on success, error code on failure. + */ +static inline int +os_mbuf_pool_init(struct os_mbuf_pool *omp, struct os_mempool *mp, uint16_t buf_len, + uint16_t nbufs) +{ + return ble_mbuf_pool_init((struct ble_mbuf_pool *)omp, (struct btdm_mempool *)mp, buf_len, + nbufs); +} + +/** + * Get an mbuf from the mbuf pool. The mbuf is allocated, and initialized + * prior to being returned. + * + * @param omp The mbuf pool to return the packet from + * @param leadingspace The amount of leadingspace to put before the data + * section by default. + * + * @return An initialized mbuf on success, and NULL on failure. + */ +static inline struct os_mbuf * +os_mbuf_get(struct os_mbuf_pool *omp, uint16_t leadingspace) +{ + return(struct os_mbuf *)ble_mbuf_get((struct ble_mbuf_pool *)omp, leadingspace); +} + +/** + * Allocate a new packet header mbuf out of the os_mbuf_pool. + * + * @param omp The mbuf pool to allocate out of + * @param user_pkthdr_len The packet header length to reserve for the caller. + * + * @return A freshly allocated mbuf on success, NULL on failure. + */ +static inline struct os_mbuf * +os_mbuf_get_pkthdr(struct os_mbuf_pool *omp, uint8_t user_pkthdr_len) +{ + return (struct os_mbuf *)ble_mbuf_get_pkthdr((struct ble_mbuf_pool *)omp, user_pkthdr_len); +} + +/** + * Duplicate a chain of mbufs. Return the start of the duplicated chain. + * + * @param omp The mbuf pool to duplicate out of + * @param om The mbuf chain to duplicate + * + * @return A pointer to the new chain of mbufs + */ +static inline struct os_mbuf * +os_mbuf_dup(struct os_mbuf *m) +{ + return (struct os_mbuf *)ble_mbuf_dup((struct ble_mbuf *)m); +} + +/** + * Locates the specified absolute offset within an mbuf chain. The offset + * can be one past than the total length of the chain, but no greater. + * + * @param om The start of the mbuf chain to seek within. + * @param off The absolute address to find. + * @param out_off On success, this points to the relative offset + * within the returned mbuf. + * + * @return The mbuf containing the specified offset on + * success. + * NULL if the specified offset is out of bounds. + */ +static inline struct os_mbuf * +os_mbuf_off(const struct os_mbuf *om, int off, uint16_t *out_off) +{ + return (struct os_mbuf *)ble_mbuf_off((struct ble_mbuf *)om, off, out_off); +} + +/* + * Copy data from an mbuf chain starting "off" bytes from the beginning, + * continuing for "len" bytes, into the indicated buffer. + * + * @param m The mbuf chain to copy from + * @param off The offset into the mbuf chain to begin copying from + * @param len The length of the data to copy + * @param dst The destination buffer to copy into + * + * @return 0 on success; + * -1 if the mbuf does not contain enough data. + */ +static inline int +os_mbuf_copydata(const struct os_mbuf *m, int off, int len, void *dst) +{ + return ble_mbuf_copydata((struct ble_mbuf *)m, off, len, dst); +} + +/** + * @brief Calculates the length of an mbuf chain. + * + * Calculates the length of an mbuf chain. If the mbuf contains a packet + * header, you should use `OS_MBUF_PKTLEN()` as a more efficient alternative to + * this function. + * + * @param om The mbuf to measure. + * + * @return The length, in bytes, of the provided mbuf + * chain. + */ +static inline uint16_t +os_mbuf_len(const struct os_mbuf *om) +{ + return ble_mbuf_len((struct ble_mbuf *)om); +} + +/** + * Append data onto a mbuf + * + * @param om The mbuf to append the data onto + * @param data The data to append onto the mbuf + * @param len The length of the data to append + * + * @return 0 on success, and an error code on failure + */ +static inline int +os_mbuf_append(struct os_mbuf *m, const void *data, uint16_t len) +{ + return ble_mbuf_append((struct ble_mbuf *)m, data, len); +} + +/** + * Reads data from one mbuf and appends it to another. On error, the specified + * data range may be partially appended. Neither mbuf is required to contain + * an mbuf packet header. + * + * @param dst The mbuf to append to. + * @param src The mbuf to copy data from. + * @param src_off The absolute offset within the source mbuf + * chain to read from. + * @param len The number of bytes to append. + * + * @return 0 on success; + * OS_EINVAL if the specified range extends beyond + * the end of the source mbuf chain. + */ +static inline int +os_mbuf_appendfrom(struct os_mbuf *dst, const struct os_mbuf *src, uint16_t src_off, + uint16_t len) +{ + return ble_mbuf_appendfrom((struct ble_mbuf *)dst, (struct ble_mbuf *)src, src_off, len); +} +/** + * Release a mbuf back to the pool + * + * @param mb The Mbuf to release back to the pool + * + * @return 0 on success, -1 on failure + */ +static inline int +os_mbuf_free(struct os_mbuf *mb) +{ + return ble_mbuf_free((struct ble_mbuf *)mb); +} +/** + * Free a chain of mbufs + * + * @param om The starting mbuf of the chain to free back into the pool + * + * @return 0 on success, -1 on failure + */ +static inline int +os_mbuf_free_chain(struct os_mbuf *om) +{ + return ble_mbuf_free_chain((struct ble_mbuf *)om); +} + +/** + * Adjust the length of a mbuf, trimming either from the head or the tail + * of the mbuf. + * + * @param mp The mbuf chain to adjust + * @param req_len The length to trim from the mbuf. If positive, trims + * from the head of the mbuf, if negative, trims from the + * tail of the mbuf. + */ +static inline void +os_mbuf_adj(struct os_mbuf *mp, int req_len) +{ + ble_mbuf_adj((struct ble_mbuf *)mp, req_len); +} + +/** + * Performs a memory compare of the specified region of an mbuf chain against a + * flat buffer. + * + * @param om The start of the mbuf chain to compare. + * @param off The offset within the mbuf chain to start the + * comparison. + * @param data The flat buffer to compare. + * @param len The length of the flat buffer. + * + * @return 0 if both memory regions are identical; + * A memcmp return code if there is a mismatch; + * INT_MAX if the mbuf is too short. + */ +static inline int +os_mbuf_cmpf(const struct os_mbuf *om, int off, const void *data, int len) +{ + return ble_mbuf_cmpf((struct ble_mbuf *)om, off, data, len); +} + +/** + * Compares the contents of two mbuf chains. The ranges of the two chains to + * be compared are specified via the two offset parameters and the len + * parameter. Neither mbuf chain is required to contain a packet header. + * + * @param om1 The first mbuf chain to compare. + * @param offset1 The absolute offset within om1 at which to + * start the comparison. + * @param om2 The second mbuf chain to compare. + * @param offset2 The absolute offset within om2 at which to + * start the comparison. + * @param len The number of bytes to compare. + * + * @return 0 if both mbuf segments are identical; + * A memcmp() return code if the segment contents + * differ; + * INT_MAX if a specified range extends beyond the + * end of its corresponding mbuf chain. + */ +static inline int +os_mbuf_cmpm(const struct os_mbuf *om1, uint16_t offset1, const struct os_mbuf *om2, + uint16_t offset2, uint16_t len) +{ + return ble_mbuf_cmpm((struct ble_mbuf *)om1, offset1, (struct ble_mbuf *)om2, offset2, len); +} + +/** + * Increases the length of an mbuf chain by adding data to the front. If there + * is insufficient room in the leading mbuf, additional mbufs are allocated and + * prepended as necessary. If this function fails to allocate an mbuf, the + * entire chain is freed. + * + * The specified mbuf chain does not need to contain a packet header. + * + * @param omp The mbuf pool to allocate from. + * @param om The head of the mbuf chain. + * @param len The number of bytes to prepend. + * + * @return The new head of the chain on success; + * NULL on failure. + */ +static inline struct os_mbuf * +os_mbuf_prepend(struct os_mbuf *om, int len) +{ + return (struct os_mbuf *)ble_mbuf_prepend((struct ble_mbuf *)om, len); +} + +/** + * Prepends a chunk of empty data to the specified mbuf chain and ensures the + * chunk is contiguous. If either operation fails, the specified mbuf chain is + * freed and NULL is returned. + * + * @param om The mbuf chain to prepend to. + * @param len The number of bytes to prepend and pullup. + * + * @return The modified mbuf on success; + * NULL on failure (and the mbuf chain is freed). + */ +static inline struct os_mbuf * +os_mbuf_prepend_pullup(struct os_mbuf *om, uint16_t len) +{ + return (struct os_mbuf *)ble_mbuf_prepend_pullup((struct ble_mbuf *)om, len); +} + +/** + * Copies the contents of a flat buffer into an mbuf chain, starting at the + * specified destination offset. If the mbuf is too small for the source data, + * it is extended as necessary. If the destination mbuf contains a packet + * header, the header length is updated. + * + * @param om The mbuf chain to copy into. + * @param off The offset within the chain to copy to. + * @param src The source buffer to copy from. + * @param len The number of bytes to copy. + * + * @return 0 on success; nonzero on failure. + */ +static inline int +os_mbuf_copyinto(struct os_mbuf *om, int off, const void *src, int len) +{ + return ble_mbuf_copyinto((struct ble_mbuf *)om, off, src, len); +} + +/** + * Attaches a second mbuf chain onto the end of the first. If the first chain + * contains a packet header, the header's length is updated. If the second + * chain has a packet header, its header is cleared. + * + * @param first The mbuf chain being attached to. + * @param second The mbuf chain that gets attached. + */ +static inline void +os_mbuf_concat(struct os_mbuf *first, struct os_mbuf *second) +{ + ble_mbuf_concat((struct ble_mbuf *)first, (struct ble_mbuf *)second); +} + +/** + * Increases the length of an mbuf chain by the specified amount. If there is + * not sufficient room in the last buffer, a new buffer is allocated and + * appended to the chain. It is an error to request more data than can fit in + * a single buffer. + * + * @param om The head of the chain to extend. + * @param len The number of bytes to extend by. + * + * @return A pointer to the new data on success; + * NULL on failure. + */ +static inline void * +os_mbuf_extend(struct os_mbuf *om, uint16_t len) +{ + return ble_mbuf_extend((struct ble_mbuf *)om, len); +} + +/** + * Rearrange a mbuf chain so that len bytes are contiguous, + * and in the data area of an mbuf (so that OS_MBUF_DATA() will + * work on a structure of size len.) Returns the resulting + * mbuf chain on success, free's it and returns NULL on failure. + * + * If there is room, it will add up to "max_protohdr - len" + * extra bytes to the contiguous region, in an attempt to avoid being + * called next time. + * + * @param om The mbuf chain to make contiguous + * @param len The number of bytes in the chain to make contiguous + * + * @return The contiguous mbuf chain on success, NULL on failure. + */ +static inline struct os_mbuf * +os_mbuf_pullup(struct os_mbuf *om, uint16_t len) +{ + return (struct os_mbuf *)ble_mbuf_pullup((struct ble_mbuf *)om, len); +} + +/** + * Removes and frees empty mbufs from the front of a chain. If the chain + * contains a packet header, it is preserved. + * + * @param om The mbuf chain to trim. + * + * @return The head of the trimmed mbuf chain. + */ +static inline struct os_mbuf * +os_mbuf_trim_front(struct os_mbuf *om) +{ + return (struct os_mbuf *)ble_mbuf_trim_front((struct ble_mbuf *)om); +} + +/** + * Increases the length of an mbuf chain by inserting a gap at the specified + * offset. The contents of the gap are indeterminate. If the mbuf chain + * contains a packet header, its total length is increased accordingly. + * + * This function never frees the provided mbuf chain. + * + * @param om The mbuf chain to widen. + * @param off The offset at which to insert the gap. + * @param len The size of the gap to insert. + * + * @return 0 on success; SYS_[...] error code on failure. + */ +static inline int +os_mbuf_widen(struct os_mbuf *om, uint16_t off, uint16_t len) +{ + return ble_mbuf_widen((struct ble_mbuf *)om, off, len); +} + +/** + * Creates a single chained mbuf from m1 and m2 utilizing all + * the available buffer space in all mbufs in the resulting + * chain. In other words, ensures there is no leading space in + * any mbuf in the resulting chain and trailing space only in + * the last mbuf in the chain. Mbufs from either chain may be + * freed if not needed. No mbufs are allocated. Note that mbufs + * from m2 are added to the end of m1. If m1 has a packet + * header, it is retained and length updated. If m2 has a packet + * header it is discarded. If m1 is NULL, NULL is returned and + * m2 is left untouched. + * + * @param m1 Pointer to first mbuf chain to pack + * @param m2 Pointer to second mbuf chain to pack + * + * @return struct os_mbuf* Pointer to resulting mbuf chain + */ +static inline struct os_mbuf * +os_mbuf_pack_chains(struct os_mbuf *m1, struct os_mbuf *m2) +{ + return (struct os_mbuf *)ble_mbuf_pack_chains((struct ble_mbuf *)m1, (struct ble_mbuf *)m2); +} +#else // CONFIG_BT_DUAL_MODE_ARCH + +/* + * Called by OS_MBUF_LEADINGSPACE() macro + */ + static inline uint16_t + _os_mbuf_leadingspace(struct os_mbuf *om) + { + uint16_t startoff; + uint16_t leadingspace; + + startoff = 0; + if (OS_MBUF_IS_PKTHDR(om)) { + startoff = om->om_pkthdr_len; + } + + leadingspace = (uint16_t) (OS_MBUF_DATA(om, uint8_t *) - + ((uint8_t *) &om->om_databuf[0] + startoff)); + + return (leadingspace); + } + + /** @endcond */ + + /** + * Returns the leading space (space at the beginning) of the mbuf. + * Works on both packet header, and regular mbufs, as it accounts + * for the additional space allocated to the packet header. + * + * @param __omp Is the mbuf pool (which contains packet header length.) + * @param __om Is the mbuf in that pool to get the leadingspace for + * + * @return Amount of leading space available in the mbuf + */ + #define OS_MBUF_LEADINGSPACE(__om) _os_mbuf_leadingspace(__om) + + + /** @cond INTERNAL_HIDDEN */ + + /* Called by OS_MBUF_TRAILINGSPACE() macro. */ + static inline uint16_t + _os_mbuf_trailingspace(struct os_mbuf *om) + { + struct os_mbuf_pool *omp; + + omp = om->om_omp; + + return (&om->om_databuf[0] + omp->omp_databuf_len) - + (om->om_data + om->om_len); + } + + /** @endcond */ + + /** + * Returns the trailing space (space at the end) of the mbuf. + * Works on both packet header and regular mbufs. + * + * @param __omp The mbuf pool for this mbuf + * @param __om Is the mbuf in that pool to get trailing space for + * + * @return The amount of trailing space available in the mbuf + */ + #define OS_MBUF_TRAILINGSPACE(__om) _os_mbuf_trailingspace(__om) -#if SOC_ESP_NIMBLE_CONTROLLER && CONFIG_BT_CONTROLLER_ENABLED /** * Initializes an mqueue. An mqueue is a queue of mbufs that ties to a * particular task's event queue. Mqueues form a helper API around a common @@ -704,8 +1245,71 @@ int r_os_mbuf_widen(struct os_mbuf *om, uint16_t off, uint16_t len); */ struct os_mbuf *r_os_mbuf_pack_chains(struct os_mbuf *m1, struct os_mbuf *m2); #define os_mbuf_pack_chains r_os_mbuf_pack_chains - +#endif // CONFIG_BT_DUAL_MODE_ARCH #else + +/* + * Called by OS_MBUF_LEADINGSPACE() macro + */ + static inline uint16_t + _os_mbuf_leadingspace(struct os_mbuf *om) + { + uint16_t startoff; + uint16_t leadingspace; + + startoff = 0; + if (OS_MBUF_IS_PKTHDR(om)) { + startoff = om->om_pkthdr_len; + } + + leadingspace = (uint16_t) (OS_MBUF_DATA(om, uint8_t *) - + ((uint8_t *) &om->om_databuf[0] + startoff)); + + return (leadingspace); + } + + /** @endcond */ + + /** + * Returns the leading space (space at the beginning) of the mbuf. + * Works on both packet header, and regular mbufs, as it accounts + * for the additional space allocated to the packet header. + * + * @param __omp Is the mbuf pool (which contains packet header length.) + * @param __om Is the mbuf in that pool to get the leadingspace for + * + * @return Amount of leading space available in the mbuf + */ + #define OS_MBUF_LEADINGSPACE(__om) _os_mbuf_leadingspace(__om) + + + /** @cond INTERNAL_HIDDEN */ + + /* Called by OS_MBUF_TRAILINGSPACE() macro. */ + static inline uint16_t + _os_mbuf_trailingspace(struct os_mbuf *om) + { + struct os_mbuf_pool *omp; + + omp = om->om_omp; + + return (&om->om_databuf[0] + omp->omp_databuf_len) - + (om->om_data + om->om_len); + } + + /** @endcond */ + + /** + * Returns the trailing space (space at the end) of the mbuf. + * Works on both packet header and regular mbufs. + * + * @param __omp The mbuf pool for this mbuf + * @param __om Is the mbuf in that pool to get trailing space for + * + * @return The amount of trailing space available in the mbuf + */ + #define OS_MBUF_TRAILINGSPACE(__om) _os_mbuf_trailingspace(__om) + /** * Initializes an mqueue. An mqueue is a queue of mbufs that ties to a * particular task's event queue. Mqueues form a helper API around a common diff --git a/porting/npl/esp-idf/README.md b/porting/npl/esp-idf/README.md new file mode 100644 index 000000000..a07740c10 --- /dev/null +++ b/porting/npl/esp-idf/README.md @@ -0,0 +1,2 @@ +This Nimble Porting Layer is used for ESP32 series chips (e.g. ESP32-H4 and new chips). +and NOT applicable to ESP32/ESP32-C3/ESP32-S3/ESP32-C2 (refer to npl/freertos). \ No newline at end of file diff --git a/porting/npl/esp-idf/include/nimble/nimble_npl_os.h b/porting/npl/esp-idf/include/nimble/nimble_npl_os.h new file mode 100644 index 000000000..1dd307173 --- /dev/null +++ b/porting/npl/esp-idf/include/nimble/nimble_npl_os.h @@ -0,0 +1,318 @@ +/* + * SPDX-FileCopyrightText: 2015-2022 The Apache Software Foundation (ASF) + * + * SPDX-License-Identifier: Apache-2.0 + * + * SPDX-FileContributor: 2025 Espressif Systems (Shanghai) CO LTD + */ + +#ifndef _NIMBLE_NPL_OS_H_ +#define _NIMBLE_NPL_OS_H_ + +#include +#include "btdm_osal.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef ARRAY_SIZE +#define ARRAY_SIZE(array) \ + (sizeof(array) / sizeof((array)[0])) +#endif + +#define BLE_NPL_OS_ALIGNMENT (4) /*ble_npl_get_os_alignment()*/ + +#define BLE_NPL_TIME_FOREVER portMAX_DELAY + +/* This should be compatible with TickType_t */ +typedef uint32_t ble_npl_time_t; +typedef int32_t ble_npl_stime_t; + +struct ble_npl_event { + struct btdm_osal_event event; +}; + +struct ble_npl_eventq { + struct btdm_osal_eventq eventq; +}; + +struct ble_npl_callout { + struct btdm_osal_callout co; +}; + +struct ble_npl_mutex { + struct btdm_osal_mutex mutex; +}; + +struct ble_npl_sem { + struct btdm_osal_sem sem; +}; + +/* + * Simple APIs are just defined as static inline below, but some are a bit more + * complex or require some global state variables and thus are defined in .c + * file instead and static inline wrapper just calls proper implementation. + * We need declarations of these functions and they are defined in header below. + */ +static inline bool +ble_npl_os_started(void) +{ + return xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED; +} + +static inline void * +ble_npl_get_current_task_id(void) +{ + return xTaskGetCurrentTaskHandle(); +} + +static inline void +ble_npl_eventq_init(struct ble_npl_eventq *evq) +{ + return btdm_osal_eventq_init(&evq->eventq); +} + +static inline void +ble_npl_eventq_deinit(struct ble_npl_eventq *evq) +{ + return btdm_osal_eventq_deinit(&evq->eventq); +} + +static inline struct ble_npl_event * +ble_npl_eventq_get(struct ble_npl_eventq *evq, ble_npl_time_t tmo) +{ + return (void *)btdm_osal_eventq_get(&evq->eventq, tmo) - offsetof(struct ble_npl_eventq, eventq); +} + +static inline void +ble_npl_eventq_put(struct ble_npl_eventq *evq, struct ble_npl_event *ev) +{ + btdm_osal_eventq_put(&evq->eventq, &ev->event); +} + +static inline void +ble_npl_eventq_remove(struct ble_npl_eventq *evq, struct ble_npl_event *ev) +{ + btdm_osal_eventq_remove(&evq->eventq, &ev->event); +} + +static inline void +ble_npl_event_run(struct ble_npl_event *ev) +{ + btdm_osal_event_run((struct btdm_osal_event *)ev); +} + +static inline bool +ble_npl_eventq_is_empty(struct ble_npl_eventq *evq) +{ + return btdm_osal_eventq_is_empty(&evq->eventq); +} + +static inline void +ble_npl_event_init(struct ble_npl_event *ev, ble_npl_event_fn *fn, void *arg) +{ + btdm_osal_event_init(&ev->event, (btdm_osal_event_fn *)fn, arg); +} +static inline void +ble_npl_event_deinit(struct ble_npl_event *ev) +{ + btdm_osal_event_deinit(&ev->event); +} + +static inline void +ble_npl_event_reset(struct ble_npl_event *ev) +{ + btdm_osal_event_reset(&ev->event); +} + +static inline bool +ble_npl_event_is_queued(struct ble_npl_event *ev) +{ + return btdm_osal_event_is_queued(&ev->event); +} + +static inline void * +ble_npl_event_get_arg(struct ble_npl_event *ev) +{ + return btdm_osal_event_get_arg(&ev->event); +} + +static inline void +ble_npl_event_set_arg(struct ble_npl_event *ev, void *arg) +{ + return btdm_osal_event_set_arg(&ev->event, arg); +} + +static inline ble_npl_error_t +ble_npl_mutex_init(struct ble_npl_mutex *mu) +{ + return btdm_osal_mutex_init(&mu->mutex); +} + +static inline ble_npl_error_t +ble_npl_mutex_deinit(struct ble_npl_mutex *mu) +{ + return btdm_osal_mutex_deinit(&mu->mutex); +} + +static inline ble_npl_error_t +ble_npl_mutex_pend(struct ble_npl_mutex *mu, ble_npl_time_t timeout) +{ + return btdm_osal_mutex_pend(&mu->mutex, timeout); +} + +static inline ble_npl_error_t +ble_npl_mutex_release(struct ble_npl_mutex *mu) +{ + return btdm_osal_mutex_release(&mu->mutex); +} + +static inline ble_npl_error_t +ble_npl_sem_init(struct ble_npl_sem *sem, uint16_t tokens) +{ + return btdm_osal_sem_init(&sem->sem, tokens); +} + +static inline ble_npl_error_t +ble_npl_sem_deinit(struct ble_npl_sem *sem) +{ + return btdm_osal_sem_deinit(&sem->sem); +} + +static inline ble_npl_error_t +ble_npl_sem_pend(struct ble_npl_sem *sem, ble_npl_time_t timeout) +{ + return btdm_osal_sem_pend(&sem->sem, timeout); +} + +static inline ble_npl_error_t +ble_npl_sem_release(struct ble_npl_sem *sem) +{ + return btdm_osal_sem_release(&sem->sem); +} + +static inline uint16_t +ble_npl_sem_get_count(struct ble_npl_sem *sem) +{ + return btdm_osal_sem_get_count(&sem->sem); +} + +static inline int +ble_npl_callout_init(struct ble_npl_callout *co, struct ble_npl_eventq *evq, + ble_npl_event_fn *ev_cb, void *ev_arg) +{ + return btdm_osal_callout_init(&co->co, &evq->eventq, (btdm_osal_event_fn *)ev_cb, ev_arg); +} + +static inline void +ble_npl_callout_deinit(struct ble_npl_callout *co) +{ + return btdm_osal_callout_deinit(&co->co); +} + +static inline ble_npl_error_t +ble_npl_callout_reset(struct ble_npl_callout *co, ble_npl_time_t ticks) +{ + return btdm_osal_callout_reset(&co->co, ticks); +} + +static inline void +ble_npl_callout_stop(struct ble_npl_callout *co) +{ + return btdm_osal_callout_stop(&co->co); +} + +static inline bool +ble_npl_callout_is_active(struct ble_npl_callout *co) +{ + return btdm_osal_callout_is_active(&co->co); +} + +static inline ble_npl_time_t +ble_npl_callout_get_ticks(struct ble_npl_callout *co) +{ + return btdm_osal_callout_get_ticks(&co->co); +} + +static inline ble_npl_time_t +ble_npl_callout_remaining_ticks(struct ble_npl_callout *co, ble_npl_time_t time) +{ + return btdm_osal_callout_remaining_ticks(&co->co, time); +} + +static inline void +ble_npl_callout_set_arg(struct ble_npl_callout *co, void *arg) +{ + return btdm_osal_callout_set_arg(&co->co, arg); +} + +static inline ble_npl_time_t +ble_npl_time_get(void) +{ + return btdm_osal_time_get(); +} + +static inline ble_npl_error_t +ble_npl_time_ms_to_ticks(uint32_t ms, ble_npl_time_t *out_ticks) +{ + return btdm_osal_time_ms_to_ticks(ms, out_ticks); +} + +static inline ble_npl_error_t +ble_npl_time_ticks_to_ms(ble_npl_time_t ticks, uint32_t *out_ms) +{ + return btdm_osal_time_ticks_to_ms(ticks, out_ms); +} + +static inline ble_npl_time_t +ble_npl_time_ms_to_ticks32(uint32_t ms) +{ + return btdm_osal_time_ms_to_ticks32(ms); +} + +static inline uint32_t +ble_npl_time_ticks_to_ms32(ble_npl_time_t ticks) +{ + return btdm_osal_time_ticks_to_ms32(ticks); +} + +static inline void +ble_npl_time_delay(ble_npl_time_t ticks) +{ + vTaskDelay(ticks); +} + +// #if NIMBLE_CFG_CONTROLLER +// static inline void +// ble_npl_hw_set_isr(int irqn, uint32_t addr) +// { +// return btdm_osal_hw_set_isr(irqn, addr); +// } +// #endif + +static inline uint32_t +ble_npl_hw_enter_critical(void) +{ + return btdm_osal_hw_enter_critical(); +} + +static inline void +ble_npl_hw_exit_critical(uint32_t ctx) +{ + btdm_osal_hw_exit_critical(ctx); +} + +static inline bool +ble_npl_hw_is_in_critical(void) +{ + return btdm_osal_hw_is_in_critical(); +} + +#ifdef __cplusplus +} +#endif + +#endif /* _NPL_H_ */ diff --git a/porting/npl/esp-idf/include/nimble/nimble_port_freertos.h b/porting/npl/esp-idf/include/nimble/nimble_port_freertos.h new file mode 100644 index 000000000..33e19eeff --- /dev/null +++ b/porting/npl/esp-idf/include/nimble/nimble_port_freertos.h @@ -0,0 +1,26 @@ +/* + * SPDX-FileCopyrightText: 2015-2022 The Apache Software Foundation (ASF) + * + * SPDX-License-Identifier: Apache-2.0 + * + * SPDX-FileContributor: 2025 Espressif Systems (Shanghai) CO LTD + */ + +#ifndef _NIMBLE_PORT_FREERTOS_H +#define _NIMBLE_PORT_FREERTOS_H + +#include "nimble/nimble_npl.h" + +#ifdef __cplusplus +extern "C" { +#endif + +void nimble_port_freertos_init(TaskFunction_t host_task_fn); + +void nimble_port_freertos_deinit(void); + +#ifdef __cplusplus +} +#endif + +#endif /* _NIMBLE_PORT_FREERTOS_H */ diff --git a/porting/npl/esp-idf/src/nimble_port_freertos.c b/porting/npl/esp-idf/src/nimble_port_freertos.c new file mode 100644 index 000000000..40ffca3a5 --- /dev/null +++ b/porting/npl/esp-idf/src/nimble_port_freertos.c @@ -0,0 +1,83 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "nimble/nimble_port.h" +#if CONFIG_BT_CONTROLLER_ENABLED +#include "esp_bt.h" +#endif + +static TaskHandle_t host_task_h = NULL; + +/** + * @brief esp_nimble_enable - Initialize the NimBLE host + * + * @param host_task + * @return esp_err_t + */ +esp_err_t esp_nimble_enable(void *host_task) +{ + /* + * Create task where NimBLE host will run. It is not strictly necessary to + * have separate task for NimBLE host, but since something needs to handle + * default queue it is just easier to make separate task which does this. + */ + xTaskCreatePinnedToCore(host_task, "nimble_host", NIMBLE_HS_STACK_SIZE, + NULL, (configMAX_PRIORITIES - 4), &host_task_h, NIMBLE_CORE); + return ESP_OK; + +} + +/** + * @brief esp_nimble_disable - Disable the NimBLE host + * + * @return esp_err_t + */ +esp_err_t esp_nimble_disable(void) +{ + if (host_task_h) { + vTaskDelete(host_task_h); + host_task_h = NULL; + } + return ESP_OK; +} + + +/** + * @brief nimble_port_freertos_init - Adapt to native nimble api + * + * @param host_task_fn + */ +void +nimble_port_freertos_init(TaskFunction_t host_task_fn) +{ + esp_nimble_enable(host_task_fn); +} + +/** + * @brief nimble_port_freertos_deinit - Adapt to native nimble api + * + */ +void +nimble_port_freertos_deinit(void) +{ + esp_nimble_disable(); +}