esp-nimble-cpp 2.4.0
Loading...
Searching...
No Matches
NimBLEStream.h
1/*
2 * Copyright 2020-2025 Ryan Powell <ryan@nable-embedded.io> and
3 * esp-nimble-cpp, NimBLE-Arduino contributors.
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18#ifndef NIMBLE_CPP_STREAM_H
19#define NIMBLE_CPP_STREAM_H
20
21#include "syscfg/syscfg.h"
22#if CONFIG_BT_NIMBLE_ENABLED && (MYNEWT_VAL(BLE_ROLE_PERIPHERAL) || MYNEWT_VAL(BLE_ROLE_CENTRAL))
23
24# if defined(CONFIG_NIMBLE_CPP_IDF)
25# include "nimble/nimble_npl.h"
26# else
27# include "nimble/nimble/include/nimble/nimble_npl.h"
28# endif
29
30# include <functional>
31# include <type_traits>
32# include <cstdarg>
33
34# if NIMBLE_CPP_ARDUINO_STRING_AVAILABLE
35# include <Stream.h>
36# else
37
38// Minimal Stream/Print stubs when Arduino not available
39class Print {
40 public:
41 virtual ~Print() {}
42 virtual size_t write(uint8_t) = 0;
43 virtual size_t write(const uint8_t* buffer, size_t size) = 0;
44 size_t print(const char* s);
45 size_t println(const char* s);
46 size_t printf(const char* format, ...) __attribute__((format(printf, 2, 3)));
47};
48
49class Stream : public Print {
50 public:
51 virtual int available() = 0;
52 virtual int read() = 0;
53 virtual int peek() = 0;
54 virtual void flush() {}
55 void setTimeout(unsigned long timeout) { m_timeout = timeout; }
56 unsigned long getTimeout() const { return m_timeout; }
57
58 protected:
59 unsigned long m_timeout{0};
60};
61# endif
62
63class NimBLEStream : public Stream {
64 public:
65 enum RxOverflowAction {
66 DROP_OLDER_DATA, // Drop older buffered data to make room for new data
67 DROP_NEW_DATA // Drop new incoming data when buffer is full
68 };
69
70 using RxOverflowCallback = std::function<RxOverflowAction(const uint8_t* data, size_t len, void* userArg)>;
71
72 NimBLEStream() = default;
73 virtual ~NimBLEStream() { end(); }
74
75 // Print/Stream TX methods
76 virtual size_t write(const uint8_t* data, size_t len) override;
77 virtual size_t write(uint8_t data) override { return write(&data, 1); }
78
79 // Template for other integral types (char, int, long, etc.)
80 template <typename T>
81 typename std::enable_if<std::is_integral<T>::value && !std::is_same<T, uint8_t>::value, size_t>::type write(T data) {
82 return write(static_cast<uint8_t>(data));
83 }
84
85 size_t availableForWrite() const;
86
87 // Read up to len bytes into buffer (non-blocking)
88 size_t read(uint8_t* buffer, size_t len);
89
90 // Stream RX methods
91 virtual int available() override;
92 virtual int read() override;
93 virtual int peek() override;
94 virtual bool ready() const = 0;
95
101 void setRxOverflowCallback(RxOverflowCallback cb, void* userArg = nullptr) {
102 m_rxOverflowCallback = cb;
103 m_rxOverflowUserArg = userArg;
104 }
105
106 operator bool() const { return ready(); }
107
108 using Print::write;
109
110 struct ByteRingBuffer;
111
112 protected:
113 bool begin();
114 void drainTx();
115 size_t pushRx(const uint8_t* data, size_t len);
116 virtual void end();
117 virtual bool send() = 0;
118 static void txDrainEventCb(struct ble_npl_event* ev);
119 static void txDrainCalloutCb(struct ble_npl_event* ev);
120
121 ByteRingBuffer* m_txBuf{nullptr};
122 ByteRingBuffer* m_rxBuf{nullptr};
123 uint8_t m_txChunkBuf[MYNEWT_VAL(BLE_ATT_PREFERRED_MTU)];
124 uint32_t m_txBufSize{1024};
125 uint32_t m_rxBufSize{1024};
126 ble_npl_event m_txDrainEvent{};
127 ble_npl_callout m_txDrainCallout{};
128 RxOverflowCallback m_rxOverflowCallback{nullptr};
129 void* m_rxOverflowUserArg{nullptr};
130 bool m_coInitialized{false};
131 bool m_eventInitialized{false};
132};
133
134# if MYNEWT_VAL(BLE_ROLE_PERIPHERAL)
135# include "NimBLECharacteristic.h"
136
137class NimBLEStreamServer : public NimBLEStream {
138 public:
139 NimBLEStreamServer() : m_charCallbacks(this) {}
140 ~NimBLEStreamServer() override { end(); }
141
142 // non-copyable
143 NimBLEStreamServer(const NimBLEStreamServer&) = delete;
144 NimBLEStreamServer& operator=(const NimBLEStreamServer&) = delete;
145
146 bool begin(NimBLECharacteristic* chr, uint32_t txBufSize = 1024, uint32_t rxBufSize = 1024);
147
148 // Convenience overload to create service/characteristic internally; service will be deleted on end()
149 bool begin(const NimBLEUUID& svcUuid,
150 const NimBLEUUID& chrUuid,
151 uint32_t txBufSize = 1024,
152 uint32_t rxBufSize = 1024,
153 bool secure = false);
154
155 void end() override;
156 size_t write(const uint8_t* data, size_t len) override;
157 uint16_t getPeerHandle() const { return m_charCallbacks.m_peerHandle; }
158 void setCallbacks(NimBLECharacteristicCallbacks* pCallbacks) { m_charCallbacks.m_userCallbacks = pCallbacks; }
159 bool ready() const override;
160 virtual void flush() override;
161
162 using NimBLEStream::write; // Inherit template write overloads
163
164 protected:
165 bool send() override;
166
167 struct ChrCallbacks : public NimBLECharacteristicCallbacks {
168 ChrCallbacks(NimBLEStreamServer* parent)
169 : m_parent(parent), m_userCallbacks(nullptr), m_peerHandle(BLE_HS_CONN_HANDLE_NONE) {}
170 void onWrite(NimBLECharacteristic* pCharacteristic, NimBLEConnInfo& connInfo) override;
171 void onSubscribe(NimBLECharacteristic* pCharacteristic, NimBLEConnInfo& connInfo, uint16_t subValue) override;
172 void onStatus(NimBLECharacteristic* pCharacteristic, NimBLEConnInfo& connInfo, int code) override;
173 // override this to avoid recursion when debug logs are enabled
174 void onStatus(NimBLECharacteristic* pCharacteristic, int code) override {
175 if (m_userCallbacks != nullptr) {
176 m_userCallbacks->onStatus(pCharacteristic, code);
177 }
178 }
179
180 NimBLEStreamServer* m_parent;
181 NimBLECharacteristicCallbacks* m_userCallbacks;
182 uint16_t m_peerHandle;
183 } m_charCallbacks;
184
185 NimBLECharacteristic* m_pChr{nullptr};
186 int m_rc{0};
187 // Whether to delete the BLE service when end() is called; set to false if service is managed externally
188 bool m_deleteSvcOnEnd{false};
189};
190# endif // BLE_ROLE_PERIPHERAL
191
192# if MYNEWT_VAL(BLE_ROLE_CENTRAL)
193# include "NimBLERemoteCharacteristic.h"
194
195class NimBLEStreamClient : public NimBLEStream {
196 public:
197 NimBLEStreamClient() = default;
198 ~NimBLEStreamClient() override { end(); }
199
200 // non-copyable
201 NimBLEStreamClient(const NimBLEStreamClient&) = delete;
202 NimBLEStreamClient& operator=(const NimBLEStreamClient&) = delete;
203
204 // Attach a discovered remote characteristic; app owns discovery/connection.
205 // Set subscribeNotify=true to receive notifications into RX buffer.
206 bool begin(NimBLERemoteCharacteristic* pChr,
207 bool subscribeNotify = false,
208 uint32_t txBufSize = 1024,
209 uint32_t rxBufSize = 1024);
210 void end() override;
211 void setNotifyCallback(NimBLERemoteCharacteristic::notify_callback cb) { m_userNotifyCallback = cb; }
212 bool ready() const override;
213 virtual void flush() override;
214
215 using NimBLEStream::write; // Inherit template write overloads
216
217 protected:
218 bool send() override;
219 void notifyCallback(NimBLERemoteCharacteristic* pChar, uint8_t* pData, size_t len, bool isNotify);
220
221 NimBLERemoteCharacteristic* m_pChr{nullptr};
222 NimBLERemoteCharacteristic::notify_callback m_userNotifyCallback{nullptr};
223};
224# endif // BLE_ROLE_CENTRAL
225
226#endif // CONFIG_BT_NIMBLE_ENABLED && (MYNEWT_VAL(BLE_ROLE_PERIPHERAL) || MYNEWT_VAL(BLE_ROLE_CENTRAL))
227#endif // NIMBLE_CPP_STREAM_H
Connection information.
Definition NimBLEConnInfo.h:33
A model of a BLE UUID.
Definition NimBLEUUID.h:41