aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Bluetooth.cpp22
-rw-r--r--Bluetooth.h21
-rw-r--r--ByteBuffer.cpp84
-rw-r--r--ByteBuffer.h52
-rw-r--r--CMakeLists.txt5
-rw-r--r--LinuxBluetooth.cpp30
-rw-r--r--log.h17
-rw-r--r--test/ByteBufferTest.cpp63
8 files changed, 193 insertions, 101 deletions
diff --git a/Bluetooth.cpp b/Bluetooth.cpp
index dd9e48e..f589d1f 100644
--- a/Bluetooth.cpp
+++ b/Bluetooth.cpp
@@ -1,7 +1,8 @@
+#include "Bluetooth.h"
+
#include <sstream>
#include <iomanip>
#include <string.h>
-#include "Bluetooth.h"
namespace trygvis {
using namespace std;
@@ -86,26 +87,31 @@ namespace trygvis {
AttPduType t = (AttPduType) bytes.get8();
if (t != type) {
- throw BluetoothException("Unexpected type: " + t);
+ throw BluetoothException("Unexpected type: " + to_string(t));
}
}
vector<AttributeData> AttPdu::parseReadByGroupType(ByteBuffer &bytes) {
+ DF;
+
checkType(bytes, READ_BY_GROUP_TYPE_RES);
if (bytes.getSize() < 4) {
- throw BluetoothException("Bad READ_BY_GROUP_TYPE_RES packet, expected at least 4 octets, got " + bytes.getSize());
+ throw BluetoothException("Bad READ_BY_GROUP_TYPE_RES packet, expected at least 4 octets, got " + to_string(bytes.getSize()));
}
uint8_t length = bytes.get8();
- DF << "length=" << (int) length;
+ D << "length=" << (int) length;
size_t count = (bytes.getSize() - 2) / length;
- DF << "count=" << count;
+ D << "count=" << count;
vector<AttributeData> values;
for (int i = 0; i < count; i++) {
- values.push_back(AttributeData::fromByteBuffer(bytes, length));
+ auto data = bytes.view(length);
+ D << "data, size=" << data.getSize() << ", bytes=" << data.toString();
+ bytes.skip(length);
+ values.push_back(AttributeData::fromByteBuffer(data));
}
return values;
@@ -115,11 +121,11 @@ namespace trygvis {
// AttributeData
// -----------------------------------------------------------------------
- AttributeData AttributeData::fromByteBuffer(ByteBuffer &bytes, uint8_t length) {
+ AttributeData AttributeData::fromByteBuffer(ByteBuffer &bytes) {
uint16_t handle = bytes.get16le();
uint16_t groupEndHandle = bytes.get16le();
- return AttributeData(handle, groupEndHandle, bytes.view(length));
+ return AttributeData(handle, groupEndHandle, bytes.view());
}
AttributeData::AttributeData(uint16_t handle, uint16_t groupEndHandle, ByteBuffer value) :
diff --git a/Bluetooth.h b/Bluetooth.h
index 15ef171..7bc5bc3 100644
--- a/Bluetooth.h
+++ b/Bluetooth.h
@@ -5,20 +5,9 @@
#include <stdexcept>
// For now
-#include <boost/log/core.hpp>
-#include <boost/log/trivial.hpp>
-#include "ByteBuffer.h"
-
-#define D BOOST_LOG_TRIVIAL(debug)
-#define I BOOST_LOG_TRIVIAL(info)
-#define W BOOST_LOG_TRIVIAL(warning)
+#include "log.h"
-#define DF BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << ": "
-#define IF BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ": "
-#define WF BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << ": "
-
-#define UUID_PRIMARY_SERVICE 0x2800
-#define UUID_SECONDARY_SERVICE 0x2801
+#include "ByteBuffer.h"
namespace trygvis {
using namespace std;
@@ -91,9 +80,11 @@ namespace trygvis {
virtual ~BluetoothAdapter();
+ virtual void runScan(void (callback)(BluetoothDevice &device)) = 0;
+
virtual void stopScan() = 0;
- virtual void runScan(void (callback)(BluetoothDevice &device)) = 0;
+ virtual void startScan() = 0;
virtual BluetoothDevice &getDevice(Mac& mac) = 0;
};
@@ -128,7 +119,7 @@ namespace trygvis {
public:
~AttributeData();
- static AttributeData fromByteBuffer(ByteBuffer &value, uint8_t length);
+ static AttributeData fromByteBuffer(ByteBuffer &value);
const uint16_t handle;
const uint16_t groupEndHandle;
diff --git a/ByteBuffer.cpp b/ByteBuffer.cpp
index f27deeb..c5f7905 100644
--- a/ByteBuffer.cpp
+++ b/ByteBuffer.cpp
@@ -1,5 +1,4 @@
#include "ByteBuffer.h"
-#include <stdint-gcc.h>
#include <string.h>
#include <sstream>
#include <iomanip>
@@ -7,75 +6,96 @@
using namespace std;
-ByteBuffer::ByteBuffer(uint8_t *bytes, size_t capacity, size_t size, size_t zero) :
- bytes(bytes), capacity(capacity), size(size), cursor(zero), zero(zero) {
+ByteBuffer::ByteBuffer(uint8_t *bytes, size_t capacity) :
+ bytes(bytes), capacity(capacity), zero(&bytes[0]), end(&bytes[capacity]) {
+ ptr = &bytes[0];
+}
+
+ByteBuffer::ByteBuffer(uint8_t *bytes, size_t capacity, size_t zero, size_t size) :
+ bytes(bytes), capacity(capacity), zero(&bytes[0]), end(&bytes[size]) {
assert(zero <= size);
+ assert(size <= capacity);
+ ptr = &bytes[0];
+}
+
+ByteBuffer::ByteBuffer(const uint8_t *bytes, size_t capacity, uint8_t *zero, uint8_t *end) :
+ bytes(bytes), capacity(capacity), zero(zero), end(end), ptr(zero) {
}
ByteBuffer &ByteBuffer::add8(uint8_t value) {
- checkAndUpdateSize(1);
- bytes[zero + cursor++] = value;
+ checkAndUpdateEnd(1);
+ (*ptr++) = value;
return *this;
}
ByteBuffer &ByteBuffer::add16le(uint16_t value) {
- checkAndUpdateSize(2);
- bytes[zero + cursor++] = (uint8_t) (value & 0xff);
- bytes[zero + cursor++] = (uint8_t) ((value >> 8) & 0xff);
+ checkAndUpdateEnd(2);
+ (*ptr++) = (uint8_t) (value & 0xff);
+ (*ptr++) = (uint8_t) ((value >> 8) & 0xff);
return *this;
}
uint8_t ByteBuffer::get8(size_t index) {
- canAccessIndex(index);
- return bytes[zero + cursor];
+ assertCanAccessRelative(index);
+ return *ptr++;
}
uint8_t ByteBuffer::get8() {
- canAccessIndex(cursor);
- return bytes[zero + cursor++];
+ assertCanAccessRelative(1);
+ return *ptr++;
}
uint16_t ByteBuffer::get16le() {
- canAccessIndex(cursor + 1);
+ assertCanAccessRelative(1);
uint16_t value;
- value = bytes[zero + cursor++];
- value |= ((uint16_t) bytes[zero + cursor++]) << 8;
+ value = *ptr++;
+ value |= ((uint16_t) *ptr++) << 8;
return value;
}
void ByteBuffer::copy(uint8_t *bytes, size_t length) {
- canAccessIndex(cursor + length);
+ assertCanAccessRelative(length);
- memcpy(bytes, &this->bytes[zero + cursor], length);
- cursor += length;
+ memcpy(bytes, ptr, length);
+ ptr += length;
}
-ByteBuffer ByteBuffer::view(size_t length) {
- canAccessIndex(cursor + length);
- size_t s = zero + cursor + length;
- return ByteBuffer(bytes, s, s, cursor);
+ByteBuffer ByteBuffer::view() const {
+ DF << "cursor=" << getCursor() << ", size=" << getSize();
+ return view(end - ptr);
}
-void ByteBuffer::checkAndUpdateSize(size_t newBytes) {
- size_t newSize = zero + cursor + newBytes;
- if (newSize >= capacity) {
- throw ByteBufferException(string("Out of bounds! zero=") + to_string(zero) + ", cursor=" + to_string(cursor) + ", size=" + to_string(size) + ", capacity=" + to_string(capacity) + ", newSize=" + to_string(newSize));
+ByteBuffer ByteBuffer::view(size_t length) const {
+ assertCanAccessRelative(length);
+ return ByteBuffer(bytes, length, ptr, ptr + length);
+}
+
+void ByteBuffer::checkAndUpdateEnd(size_t newBytes) {
+ uint8_t *newPtr = ptr + newBytes;
+ if (newPtr >= end) {
+ throw ByteBufferException(string("New size is too large! cursor=") + to_string(getCursor()) + ", size=" + to_string(getSize()) + ", capacity=" + to_string(capacity));
+ }
+
+ if (newPtr > end) {
+ end = newPtr;
}
+}
- size = max(newSize, size);
+void ByteBuffer::assertCanAccessRelative(size_t diff) const {
+ assertCanAccessIndex(ptr + diff - 1);
}
-void ByteBuffer::canAccessIndex(size_t index) {
- if (zero + index >= size) {
- throw ByteBufferException(string("Out of bounds! zero=") + to_string(zero) + ", index=" + to_string(index) + ", size=" + to_string(size));
+void ByteBuffer::assertCanAccessIndex(uint8_t *p) const {
+ if (p >= end || p < zero) {
+ throw ByteBufferException(string("Out of bounds! size=") + to_string(getSize()));
}
}
std::string ByteBuffer::toString() const {
stringstream s;
- for(size_t i = zero; i < size; i++) {
- s << hex << setfill('0') << setw(2) << (int) bytes[i] << " ";
+ for (uint8_t *i = (uint8_t *) zero; i < end; i++) {
+ s << hex << setfill('0') << setw(2) << (int) *i << " ";
}
return string(s.str());
diff --git a/ByteBuffer.h b/ByteBuffer.h
index 828ee4b..ee54a0a 100644
--- a/ByteBuffer.h
+++ b/ByteBuffer.h
@@ -6,6 +6,9 @@
#include <string>
#include <stdexcept>
+// For now
+#include "log.h"
+
class ByteBufferException : public std::runtime_error {
public:
ByteBufferException(std::string const &what) : std::runtime_error(what) {
@@ -14,22 +17,31 @@ public:
class ByteBuffer {
public:
- ByteBuffer(uint8_t *bytes, size_t capacity, size_t size, size_t zero = 0);
+ ByteBuffer(uint8_t *bytes, size_t capacity);
+
+ ByteBuffer(uint8_t *bytes, size_t capacity, size_t zero, size_t size);
- inline size_t getSize() {
- return size;
+ inline size_t getSize() const {
+ DF << "end=" << (uint64_t)end << ", zero=" << (uint64_t)zero;
+ return end - zero;
}
- inline size_t getCapacity() {
+ inline size_t getCapacity() const {
return capacity;
}
- inline size_t getCursor() {
- return cursor;
+ inline size_t getCursor() const {
+ return ptr - zero;
}
inline void setCursor(size_t newCursor) {
- cursor = newCursor;
+ assertCanAccessRelative(newCursor);
+ ptr = ptr + newCursor;
+ }
+
+ inline void skip(size_t length) {
+ checkAndUpdateEnd(length);
+ ptr += length;
}
ByteBuffer &add8(uint8_t value);
@@ -44,20 +56,30 @@ public:
void copy(uint8_t *bytes, size_t length);
- ByteBuffer view(size_t length);
+ /**
+ * Creates a view from cursor to size.
+ */
+ ByteBuffer view() const;
+
+ // TODO: should return const
+ ByteBuffer view(size_t length) const;
std::string toString() const;
private:
- void checkAndUpdateSize(size_t count);
+ ByteBuffer(const uint8_t *bytes, size_t capacity, uint8_t *zero, uint8_t *end);
+
+ void checkAndUpdateEnd(size_t count);
+
+ void assertCanAccessRelative(size_t diff) const;
- void canAccessIndex(size_t count);
+ void assertCanAccessIndex(uint8_t *p) const;
- uint8_t *bytes;
- size_t zero;
- size_t size;
- size_t capacity;
- size_t cursor;
+ const uint8_t *bytes;
+ const size_t capacity;
+ const uint8_t *zero;
+ const uint8_t *end;
+ uint8_t *ptr;
};
#endif
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 1220f20..0f2cbf2 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -26,7 +26,7 @@ target_link_libraries(ble_toys ${Boost_LIBRARIES})
target_link_libraries(ble_toys ble)
enable_testing()
-find_package(Boost COMPONENTS unit_test_framework REQUIRED)
+find_package(Boost COMPONENTS log unit_test_framework REQUIRED)
file(GLOB TEST_SRCS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} test/*.cpp)
foreach(testSrc ${TEST_SRCS})
@@ -39,8 +39,9 @@ foreach(testSrc ${TEST_SRCS})
include_directories(${PROJECT_SOURCE_DIR})
#link to Boost libraries AND your targets and dependencies
- target_link_libraries(${testName} ${Boost_LIBRARIES})
target_link_libraries(${testName} ble)
+ target_link_libraries(${testName} pthread)
+ target_link_libraries(${testName} ${Boost_LIBRARIES})
#I like to move testing binaries into a testBin directory
set_target_properties(${testName} PROPERTIES
diff --git a/LinuxBluetooth.cpp b/LinuxBluetooth.cpp
index c30a2b7..1399161 100644
--- a/LinuxBluetooth.cpp
+++ b/LinuxBluetooth.cpp
@@ -1,3 +1,5 @@
+#include "Bluetooth.h"
+
#include <string.h>
#include <stropts.h>
#include <sys/select.h>
@@ -10,8 +12,6 @@
#include <sstream>
#include <iomanip>
-#include "Bluetooth.h"
-
// Got to love magic constants. Taken from bluez.git/tools/btgatt-client.c
#define ATT_CID 4
@@ -31,14 +31,15 @@ namespace trygvis {
~LinuxBluetoothAdapter();
- void runScan(void (*callback)(BluetoothDevice &device));
+ void runScan(void (*callback)(BluetoothDevice &device)) override;
BluetoothDevice &getDevice(Mac &mac) override;
- private:
- void startScan();
+ void startScan() override;
- void stopScan();
+ void stopScan() override;
+
+ private:
int hciDeviceId;
int hciSocket;
@@ -151,7 +152,7 @@ namespace trygvis {
DF;
uint8_t buffer[MAX_MTU];
- ByteBuffer out = ByteBuffer(buffer, MAX_MTU, 0);
+ ByteBuffer out = ByteBuffer(buffer, MAX_MTU);
AttPdu::makeReadByGroupType(out, 0x0001, 0xffff, UUID_PRIMARY_SERVICE);
@@ -161,9 +162,14 @@ namespace trygvis {
D << "written=" << written;
ssize_t r = read(l2cap, buffer, MAX_MTU);
- ByteBuffer in = ByteBuffer(buffer, MAX_MTU, r);
- D << "read: " << r << " bytes";
+ if (r == -1) {
+ throw BluetoothException(this, "read(): " + errnoAsString());
+ }
+
+ ByteBuffer in = ByteBuffer(buffer, r);
+
+ D << "read: " << r << " bytes: " << in.toString();
vector<AttributeData> values = AttPdu::parseReadByGroupType(in);
@@ -188,7 +194,7 @@ namespace trygvis {
D << "HCI socket: " << hciSocket;
if (hciSocket == -1) {
- throw BluetoothException(this, "Could not open HCI device " + hciDeviceId);
+ throw BluetoothException(this, "Could not open HCI device " + to_string(hciDeviceId));
}
hci_filter_clear(&hciFilter);
@@ -212,7 +218,7 @@ namespace trygvis {
struct hci_dev_info di;
if (hci_devinfo(hciDeviceId, &di) < 0) {
- throw BluetoothException(this, "hci_devinfo: " + hciDeviceId);
+ throw BluetoothException(this, "hci_devinfo: " + to_string(hciDeviceId));
}
D << "hciDeviceId.dev_id=" << di.dev_id;
@@ -227,7 +233,7 @@ namespace trygvis {
int up = hci_test_bit(HCI_UP, &di.flags);
if (!up) {
- throw BluetoothException(this, "HCI adapter is not up: " + hciDeviceId);
+ throw BluetoothException(this, "HCI adapter is not up: " + to_string(hciDeviceId));
}
if (hci_le_set_scan_parameters(hciSocket, 0x01, htobs(0x0010), htobs(0x0010), 0x00, 0, 1000) < 0) {
diff --git a/log.h b/log.h
new file mode 100644
index 0000000..dcfe83e
--- /dev/null
+++ b/log.h
@@ -0,0 +1,17 @@
+#ifndef LOG_H
+#define LOG_H
+
+#include <boost/log/core.hpp>
+#include <boost/log/trivial.hpp>
+#define D BOOST_LOG_TRIVIAL(debug)
+#define I BOOST_LOG_TRIVIAL(info)
+#define W BOOST_LOG_TRIVIAL(warning)
+
+#define DF BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << ": "
+#define IF BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ": "
+#define WF BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << ": "
+
+#define UUID_PRIMARY_SERVICE 0x2800
+#define UUID_SECONDARY_SERVICE 0x2801
+
+#endif
diff --git a/test/ByteBufferTest.cpp b/test/ByteBufferTest.cpp
index f98a770..d6e45f7 100644
--- a/test/ByteBufferTest.cpp
+++ b/test/ByteBufferTest.cpp
@@ -6,21 +6,36 @@
#define BOOST_TEST_MODULE "ByteBuffer"
#include <boost/test/unit_test.hpp>
+#include "Bluetooth.h"
-void checkBuffer(ByteBuffer& buffer, size_t size, size_t capacity, size_t cursor) {
- BOOST_CHECK(buffer.getSize() == size);
- BOOST_CHECK(buffer.getCapacity() == capacity);
- BOOST_CHECK(buffer.getCursor() == cursor);
-}
+#define checkBuffer(buffer, size, capacity, cursor) \
+ D << "size=" << buffer.getSize() << ", capacity=" << buffer.getCapacity() << ", cursor=" << buffer.getCursor(); \
+ BOOST_REQUIRE_EQUAL(buffer.getSize(), size); \
+ BOOST_REQUIRE_EQUAL(buffer.getCapacity(), capacity); \
+ BOOST_REQUIRE_EQUAL(buffer.getCursor(), cursor)
-BOOST_AUTO_TEST_CASE(empty_buffer) {
- uint8_t bytes[1000];
+class Bytes {
+public:
+ Bytes(size_t size) : capacity(size) {
+ _bytes = new uint8_t[size + 0x100];
- for (int i = 0; i < sizeof(bytes); i++) {
- bytes[i] = (uint8_t) i;
+ bytes = (uint8_t *) (((uint64_t) &_bytes[0x100]) & 0xffffffffffffff00);
+
+ for (int i = 0; i < size; i++) {
+ bytes[i] = (uint8_t) i;
+ }
+ }
+ ~Bytes() {
+ delete _bytes;
}
+ uint8_t *bytes;
+ uint8_t *_bytes;
+ size_t capacity;
+};
- ByteBuffer buffer(bytes, sizeof(bytes), 0, 0);
+BOOST_AUTO_TEST_CASE(empty_buffer) {
+ Bytes b(1000);
+ ByteBuffer buffer(b.bytes, b.capacity, 0, 0);
checkBuffer(buffer, 0, 1000, 0);
@@ -32,15 +47,29 @@ BOOST_AUTO_TEST_CASE(empty_buffer) {
}
BOOST_AUTO_TEST_CASE(basic) {
- uint8_t bytes[1000];
-
- for (int i = 0; i < sizeof(bytes); i++) {
- bytes[i] = (uint8_t) i;
- }
-
- ByteBuffer buffer(bytes, sizeof(bytes), 10, 0);
+ Bytes b(1000);
+ ByteBuffer buffer(b.bytes, 1000, 0, 10);
checkBuffer(buffer, 10, 1000, 0);
buffer.get8();
checkBuffer(buffer, 10, 1000, 1);
}
+
+BOOST_AUTO_TEST_CASE(view) {
+ Bytes b(1000);
+ ByteBuffer buffer(b.bytes, b.capacity, 0, 10);
+
+ BOOST_REQUIRE_EQUAL(buffer.get8(), 0);
+// checkBuffer(buffer, 10, 1000, 1);
+
+ ByteBuffer view1 = buffer.view();
+ checkBuffer(view1, 9, 9, 0);
+
+ BOOST_REQUIRE_EQUAL(view1.get8(), 1);
+ BOOST_REQUIRE_EQUAL(view1.get8(), 2);
+
+ ByteBuffer view2 = view1.view();
+ checkBuffer(view2, 7, 7, 0);
+
+ BOOST_REQUIRE_EQUAL(view1.get8(), 3);
+}